|
|
|
@ -168,6 +168,8 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { |
|
|
|
|
if (item->type == Item::Signed) return item->sig->is_signed ? Qt::Checked : Qt::Unchecked; |
|
|
|
|
} else if (role == Qt::DecorationRole && index.column() == 0 && item->type == Item::ExtraInfo) { |
|
|
|
|
return utils::icon(item->parent->extra_expanded ? "chevron-compact-down" : "chevron-compact-up"); |
|
|
|
|
} else if (role == Qt::ToolTipRole && item->type == Item::Sig) { |
|
|
|
|
return (index.column() == 0) ? item->sig->name : item->sig_val; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return {}; |
|
|
|
@ -323,11 +325,25 @@ QSize SignalItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo |
|
|
|
|
int spacing = option.widget->style()->pixelMetric(QStyle::PM_TreeViewIndentation) + color_label_width + 8; |
|
|
|
|
it = width_cache.insert(text, option.fontMetrics.width(text) + spacing); |
|
|
|
|
} |
|
|
|
|
width = std::min(width, it.value()); |
|
|
|
|
width = std::min<int>(option.widget->size().width() / 3.0, it.value()); |
|
|
|
|
} |
|
|
|
|
return {width, QApplication::fontMetrics().height()}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool SignalItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { |
|
|
|
|
if (event && event->type() == QEvent::ToolTip && index.isValid()) { |
|
|
|
|
auto item = (SignalModel::Item *)index.internalPointer(); |
|
|
|
|
if (item->type == SignalModel::Item::Sig && index.column() == 1) { |
|
|
|
|
QRect rc = option.rect.adjusted(0, 0, -option.rect.width() * 0.4, 0); |
|
|
|
|
if (rc.contains(event->pos())) { |
|
|
|
|
event->setAccepted(false); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return QStyledItemDelegate::helpEvent(event, view, option, index); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { |
|
|
|
|
int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; |
|
|
|
|
int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); |
|
|
|
@ -363,25 +379,30 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op |
|
|
|
|
painter->fillRect(option.rect, option.palette.highlight()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
drawSparkline(painter, option, index); |
|
|
|
|
int adjust_right = ((SignalView *)parent())->tree->indexWidget(index)->sizeHint().width() + 2 * h_margin; |
|
|
|
|
QRect r = option.rect.adjusted(h_margin, v_margin, -adjust_right, -v_margin); |
|
|
|
|
// draw signal value
|
|
|
|
|
int right_offset = ((SignalView *)parent())->tree->indexWidget(index)->sizeHint().width() + 2 * h_margin; |
|
|
|
|
QRect rc = option.rect.adjusted(0, 0, -right_offset, 0); |
|
|
|
|
auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, rc.width()); |
|
|
|
|
QRect value_rect = r.adjusted(r.width() * 0.6 + h_margin, 0, 0, 0); |
|
|
|
|
auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, value_rect.width()); |
|
|
|
|
painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); |
|
|
|
|
painter->drawText(rc, Qt::AlignRight | Qt::AlignVCenter, text); |
|
|
|
|
painter->drawText(value_rect, Qt::AlignRight | Qt::AlignVCenter, text); |
|
|
|
|
|
|
|
|
|
QRect sparkline_rect = r.adjusted(0, 0, -r.width() * 0.4 - h_margin, 0); |
|
|
|
|
drawSparkline(painter, sparkline_rect, index); |
|
|
|
|
} else { |
|
|
|
|
QStyledItemDelegate::paint(painter, option, index); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { |
|
|
|
|
void SignalItemDelegate::drawSparkline(QPainter *painter, const QRect &rect, const QModelIndex &index) const { |
|
|
|
|
static std::vector<QPointF> points; |
|
|
|
|
const auto &msg_id = ((SignalView *)parent())->msg_id; |
|
|
|
|
const auto &msgs = can->events().at(msg_id); |
|
|
|
|
|
|
|
|
|
uint64_t ts = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9; |
|
|
|
|
auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time = (uint64_t)std::max<int64_t>(ts - settings.sparkline_range * 1e9, 0)}); |
|
|
|
|
auto last = std::upper_bound(first, msgs.cend(), CanEvent{.mono_time = ts}); |
|
|
|
|
|
|
|
|
|
if (first != last) { |
|
|
|
|
double min = std::numeric_limits<double>::max(); |
|
|
|
|
double max = std::numeric_limits<double>::lowest(); |
|
|
|
@ -398,16 +419,13 @@ void SignalItemDelegate::drawSparkline(QPainter *painter, const QStyleOptionView |
|
|
|
|
max += 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); |
|
|
|
|
int v_margin = std::max(option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin) + 2, 4); |
|
|
|
|
const double xscale = (option.rect.width() - 175.0 - h_margin * 2) / settings.sparkline_range; |
|
|
|
|
const double yscale = (option.rect.height() - v_margin * 2) / (max - min); |
|
|
|
|
const int left = option.rect.left(); |
|
|
|
|
const int top = option.rect.top() + v_margin; |
|
|
|
|
const double xscale = rect.width() / (double)settings.sparkline_range; |
|
|
|
|
const double yscale = rect.height() / (max - min); |
|
|
|
|
for (auto &pt : points) { |
|
|
|
|
pt.rx() = left + pt.x() * xscale; |
|
|
|
|
pt.ry() = top + std::abs(pt.y() - max) * yscale; |
|
|
|
|
pt.rx() = rect.left() + pt.x() * xscale; |
|
|
|
|
pt.ry() = rect.top() + std::abs(pt.y() - max) * yscale; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
painter->setPen(getColor(sig)); |
|
|
|
|
painter->drawPolyline(points.data(), points.size()); |
|
|
|
|
if ((points.back().x() - points.front().x()) / points.size() > 10) { |
|
|
|
|