cabana: colorful logs based on activity (#27008)
* color logs
* remove space
* update in updateColors
old-commit-hash: b2675cef9a
beeps
parent
802bc4e8e2
commit
fc3dac373e
9 changed files with 176 additions and 130 deletions
@ -0,0 +1,99 @@ |
||||
#include "tools/cabana/util.h" |
||||
|
||||
#include <QFontDatabase> |
||||
#include <QPainter> |
||||
|
||||
static QColor blend(QColor a, QColor b) { |
||||
return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); |
||||
} |
||||
|
||||
const QVector<QColor> &HexColors::compute(const QByteArray &dat, double ts, uint32_t freq) { |
||||
if (prev_dat.size() != dat.size()) { |
||||
colors.resize(dat.size()); |
||||
last_change_t.resize(dat.size()); |
||||
std::fill(colors.begin(), colors.end(), QColor(0, 0, 0, 0)); |
||||
std::fill(last_change_t.begin(), last_change_t.end(), ts); |
||||
} else { |
||||
for (int i = 0; i < dat.size(); ++i) { |
||||
const uint8_t last = prev_dat[i]; |
||||
const uint8_t cur = dat[i]; |
||||
|
||||
if (last != cur) { |
||||
double delta_t = ts - last_change_t[i]; |
||||
if (delta_t * freq > periodic_threshold) { |
||||
// Last change was while ago, choose color based on delta up or down
|
||||
if (cur > last) { |
||||
colors[i] = QColor(0, 187, 255, start_alpha); // Cyan
|
||||
} else { |
||||
colors[i] = QColor(255, 0, 0, start_alpha); // Red
|
||||
} |
||||
} else { |
||||
// Periodic changes
|
||||
colors[i] = blend(colors[i], QColor(102, 86, 169, start_alpha / 2)); // Greyish/Blue
|
||||
} |
||||
|
||||
last_change_t[i] = ts; |
||||
} else { |
||||
// Fade out
|
||||
float alpha_delta = 1.0 / (freq + 1) / fade_time; |
||||
colors[i].setAlphaF(std::max(0.0, colors[i].alphaF() - alpha_delta)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
prev_dat = dat; |
||||
return colors; |
||||
} |
||||
|
||||
void HexColors::clear() { |
||||
prev_dat.clear(); |
||||
last_change_t.clear(); |
||||
colors.clear(); |
||||
} |
||||
|
||||
QList<QVariant> HexColors::toVariantList(const QVector<QColor> &colors) { |
||||
QList<QVariant> ret; |
||||
ret.reserve(colors.size()); |
||||
for (auto &c : colors) ret.append(c); |
||||
return ret; |
||||
} |
||||
|
||||
// MessageBytesDelegate
|
||||
|
||||
MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { |
||||
fixed_font = QFontDatabase::systemFont(QFontDatabase::FixedFont); |
||||
} |
||||
|
||||
void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { |
||||
QList<QVariant> colors = index.data(Qt::UserRole).toList(); |
||||
if (colors.empty()) { |
||||
QStyledItemDelegate::paint(painter, option, index); |
||||
return; |
||||
} |
||||
QStyleOptionViewItemV4 opt = option; |
||||
initStyleOption(&opt, index); |
||||
|
||||
if ((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Active)) { |
||||
painter->setPen(option.palette.color(QPalette::HighlightedText)); |
||||
} else { |
||||
painter->setPen(option.palette.color(QPalette::Text)); |
||||
} |
||||
|
||||
painter->setFont(fixed_font); |
||||
QRect space = painter->boundingRect(opt.rect, opt.displayAlignment, " "); |
||||
QRect pos = painter->boundingRect(opt.rect, opt.displayAlignment, "00"); |
||||
pos.moveLeft(pos.x() + space.width()); |
||||
|
||||
int m = space.width() / 2; |
||||
const QMargins margins(m + 1, m, m, m); |
||||
|
||||
int i = 0; |
||||
for (auto &byte : opt.text.split(" ")) { |
||||
if (i < colors.size()) { |
||||
painter->fillRect(pos.marginsAdded(margins), colors[i].value<QColor>()); |
||||
} |
||||
painter->drawText(pos, opt.displayAlignment, byte); |
||||
pos.moveLeft(pos.right() + space.width()); |
||||
i++; |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
#pragma once |
||||
|
||||
#include <QByteArray> |
||||
#include <QColor> |
||||
#include <QFont> |
||||
#include <QStyledItemDelegate> |
||||
#include <QVector> |
||||
|
||||
class HexColors { |
||||
public: |
||||
const QVector<QColor> &compute(const QByteArray &dat, double ts, uint32_t freq); |
||||
static QList<QVariant> toVariantList(const QVector<QColor> &colors); |
||||
void clear(); |
||||
|
||||
private: |
||||
const int periodic_threshold = 10; |
||||
const int start_alpha = 128; |
||||
const float fade_time = 2.0; |
||||
QByteArray prev_dat; |
||||
QVector<double> last_change_t; |
||||
QVector<QColor> colors; |
||||
}; |
||||
|
||||
class MessageBytesDelegate : public QStyledItemDelegate { |
||||
Q_OBJECT |
||||
public: |
||||
MessageBytesDelegate(QObject *parent); |
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; |
||||
QFont fixed_font; |
||||
}; |
||||
|
||||
inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } |
||||
inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } |
||||
inline const QString &getColor(int i) { |
||||
// TODO: add more colors
|
||||
static const QString SIGNAL_COLORS[] = {"#9FE2BF", "#40E0D0", "#6495ED", "#CCCCFF", "#FF7F50", "#FFBF00"}; |
||||
return SIGNAL_COLORS[i % std::size(SIGNAL_COLORS)]; |
||||
} |
Loading…
Reference in new issue