Cabana: drag to adjust signal size (#26172)

* drag to adjust signal size

* rename

* override setSelection

* use signal color as selection color while resing

* helper funtion

* hide tooltip if not in signal

* cleanup

* cabana: remove unused metatype (#26175)

remove unused metatype

* cabana: improve signal highlight on hover (#26161)

* just change font color

* merge master

* cleanup
pull/26178/head
Dean Lee 3 years ago committed by GitHub
parent f957f3391d
commit d6a0f1c25a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 100
      tools/cabana/binaryview.cc
  2. 18
      tools/cabana/binaryview.h
  3. 23
      tools/cabana/detailwidget.cc
  4. 3
      tools/cabana/detailwidget.h

@ -13,21 +13,23 @@
const int CELL_HEIGHT = 30; const int CELL_HEIGHT = 30;
static std::pair<int, int> getSignalRange(const Signal *s) {
int from = s->is_little_endian ? s->start_bit : bigEndianBitIndex(s->start_bit);
int to = from + s->size - 1;
return {from, to};
}
BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { BinaryView::BinaryView(QWidget *parent) : QTableView(parent) {
model = new BinaryViewModel(this); model = new BinaryViewModel(this);
setModel(model); setModel(model);
setItemDelegate(new BinaryItemDelegate(this)); delegate = new BinaryItemDelegate(this);
setItemDelegate(delegate);
horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
horizontalHeader()->hide(); horizontalHeader()->hide();
verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setMouseTracking(true); setMouseTracking(true);
// replace selection model
auto old_model = selectionModel();
setSelectionModel(new BinarySelectionModel(model));
delete old_model;
QObject::connect(model, &QAbstractItemModel::modelReset, [this]() { QObject::connect(model, &QAbstractItemModel::modelReset, [this]() {
setFixedHeight((CELL_HEIGHT + 1) * std::min(model->rowCount(), 8) + 2); setFixedHeight((CELL_HEIGHT + 1) * std::min(model->rowCount(), 8) + 2);
}); });
@ -41,12 +43,42 @@ void BinaryView::highlight(const Signal *sig) {
} }
} }
void BinaryView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) {
QModelIndex tl = indexAt({qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())});
QModelIndex br = indexAt({qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())});
if (!tl.isValid() || !br.isValid())
return;
if (tl < anchor_index) {
br = anchor_index;
} else if (anchor_index < br) {
tl = anchor_index;
}
QItemSelection 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);
}
void BinaryView::mousePressEvent(QMouseEvent *event) {
delegate->setSelectionColor(style()->standardPalette().color(QPalette::Active, QPalette::Highlight));
anchor_index = indexAt(event->pos());
if (getResizingSignal() != nullptr) {
auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer();
delegate->setSelectionColor(item->bg_color);
}
QTableView::mousePressEvent(event);
}
void BinaryView::mouseMoveEvent(QMouseEvent *event) { void BinaryView::mouseMoveEvent(QMouseEvent *event) {
if (auto index = indexAt(event->pos()); index.isValid()) { if (auto index = indexAt(event->pos()); index.isValid()) {
auto item = (BinaryViewModel::Item *)index.internalPointer(); auto item = (BinaryViewModel::Item *)index.internalPointer();
highlight(item->sig); highlight(item->sig);
if (item->sig) item->sig ? QToolTip::showText(event->globalPos(), item->sig->name.c_str(), this, rect())
QToolTip::showText(event->globalPos(), item->sig->name.c_str(), this, rect()); : QToolTip::hideText();
} }
QTableView::mouseMoveEvent(event); QTableView::mouseMoveEvent(event);
} }
@ -55,10 +87,21 @@ void BinaryView::mouseReleaseEvent(QMouseEvent *event) {
QTableView::mouseReleaseEvent(event); QTableView::mouseReleaseEvent(event);
if (auto indexes = selectedIndexes(); !indexes.isEmpty()) { if (auto indexes = selectedIndexes(); !indexes.isEmpty()) {
int start_bit = indexes.first().row() * 8 + indexes.first().column(); int from = indexes.first().row() * 8 + indexes.first().column();
int size = indexes.back().row() * 8 + indexes.back().column() - start_bit + 1; int to = indexes.back().row() * 8 + indexes.back().column();
emit cellsSelected(start_bit, size); if (auto sig = getResizingSignal()) {
auto [sig_from, sig_to] = getSignalRange(sig);
if (from >= sig_from && to <= sig_to) { // reduce size
emit(from == sig_from ? resizeSignal(sig, to, sig_to) : resizeSignal(sig, sig_from, from));
} else { // increase size
emit resizeSignal(sig, std::min(from, sig_from), std::max(to, sig_to));
}
} else {
emit addSignal(from, to);
}
clearSelection();
} }
anchor_index = QModelIndex();
} }
void BinaryView::leaveEvent(QEvent *event) { void BinaryView::leaveEvent(QEvent *event) {
@ -78,6 +121,19 @@ void BinaryView::updateState() {
model->updateState(); model->updateState();
} }
const Signal *BinaryView::getResizingSignal() const {
if (anchor_index.isValid()) {
auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer();
if (item && item->sig) {
int archor_pos = anchor_index.row() * 8 + anchor_index.column();
auto [sig_from, sig_to] = getSignalRange(item->sig);
if (archor_pos == sig_from || archor_pos == sig_to)
return item->sig;
}
}
return nullptr;
}
// BinaryViewModel // BinaryViewModel
void BinaryViewModel::setMessage(const QString &message_id) { void BinaryViewModel::setMessage(const QString &message_id) {
@ -93,8 +149,7 @@ void BinaryViewModel::setMessage(const QString &message_id) {
items.resize(row_count * column_count); items.resize(row_count * column_count);
for (int i = 0; i < dbc_msg->sigs.size(); ++i) { for (int i = 0; i < dbc_msg->sigs.size(); ++i) {
const auto &sig = dbc_msg->sigs[i]; const auto &sig = dbc_msg->sigs[i];
const int start = sig.is_little_endian ? sig.start_bit : bigEndianBitIndex(sig.start_bit); auto [start, end] = getSignalRange(&sig);
const int end = start + sig.size - 1;
for (int j = start; j <= end; ++j) { for (int j = start; j <= end; ++j) {
int idx = column_count * (j / 8) + j % 8; int idx = column_count * (j / 8) + j % 8;
if (idx >= items.size()) { if (idx >= items.size()) {
@ -165,21 +220,6 @@ QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, i
return {}; return {};
} }
// BinarySelectionModel
void BinarySelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) {
QItemSelection new_selection = selection;
if (auto indexes = selection.indexes(); !indexes.isEmpty()) {
auto [begin_idx, end_idx] = (QModelIndex[]){indexes.first(), indexes.back()};
for (int row = begin_idx.row(); row <= end_idx.row(); ++row) {
int left_col = (row == begin_idx.row()) ? begin_idx.column() : 0;
int right_col = (row == end_idx.row()) ? end_idx.column() : 7;
new_selection.merge({model()->index(row, left_col), model()->index(row, right_col)}, command);
}
}
QItemSelectionModel::select(new_selection, command);
}
// BinaryItemDelegate // BinaryItemDelegate
BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {
@ -187,7 +227,7 @@ BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(pa
small_font.setPointSize(6); small_font.setPointSize(6);
hex_font = QFontDatabase::systemFont(QFontDatabase::FixedFont); hex_font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
hex_font.setBold(true); hex_font.setBold(true);
highlight_color = QApplication::style()->standardPalette().color(QPalette::Active, QPalette::Highlight); selection_color = QApplication::style()->standardPalette().color(QPalette::Active, QPalette::Highlight);
} }
QSize BinaryItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize BinaryItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
@ -204,7 +244,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
// background // background
QColor bg_color = hover ? hoverColor(item->bg_color) : item->bg_color; 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 = highlight_color; bg_color = selection_color;
} }
painter->fillRect(option.rect, bg_color); painter->fillRect(option.rect, bg_color);

@ -12,10 +12,11 @@ public:
BinaryItemDelegate(QObject *parent); BinaryItemDelegate(QObject *parent);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setSelectionColor(const QColor &color) { selection_color = color; }
private: private:
QFont small_font, hex_font; QFont small_font, hex_font;
QColor highlight_color; QColor selection_color;
}; };
class BinaryViewModel : public QAbstractTableModel { class BinaryViewModel : public QAbstractTableModel {
@ -48,13 +49,6 @@ private:
std::vector<Item> items; std::vector<Item> items;
}; };
// the default QItemSelectionModel does not support our selection mode.
class BinarySelectionModel : public QItemSelectionModel {
public:
BinarySelectionModel(QAbstractItemModel *model = nullptr) : QItemSelectionModel(model) {}
void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override;
};
class BinaryView : public QTableView { class BinaryView : public QTableView {
Q_OBJECT Q_OBJECT
@ -66,15 +60,21 @@ public:
const Signal *hoveredSignal() const { return hovered_sig; } const Signal *hoveredSignal() const { return hovered_sig; }
signals: signals:
void cellsSelected(int start_bit, int size);
void signalHovered(const Signal *sig); void signalHovered(const Signal *sig);
void addSignal(int from, int size);
void resizeSignal(const Signal *sig, int from, int size);
private: private:
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override;
void leaveEvent(QEvent *event) override; void leaveEvent(QEvent *event) override;
const Signal *getResizingSignal() const;
QString msg_id; QString msg_id;
QModelIndex anchor_index;
BinaryViewModel *model; BinaryViewModel *model;
BinaryItemDelegate *delegate;
const Signal *hovered_sig = nullptr; const Signal *hovered_sig = nullptr;
}; };

@ -73,7 +73,8 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) {
main_layout->addWidget(history_log); main_layout->addWidget(history_log);
QObject::connect(edit_btn, &QPushButton::clicked, this, &DetailWidget::editMsg); QObject::connect(edit_btn, &QPushButton::clicked, this, &DetailWidget::editMsg);
QObject::connect(binary_view, &BinaryView::cellsSelected, this, &DetailWidget::addSignal); QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal);
QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal);
QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState); QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState);
QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &DetailWidget::dbcMsgChanged); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &DetailWidget::dbcMsgChanged);
QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { setMessage(messages[index]); }); QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { setMessage(messages[index]); });
@ -159,9 +160,9 @@ void DetailWidget::editMsg() {
} }
} }
void DetailWidget::addSignal(int start_bit, int size) { void DetailWidget::addSignal(int start_bit, int to) {
if (dbc()->msg(msg_id)) { if (dbc()->msg(msg_id)) {
AddSignalDialog dlg(msg_id, start_bit, size, this); AddSignalDialog dlg(msg_id, start_bit, to - start_bit + 1, this);
if (dlg.exec()) { if (dlg.exec()) {
dbc()->addSignal(msg_id, dlg.form->getSignal()); dbc()->addSignal(msg_id, dlg.form->getSignal());
dbcMsgChanged(); dbcMsgChanged();
@ -169,6 +170,22 @@ void DetailWidget::addSignal(int start_bit, int size) {
} }
} }
void DetailWidget::resizeSignal(const Signal *sig, int from, int to) {
assert(sig != nullptr);
Signal s = *sig;
s.start_bit = s.is_little_endian ? from : bigEndianBitIndex(from);;
s.size = to - from + 1;
if (s.is_little_endian) {
s.lsb = s.start_bit;
s.msb = s.start_bit + s.size - 1;
} else {
s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1);
s.msb = s.start_bit;
}
dbc()->updateSignal(msg_id, s.name.c_str(), s);
dbcMsgChanged();
}
void DetailWidget::saveSignal() { void DetailWidget::saveSignal() {
SignalEdit *sig_form = qobject_cast<SignalEdit *>(QObject::sender()); SignalEdit *sig_form = qobject_cast<SignalEdit *>(QObject::sender());
auto s = sig_form->form->getSignal(); auto s = sig_form->form->getSignal();

@ -39,7 +39,8 @@ signals:
void removeChart(const Signal *sig); void removeChart(const Signal *sig);
private: private:
void addSignal(int start_bit, int size); void addSignal(int start_bit, int to);
void resizeSignal(const Signal *sig, int from, int to);
void saveSignal(); void saveSignal();
void removeSignal(); void removeSignal();
void editMsg(); void editMsg();

Loading…
Cancel
Save