Cabana: improve binary view (#26525)

* improve

* set minimum width

* click signal to open&hide form

* disable vertical header's click
pull/26534/head
Dean Lee 2 years ago committed by GitHub
parent 2cd1571f4a
commit 66edb15b8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 80
      tools/cabana/binaryview.cc
  2. 5
      tools/cabana/binaryview.h
  3. 6
      tools/cabana/canmessages.h
  4. 12
      tools/cabana/detailwidget.cc
  5. 1
      tools/cabana/detailwidget.h
  6. 3
      tools/cabana/signaledit.cc

@ -23,11 +23,13 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) {
delegate = new BinaryItemDelegate(this); delegate = new BinaryItemDelegate(this);
setItemDelegate(delegate); setItemDelegate(delegate);
horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
verticalHeader()->setSectionsClickable(false);
horizontalHeader()->hide(); horizontalHeader()->hide();
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
setFrameShape(QFrame::NoFrame); setFrameShape(QFrame::NoFrame);
setShowGrid(false);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
setMouseTracking(true); setMouseTracking(true);
} }
@ -46,25 +48,10 @@ void BinaryView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF
return; return;
QItemSelection selection; QItemSelection selection;
auto [tl, br] = std::minmax(anchor_index, index); auto [start, size, is_lb] = getSelection(index);
if ((resize_sig && resize_sig->is_little_endian) || (!resize_sig && index < anchor_index)) { for (int i = start; i < start + size; ++i) {
// little_endian selection auto idx = model->bitIndex(i, is_lb);
if (tl.row() == br.row()) { selection.merge({idx, idx}, flags);
selection.merge({model->index(tl.row(), tl.column()), model->index(tl.row(), br.column())}, flags);
} else {
for (int row = tl.row(); row <= br.row(); ++row) {
int left_col = (row == br.row()) ? br.column() : 0;
int right_col = (row == tl.row()) ? tl.column() : 7;
selection.merge({model->index(row, left_col), model->index(row, right_col)}, flags);
}
}
} else {
// big endian selection
for (int row = tl.row(); row <= br.row(); ++row) {
int left_col = (row == tl.row()) ? tl.column() : 0;
int right_col = (row == br.row()) ? br.column() : 7;
selection.merge({model->index(row, left_col), model->index(row, right_col)}, flags);
}
} }
selectionModel()->select(selection, flags); selectionModel()->select(selection, flags);
} }
@ -74,18 +61,17 @@ void BinaryView::mousePressEvent(QMouseEvent *event) {
if (auto index = indexAt(event->pos()); index.isValid() && index.column() != 8) { if (auto index = indexAt(event->pos()); index.isValid() && index.column() != 8) {
anchor_index = index; anchor_index = index;
auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer();
if (item && item->sigs.size() > 0) {
int bit_idx = get_bit_index(anchor_index, true); int bit_idx = get_bit_index(anchor_index, true);
for (auto s : item->sigs) { for (auto s : item->sigs) {
if (bit_idx == s->lsb || bit_idx == s->msb) { if (bit_idx == s->lsb || bit_idx == s->msb) {
anchor_index = model->bitIndex(bit_idx == s->lsb ? s->msb : s->lsb, true);
resize_sig = s; resize_sig = s;
delegate->setSelectionColor(item->bg_color); delegate->setSelectionColor(item->bg_color);
break; break;
} }
} }
} }
} event->accept();
QTableView::mousePressEvent(event);
} }
void BinaryView::mouseMoveEvent(QMouseEvent *event) { void BinaryView::mouseMoveEvent(QMouseEvent *event) {
@ -104,28 +90,14 @@ void BinaryView::mouseReleaseEvent(QMouseEvent *event) {
auto release_index = indexAt(event->pos()); auto release_index = indexAt(event->pos());
if (release_index.isValid() && anchor_index.isValid()) { if (release_index.isValid() && anchor_index.isValid()) {
if (release_index.column() == 8) { if (selectionModel()->hasSelection()) {
release_index = model->index(release_index.row(), 7); auto [start_bit, size, is_lb] = getSelection(release_index);
} resize_sig ? emit resizeSignal(resize_sig, start_bit, size)
bool little_endian = (resize_sig && resize_sig->is_little_endian) || (!resize_sig && release_index < anchor_index); : emit addSignal(start_bit, size, is_lb);
int release_bit_idx = get_bit_index(release_index, little_endian);
int archor_bit_idx = get_bit_index(anchor_index, little_endian);
if (resize_sig) {
auto [sig_from, sig_to] = getSignalRange(resize_sig);
int start_bit, end_bit;
if (archor_bit_idx == sig_from) {
std::tie(start_bit, end_bit) = std::minmax(release_bit_idx, sig_to);
if (start_bit >= sig_from && start_bit <= sig_to)
start_bit = std::min(start_bit + 1, sig_to);
} else { } else {
std::tie(start_bit, end_bit) = std::minmax(release_bit_idx, sig_from); auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer();
if (end_bit >= sig_from && end_bit <= sig_to) if (item && item->sigs.size() > 0)
end_bit = std::max(end_bit - 1, sig_from); emit signalClicked(item->sigs.back());
}
emit resizeSignal(resize_sig, start_bit, end_bit - start_bit + 1);
} else {
auto [sart_bit, end_bit] = std::minmax(archor_bit_idx, release_bit_idx);
emit addSignal(sart_bit, end_bit - sart_bit + 1, little_endian);
} }
} }
clearSelection(); clearSelection();
@ -156,6 +128,17 @@ QSet<const Signal *> BinaryView::getOverlappingSignals() const {
return overlapping; return overlapping;
} }
std::tuple<int, int, bool> BinaryView::getSelection(QModelIndex index) {
if (index.column() == 8) {
index = model->index(index.row(), 7);
}
bool is_lb = (resize_sig && resize_sig->is_little_endian) || (!resize_sig && index < anchor_index);
int cur_bit_idx = get_bit_index(index, is_lb);
int anchor_bit_idx = get_bit_index(anchor_index, is_lb);
auto [start_bit, end_bit] = std::minmax(cur_bit_idx, anchor_bit_idx);
return {start_bit, end_bit - start_bit + 1, is_lb};
}
// BinaryViewModel // BinaryViewModel
void BinaryViewModel::setMessage(const QString &message_id) { void BinaryViewModel::setMessage(const QString &message_id) {
@ -203,7 +186,7 @@ void BinaryViewModel::updateState() {
char hex[3] = {'\0'}; char hex[3] = {'\0'};
for (int i = 0; i < std::min(binary.size(), row_count); ++i) { for (int i = 0; i < std::min(binary.size(), row_count); ++i) {
for (int j = 0; j < column_count - 1; ++j) { for (int j = 0; j < column_count - 1; ++j) {
items[i * column_count + j].val = QChar((binary[i] >> (7 - j)) & 1 ? '1' : '0'); items[i * column_count + j].val = ((binary[i] >> (7 - j)) & 1) != 0 ? '1' : '0';
} }
hex[0] = toHex(binary[i] >> 4); hex[0] = toHex(binary[i] >> 4);
hex[1] = toHex(binary[i] & 0xf); hex[1] = toHex(binary[i] & 0xf);
@ -250,17 +233,16 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
painter->save(); painter->save();
// background // background
bool hover = item->sigs.contains(bin_view->hoveredSignal());
QColor bg_color = hover ? hoverColor(item->bg_color) : item->bg_color;
if (option.state & QStyle::State_Selected) { if (option.state & QStyle::State_Selected) {
bg_color = selection_color; painter->fillRect(option.rect, selection_color);
} else if (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig)) {
painter->fillRect(option.rect, item->bg_color);
} }
painter->fillRect(option.rect, bg_color);
// text // text
if (index.column() == 8) { // hex column if (index.column() == 8) { // hex column
painter->setFont(hex_font); painter->setFont(hex_font);
} else if (hover) { } else if (option.state & QStyle::State_Selected || (!bin_view->resize_sig && item->sigs.contains(bin_view->hovered_sig))) {
painter->setPen(Qt::white); painter->setPen(Qt::white);
} }
painter->drawText(option.rect, Qt::AlignCenter, item->val); painter->drawText(option.rect, Qt::AlignCenter, item->val);

@ -32,6 +32,7 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { return {}; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { return {}; }
int rowCount(const QModelIndex &parent = QModelIndex()) const override { return row_count; } int rowCount(const QModelIndex &parent = QModelIndex()) const override { return row_count; }
int columnCount(const QModelIndex &parent = QModelIndex()) const override { return column_count; } int columnCount(const QModelIndex &parent = QModelIndex()) const override { return column_count; }
inline QModelIndex bitIndex(int bit, bool is_lb) const { return index(bit / 8, is_lb ? (7 - bit % 8) : bit % 8); }
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override { QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override {
return createIndex(row, column, (void *)&items[row * column_count + column]); return createIndex(row, column, (void *)&items[row * column_count + column]);
} }
@ -63,15 +64,16 @@ public:
void setMessage(const QString &message_id); void setMessage(const QString &message_id);
void highlight(const Signal *sig); void highlight(const Signal *sig);
QSet<const Signal*> getOverlappingSignals() const; QSet<const Signal*> getOverlappingSignals() const;
inline const Signal *hoveredSignal() const { return hovered_sig; }
inline void updateState() { model->updateState(); } inline void updateState() { model->updateState(); }
signals: signals:
void signalClicked(const Signal *sig);
void signalHovered(const Signal *sig); void signalHovered(const Signal *sig);
void addSignal(int start_bit, int size, bool little_endian); void addSignal(int start_bit, int size, bool little_endian);
void resizeSignal(const Signal *sig, int from, int size); void resizeSignal(const Signal *sig, int from, int size);
private: private:
std::tuple<int, int, bool> getSelection(QModelIndex index);
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override; void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
@ -83,4 +85,5 @@ private:
BinaryItemDelegate *delegate; BinaryItemDelegate *delegate;
const Signal *resize_sig = nullptr; const Signal *resize_sig = nullptr;
const Signal *hovered_sig = nullptr; const Signal *hovered_sig = nullptr;
friend class BinaryItemDelegate;
}; };

@ -80,11 +80,5 @@ inline const QString &getColor(int i) {
return SIGNAL_COLORS[i % std::size(SIGNAL_COLORS)]; return SIGNAL_COLORS[i % std::size(SIGNAL_COLORS)];
} }
inline QColor hoverColor(const QColor &color) {
QColor c = color.convertTo(QColor::Hsv);
c.setHsv(color.hue(), 180, 180);
return c;
}
// A global pointer referring to the unique CANMessages object // A global pointer referring to the unique CANMessages object
extern CANMessages *can; extern CANMessages *can;

@ -17,6 +17,7 @@
DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) {
undo_stack = new QUndoStack(this); undo_stack = new QUndoStack(this);
setMinimumWidth(500);
QVBoxLayout *main_layout = new QVBoxLayout(this); QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setContentsMargins(0, 0, 0, 0);
main_layout->setSpacing(0); main_layout->setSpacing(0);
@ -90,6 +91,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
tab_widget->addTab(history_log, "Logs"); tab_widget->addTab(history_log, "Logs");
main_layout->addWidget(tab_widget); main_layout->addWidget(tab_widget);
QObject::connect(binary_view, &BinaryView::signalClicked, this, &DetailWidget::showForm);
QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal); QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal);
QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal);
QObject::connect(tab_widget, &QTabWidget::currentChanged, [this]() { updateState(); }); QObject::connect(tab_widget, &QTabWidget::currentChanged, [this]() { updateState(); });
@ -197,9 +199,15 @@ void DetailWidget::updateState(const QHash<QString, CanData> * msgs) {
void DetailWidget::showFormClicked() { void DetailWidget::showFormClicked() {
auto s = qobject_cast<SignalEdit *>(sender()); auto s = qobject_cast<SignalEdit *>(sender());
showForm(s->sig);
}
void DetailWidget::showForm(const Signal *sig) {
setUpdatesEnabled(false); setUpdatesEnabled(false);
for (auto f : signal_list) for (auto f : signal_list) {
f->updateForm(f == s && !f->isFormVisible()); f->updateForm(f->sig == sig && !f->isFormVisible());
if (f->sig == sig) scroll->ensureWidgetVisible(f);
}
setUpdatesEnabled(true); setUpdatesEnabled(true);
} }

@ -28,6 +28,7 @@ public:
QUndoStack *undo_stack = nullptr; QUndoStack *undo_stack = nullptr;
private: private:
void showForm(const Signal *sig);
void showFormClicked(); void showFormClicked();
void updateChartState(const QString &id, const Signal *sig, bool opened); void updateChartState(const QString &id, const Signal *sig, bool opened);
void showTabBarContextMenu(const QPoint &pt); void showTabBarContextMenu(const QPoint &pt);

@ -196,9 +196,8 @@ void SignalEdit::updateForm(bool visible) {
} }
void SignalEdit::signalHovered(const Signal *s) { void SignalEdit::signalHovered(const Signal *s) {
auto bg_color = sig == s ? hoverColor(getColor(form_idx)) : QColor(getColor(form_idx));
auto color = sig == s ? "white" : "black"; auto color = sig == s ? "white" : "black";
color_label->setStyleSheet(QString("color:%1; background-color:%2").arg(color).arg(bg_color.name())); color_label->setStyleSheet(QString("color:%1; background-color:%2").arg(color).arg(getColor(form_idx)));
} }
void SignalEdit::enterEvent(QEvent *event) { void SignalEdit::enterEvent(QEvent *event) {

Loading…
Cancel
Save