From 935032477d4ffe84a5130ae08553b53c424dcc83 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Mon, 6 Sep 2021 20:34:11 -0400 Subject: [PATCH] Modified CANDataGrid component to have two modes for better graphics, updated version number and presentation on main window --- candatagrid.cpp | 345 ++++++++++++++++++++++++++-------------- candatagrid.h | 32 +++- config.h | 2 +- dbc/dbcsignaleditor.cpp | 2 + mainwindow.cpp | 2 +- 5 files changed, 263 insertions(+), 120 deletions(-) diff --git a/candatagrid.cpp b/candatagrid.cpp index a879ba1..53e29f7 100644 --- a/candatagrid.cpp +++ b/candatagrid.cpp @@ -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]; @@ -211,26 +318,26 @@ void CANDataGrid::paintEvent(QPaintEvent *event) 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 ((prevByte & (1 << (7-x))) == (1 << (7-x))) prevBit = true; if (thisBit) { 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); + 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); + 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) diff --git a/candatagrid.h b/candatagrid.h index a48321a..6ae159d 100644 --- a/candatagrid.h +++ b/candatagrid.h @@ -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 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 diff --git a/config.h b/config.h index 0ce62ef..99412e5 100644 --- a/config.h +++ b/config.h @@ -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 diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index 0c33ecb..b81c11c 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -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); diff --git a/mainwindow.cpp b/mainwindow.cpp index 45bfef1..89e1d42 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -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)