Modified CANDataGrid component to have two modes for better graphics,

updated version number and presentation on main window
This commit is contained in:
Collin Kidder
2021-09-06 20:34:11 -04:00
parent f752e84888
commit 935032477d
5 changed files with 263 additions and 120 deletions
+227 -114
View File
@@ -12,6 +12,8 @@ CANDataGrid::CANDataGrid(QWidget *parent) :
{
ui->setupUi(this);
gridMode = GridMode::CHANGED_BITS;
memset(data, 0, 8);
memset(refData, 0, 8);
memset(usedData, 0, 8);
@@ -19,6 +21,14 @@ CANDataGrid::CANDataGrid(QWidget *parent) :
for (int x = 0; x < 8; x++)
for (int y = 0; y < 8; y++)
textStates[x][y] = GridTextState::NORMAL;
blackBrush = QBrush(Qt::black);
whiteBrush = QBrush(Qt::white);
redBrush = QBrush(Qt::red);
greenBrush = QBrush(Qt::green);
greenHashBrush = QBrush(QColor(0, 0xB6, 0), Qt::BDiagPattern);
blackHashBrush = QBrush(QColor(0, 0, 0), Qt::FDiagPattern);
grayBrush = QBrush(QColor(230,230,230));
}
CANDataGrid::~CANDataGrid()
@@ -26,6 +36,16 @@ CANDataGrid::~CANDataGrid()
delete ui;
}
GridMode CANDataGrid::getMode()
{
return gridMode;
}
void CANDataGrid::setMode(GridMode mode)
{
gridMode = mode;
}
void CANDataGrid::mousePressEvent(QMouseEvent *event)
{
QPoint clickedPoint = event->pos();
@@ -95,17 +115,181 @@ int CANDataGrid::getUsedSignalNum(int bit)
return usedSignalNum[bit];
}
void CANDataGrid::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
qDebug() << "CANDataGrid Paint Event";
paintCommonBeginning();
if (gridMode == GridMode::CHANGED_BITS) paintChangedBits();
if (gridMode == GridMode::SIGNAL_VIEW) paintSignalView();
paintCommonEnding();
}
void CANDataGrid::paintCommonBeginning()
{
int x;
painter = new QPainter(this);
viewport = painter->viewport();
xSpan = viewport.right() - viewport.left();
ySpan = viewport.bottom() - viewport.top();
qDebug() << "XSpan" << xSpan << " YSpan " << ySpan;
xSector = xSpan / 9;
ySector = ySpan / 9;
//the whole thing is broken up into 81 chunks which are broken up
//into the 8x8 grid of bits in the bottom right and the other parts
//taken up by helper text
if (gridMode == GridMode::CHANGED_BITS)
{
bigTextSize = qMin(xSector, ySector) * 0.6;
smallTextSize = qMin(xSector, ySector) * 0.5;
}
if (gridMode == GridMode::SIGNAL_VIEW)
{
bigTextSize = qMin(xSector, ySector) * 0.5;
smallTextSize = qMin(xSector, ySector) * 0.25;
}
sigNameTextSize = qMin(xSector, ySector) * 0.19;
painter->setPen(QPen(QApplication::palette().color(QPalette::Text)));
mainFont.setPixelSize(bigTextSize);
painter->setFont(mainFont);
smallFont.setPixelSize(smallTextSize);
boldFont.setPixelSize(bigTextSize);
boldFont.setBold(true);
sigNameFont.setPixelSize(sigNameTextSize);
smallMetric = new QFontMetrics(sigNameFont);
painter->setFont(smallFont);
painter->drawText(QRect(viewport.left(), viewport.top(), xSector, ySector), Qt::AlignCenter, "BITS ->");
painter->setFont(boldFont);
for (x = 0; x < 8; x++)
{
painter->drawText(QRect(viewport.left() + (x+1) * xSector, viewport.top(), xSector, ySector), Qt::AlignCenter, QString::number(7-x));
}
//for (y = 0; y < 8; y++)
//{
// painter->drawText(QRect(viewport.left() + xSector, viewport.top() + ySector * (y + 2), xSector, ySector), Qt::AlignCenter, QString::number(y));
//}
painter->drawText(viewport.left() + 4, viewport.top() + ySector * 3, "B");
painter->drawText(viewport.left() + 4, viewport.top() + ySector * 4, "Y");
painter->drawText(viewport.left() + 4, viewport.top() + ySector * 5, "T");
painter->drawText(viewport.left() + 4, viewport.top() + ySector * 6, "E");
painter->drawText(viewport.left() + 4, viewport.top() + ySector * 7, "S");
painter->drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 1, xSector, ySector), Qt::AlignCenter, "0");
painter->drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 2, xSector, ySector), Qt::AlignCenter, "1");
painter->drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 3, xSector, ySector), Qt::AlignCenter, "2");
painter->drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 4, xSector, ySector), Qt::AlignCenter, "3");
painter->drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 5, xSector, ySector), Qt::AlignCenter, "4");
painter->drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 6, xSector, ySector), Qt::AlignCenter, "5");
painter->drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 7, xSector, ySector), Qt::AlignCenter, "6");
painter->drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 8, xSector, ySector), Qt::AlignCenter, "7");
painter->setPen(QPen(Qt::black));
painter->setFont(mainFont);
}
void CANDataGrid::paintChangedBits()
{
int x, y, bit;
unsigned char prevByte, thisByte;
bool thisBit, prevBit;
int usedSigNum;
QString prevSigName;
//now, color the bitfield by seeing if a given bit is freshly set/unset in the new data
//compared to the old. Bits that are not set in either are white, bits set in both are black
//bits that used to be set but now are unset are red, bits that used to be unset but now are set
//are green
for (y = 0; y < 8; y++)
{
thisByte = data[y];
prevByte = refData[y];
for (x = 0; x < 8; x++)
{
bit = (y * 8) + (7 - x);
thisBit = false;
prevBit = false;
if ((thisByte & (1 << (7-x))) == (1 << (7-x))) thisBit = true;
if ((prevByte & (1 << (7-x))) == (1 << (7-x))) prevBit = true;
if (thisBit)
{
if (prevBit)
{
painter->setBrush(blackBrush);
}
else
{
painter->setBrush(greenBrush);
}
}
else
{
if (prevBit)
{
painter->setBrush(redBrush);
}
else
{
usedSigNum = -1;
if ((usedData[y] & (1 << (7-x))) == (1 << (7-x)))
{
grayBrush = QBrush(QColor(0xB6, 0xB6, 0xB6), Qt::BDiagPattern);
painter->setBrush(grayBrush);
}
else painter->setBrush(whiteBrush);
}
}
//painter->fillRect(viewport.left() + (x+2) * xSector, viewport.top() + (y+2) * ySector, xSector, ySector, redBrush);
painter->drawRect(viewport.left() + (x+1) * xSector, viewport.top() + (y+1) * ySector, xSector, ySector);
switch (textStates[x][y])
{
case GridTextState::NORMAL:
if (thisBit && prevBit) painter->setPen(QPen(Qt::gray));
else painter->setPen(QPen(Qt::black));
painter->setFont(mainFont);
break;
case GridTextState::BOLD_BLUE:
painter->setPen(QPen(Qt::blue));
painter->setFont(boldFont);
break;
case GridTextState::INVERT:
painter->setFont(mainFont);
QColor brushColor = painter->brush().color();
painter->setPen(QColor(255-brushColor.red(), 255-brushColor.green(), 255-brushColor.blue()));
break;
}
//change style of bit number output for current signal
//if (thisBit) painter->setFont(boldFont);
// else painter->setFont(mainFont);
painter->setFont(smallFont);
painter->drawText(viewport.left() + (x+1) * xSector + (xSector / 3), viewport.top() + (y + 2) * ySector - (ySector * 0.4), QString::number(bit));
painter->setFont(mainFont);
painter->setPen(QPen(Qt::black));
}
}
}
void CANDataGrid::paintSignalView()
{
int x, y, bit;
unsigned char prevByte, thisByte;
bool thisBit, prevBit;
QBrush blackBrush, whiteBrush, redBrush, greenBrush, grayBrush;
QBrush greenHashBrush, blackHashBrush;
QPainter painter(this);
int usedSigNum;
QString prevSigName;
@@ -124,83 +308,6 @@ void CANDataGrid::paintEvent(QPaintEvent *event)
}
}
QRect viewport = painter.viewport();
int xSpan = viewport.right() - viewport.left();
int ySpan = viewport.bottom() - viewport.top();
qDebug() << "XSpan" << xSpan << " YSpan " << ySpan;
int xSector = xSpan / 9;
int ySector = ySpan / 9;
blackBrush = QBrush(Qt::black);
whiteBrush = QBrush(Qt::white);
redBrush = QBrush(Qt::red);
greenBrush = QBrush(Qt::green);
greenHashBrush = QBrush(QColor(0, 0xB6, 0), Qt::BDiagPattern);
blackHashBrush = QBrush(QColor(0, 0, 0), Qt::FDiagPattern);
grayBrush = QBrush(QColor(230,230,230));
//the whole thing is broken up into 81 chunks which are broken up
//into the 8x8 grid of bits in the bottom right and the other parts
//taken up by helper text
double bigTextSize = qMin(xSector, ySector) * 0.5;
double smallTextSize = qMin(xSector, ySector) * 0.25;
double sigNameTextSize = qMin(xSector, ySector) * 0.19;
painter.setPen(QPen(QApplication::palette().color(QPalette::Text)));
QFont mainFont;
mainFont.setPixelSize(bigTextSize);
painter.setFont(mainFont);
QFont smallFont;
smallFont.setPixelSize(smallTextSize);
QFont boldFont;
boldFont.setPixelSize(bigTextSize);
boldFont.setBold(true);
QFont sigNameFont;
sigNameFont.setPixelSize(sigNameTextSize);
QFontMetrics smallMetric(sigNameFont);
painter.setFont(smallFont);
painter.drawText(QRect(viewport.left(), viewport.top(), xSector, ySector), Qt::AlignCenter, "BITS ->");
painter.setFont(boldFont);
for (x = 0; x < 8; x++)
{
painter.drawText(QRect(viewport.left() + (x+1) * xSector, viewport.top(), xSector, ySector), Qt::AlignCenter, QString::number(7-x));
}
//for (y = 0; y < 8; y++)
//{
// painter.drawText(QRect(viewport.left() + xSector, viewport.top() + ySector * (y + 2), xSector, ySector), Qt::AlignCenter, QString::number(y));
//}
painter.drawText(viewport.left() + 4, viewport.top() + ySector * 3, "B");
painter.drawText(viewport.left() + 4, viewport.top() + ySector * 4, "Y");
painter.drawText(viewport.left() + 4, viewport.top() + ySector * 5, "T");
painter.drawText(viewport.left() + 4, viewport.top() + ySector * 6, "E");
painter.drawText(viewport.left() + 4, viewport.top() + ySector * 7, "S");
painter.drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 1, xSector, ySector), Qt::AlignCenter, "0");
painter.drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 2, xSector, ySector), Qt::AlignCenter, "1");
painter.drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 3, xSector, ySector), Qt::AlignCenter, "2");
painter.drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 4, xSector, ySector), Qt::AlignCenter, "3");
painter.drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 5, xSector, ySector), Qt::AlignCenter, "4");
painter.drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 6, xSector, ySector), Qt::AlignCenter, "5");
painter.drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 7, xSector, ySector), Qt::AlignCenter, "6");
painter.drawText(QRect(viewport.left() + (xSector / 4.0), viewport.top() + ySector * 8, xSector, ySector), Qt::AlignCenter, "7");
//now, color the bitfield by seeing if a given bit is freshly set/unset in the new data
//compared to the old. Bits that are not set in either are white, bits set in both are black
//bits that used to be set but now are unset are red, bits that used to be unset but now are set
//are green
painter.setPen(QPen(Qt::black));
painter.setFont(mainFont);
for (y = 0; y < 8; y++)
{
thisByte = data[y];
@@ -217,20 +324,20 @@ void CANDataGrid::paintEvent(QPaintEvent *event)
{
if (prevBit)
{
if (signalColors.count() > 0) painter.setBrush(blackHashBrush);
else painter.setBrush(blackBrush);
if (signalColors.count() > 0) painter->setBrush(blackHashBrush);
else painter->setBrush(blackBrush);
}
else
{
if (signalColors.count() > 0) painter.setBrush(greenHashBrush);
else painter.setBrush(greenBrush);
if (signalColors.count() > 0) painter->setBrush(greenHashBrush);
else painter->setBrush(greenBrush);
}
}
else
{
if (prevBit)
{
painter.setBrush(redBrush);
painter->setBrush(redBrush);
}
else
{
@@ -241,49 +348,49 @@ void CANDataGrid::paintEvent(QPaintEvent *event)
if (usedSigNum == -1)
{
grayBrush = QBrush(QColor(0xB6, 0xB6, 0xB6), Qt::BDiagPattern);
painter.setBrush(grayBrush);
painter->setBrush(grayBrush);
}
else painter.setBrush(QBrush(signalColors[usedSigNum]));
else painter->setBrush(QBrush(signalColors[usedSigNum]));
}
else painter.setBrush(whiteBrush);
else painter->setBrush(whiteBrush);
}
}
//painter.fillRect(viewport.left() + (x+2) * xSector, viewport.top() + (y+2) * ySector, xSector, ySector, redBrush);
painter.drawRect(viewport.left() + (x+1) * xSector, viewport.top() + (y+1) * ySector, xSector, ySector);
//painter->fillRect(viewport.left() + (x+2) * xSector, viewport.top() + (y+2) * ySector, xSector, ySector, redBrush);
painter->drawRect(viewport.left() + (x+1) * xSector, viewport.top() + (y+1) * ySector, xSector, ySector);
switch (textStates[x][y])
{
case GridTextState::NORMAL:
//if (thisBit && prevBit) painter.setPen(QPen(Qt::gray));
/*else*/ painter.setPen(QPen(Qt::black));
painter.setFont(mainFont);
//if (thisBit && prevBit) painter->setPen(QPen(Qt::gray));
/*else*/ painter->setPen(QPen(Qt::black));
painter->setFont(mainFont);
break;
case GridTextState::BOLD_BLUE:
painter.setPen(QPen(Qt::blue));
painter.setFont(boldFont);
painter->setPen(QPen(Qt::blue));
painter->setFont(boldFont);
break;
case GridTextState::INVERT:
painter.setFont(mainFont);
QColor brushColor = painter.brush().color();
painter.setPen(QColor(255-brushColor.red(), 255-brushColor.green(), 255-brushColor.blue()));
painter->setFont(mainFont);
QColor brushColor = painter->brush().color();
painter->setPen(QColor(255-brushColor.red(), 255-brushColor.green(), 255-brushColor.blue()));
break;
}
//change style of bit number output for current signal
//if (thisBit) painter.setFont(boldFont);
// else painter.setFont(mainFont);
painter.setFont(smallFont);
//if (thisBit) painter->setFont(boldFont);
// else painter->setFont(mainFont);
painter->setFont(smallFont);
painter.drawText(viewport.left() + (x+1) * xSector + (xSector / 8), viewport.top() + (y + 2) * ySector - (ySector * 0.7), QString::number(bit));
painter->drawText(viewport.left() + (x+1) * xSector + (xSector / 8), viewport.top() + (y + 2) * ySector - (ySector * 0.7), QString::number(bit));
painter.setFont(mainFont);
painter.setPen(QPen(Qt::black));
painter->setFont(mainFont);
painter->setPen(QPen(Qt::black));
}
}
//now if signal names are loaded we'll go through all the bits again and try to label over top of the grid
if (signalNames.count() > 0)
{
painter.setFont(sigNameFont);
painter->setFont(sigNameFont);
for (y = 0; y < 8; y++)
{
for (x = 0; x < 8; x++)
@@ -297,32 +404,38 @@ void CANDataGrid::paintEvent(QPaintEvent *event)
{
prevSigName = signalNames[usedSigNum];
int textWidth = smallMetric.horizontalAdvance(prevSigName);
int textWidth = smallMetric->horizontalAdvance(prevSigName);
if (textWidth > xSector) //signal name is too long for a single cell. Try to wrap it
{
int numAvgChars = xSector / smallMetric.averageCharWidth();
painter.drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.4), prevSigName.left(numAvgChars - 1));
int numAvgChars = xSector / smallMetric->averageCharWidth();
painter->drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.4), prevSigName.left(numAvgChars - 1));
QString remainder = prevSigName.mid(numAvgChars - 1, -1);
textWidth = smallMetric.horizontalAdvance(prevSigName);
textWidth = smallMetric->horizontalAdvance(prevSigName);
if (textWidth > xSector)
{
painter.drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.2), remainder.left(numAvgChars - 1));
painter->drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.2), remainder.left(numAvgChars - 1));
}
else painter.drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.2), remainder);
else painter->drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.2), remainder);
}
else painter->drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.4), prevSigName);
}
else painter.drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.4), prevSigName);
}
}
}
}
}
void CANDataGrid::paintCommonEnding()
{
upperLeft.setX(viewport.left() + 1 * xSector);
upperLeft.setY(viewport.top() + 1 * ySector);
gridSize.setX(xSector);
gridSize.setY(ySector);
delete painter;
delete smallMetric;
}
void CANDataGrid::saveImage(QString filename, int width, int height)
+30 -2
View File
@@ -20,8 +20,8 @@ class CANDataGrid;
* FlowView that uses all of the above functionality plus this functionality in order to show which bits are set as triggers for stopping
* the flowview playback.
*
* Now the control also tracks which signal is using which bit. Currently this is not used for graphical output. I tried but couldn't make it look
* like I wanted. So, it's un-used as of yet.
* Now the control also tracks which signal is using which bit. The graphical representation does exist now but some tweaking is probably
* still needed. Also, it seems like it is necessary to allow for a variety of modes.
*/
enum GridTextState
@@ -31,6 +31,12 @@ enum GridTextState
INVERT
};
enum GridMode
{
CHANGED_BITS,
SIGNAL_VIEW
};
class CANDataGrid : public QWidget
{
Q_OBJECT
@@ -49,6 +55,8 @@ public:
void setSignalNames(int sigIdx, const QString sigName);
void clearSignalNames();
int getUsedSignalNum(int bit);
GridMode getMode();
void setMode(GridMode mode);
protected:
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
@@ -66,6 +74,26 @@ private:
QVector<QColor> signalColors;
GridTextState textStates[8][8];
QPoint upperLeft, gridSize;
GridMode gridMode;
QBrush blackBrush, whiteBrush, redBrush, greenBrush, grayBrush;
QBrush greenHashBrush, blackHashBrush;
QPainter *painter;
QRect viewport;
int xSpan;
int ySpan;
int xSector;
int ySector;
double bigTextSize, smallTextSize, sigNameTextSize;
QFont mainFont;
QFont smallFont;
QFont boldFont;
QFont sigNameFont;
QFontMetrics *smallMetric;
void paintChangedBits();
void paintSignalView();
void paintCommonBeginning();
void paintCommonEnding();
};
#endif // CANDATAGRID_H
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef CONFIG
#define CONFIG
#define VERSION 206
#define VERSION 207
//try to keep this in sync.
//SavvyCAN will complain if you connect a GVRET board with a revision
+2
View File
@@ -35,6 +35,8 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
ui->comboType->addItem("DOUBLE PRECISION");
ui->comboType->addItem("STRING");
ui->bitfield->setMode(GridMode::SIGNAL_VIEW);
connect(ui->bitfield, SIGNAL(gridClicked(int,int)), this, SLOT(bitfieldClicked(int,int)));
connect(ui->valuesTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomMenuValues(QPoint)));
ui->valuesTable->setContextMenuPolicy(Qt::CustomContextMenu);
+1 -1
View File
@@ -37,7 +37,7 @@ MainWindow::MainWindow(QWidget *parent) :
selfRef = this;
this->setWindowTitle("Savvy CAN V" + QString::number(VERSION) + " Built [" + QString(__DATE__) +"]");
this->setWindowTitle("Savvy CAN V" + QString::number(VERSION) + " [Built " + QString(__DATE__) +"]");
model = new CANFrameModel(this); // set parent to mainwindow to prevent canframemodel to change thread (might be done by setModel but just in case)