Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/qt/forms/debugwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@
<number>12</number>
</property>
<property name="value">
<number>6</number>
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
Expand Down
22 changes: 20 additions & 2 deletions src/qt/rpcconsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@
#include <QTimer>
#include <QVariant>

#include <chrono>

const int CONSOLE_HISTORY = 50;
const int INITIAL_TRAFFIC_GRAPH_MINS = 30;
const int INITIAL_TRAFFIC_GRAPH_MINS = 5;
const QSize FONT_RANGE(4, 40);
const char fontSizeSettingsKey[] = "consoleFontSize";

Expand Down Expand Up @@ -1140,7 +1142,7 @@ void RPCConsole::on_sldGraphRange_valueChanged(int value)

void RPCConsole::setTrafficGraphRange(int mins)
{
ui->trafficGraph->setGraphRangeMins(mins);
ui->trafficGraph->setGraphRange(std::chrono::minutes{mins});
ui->lblGraphRange->setText(GUIUtil::formatDurationStr(std::chrono::minutes{mins}));
}

Expand Down Expand Up @@ -1226,6 +1228,22 @@ void RPCConsole::updateDetailWidget()
void RPCConsole::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
if (width()<=minimumWidth()*2){
ui->groupBox->hide();
}else{
ui->groupBox->show();
}
if (height()==minimumHeight()){
ui->sldGraphRange->hide();
ui->lblGraphRange->hide();
ui->btnClearTrafficGraph->hide();
}else{
ui->sldGraphRange->show();
ui->lblGraphRange->show();
ui->btnClearTrafficGraph->show();
}


}

void RPCConsole::showEvent(QShowEvent *event)
Expand Down
95 changes: 62 additions & 33 deletions src/qt/trafficgraphwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
#include <QColor>
#include <QTimer>

#include <chrono>
#include <cmath>
#include <cfloat>

#define DESIRED_SAMPLES 800
#define DESIRED_SAMPLES 300

#define XMARGIN 10
#define YMARGIN 10
Expand Down Expand Up @@ -47,30 +49,43 @@ int TrafficGraphWidget::getGraphRangeMins() const
return nMins;
}

int TrafficGraphWidget::y_value(float value)
{
int h = height() - YMARGIN * 2;
return YMARGIN + h - (h * 1.0 * (fToggle ? (pow(value, 0.30102) / pow(fMax, 0.30102)) : (value / fMax)));
}

void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
{
int sampleCount = samples.size();
if(sampleCount > 0) {
if(sampleCount > 0 && fMax > 0) {
int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
int x = XMARGIN + w;
path.moveTo(x, YMARGIN + h);
for(int i = 0; i < sampleCount; ++i) {
x = XMARGIN + w - w * i / DESIRED_SAMPLES;
int y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
x = XMARGIN + w - w * i / DESIRED_SAMPLES / (getGraphRangeMins()/5);
int y = y_value(samples.at(i));
path.lineTo(x, y);
}
path.lineTo(x, YMARGIN + h);
}
}

void TrafficGraphWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
QWidget::mousePressEvent(event);
fToggle = !fToggle;
update();
}

void TrafficGraphWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.fillRect(rect(), Qt::black);

if(fMax <= 0.0f) return;

QColor axisCol(Qt::gray);
QColor axisCol(QColor(78,78,78,255));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't check to see if there was a Qt defined dark gray - It is ideal to let the samples stand out above the scale lines - we can tweak this. Note: there is plenty of room unused in the side panel - I have some code laying around to define user preferred color palettes - could be a useful feature for usability/accessibility.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A thought was to implement Solarized Light/Dark color palettes as user options - I am a fan - and plenty of research has gone into these color schemes.

int h = height() - YMARGIN * 2;
painter.setPen(axisCol);
painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);
Expand All @@ -82,44 +97,55 @@ void TrafficGraphWidget::paintEvent(QPaintEvent *)
const QString units = tr("kB/s");
const float yMarginText = 2.0;

