mirror of https://github.com/commaai/openpilot.git
Cabana: improve binary view (#26525)
* improve * set minimum width * click signal to open&hide form * disable vertical header's click
This commit is contained in:
parent
2cd1571f4a
commit
66edb15b8f
|
@ -23,11 +23,13 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) {
|
|||
delegate = new BinaryItemDelegate(this);
|
||||
setItemDelegate(delegate);
|
||||
horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
verticalHeader()->setSectionsClickable(false);
|
||||
horizontalHeader()->hide();
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
setShowGrid(false);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
@ -46,46 +48,30 @@ void BinaryView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF
|
|||
return;
|
||||
|
||||
QItemSelection selection;
|
||||
auto [tl, br] = std::minmax(anchor_index, index);
|
||||
if ((resize_sig && resize_sig->is_little_endian) || (!resize_sig && index < anchor_index)) {
|
||||
// little_endian selection
|
||||
if (tl.row() == br.row()) {
|
||||
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);
|
||||
}
|
||||
auto [start, size, is_lb] = getSelection(index);
|
||||
for (int i = start; i < start + size; ++i) {
|
||||
auto idx = model->bitIndex(i, is_lb);
|
||||
selection.merge({idx, idx}, flags);
|
||||
}
|
||||
selectionModel()->select(selection, flags);
|
||||
}
|
||||
|
||||
void BinaryView::mousePressEvent(QMouseEvent *event) {
|
||||
delegate->setSelectionColor(style()->standardPalette().color(QPalette::Active, QPalette::Highlight));
|
||||
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;
|
||||
auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer();
|
||||
if (item && item->sigs.size() > 0) {
|
||||
int bit_idx = get_bit_index(anchor_index, true);
|
||||
for (auto s : item->sigs) {
|
||||
if (bit_idx == s->lsb || bit_idx == s->msb) {
|
||||
resize_sig = s;
|
||||
delegate->setSelectionColor(item->bg_color);
|
||||
break;
|
||||
}
|
||||
int bit_idx = get_bit_index(anchor_index, true);
|
||||
for (auto s : item->sigs) {
|
||||
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;
|
||||
delegate->setSelectionColor(item->bg_color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
QTableView::mousePressEvent(event);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void BinaryView::mouseMoveEvent(QMouseEvent *event) {
|
||||
|
@ -104,28 +90,14 @@ void BinaryView::mouseReleaseEvent(QMouseEvent *event) {
|
|||
|
||||
auto release_index = indexAt(event->pos());
|
||||
if (release_index.isValid() && anchor_index.isValid()) {
|
||||
if (release_index.column() == 8) {
|
||||
release_index = model->index(release_index.row(), 7);
|
||||
}
|
||||
bool little_endian = (resize_sig && resize_sig->is_little_endian) || (!resize_sig && release_index < anchor_index);
|
||||
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 {
|
||||
std::tie(start_bit, end_bit) = std::minmax(release_bit_idx, sig_from);
|
||||
if (end_bit >= sig_from && end_bit <= sig_to)
|
||||
end_bit = std::max(end_bit - 1, sig_from);
|
||||
}
|
||||
emit resizeSignal(resize_sig, start_bit, end_bit - start_bit + 1);
|
||||
if (selectionModel()->hasSelection()) {
|
||||
auto [start_bit, size, is_lb] = getSelection(release_index);
|
||||
resize_sig ? emit resizeSignal(resize_sig, start_bit, size)
|
||||
: emit addSignal(start_bit, size, is_lb);
|
||||
} 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);
|
||||
auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer();
|
||||
if (item && item->sigs.size() > 0)
|
||||
emit signalClicked(item->sigs.back());
|
||||
}
|
||||
}
|
||||
clearSelection();
|
||||
|
@ -156,6 +128,17 @@ QSet<const Signal *> BinaryView::getOverlappingSignals() const {
|
|||
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
|
||||
|
||||
void BinaryViewModel::setMessage(const QString &message_id) {
|
||||
|
@ -203,7 +186,7 @@ void BinaryViewModel::updateState() {
|
|||
char hex[3] = {'\0'};
|
||||
for (int i = 0; i < std::min(binary.size(), row_count); ++i) {
|
||||
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[1] = toHex(binary[i] & 0xf);
|
||||
|
@ -250,17 +233,16 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
|||
painter->save();
|
||||
|
||||
// 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) {
|
||||
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
|
||||
if (index.column() == 8) { // hex column
|
||||
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->drawText(option.rect, Qt::AlignCenter, item->val);
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { return {}; }
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override { return row_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 {
|
||||
return createIndex(row, column, (void *)&items[row * column_count + column]);
|
||||
}
|
||||
|
@ -63,15 +64,16 @@ public:
|
|||
void setMessage(const QString &message_id);
|
||||
void highlight(const Signal *sig);
|
||||
QSet<const Signal*> getOverlappingSignals() const;
|
||||
inline const Signal *hoveredSignal() const { return hovered_sig; }
|
||||
inline void updateState() { model->updateState(); }
|
||||
|
||||
signals:
|
||||
void signalClicked(const Signal *sig);
|
||||
void signalHovered(const Signal *sig);
|
||||
void addSignal(int start_bit, int size, bool little_endian);
|
||||
void resizeSignal(const Signal *sig, int from, int size);
|
||||
|
||||
private:
|
||||
std::tuple<int, int, bool> getSelection(QModelIndex index);
|
||||
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
@ -83,4 +85,5 @@ private:
|
|||
BinaryItemDelegate *delegate;
|
||||
const Signal *resize_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)];
|
||||
}
|
||||
|
||||
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
|
||||
extern CANMessages *can;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) {
|
||||
undo_stack = new QUndoStack(this);
|
||||
|
||||
setMinimumWidth(500);
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(0, 0, 0, 0);
|
||||
main_layout->setSpacing(0);
|
||||
|
@ -90,6 +91,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
|
|||
tab_widget->addTab(history_log, "Logs");
|
||||
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::addSignal, this, &DetailWidget::addSignal);
|
||||
QObject::connect(tab_widget, &QTabWidget::currentChanged, [this]() { updateState(); });
|
||||
|
@ -197,9 +199,15 @@ void DetailWidget::updateState(const QHash<QString, CanData> * msgs) {
|
|||
|
||||
void DetailWidget::showFormClicked() {
|
||||
auto s = qobject_cast<SignalEdit *>(sender());
|
||||
showForm(s->sig);
|
||||
}
|
||||
|
||||
void DetailWidget::showForm(const Signal *sig) {
|
||||
setUpdatesEnabled(false);
|
||||
for (auto f : signal_list)
|
||||
f->updateForm(f == s && !f->isFormVisible());
|
||||
for (auto f : signal_list) {
|
||||
f->updateForm(f->sig == sig && !f->isFormVisible());
|
||||
if (f->sig == sig) scroll->ensureWidgetVisible(f);
|
||||
}
|
||||
setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
QUndoStack *undo_stack = nullptr;
|
||||
|
||||
private:
|
||||
void showForm(const Signal *sig);
|
||||
void showFormClicked();
|
||||
void updateChartState(const QString &id, const Signal *sig, bool opened);
|
||||
void showTabBarContextMenu(const QPoint &pt);
|
||||
|
|
|
@ -196,9 +196,8 @@ void SignalEdit::updateForm(bool visible) {
|
|||
}
|
||||
|
||||
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";
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue