mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-28 00:42:19 -07:00
[Client] Show latency details when clicking the ping display
Clicking the status bar ping area opens a popup with a larger instance of the latency graph plus the numeric statistics, selectable and mirrored into the accessible name. Qt::Popup closes it on any outside click; contents refresh live while open. Took 33 seconds
This commit is contained in:
parent
b11fb3d7ca
commit
ad2ff25f1c
3 changed files with 83 additions and 8 deletions
|
|
@ -44,8 +44,7 @@ void LatencyGraphWidget::paintEvent(QPaintEvent * /* event */)
|
||||||
QColor color;
|
QColor color;
|
||||||
color.setHsv(qRound(120.0 * (1.0 - colorRatio)), 255, 255);
|
color.setHsv(qRound(120.0 * (1.0 - colorRatio)), 255, 255);
|
||||||
|
|
||||||
const QRectF bar(static_cast<qreal>(i) * widthPerBar + 1.0,
|
const QRectF bar(static_cast<qreal>(i) * widthPerBar + 1.0, static_cast<qreal>(height()) - barHeight,
|
||||||
static_cast<qreal>(height()) - barHeight,
|
|
||||||
qMax(1.0, widthPerBar - 2.0), barHeight);
|
qMax(1.0, widthPerBar - 2.0), barHeight);
|
||||||
painter.fillRect(bar, color);
|
painter.fillRect(bar, color);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@
|
||||||
|
|
||||||
#include "latency_graph_widget.h"
|
#include "latency_graph_widget.h"
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
LatencyStatusWidget::LatencyStatusWidget(QWidget *parent) : QWidget(parent)
|
LatencyStatusWidget::LatencyStatusWidget(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
@ -24,6 +26,12 @@ LatencyStatusWidget::LatencyStatusWidget(QWidget *parent) : QWidget(parent)
|
||||||
layout->addWidget(latencyGraph);
|
layout->addWidget(latencyGraph);
|
||||||
layout->addWidget(pingLabel);
|
layout->addWidget(pingLabel);
|
||||||
|
|
||||||
|
// Clicking anywhere in the area opens the detail view.
|
||||||
|
for (QObject *child : QList<QObject *>{pingLabel, latencyGraph}) {
|
||||||
|
child->installEventFilter(this);
|
||||||
|
}
|
||||||
|
setCursor(Qt::PointingHandCursor);
|
||||||
|
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,17 +42,73 @@ void LatencyStatusWidget::updateStats(int lastMs, int medianMs, int p95Ms, int m
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString stats = tr("Connection quality over the last %n sample(s):", "", sampleCount) + "\n" +
|
const QString stats = statsText(lastMs, medianMs, p95Ms, maxMs, sampleCount);
|
||||||
tr("Last: %1 ms").arg(lastMs) + "\n" + tr("Median: %1 ms").arg(medianMs) + "\n" +
|
|
||||||
tr("95th percentile: %1 ms").arg(p95Ms) + "\n" + tr("Maximum: %1 ms").arg(maxMs);
|
|
||||||
|
|
||||||
pingLabel->setText(tr("Ping: %1 ms").arg(lastMs));
|
pingLabel->setText(tr("Ping: %1 ms").arg(lastMs));
|
||||||
pingLabel->setToolTip(stats);
|
pingLabel->setToolTip(stats);
|
||||||
pingLabel->setAccessibleDescription(stats);
|
pingLabel->setAccessibleDescription(stats);
|
||||||
|
if (popup && popup->isVisible() && detailLabel) {
|
||||||
|
detailLabel->setText(stats);
|
||||||
|
}
|
||||||
show();
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LatencyStatusWidget::updateSamples(const QList<int> &samplesMs)
|
void LatencyStatusWidget::updateSamples(const QList<int> &samplesMs)
|
||||||
{
|
{
|
||||||
|
latestSamples = samplesMs;
|
||||||
latencyGraph->setSamples(samplesMs);
|
latencyGraph->setSamples(samplesMs);
|
||||||
|
if (popup && popup->isVisible() && detailGraph) {
|
||||||
|
detailGraph->setSamples(samplesMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LatencyStatusWidget::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
if ((watched == pingLabel || watched == latencyGraph) && event->type() == QEvent::MouseButtonPress) {
|
||||||
|
togglePopup();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return QWidget::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LatencyStatusWidget::togglePopup()
|
||||||
|
{
|
||||||
|
if (!popup) {
|
||||||
|
popup = new QWidget(this, Qt::Popup | Qt::FramelessWindowHint);
|
||||||
|
auto *layout = new QVBoxLayout(popup);
|
||||||
|
layout->setContentsMargins(8, 8, 8, 8);
|
||||||
|
|
||||||
|
detailLabel = new QLabel(popup);
|
||||||
|
detailLabel->setAccessibleName(tr("Connection latency details"));
|
||||||
|
detailLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
|
||||||
|
detailGraph = new LatencyGraphWidget(popup);
|
||||||
|
detailGraph->setFixedSize(280, 80);
|
||||||
|
|
||||||
|
layout->addWidget(detailLabel, 0, Qt::AlignLeft);
|
||||||
|
layout->addWidget(detailGraph, 0, Qt::AlignHCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (popup->isVisible()) {
|
||||||
|
popup->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Qt::Popup closes itself on any outside click, so just position and show.
|
||||||
|
if (latestSamples.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
detailGraph->setSamples(latestSamples);
|
||||||
|
detailLabel->setText(pingLabel->toolTip());
|
||||||
|
popup->adjustSize();
|
||||||
|
const QPoint anchor = mapToGlobal(QPoint(width() / 2, 0));
|
||||||
|
popup->move(anchor.x() - popup->width() / 2, anchor.y() - popup->height() - 6);
|
||||||
|
popup->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LatencyStatusWidget::statsText(int lastMs, int medianMs, int p95Ms, int maxMs, int sampleCount) const
|
||||||
|
{
|
||||||
|
return tr("Connection quality over the last %n sample(s):", "", sampleCount) + "\n" +
|
||||||
|
tr("Last: %1 ms").arg(lastMs) + "\n" + tr("Median: %1 ms").arg(medianMs) + "\n" +
|
||||||
|
tr("95th percentile: %1 ms").arg(p95Ms) + "\n" + tr("Maximum: %1 ms").arg(maxMs);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,11 @@ class LatencyGraphWidget;
|
||||||
* @brief Status bar presentation of server round-trip health.
|
* @brief Status bar presentation of server round-trip health.
|
||||||
*
|
*
|
||||||
* Combines the textual "Ping" readout with a small LatencyGraphWidget
|
* Combines the textual "Ping" readout with a small LatencyGraphWidget
|
||||||
* sparkline of the rolling sample window. Stays hidden while disconnected or
|
* sparkline of the rolling sample window. Clicking anywhere in the area opens
|
||||||
* before any samples exist. Owns all latency display state so MainWindow only
|
* a popup with a larger graph and the numeric statistics. It closes on any
|
||||||
* needs to forward two signals here.
|
* outside click. Stays hidden while disconnected or before any samples exist.
|
||||||
|
* Owns all latency display state so MainWindow only needs to forward two
|
||||||
|
* signals here.
|
||||||
*/
|
*/
|
||||||
class LatencyStatusWidget : public QWidget
|
class LatencyStatusWidget : public QWidget
|
||||||
{
|
{
|
||||||
|
|
@ -30,9 +32,19 @@ public slots:
|
||||||
void updateStats(int lastMs, int medianMs, int p95Ms, int maxMs, int sampleCount);
|
void updateStats(int lastMs, int medianMs, int p95Ms, int maxMs, int sampleCount);
|
||||||
void updateSamples(const QList<int> &samplesMs);
|
void updateSamples(const QList<int> &samplesMs);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void togglePopup();
|
||||||
|
QString statsText(int lastMs, int medianMs, int p95Ms, int maxMs, int sampleCount) const;
|
||||||
|
|
||||||
QLabel *pingLabel = nullptr;
|
QLabel *pingLabel = nullptr;
|
||||||
LatencyGraphWidget *latencyGraph = nullptr;
|
LatencyGraphWidget *latencyGraph = nullptr;
|
||||||
|
QWidget *popup = nullptr;
|
||||||
|
LatencyGraphWidget *detailGraph = nullptr;
|
||||||
|
QLabel *detailLabel = nullptr;
|
||||||
|
QList<int> latestSamples;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue