Skip to content

Commit

Permalink
Merge g492 via qt_traffic_tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
luke-jr committed Feb 14, 2025
2 parents 27ec372 + 25b56d7 commit 66c0638
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 3 deletions.
34 changes: 34 additions & 0 deletions src/qt/guiutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,40 @@ QString formatBytes(uint64_t bytes)
return QObject::tr("%1 GB").arg(bytes / 1'000'000'000);
}

QString formatBytesps(float val)
{
if (val < 10)
//: "Bytes per second"
return QObject::tr("%1 B/s").arg(0.01 * int(val * 100));
if (val < 100)
//: "Bytes per second"
return QObject::tr("%1 B/s").arg(0.1 * int(val * 10));
if (val < 1'000)
//: "Bytes per second"
return QObject::tr("%1 B/s").arg((int)val);
if (val < 10'000)
//: "Kilobytes per second"
return QObject::tr("%1 kB/s").arg(0.01 * ((int)val / 10));
if (val < 100'000)
//: "Kilobytes per second"
return QObject::tr("%1 kB/s").arg(0.1 * ((int)val / 100));
if (val < 1'000'000)
//: "Kilobytes per second"
return QObject::tr("%1 kB/s").arg((int)val / 1'000);
if (val < 10'000'000)
//: "Megabytes per second"
return QObject::tr("%1 MB/s").arg(0.01 * ((int)val / 10'000));
if (val < 100'000'000)
//: "Megabytes per second"
return QObject::tr("%1 MB/s").arg(0.1 * ((int)val / 100'000));
if (val < 10'000'000'000)
//: "Megabytes per second"
return QObject::tr("%1 MB/s").arg((long)val / 1'000'000);

//: "Gigabytes per second"
return QObject::tr("%1 GB/s").arg((long)val / 1'000'000'000);
}

qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize, qreal font_size) {
while(font_size >= minPointSize) {
font.setPointSizeF(font_size);
Expand Down
1 change: 1 addition & 0 deletions src/qt/guiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ namespace GUIUtil
QString formatNiceTimeOffset(qint64 secs);

QString formatBytes(uint64_t bytes);
QString formatBytesps(float bytes);

qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize = 4, qreal startPointSize = 14);

Expand Down
102 changes: 99 additions & 3 deletions src/qt/trafficgraphwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
#include <interfaces/node.h>
#include <qt/trafficgraphwidget.h>
#include <qt/clientmodel.h>
#include <qt/guiutil.h>

#include <QMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QColor>
#include <QTimer>
#include <QToolTip>

#include <chrono>
#include <cmath>
Expand All @@ -25,7 +28,12 @@ TrafficGraphWidget::TrafficGraphWidget(QWidget* parent)
vSamplesOut()
{
timer = new QTimer(this);
tt_timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &TrafficGraphWidget::updateRates);
connect(tt_timer, &QTimer::timeout, this, &TrafficGraphWidget::updateToolTip);
tt_timer->setInterval(500);
tt_timer->start();
setMouseTracking(true);
}

void TrafficGraphWidget::setClientModel(ClientModel *model)
Expand All @@ -48,7 +56,7 @@ int TrafficGraphWidget::y_value(float value)
void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
{
int sampleCount = samples.size();
if(sampleCount > 0 && fMax > 0) {
if(sampleCount > 0) {
int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
int x = XMARGIN + w;
path.moveTo(x, YMARGIN + h);
Expand All @@ -68,6 +76,44 @@ void TrafficGraphWidget::mousePressEvent(QMouseEvent *event)
update();
}

float floatmax(float a, float b)
{
if (a > b) return a;
else return b;
}

void TrafficGraphWidget::mouseMoveEvent(QMouseEvent *event)
{
QWidget::mouseMoveEvent(event);
static int last_x = -1;
static int last_y = -1;
int x = event->x();
int y = event->y();
x_offset = event->globalX() - x;
y_offset = event->globalY() - y;
if (last_x == x && last_y == y) return; // Do nothing if mouse hasn't moved
int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
int i = (w + XMARGIN - x) * DESIRED_SAMPLES / w;
unsigned int smallest_distance = 50; int closest_i = -1;
int sampleSize = vTimeStamp.size();
if (sampleSize && i >= -10 && i < sampleSize + 2 && y <= h + YMARGIN + 3) {
for (int test_i = std::max(i - 2, 0); test_i < std::min(i + 10, sampleSize); test_i++) {
float val = floatmax(vSamplesIn.at(test_i), vSamplesOut.at(test_i));
int y_data = y_value(val);
unsigned int distance = abs(y - y_data);
if (distance < smallest_distance) {
smallest_distance = distance;
closest_i = test_i;
}
}
}
if (ttpoint != closest_i) {
ttpoint = closest_i;
update(); // Calls paintEvent() to draw or delete the highlighted point
}
last_x = x; last_y = y;
}

void TrafficGraphWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
Expand Down Expand Up @@ -130,18 +176,63 @@ void TrafficGraphWidget::paintEvent(QPaintEvent *)
painter.setPen(Qt::red);
painter.drawPath(p);
}
int sampleCount = vTimeStamp.size();
if (ttpoint >= 0 && ttpoint < sampleCount) {
painter.setPen(Qt::yellow);
int w = width() - XMARGIN * 2;
int x = XMARGIN + w - w * ttpoint / DESIRED_SAMPLES;
int y = y_value(floatmax(vSamplesIn.at(ttpoint), vSamplesOut.at(ttpoint)));
painter.drawEllipse(QPointF(x, y), 3, 3);
QString strTime;
int64_t sampleTime = vTimeStamp.at(ttpoint);
int age = GetTime() - sampleTime/1000;
if (age < 60*60*23)
strTime = QString::fromStdString(FormatISO8601Time(sampleTime/1000));
else
strTime = QString::fromStdString(FormatISO8601DateTime(sampleTime/1000));
int milliseconds_between_samples = 1000;
if (ttpoint > 0)
milliseconds_between_samples = std::min(milliseconds_between_samples, int(vTimeStamp.at(ttpoint-1) - sampleTime));
if (ttpoint + 1 < sampleCount)
milliseconds_between_samples = std::min(milliseconds_between_samples, int(sampleTime - vTimeStamp.at(ttpoint+1)));
if (milliseconds_between_samples < 1000)
strTime += QString::fromStdString(strprintf(".%03d", (sampleTime%1000)));
QString strData = tr("In") + " " + GUIUtil::formatBytesps(vSamplesIn.at(ttpoint)*1000) + "\n" + tr("Out") + " " + GUIUtil::formatBytesps(vSamplesOut.at(ttpoint)*1000);
// Line below allows ToolTip to move faster than once every 10 seconds.
QToolTip::showText(QPoint(x + x_offset, y + y_offset), strTime + "\n. " + strData);
QToolTip::showText(QPoint(x + x_offset, y + y_offset), strTime + "\n " + strData);
tt_time = GetTime();
} else
QToolTip::hideText();
}

void TrafficGraphWidget::updateToolTip()
{
if (!QToolTip::isVisible()) {
if (ttpoint >= 0) { // Remove the yellow circle if the ToolTip has gone due to mouse moving elsewhere.
ttpoint = -1;
update();
}
} else if (GetTime() >= tt_time + 9) { // ToolTip is about to expire so refresh it.
update();
}
}

void TrafficGraphWidget::updateRates()
{
if(!clientModel) return;

int64_t nTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
static int64_t nLastTime = nTime - timer->interval();
int nRealInterval = nTime - nLastTime;
quint64 bytesIn = clientModel->node().getTotalBytesRecv(),
bytesOut = clientModel->node().getTotalBytesSent();
float in_rate_kilobytes_per_sec = static_cast<float>(bytesIn - nLastBytesIn) / timer->interval();
float out_rate_kilobytes_per_sec = static_cast<float>(bytesOut - nLastBytesOut) / timer->interval();
float in_rate_kilobytes_per_sec = static_cast<float>(bytesIn - nLastBytesIn) / nRealInterval;
float out_rate_kilobytes_per_sec = static_cast<float>(bytesOut - nLastBytesOut) / nRealInterval;
vSamplesIn.push_front(in_rate_kilobytes_per_sec);
vSamplesOut.push_front(out_rate_kilobytes_per_sec);
vTimeStamp.push_front(nLastTime);
nLastTime = nTime;
nLastBytesIn = bytesIn;
nLastBytesOut = bytesOut;

Expand All @@ -151,6 +242,9 @@ void TrafficGraphWidget::updateRates()
while(vSamplesOut.size() > DESIRED_SAMPLES) {
vSamplesOut.pop_back();
}
while(vTimeStamp.size() > DESIRED_SAMPLES) {
vTimeStamp.pop_back();
}

float tmax = 0.0f;
for (const float f : vSamplesIn) {
Expand All @@ -160,6 +254,7 @@ void TrafficGraphWidget::updateRates()
if(f > tmax) tmax = f;
}
fMax = tmax;
if (ttpoint >=0 && ttpoint < vTimeStamp.size()) ttpoint++; // Move the selected point to the left
update();
}

Expand All @@ -179,6 +274,7 @@ void TrafficGraphWidget::clear()

vSamplesOut.clear();
vSamplesIn.clear();
vTimeStamp.clear();
fMax = 0.0f;

if(clientModel) {
Expand Down
8 changes: 8 additions & 0 deletions src/qt/trafficgraphwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,28 @@ class TrafficGraphWidget : public QWidget
int y_value(float value);
void mousePressEvent(QMouseEvent *event) override;
bool fToggle = true;
void mouseMoveEvent(QMouseEvent *event) override;
int ttpoint = -1;
int x_offset = 0;
int y_offset = 0;
int64_t tt_time = 0;

public Q_SLOTS:
void updateRates();
void updateToolTip();
void setGraphRange(std::chrono::minutes new_range);
void clear();

private:
void paintPath(QPainterPath &path, QQueue<float> &samples);

QTimer* timer{nullptr};
QTimer* tt_timer{nullptr};
float fMax{0.0f};
std::chrono::minutes m_range{0};
QQueue<float> vSamplesIn;
QQueue<float> vSamplesOut;
QQueue<int64_t> vTimeStamp;
quint64 nLastBytesIn{0};
quint64 nLastBytesOut{0};
ClientModel* clientModel{nullptr};
Expand Down
8 changes: 8 additions & 0 deletions src/util/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ std::optional<int64_t> ParseISO8601DateTime(std::string_view str)
return int64_t{TicksSinceEpoch<std::chrono::seconds>(tp)};
}

std::string FormatISO8601Time(int64_t nTime)
{
const std::chrono::sys_seconds secs{std::chrono::seconds{nTime}};
const auto days{std::chrono::floor<std::chrono::days>(secs)};
const std::chrono::hh_mm_ss hms{secs - days};
return strprintf("%02i:%02i:%02iZ", hms.hours().count(), hms.minutes().count(), hms.seconds().count());
}

struct timeval MillisToTimeval(int64_t nTimeout)
{
struct timeval timeout;
Expand Down
1 change: 1 addition & 0 deletions src/util/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ T GetTime()
*/
std::string FormatISO8601DateTime(int64_t nTime);
std::string FormatISO8601Date(int64_t nTime);
std::string FormatISO8601Time(int64_t nTime);
std::optional<int64_t> ParseISO8601DateTime(std::string_view str);

/**
Expand Down

0 comments on commit 66c0638

Please sign in to comment.