// draw lines
painter.setPen(axisCol);
painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
for(float y = val; y < fMax; y += val) {
int yy = YMARGIN + h - h * y / fMax;
painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
}
// if we drew 3 or fewer lines, break them up at the next lower order of magnitude
if(fMax / val <= 3.0f) {
axisCol = axisCol.darker();
// if we drew 10 or 3 fewer lines, break them up at the next lower order of magnitude
if(fMax / val <= (fToggle ? 10.0f : 3.0f)) {
float oldval = val;
val = pow(10.0f, base - 1);
painter.setPen(axisCol);
painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
painter.setPen(axisCol.lighter());
painter.drawText(XMARGIN, y_value(val)-yMarginText, QString("%1 %2").arg(val).arg(units));
if (fToggle) {
int yy = y_value(val*0.1);
painter.drawText(XMARGIN, yy-yMarginText, QString("%1 %2").arg(val*0.1).arg(units));
painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
}
int count = 1;
for(float y = val; y < fMax; y += val, count++) {
// don't overwrite lines drawn above
for(float y = val; y < (!fToggle || fMax / val < 20 ? fMax : oldval); y += val, count++) {
if(count % 10 == 0)
continue;
int yy = YMARGIN + h - h * y / fMax;
int yy = y_value(y);
painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
}
val = oldval;
}
// draw lines
painter.setPen(axisCol);
for(float y = val; y < fMax; y += val) {
int yy = y_value(y);
painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
}
painter.drawText(XMARGIN, y_value(val)-yMarginText, QString("%1 %2").arg(val).arg(units));

painter.setRenderHint(QPainter::Antialiasing);

if(!vSamplesIn.empty()) {
QPainterPath p;
paintPath(p, vSamplesIn);
painter.fillPath(p, QColor(0, 255, 0, 128));
painter.setPen(Qt::green);
QPen ppen (QColor(0,255,0,0),0,Qt::SolidLine);
painter.setPen(ppen);
painter.fillPath(p, QColor(0, 255, 0, 255));
painter.drawPath(p);
}

if(!vSamplesOut.empty()) {
QPainterPath p;
paintPath(p, vSamplesOut);
painter.fillPath(p, QColor(255, 0, 0, 128));
painter.setPen(Qt::red);
QPen ppen (QColor(255,0,0,0),0,Qt::SolidLine);
painter.setPen(ppen);
painter.fillPath(p, QColor(255, 0, 0, 255));
painter.drawPath(p);
}

painter.fillRect(0,0,XMARGIN,height(), Qt::black);
}

void TrafficGraphWidget::updateRates()
Expand All @@ -135,32 +161,35 @@ void TrafficGraphWidget::updateRates()
nLastBytesIn = bytesIn;
nLastBytesOut = bytesOut;

while(vSamplesIn.size() > DESIRED_SAMPLES) {
while(vSamplesIn.size() > FLT_MAX - 1) {
Copy link
Contributor

@rebroad rebroad Feb 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how much memory does this need?

concept ACK implementation NACK - it's unnecessary to store so many sample points, given the granulatory can be decreased as the times period gets longer. Resampling as the data gets older is a better way (as it avoids wasting memory on data that will never be displayed).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree - I have been thinking about how to do this. Maybe pruning the list at larger intervals - keeping samples that are above a moving average. Open to suggestions on implementation. :)

Thanks for looking at this!

Copy link
Contributor Author

@RandyMcMillan RandyMcMillan Feb 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can chunk the end of the list at DESIRED_SAMPLES intervals - calculate the moving average - pruning samples that fall below it.

vSamplesIn.pop_back();
}
while(vSamplesOut.size() > DESIRED_SAMPLES) {
while(vSamplesOut.size() > FLT_MAX - 1) {
vSamplesOut.pop_back();
}

float tmax = 0.0f;
for (const float f : vSamplesIn) {
for (const float f : vSamplesIn.mid(0,(DESIRED_SAMPLES*getGraphRangeMins()/5))) {
if(f > tmax) tmax = f;
}
for (const float f : vSamplesOut) {
for (const float f : vSamplesOut.mid(0,(DESIRED_SAMPLES*getGraphRangeMins()/5))) {
if(f > tmax) tmax = f;
}
fMax = tmax;
update();
}

void TrafficGraphWidget::setGraphRangeMins(int mins)
void TrafficGraphWidget::setGraphRange(std::chrono::minutes new_range)
{
nMins = mins;
int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES;
using namespace std::chrono_literals;
const auto range{new_range};
nMins = new_range.count();
auto msecs_per_sample = nMins * 60 * 1000 / (DESIRED_SAMPLES * (range.count() / 5));
timer->stop();
timer->setInterval(msecsPerSample);
timer->setInterval(msecs_per_sample);

clear();
update();
timer->start();
}

void TrafficGraphWidget::clear()
Expand Down
9 changes: 7 additions & 2 deletions src/qt/trafficgraphwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <QWidget>
#include <QQueue>

#include <chrono>

class ClientModel;

QT_BEGIN_NAMESPACE
Expand All @@ -26,18 +28,21 @@ class TrafficGraphWidget : public QWidget

protected:
void paintEvent(QPaintEvent *) override;
int y_value(float value);
void mouseDoubleClickEvent(QMouseEvent *event) override;
bool fToggle = false;

public Q_SLOTS:
void updateRates();
void setGraphRangeMins(int mins);
void setGraphRange(std::chrono::minutes new_range);
void clear();

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

QTimer *timer;
float fMax;
int nMins;
long nMins;
QQueue<float> vSamplesIn;
QQueue<float> vSamplesOut;
quint64 nLastBytesIn;
Expand Down