mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-12 19:20:42 +02:00
Merge g492 via qt_traffic_tooltip
This commit is contained in:
commit
1b0204cba3
@ -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);
|
||||
|
@ -288,6 +288,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);
|
||||
|
||||
|
@ -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>
|
||||
@ -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)
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -179,6 +274,7 @@ void TrafficGraphWidget::clear()
|
||||
|
||||
vSamplesOut.clear();
|
||||
vSamplesIn.clear();
|
||||
vTimeStamp.clear();
|
||||
fMax = 0.0f;
|
||||
|
||||
if(clientModel) {
|
||||
|
@ -31,9 +31,15 @@ protected:
|
||||
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();
|
||||
|
||||
@ -41,10 +47,12 @@ 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};
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user