mirror of
https://github.com/Mahdi-zarei/nekoray.git
synced 2025-12-19 05:30:06 +08:00
Replace QtCharts with SpeedWidget (#379)
* Replace QtCharts with SpeedWidget * Replace QtCharts with SpeedWidget
This commit is contained in:
parent
9e1272984a
commit
e38dab01a0
330
3rdparty/qv2ray/v2/ui/widgets/speedchart/SpeedWidget.cpp
vendored
Normal file
330
3rdparty/qv2ray/v2/ui/widgets/speedchart/SpeedWidget.cpp
vendored
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2015 Anton Lashkov <lenton_91@mail.ru>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
* USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If
|
||||||
|
* you modify file(s), you may extend this exception to your version of the
|
||||||
|
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||||
|
* delete this exception statement from your version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SpeedWidget.hpp"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
#define VIEWABLE 120
|
||||||
|
|
||||||
|
// table of supposed nice steps for grid marks to get nice looking quarters of scale
|
||||||
|
const static double roundingTable[] = { 1.2, 1.6, 2, 2.4, 2.8, 3.2, 4, 6, 8 };
|
||||||
|
|
||||||
|
// use binary prefix standards from IEC 60027-2
|
||||||
|
// see http://en.wikipedia.org/wiki/Kilobyte
|
||||||
|
enum SizeUnit : int
|
||||||
|
{
|
||||||
|
Byte, // 1000^0,
|
||||||
|
KByte, // 1000^1,
|
||||||
|
MByte, // 1000^2,
|
||||||
|
GByte, // 1000^3,
|
||||||
|
TByte, // 1000^4,
|
||||||
|
PByte, // 1000^5,
|
||||||
|
EByte // 1000^6
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SplittedValue
|
||||||
|
{
|
||||||
|
double arg;
|
||||||
|
SizeUnit unit;
|
||||||
|
qint64 sizeInBytes() const
|
||||||
|
{
|
||||||
|
auto size = arg;
|
||||||
|
for (int i = 0; i < static_cast<int>(unit); ++i)
|
||||||
|
{
|
||||||
|
size *= 1024;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpeedWidget::SpeedWidget(QWidget *parent) : QGraphicsView(parent)
|
||||||
|
{
|
||||||
|
UpdateSpeedPlotSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedWidget::AddPointData(QMap<SpeedWidget::GraphType, long> data)
|
||||||
|
{
|
||||||
|
SpeedWidget::PointData point;
|
||||||
|
point.x = QDateTime::currentMSecsSinceEpoch() / 1000;
|
||||||
|
for (const auto &[id, data] : data.toStdMap())
|
||||||
|
{
|
||||||
|
if (m_properties.contains(id))
|
||||||
|
point.y[id] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataCollection.push_back(point);
|
||||||
|
|
||||||
|
while (dataCollection.length() > VIEWABLE)
|
||||||
|
{
|
||||||
|
dataCollection.removeFirst();
|
||||||
|
}
|
||||||
|
replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString unitString(const SizeUnit unit, const bool isSpeed)
|
||||||
|
{
|
||||||
|
const static QStringList units{ "B", "KB", "MB", "GB", "TB", "PB", "EB" };
|
||||||
|
auto unitString = units[unit];
|
||||||
|
if (isSpeed)
|
||||||
|
unitString += "/s";
|
||||||
|
return unitString;
|
||||||
|
}
|
||||||
|
|
||||||
|
int friendlyUnitPrecision(const SizeUnit unit)
|
||||||
|
{
|
||||||
|
// friendlyUnit's number of digits after the decimal point
|
||||||
|
switch (unit)
|
||||||
|
{
|
||||||
|
case SizeUnit::Byte: return 0;
|
||||||
|
case SizeUnit::KByte:
|
||||||
|
case SizeUnit::MByte: return 1;
|
||||||
|
case SizeUnit::GByte: return 2;
|
||||||
|
default: return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SplittedValue getRoundedYScale(double value)
|
||||||
|
{
|
||||||
|
if (value == 0.0)
|
||||||
|
return { 0, SizeUnit::Byte };
|
||||||
|
|
||||||
|
if (value <= 12.0)
|
||||||
|
return { 12, SizeUnit::Byte };
|
||||||
|
|
||||||
|
auto calculatedUnit = SizeUnit::Byte;
|
||||||
|
|
||||||
|
while (value > 1000)
|
||||||
|
{
|
||||||
|
value /= 1000;
|
||||||
|
calculatedUnit = static_cast<SizeUnit>(static_cast<int>(calculatedUnit) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > 100.0)
|
||||||
|
{
|
||||||
|
int roundedValue = static_cast<int>(value / 40) * 40;
|
||||||
|
while (roundedValue < value)
|
||||||
|
roundedValue += 40;
|
||||||
|
return { static_cast<double>(roundedValue), calculatedUnit };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > 10.0)
|
||||||
|
{
|
||||||
|
int roundedValue = static_cast<int>(value / 4) * 4;
|
||||||
|
while (roundedValue < value)
|
||||||
|
roundedValue += 4;
|
||||||
|
return { static_cast<double>(roundedValue), calculatedUnit };
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &roundedValue : roundingTable)
|
||||||
|
{
|
||||||
|
if (value <= roundedValue)
|
||||||
|
return { roundedValue, calculatedUnit };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { 10.0, calculatedUnit };
|
||||||
|
}
|
||||||
|
|
||||||
|
QString formatLabel(const double argValue, const SizeUnit unit)
|
||||||
|
{
|
||||||
|
// check is there need for digits after decimal separator
|
||||||
|
const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0;
|
||||||
|
return QLocale::system().toString(argValue, 'f', precision) + " " + unitString(unit, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct QvGraphPenConfig
|
||||||
|
{
|
||||||
|
int R = 150;
|
||||||
|
int G = 150;
|
||||||
|
int B = 150;
|
||||||
|
float width = 1.5f;
|
||||||
|
Qt::PenStyle style = Qt::SolidLine;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SpeedWidget::UpdateSpeedPlotSettings()
|
||||||
|
{
|
||||||
|
const static std::pair<QvGraphPenConfig, QvGraphPenConfig> DefaultPen{ { 134, 196, 63, 1.5f, Qt::SolidLine }, { 50, 153, 255, 1.5f, Qt::SolidLine } };
|
||||||
|
const static std::pair<QvGraphPenConfig, QvGraphPenConfig> DirectPen{ { 0, 210, 240, 1.5f, Qt::DotLine }, { 235, 220, 42, 1.5f, Qt::DotLine } };
|
||||||
|
|
||||||
|
const auto getPen = [](const QvGraphPenConfig &conf)
|
||||||
|
{
|
||||||
|
QPen p{ { conf.R, conf.G, conf.B } };
|
||||||
|
p.setStyle(conf.style);
|
||||||
|
p.setWidthF(conf.width);
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
|
||||||
|
m_properties.clear();
|
||||||
|
|
||||||
|
m_properties[OUTBOUND_PROXY_UP] = { tr("Proxy") + " ↑", getPen(DefaultPen.first) };
|
||||||
|
m_properties[OUTBOUND_PROXY_DOWN] = { tr("Proxy") + " ↓", getPen(DefaultPen.second) };
|
||||||
|
|
||||||
|
m_properties[OUTBOUND_DIRECT_UP] = { tr("Direct") + " ↑", getPen(DirectPen.first) };
|
||||||
|
m_properties[OUTBOUND_DIRECT_DOWN] = { tr("Direct") + " ↓", getPen(DirectPen.second) };
|
||||||
|
|
||||||
|
// m_properties[INBOUND_UP] = { tr("Total") + " ↑", getPen((*Graph->colorConfig)[API_INBOUND].value1) };
|
||||||
|
// m_properties[INBOUND_DOWN] = { tr("Total") + " ↓", getPen((*Graph->colorConfig)[API_INBOUND].value2) };
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedWidget::Clear()
|
||||||
|
{
|
||||||
|
dataCollection.clear();
|
||||||
|
m_properties.clear();
|
||||||
|
UpdateSpeedPlotSettings();
|
||||||
|
replot();
|
||||||
|
}
|
||||||
|
void SpeedWidget::replot()
|
||||||
|
{
|
||||||
|
viewport()->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 SpeedWidget::maxYValue()
|
||||||
|
{
|
||||||
|
quint64 maxYValue = 0;
|
||||||
|
|
||||||
|
for (int id = 0; id < NB_GRAPHS; ++id)
|
||||||
|
for (int i = dataCollection.size() - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j)
|
||||||
|
if (dataCollection[i].y[id] > maxYValue)
|
||||||
|
maxYValue = dataCollection[i].y[id];
|
||||||
|
|
||||||
|
return maxYValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedWidget::paintEvent(QPaintEvent *)
|
||||||
|
{
|
||||||
|
const auto fullRect = viewport()->rect();
|
||||||
|
auto rect = viewport()->rect();
|
||||||
|
|
||||||
|
// Add padding
|
||||||
|
rect.adjust(4, 4, 0, -4);
|
||||||
|
|
||||||
|
const auto niceScale = getRoundedYScale(maxYValue());
|
||||||
|
|
||||||
|
// draw Y axis speed labels
|
||||||
|
const QVector<QString> speedLabels = {
|
||||||
|
formatLabel(niceScale.arg, niceScale.unit),
|
||||||
|
formatLabel((0.75 * niceScale.arg), niceScale.unit),
|
||||||
|
formatLabel((0.50 * niceScale.arg), niceScale.unit),
|
||||||
|
formatLabel((0.25 * niceScale.arg), niceScale.unit),
|
||||||
|
formatLabel(0.0, niceScale.unit),
|
||||||
|
};
|
||||||
|
|
||||||
|
QPainter painter(viewport());
|
||||||
|
painter.setRenderHints(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
const auto fontMetrics = painter.fontMetrics();
|
||||||
|
rect.adjust(0, fontMetrics.height(), 0, 0); // Add top padding for top speed text
|
||||||
|
|
||||||
|
int yAxisWidth = 0;
|
||||||
|
for (const auto &label : speedLabels)
|
||||||
|
if (fontMetrics.horizontalAdvance(label) > yAxisWidth)
|
||||||
|
yAxisWidth = fontMetrics.horizontalAdvance(label);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (const auto &label : speedLabels)
|
||||||
|
{
|
||||||
|
QRectF labelRect(rect.topLeft() + QPointF(-yAxisWidth, (i++) * 0.25 * rect.height() - fontMetrics.height()), QSizeF(2 * yAxisWidth, fontMetrics.height()));
|
||||||
|
painter.drawText(labelRect, label, Qt::AlignRight | Qt::AlignTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw grid lines
|
||||||
|
rect.adjust(yAxisWidth + 4, 0, 0, 0);
|
||||||
|
QPen gridPen;
|
||||||
|
gridPen.setStyle(Qt::DashLine);
|
||||||
|
gridPen.setWidthF(1);
|
||||||
|
gridPen.setColor(QColor(128, 128, 128, 128));
|
||||||
|
|
||||||
|
// Set antialiasing for graphs
|
||||||
|
painter.setPen(gridPen);
|
||||||
|
painter.drawLine(fullRect.left(), rect.top(), rect.right(), rect.top());
|
||||||
|
painter.drawLine(fullRect.left(), rect.top() + 0.25 * rect.height(), rect.right(), rect.top() + 0.25 * rect.height());
|
||||||
|
painter.drawLine(fullRect.left(), rect.top() + 0.50 * rect.height(), rect.right(), rect.top() + 0.50 * rect.height());
|
||||||
|
painter.drawLine(fullRect.left(), rect.top() + 0.75 * rect.height(), rect.right(), rect.top() + 0.75 * rect.height());
|
||||||
|
painter.drawLine(fullRect.left(), rect.bottom(), rect.right(), rect.bottom());
|
||||||
|
|
||||||
|
constexpr auto TIME_AXIS_DIVISIONS = 6;
|
||||||
|
for (int i = 0; i < TIME_AXIS_DIVISIONS; ++i)
|
||||||
|
{
|
||||||
|
const int x = rect.left() + (i * rect.width()) / TIME_AXIS_DIVISIONS;
|
||||||
|
painter.drawLine(x, fullRect.top(), x, fullRect.bottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw graphs
|
||||||
|
// Need, else graphs cross left gridline
|
||||||
|
rect.adjust(3, 0, 0, 0);
|
||||||
|
//
|
||||||
|
const double yMultiplier = (niceScale.arg == 0.0) ? 0.0 : (static_cast<double>(rect.height()) / niceScale.sizeInBytes());
|
||||||
|
const double xTickSize = static_cast<double>(rect.width()) / VIEWABLE;
|
||||||
|
|
||||||
|
for (auto it = m_properties.constKeyValueBegin(); it != m_properties.constKeyValueEnd(); it++)
|
||||||
|
{
|
||||||
|
QVector<QPoint> points;
|
||||||
|
|
||||||
|
for (int i = static_cast<int>(dataCollection.size()) - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j)
|
||||||
|
{
|
||||||
|
const int newX = rect.right() - j * xTickSize;
|
||||||
|
const int newY = rect.bottom() - dataCollection[i].y[it->first] * yMultiplier;
|
||||||
|
points.push_back({ newX, newY });
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.setPen(it->second.pen);
|
||||||
|
painter.drawPolyline(points.data(), points.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw legend
|
||||||
|
double legendHeight = 0;
|
||||||
|
int legendWidth = 0;
|
||||||
|
|
||||||
|
for (const auto &property : qAsConst(m_properties))
|
||||||
|
{
|
||||||
|
if (fontMetrics.horizontalAdvance(property.name) > legendWidth)
|
||||||
|
legendWidth = fontMetrics.horizontalAdvance(property.name);
|
||||||
|
|
||||||
|
legendHeight += 1.5 * fontMetrics.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QPoint legendTopLeft(rect.left() + 4, fullRect.top() + 4);
|
||||||
|
QRectF legendBackgroundRect(QPoint(legendTopLeft.x() - 4, legendTopLeft.y() - 4), QSizeF(legendWidth + 8, legendHeight + 8));
|
||||||
|
auto legendBackgroundColor = QWidget::palette().color(QWidget::backgroundRole());
|
||||||
|
legendBackgroundColor.setAlpha(128); // 50% transparent
|
||||||
|
painter.fillRect(legendBackgroundRect, legendBackgroundColor);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (const auto &property : qAsConst(m_properties))
|
||||||
|
{
|
||||||
|
int nameSize = fontMetrics.horizontalAdvance(property.name);
|
||||||
|
double indent = 1.5 * (i++) * fontMetrics.height();
|
||||||
|
painter.setPen(property.pen);
|
||||||
|
painter.drawLine(legendTopLeft + QPointF(0, indent + fontMetrics.height()), legendTopLeft + QPointF(nameSize, indent + fontMetrics.height()));
|
||||||
|
painter.drawText(QRectF(legendTopLeft + QPointF(0, indent), QSizeF(2 * nameSize, fontMetrics.height())), property.name, QTextOption(Qt::AlignVCenter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
3rdparty/qv2ray/v2/ui/widgets/speedchart/SpeedWidget.hpp
vendored
Normal file
83
3rdparty/qv2ray/v2/ui/widgets/speedchart/SpeedWidget.hpp
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2015 Anton Lashkov <lenton_91@mail.ru>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||||
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
* exception statement from your version.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QGraphicsView>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QPen>
|
||||||
|
|
||||||
|
class SpeedWidget : public QGraphicsView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum GraphType
|
||||||
|
{
|
||||||
|
INBOUND_UP,
|
||||||
|
INBOUND_DOWN,
|
||||||
|
OUTBOUND_PROXY_UP,
|
||||||
|
OUTBOUND_PROXY_DOWN,
|
||||||
|
OUTBOUND_DIRECT_UP,
|
||||||
|
OUTBOUND_DIRECT_DOWN,
|
||||||
|
OUTBOUND_BLOCK_UP,
|
||||||
|
OUTBOUND_BLOCK_DOWN,
|
||||||
|
NB_GRAPHS,
|
||||||
|
};
|
||||||
|
struct PointData
|
||||||
|
{
|
||||||
|
qint64 x;
|
||||||
|
quint64 y[NB_GRAPHS];
|
||||||
|
PointData()
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < NB_GRAPHS; i++)
|
||||||
|
y[i] = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit SpeedWidget(QWidget *parent = nullptr);
|
||||||
|
void UpdateSpeedPlotSettings();
|
||||||
|
void AddPointData(QMap<SpeedWidget::GraphType, long> data);
|
||||||
|
void Clear();
|
||||||
|
void replot();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct GraphProperties
|
||||||
|
{
|
||||||
|
GraphProperties(){};
|
||||||
|
GraphProperties(const QString &name, const QPen &pen) : name(name), pen(pen){};
|
||||||
|
QString name;
|
||||||
|
QPen pen;
|
||||||
|
};
|
||||||
|
|
||||||
|
quint64 maxYValue();
|
||||||
|
QList<PointData> dataCollection;
|
||||||
|
|
||||||
|
QMap<GraphType, GraphProperties> m_properties;
|
||||||
|
};
|
||||||
@ -11,7 +11,7 @@ if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND WIN32)
|
|||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Network LinguistTools Charts DBus)
|
find_package(Qt6 REQUIRED COMPONENTS Widgets Network LinguistTools DBus)
|
||||||
|
|
||||||
if (NKR_CROSS)
|
if (NKR_CROSS)
|
||||||
set_property(TARGET Qt6::moc PROPERTY IMPORTED_LOCATION /usr/bin/moc)
|
set_property(TARGET Qt6::moc PROPERTY IMPORTED_LOCATION /usr/bin/moc)
|
||||||
@ -87,6 +87,8 @@ set(PROJECT_SOURCES
|
|||||||
3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.cpp
|
3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.cpp
|
||||||
3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp
|
3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp
|
||||||
3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.ui
|
3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.ui
|
||||||
|
3rdparty/qv2ray/v2/ui/widgets/speedchart/SpeedWidget.cpp
|
||||||
|
3rdparty/qv2ray/v2/ui/widgets/speedchart/SpeedWidget.hpp
|
||||||
3rdparty/qv2ray/v2/proxy/QvProxyConfigurator.cpp
|
3rdparty/qv2ray/v2/proxy/QvProxyConfigurator.cpp
|
||||||
|
|
||||||
src/api/gRPC.cpp
|
src/api/gRPC.cpp
|
||||||
@ -204,8 +206,6 @@ set(PROJECT_SOURCES
|
|||||||
include/stats/connections/connectionLister.hpp
|
include/stats/connections/connectionLister.hpp
|
||||||
src/stats/connectionLister/connectionLister.cpp
|
src/stats/connectionLister/connectionLister.cpp
|
||||||
src/configs/proxy/Json2Bean.cpp
|
src/configs/proxy/Json2Bean.cpp
|
||||||
include/ui/utils/TrafficChart.h
|
|
||||||
include/ui/utils/CustomChartView.h
|
|
||||||
include/sys/windows/eventHandler.h
|
include/sys/windows/eventHandler.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ target_sources(nekoray PRIVATE ${CMAKE_BINARY_DIR}/translations.qrc)
|
|||||||
# Target Link
|
# Target Link
|
||||||
|
|
||||||
target_link_libraries(nekoray PRIVATE
|
target_link_libraries(nekoray PRIVATE
|
||||||
Qt6::Widgets Qt6::Network Qt6::Charts Qt6::DBus
|
Qt6::Widgets Qt6::Network Qt6::DBus
|
||||||
Threads::Threads
|
Threads::Threads
|
||||||
${NKR_EXTERNAL_TARGETS}
|
${NKR_EXTERNAL_TARGETS}
|
||||||
${PLATFORM_LIBRARIES}
|
${PLATFORM_LIBRARIES}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "include/global/NekoGui.hpp"
|
#include "include/global/NekoGui.hpp"
|
||||||
#include "include/stats/connections/connectionLister.hpp"
|
#include "include/stats/connections/connectionLister.hpp"
|
||||||
#include "utils/TrafficChart.h"
|
#include "3rdparty/qv2ray/v2/ui/widgets/speedchart/SpeedWidget.hpp"
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include <QtDBus>
|
#include <QtDBus>
|
||||||
#endif
|
#endif
|
||||||
@ -191,7 +191,7 @@ private:
|
|||||||
//
|
//
|
||||||
int toolTipID;
|
int toolTipID;
|
||||||
//
|
//
|
||||||
TrafficChart* trafficGraph;
|
SpeedWidget *speedChartWidget;
|
||||||
|
|
||||||
QList<std::shared_ptr<NekoGui::ProxyEntity>> get_now_selected_list();
|
QList<std::shared_ptr<NekoGui::ProxyEntity>> get_now_selected_list();
|
||||||
|
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtCharts/QChartView>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
class CustomChartView : public QChartView
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CustomChartView(QChart *chart, QWidget *parent = nullptr)
|
|
||||||
: QChartView(chart, parent),
|
|
||||||
tooltipTimer(new QTimer(this)),
|
|
||||||
lastMousePos(QPoint(-1, -1))
|
|
||||||
{
|
|
||||||
setMouseTracking(true);
|
|
||||||
tooltipTimer->setInterval(200);
|
|
||||||
tooltipTimer->setSingleShot(true);
|
|
||||||
connect(tooltipTimer, &QTimer::timeout, this, [=]{emit mouseStopEvent(lastMousePos);});
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void mouseStopEvent(QPoint pos);
|
|
||||||
|
|
||||||
void mouseStartMoving();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void mouseMoveEvent(QMouseEvent *event) override
|
|
||||||
{
|
|
||||||
lastMousePos = event->pos();
|
|
||||||
event->ignore();
|
|
||||||
emit mouseStartMoving();
|
|
||||||
tooltipTimer->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QTimer *tooltipTimer;
|
|
||||||
QPoint lastMousePos;
|
|
||||||
};
|
|
||||||
@ -1,315 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <set>
|
|
||||||
#include <QSplineSeries>
|
|
||||||
#include <QDateTimeAxis>
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <QValueAxis>
|
|
||||||
#include <QToolTip>
|
|
||||||
#include <QLegendMarker>
|
|
||||||
#include <QStyleHints>
|
|
||||||
|
|
||||||
#include "CustomChartView.h"
|
|
||||||
|
|
||||||
class TrafficChart
|
|
||||||
{
|
|
||||||
QChart *chart;
|
|
||||||
CustomChartView *chartView;
|
|
||||||
|
|
||||||
QVector<int> proxyDlRaw;
|
|
||||||
QVector<int> proxyUlRaw;
|
|
||||||
QVector<int> directDlRaw;
|
|
||||||
QVector<int> directUlRaw;
|
|
||||||
|
|
||||||
QSplineSeries *proxyDlLine;
|
|
||||||
QSplineSeries *proxyUpLine;
|
|
||||||
QSplineSeries *directDlLine;
|
|
||||||
QSplineSeries *directUpLine;
|
|
||||||
std::multiset<int> dataSet;
|
|
||||||
|
|
||||||
QDateTimeAxis *timeAxis;
|
|
||||||
QValueAxis *valueAxis;
|
|
||||||
|
|
||||||
QMutex tooltipMu;
|
|
||||||
|
|
||||||
int scaleFactor = 1;
|
|
||||||
int intervalRange = 90;
|
|
||||||
|
|
||||||
void updateMagnitude()
|
|
||||||
{
|
|
||||||
auto currMax = dataSet.rbegin().operator*();
|
|
||||||
if (currMax == 0) return;
|
|
||||||
auto prevScale = scaleFactor;
|
|
||||||
// calc new magnitude
|
|
||||||
if (currMax <= 1000)
|
|
||||||
{
|
|
||||||
scaleFactor = 1;
|
|
||||||
}
|
|
||||||
else if (currMax <= 1000000)
|
|
||||||
{
|
|
||||||
scaleFactor = 1000;
|
|
||||||
}
|
|
||||||
else if (currMax <= 1000000000)
|
|
||||||
{
|
|
||||||
scaleFactor = 1000000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scaleFactor = 1000000000;
|
|
||||||
}
|
|
||||||
valueAxis->setMax(static_cast<double>(currMax) / static_cast<double>(scaleFactor) * 1.1);
|
|
||||||
if (prevScale == scaleFactor) return;
|
|
||||||
valueAxis->setLabelFormat(getRateLabel());
|
|
||||||
scaleData();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] QString getRateLabel() const
|
|
||||||
{
|
|
||||||
if (scaleFactor == 1) return "%.0f B/s";
|
|
||||||
if (scaleFactor == 1000) return "%.2f KB/s";
|
|
||||||
if (scaleFactor == 1000000) return "%.2f MB/s";
|
|
||||||
if (scaleFactor == 1000000000) return "%.2f GB/s";
|
|
||||||
return "%.0f ?/s";
|
|
||||||
}
|
|
||||||
|
|
||||||
void scaleData() const
|
|
||||||
{
|
|
||||||
auto data = proxyDlLine->points();
|
|
||||||
for (int i = 0; i < data.size(); i++)
|
|
||||||
{
|
|
||||||
data[i] = {data[i].x(), static_cast<double>(proxyDlRaw[i]) / scaleFactor};
|
|
||||||
}
|
|
||||||
proxyDlLine->replace(data);
|
|
||||||
|
|
||||||
data = proxyUpLine->points();
|
|
||||||
for (int i = 0; i < data.size(); i++)
|
|
||||||
{
|
|
||||||
data[i] = {data[i].x(), static_cast<double>(proxyUlRaw[i]) / scaleFactor};
|
|
||||||
}
|
|
||||||
proxyUpLine->replace(data);
|
|
||||||
|
|
||||||
data = directDlLine->points();
|
|
||||||
for (int i = 0; i < data.size(); i++)
|
|
||||||
{
|
|
||||||
data[i] = {data[i].x(), static_cast<double>(directDlRaw[i]) / scaleFactor};
|
|
||||||
}
|
|
||||||
directDlLine->replace(data);
|
|
||||||
|
|
||||||
data = directUpLine->points();
|
|
||||||
for (int i = 0; i < data.size(); i++)
|
|
||||||
{
|
|
||||||
data[i] = {data[i].x(), static_cast<double>(directUlRaw[i]) / scaleFactor};
|
|
||||||
}
|
|
||||||
directUpLine->replace(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit TrafficChart()
|
|
||||||
{
|
|
||||||
// init
|
|
||||||
chart = new QChart;
|
|
||||||
updateTheme();
|
|
||||||
chart->setTitle(QObject::tr("Traffic Chart"));
|
|
||||||
chart->legend()->setVisible(true);
|
|
||||||
chart->legend()->setAlignment(Qt::AlignBottom);
|
|
||||||
chart->setMargins(QMargins(0, 0, 0, 0));
|
|
||||||
|
|
||||||
proxyDlLine = new QSplineSeries;
|
|
||||||
proxyDlLine->setName(QObject::tr("Proxy Dl"));
|
|
||||||
proxyDlLine->setColor(Qt::darkMagenta);
|
|
||||||
auto pen = proxyDlLine->pen();
|
|
||||||
pen.setWidth(3);
|
|
||||||
proxyDlLine->setPen(pen);
|
|
||||||
chart->addSeries(proxyDlLine);
|
|
||||||
|
|
||||||
proxyUpLine = new QSplineSeries;
|
|
||||||
proxyUpLine->setName(QObject::tr("Proxy Ul"));
|
|
||||||
proxyUpLine->setColor(Qt::darkRed);
|
|
||||||
pen = proxyUpLine->pen();
|
|
||||||
pen.setWidth(3);
|
|
||||||
proxyUpLine->setPen(pen);
|
|
||||||
chart->addSeries(proxyUpLine);
|
|
||||||
|
|
||||||
directDlLine = new QSplineSeries;
|
|
||||||
directDlLine->setName(QObject::tr("Direct Dl"));
|
|
||||||
directDlLine->setColor(Qt::darkGreen);
|
|
||||||
pen = directDlLine->pen();
|
|
||||||
pen.setWidth(3);
|
|
||||||
directDlLine->setPen(pen);
|
|
||||||
chart->addSeries(directDlLine);
|
|
||||||
|
|
||||||
directUpLine = new QSplineSeries;
|
|
||||||
directUpLine->setName(QObject::tr("Direct Ul"));
|
|
||||||
directUpLine->setColor(Qt::darkYellow);
|
|
||||||
pen = directUpLine->pen();
|
|
||||||
pen.setWidth(3);
|
|
||||||
directUpLine->setPen(pen);
|
|
||||||
chart->addSeries(directUpLine);
|
|
||||||
|
|
||||||
timeAxis = new QDateTimeAxis;
|
|
||||||
timeAxis->setFormat("hh:mm:ss");
|
|
||||||
timeAxis->setTickCount(10);
|
|
||||||
auto gridPen = timeAxis->gridLinePen();
|
|
||||||
gridPen.setWidth(1);
|
|
||||||
gridPen.setDashPattern({1,3});
|
|
||||||
gridPen.setColor(Qt::darkGray);
|
|
||||||
timeAxis->setGridLinePen(gridPen);
|
|
||||||
chart->addAxis(timeAxis, Qt::AlignBottom);
|
|
||||||
proxyDlLine->attachAxis(timeAxis);
|
|
||||||
proxyUpLine->attachAxis(timeAxis);
|
|
||||||
directDlLine->attachAxis(timeAxis);
|
|
||||||
directUpLine->attachAxis(timeAxis);
|
|
||||||
|
|
||||||
valueAxis = new QValueAxis;
|
|
||||||
valueAxis->setLabelFormat("%.0f B/s");
|
|
||||||
valueAxis->setMin(0);
|
|
||||||
valueAxis->setMax(1000);
|
|
||||||
valueAxis->setGridLinePen(gridPen);
|
|
||||||
chart->addAxis(valueAxis, Qt::AlignLeft);
|
|
||||||
proxyDlLine->attachAxis(valueAxis);
|
|
||||||
proxyUpLine->attachAxis(valueAxis);
|
|
||||||
directDlLine->attachAxis(valueAxis);
|
|
||||||
directUpLine->attachAxis(valueAxis);
|
|
||||||
|
|
||||||
// initial values
|
|
||||||
auto now = QDateTime::currentDateTime();
|
|
||||||
timeAxis->setRange(now.addSecs(-intervalRange + 1), now);
|
|
||||||
for (int i = 0; i < intervalRange; ++i)
|
|
||||||
{
|
|
||||||
proxyDlLine->append(now.addSecs(-intervalRange+i+1).toMSecsSinceEpoch(), 0);
|
|
||||||
proxyUpLine->append(now.addSecs(-intervalRange+i+1).toMSecsSinceEpoch(), 0);
|
|
||||||
directDlLine->append(now.addSecs(-intervalRange+i+1).toMSecsSinceEpoch(), 0);
|
|
||||||
directUpLine->append(now.addSecs(-intervalRange+i+1).toMSecsSinceEpoch(), 0);
|
|
||||||
|
|
||||||
proxyDlRaw << 0;
|
|
||||||
proxyUlRaw << 0;
|
|
||||||
directDlRaw << 0;
|
|
||||||
directUlRaw << 0;
|
|
||||||
|
|
||||||
dataSet.insert(0);
|
|
||||||
dataSet.insert(0);
|
|
||||||
dataSet.insert(0);
|
|
||||||
dataSet.insert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
chartView = new CustomChartView(chart);
|
|
||||||
chartView->setRenderHint(QPainter::Antialiasing);
|
|
||||||
|
|
||||||
QObject::connect(chartView, &CustomChartView::mouseStopEvent, chartView, [=](const QPoint pos)
|
|
||||||
{
|
|
||||||
if (!chartView->rect().contains(chartView->mapFromGlobal(QCursor::pos()))) return;
|
|
||||||
auto x = chart->mapToValue(pos).x();
|
|
||||||
int idx = -1;
|
|
||||||
int mn=5000000;
|
|
||||||
for (int i=0;i<proxyDlLine->count();i++)
|
|
||||||
{
|
|
||||||
if (auto dif = abs(proxyDlLine->at(i).x()-x); dif <= 500000)
|
|
||||||
{
|
|
||||||
if (dif < mn)
|
|
||||||
{
|
|
||||||
mn = dif;
|
|
||||||
idx = i;
|
|
||||||
}
|
|
||||||
else if (idx > 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (idx == -1) return;
|
|
||||||
const auto format = getRateLabel();
|
|
||||||
const auto data = QString::asprintf(
|
|
||||||
QString("Proxy Dl: " + format + "\nProxy Ul: " + format + "\nDirect Dl: " + format + "\nDirect Ul: " + format).toStdString().c_str(),
|
|
||||||
proxyDlLine->at(idx).y(), proxyUpLine->at(idx).y(), directDlLine->at(idx).y(), directUpLine->at(idx).y());
|
|
||||||
QToolTip::showText(chartView->mapToGlobal(pos), data);
|
|
||||||
});
|
|
||||||
|
|
||||||
QObject::connect(chartView, &CustomChartView::mouseStartMoving, chartView, [=]
|
|
||||||
{
|
|
||||||
if (QToolTip::isVisible())
|
|
||||||
{
|
|
||||||
QToolTip::hideText();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (QLegendMarker* marker : chart->legend()->markers())
|
|
||||||
{
|
|
||||||
QObject::connect(marker, &QLegendMarker::clicked, chartView, [=]
|
|
||||||
{
|
|
||||||
auto series = static_cast<QLineSeries*>(marker->series());
|
|
||||||
double alpha;
|
|
||||||
if (series->isVisible())
|
|
||||||
{
|
|
||||||
series->hide();
|
|
||||||
marker->setVisible(true);
|
|
||||||
alpha = 0.5;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
series->show();
|
|
||||||
alpha = 1.0;
|
|
||||||
}
|
|
||||||
QBrush brush = marker->labelBrush();
|
|
||||||
QColor color = brush.color();
|
|
||||||
color.setAlphaF(alpha);
|
|
||||||
brush.setColor(color);
|
|
||||||
marker->setLabelBrush(brush);
|
|
||||||
|
|
||||||
brush = marker->brush();
|
|
||||||
color = brush.color();
|
|
||||||
color.setAlphaF(alpha);
|
|
||||||
brush.setColor(color);
|
|
||||||
marker->setBrush(brush);
|
|
||||||
|
|
||||||
QPen markerPen = marker->pen();
|
|
||||||
color = markerPen.color();
|
|
||||||
color.setAlphaF(alpha);
|
|
||||||
markerPen.setColor(color);
|
|
||||||
marker->setPen(markerPen);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] QChartView* getChartView() const
|
|
||||||
{
|
|
||||||
return chartView;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateChart(int pDl, int pUl, int dDl, int dUl)
|
|
||||||
{
|
|
||||||
auto now = QDateTime::currentDateTime();
|
|
||||||
dataSet.insert(pDl);
|
|
||||||
dataSet.insert(pUl);
|
|
||||||
dataSet.insert(dDl);
|
|
||||||
dataSet.insert(dUl);
|
|
||||||
|
|
||||||
dataSet.erase(dataSet.find(proxyDlRaw.first()));
|
|
||||||
dataSet.erase(dataSet.find(proxyUlRaw.first()));
|
|
||||||
dataSet.erase(dataSet.find(directDlRaw.first()));
|
|
||||||
dataSet.erase(dataSet.find(directUlRaw.first()));
|
|
||||||
|
|
||||||
proxyDlLine->remove(0);
|
|
||||||
proxyUpLine->remove(0);
|
|
||||||
directDlLine->remove(0);
|
|
||||||
directUpLine->remove(0);
|
|
||||||
|
|
||||||
proxyDlRaw.removeFirst();
|
|
||||||
proxyUlRaw.removeFirst();
|
|
||||||
directDlRaw.removeFirst();
|
|
||||||
directUlRaw.removeFirst();
|
|
||||||
|
|
||||||
proxyDlLine->append(now.toMSecsSinceEpoch(), static_cast<double>(pDl) / static_cast<double>(scaleFactor));
|
|
||||||
proxyUpLine->append(now.toMSecsSinceEpoch(), static_cast<double>(pUl) / static_cast<double>(scaleFactor));
|
|
||||||
directDlLine->append(now.toMSecsSinceEpoch(), static_cast<double>(dDl) / static_cast<double>(scaleFactor));
|
|
||||||
directUpLine->append(now.toMSecsSinceEpoch(), static_cast<double>(dUl) / static_cast<double>(scaleFactor));
|
|
||||||
|
|
||||||
proxyDlRaw << pDl;
|
|
||||||
proxyUlRaw << pUl;
|
|
||||||
directDlRaw << dDl;
|
|
||||||
directUlRaw << dUl;
|
|
||||||
|
|
||||||
timeAxis->setRange(now.addSecs(-intervalRange + 1), now);
|
|
||||||
|
|
||||||
updateMagnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateTheme()
|
|
||||||
{
|
|
||||||
chart->setTheme(qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark ? QChart::ChartThemeDark : QChart::ChartThemeLight);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -2127,4 +2127,15 @@ Direct: %2</source>
|
|||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SpeedWidget</name>
|
||||||
|
<message>
|
||||||
|
<source>Proxy</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Direct</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
</TS>
|
</TS>
|
||||||
|
|||||||
@ -2153,4 +2153,15 @@ Release note:
|
|||||||
<translation type="unfinished">Некоторые правила не удалось добавить, исправьте их перед сохранением:</translation>
|
<translation type="unfinished">Некоторые правила не удалось добавить, исправьте их перед сохранением:</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SpeedWidget</name>
|
||||||
|
<message>
|
||||||
|
<source>Proxy</source>
|
||||||
|
<translation>Прокси</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Direct</source>
|
||||||
|
<translation>Напрямую</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
</TS>
|
</TS>
|
||||||
|
|||||||
@ -2083,7 +2083,7 @@ Release note:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Direct</source>
|
<source>Direct</source>
|
||||||
<translation>直接</translation>
|
<translation>直连</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Proxy</source>
|
<source>Proxy</source>
|
||||||
@ -2141,4 +2141,15 @@ Release note:
|
|||||||
<translation>某些规则无法添加,请在保存之前修复它们:</translation>
|
<translation>某些规则无法添加,请在保存之前修复它们:</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SpeedWidget</name>
|
||||||
|
<message>
|
||||||
|
<source>Proxy</source>
|
||||||
|
<translation>代理</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Direct</source>
|
||||||
|
<translation>直连</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
</TS>
|
</TS>
|
||||||
|
|||||||
@ -47,7 +47,6 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QStyleHints>
|
#include <QStyleHints>
|
||||||
#include <QToolTip>
|
#include <QToolTip>
|
||||||
#include <QtCharts>
|
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <3rdparty/QHotkey/qhotkey.h>
|
#include <3rdparty/QHotkey/qhotkey.h>
|
||||||
#include <include/api/gRPC.h>
|
#include <include/api/gRPC.h>
|
||||||
@ -89,7 +88,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||||||
connect(qApp->styleHints(), &QStyleHints::colorSchemeChanged, this, [=](const Qt::ColorScheme& scheme) {
|
connect(qApp->styleHints(), &QStyleHints::colorSchemeChanged, this, [=](const Qt::ColorScheme& scheme) {
|
||||||
new SyntaxHighlighter(scheme == Qt::ColorScheme::Dark, qvLogDocument);
|
new SyntaxHighlighter(scheme == Qt::ColorScheme::Dark, qvLogDocument);
|
||||||
themeManager->ApplyTheme(NekoGui::dataStore->theme, true);
|
themeManager->ApplyTheme(NekoGui::dataStore->theme, true);
|
||||||
if (trafficGraph) trafficGraph->updateTheme();
|
|
||||||
});
|
});
|
||||||
connect(themeManager, &ThemeManager::themeChanged, this, [=](const QString& theme){
|
connect(themeManager, &ThemeManager::themeChanged, this, [=](const QString& theme){
|
||||||
if (theme.toLower().contains("vista")) {
|
if (theme.toLower().contains("vista")) {
|
||||||
@ -256,9 +254,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// setup Traffic Graph
|
// setup Speed Chart
|
||||||
trafficGraph = new TrafficChart();
|
speedChartWidget = new SpeedWidget(this);
|
||||||
ui->graph_tab->layout()->addWidget(trafficGraph->getChartView());
|
ui->graph_tab->layout()->addWidget(speedChartWidget);
|
||||||
|
|
||||||
// table UI
|
// table UI
|
||||||
ui->proxyListTable->callback_save_order = [=] {
|
ui->proxyListTable->callback_save_order = [=] {
|
||||||
@ -1165,7 +1163,15 @@ void MainWindow::refresh_status(const QString &traffic_update) {
|
|||||||
|
|
||||||
void MainWindow::update_traffic_graph(int proxyDl, int proxyUp, int directDl, int directUp)
|
void MainWindow::update_traffic_graph(int proxyDl, int proxyUp, int directDl, int directUp)
|
||||||
{
|
{
|
||||||
if (trafficGraph) trafficGraph->updateChart(proxyDl, proxyUp, directDl, directUp);;
|
if (speedChartWidget) {
|
||||||
|
QMap<SpeedWidget::GraphType, long> pointData;
|
||||||
|
pointData[SpeedWidget::OUTBOUND_PROXY_UP] = proxyUp;
|
||||||
|
pointData[SpeedWidget::OUTBOUND_PROXY_DOWN] = proxyDl;
|
||||||
|
pointData[SpeedWidget::OUTBOUND_DIRECT_UP] = directUp;
|
||||||
|
pointData[SpeedWidget::OUTBOUND_DIRECT_DOWN] = directDl;
|
||||||
|
|
||||||
|
speedChartWidget->AddPointData(pointData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// table显示
|
// table显示
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user