Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom widget for speed button in the status bar #7427

Closed
wants to merge 1 commit into from
Closed

Add custom widget for speed button in the status bar #7427

wants to merge 1 commit into from

Conversation

zeule
Copy link
Contributor

@zeule zeule commented Sep 11, 2017

Since a proportional font is used usually for GUI texts, the width
of speed status labels can fluctuate significantly due to speed changes
and digit variability. Because of that the download speed button jitters
in the status bar from left to right, creating unpleasant visual
experience.

Here we replace it with a custom widget, that attempts to allocate
constant-sized placeholders for its text labels, thus eliminating the
jitter.

Example of the problem: https://streamable.com/jhsqz

@zeule zeule added the GUI GUI-related issues/changes label Sep 11, 2017
public:
StatusSpeedButton(QWidget *parent = nullptr);

void setCurrentSpeed(quint64 currentSpeed);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe joining these 3 into a single call would be better, because each of them calls QWidget::updateGeometry()

Copy link
Member

Choose a reason for hiding this comment

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

From the current use POV it's better. But not from the abstract design POV. Although you can track appropriate value changes (ie. have cached value in your class and compare it with new one).

Copy link
Member

Choose a reason for hiding this comment

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

Although you can track appropriate value changes (ie. have cached value in your class and compare it with new one).

Incidentally, this will prevent unnecessary calculations for those values which are updated rarely (e.g. speed limits).

@zeule
Copy link
Contributor Author

zeule commented Sep 11, 2017

@LordNyriox: there is no need in that, I believe, because status bar will not provide updates in that case.

@zeule
Copy link
Contributor Author

zeule commented Sep 11, 2017

@LordNyriox: thanks! Corrected.

QString numberPart;
if (unit == SizeUnit::Byte) {
numberPart = QString(QLatin1String("%1")).arg(bytesValue, fieldWidth, 10, fill);
} else {
Copy link
Member

Choose a reason for hiding this comment

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

coding style

Copy link
Contributor

@thalieht thalieht left a comment

Choose a reason for hiding this comment

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

Coding style


#include <QApplication>
#include <QStylePainter>
#include <QStyleOptionButton>
Copy link
Contributor

Choose a reason for hiding this comment

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

One up.

* @brief Status bar button with speed text
*
*/
class StatusSpeedButton final: public QPushButton
Copy link
Contributor

Choose a reason for hiding this comment

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

New rule: spaces around the colon.

@glassez
Copy link
Member

glassez commented Sep 11, 2017

FYI, StatusBar instance isn't created if it isn't showed and it is deleted when it becomes unused (unvisible from user POV).

@@ -69,23 +70,13 @@ StatusBar::StatusBar(QWidget *parent)
.arg(tr("No direct connections. This may indicate network configuration problems.")));
connect(m_connecStatusLblIcon, &QAbstractButton::clicked, this, &StatusBar::connectionButtonClicked);

m_dlSpeedLbl = new QPushButton(this);
m_dlSpeedLbl = new StatusSpeedButton(this);
Copy link
Member

Choose a reason for hiding this comment

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

m_dlSpeedLbl -> m_dlSpeedButton


m_upSpeedLbl = new QPushButton(this);
m_upSpeedLbl = new StatusSpeedButton(this);
Copy link
Member

Choose a reason for hiding this comment

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

m_upSpeedLbl -> m_upSpeedButton

#include "base/unicodestrings.h"
#include "base/utils/misc.h"

StatusSpeedButton::StatusSpeedButton(QWidget* parent)
Copy link
Member

Choose a reason for hiding this comment

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

QWidget *parent

}

void StatusSpeedButton::updateSection(QStaticText &section, quint64 bytes, bool isSpeed,
int minMantissaDigits, const QString& templateText)
Copy link
Member

Choose a reason for hiding this comment

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

Please realign all pointers and references.

using base = QPushButton;

public:
StatusSpeedButton(QWidget *parent = nullptr);
Copy link
Member

Choose a reason for hiding this comment

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

explicit

void setSpeedLimit(int speedLimit);
void setTotalPayload(quint64 totalPayload);

protected:
Copy link
Member

Choose a reason for hiding this comment

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

protected is meaningless in final class

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not final now.

public:
StatusSpeedButton(QWidget *parent = nullptr);

void setCurrentSpeed(quint64 currentSpeed);
Copy link
Member

Choose a reason for hiding this comment

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

From the current use POV it's better. But not from the abstract design POV. Although you can track appropriate value changes (ie. have cached value in your class and compare it with new one).

public:
StatusSpeedButton(QWidget *parent = nullptr);

void setCurrentSpeed(quint64 currentSpeed);
Copy link
Member

Choose a reason for hiding this comment

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

Although you can track appropriate value changes (ie. have cached value in your class and compare it with new one).

Incidentally, this will prevent unnecessary calculations for those values which are updated rarely (e.g. speed limits).

@zeule
Copy link
Contributor Author

zeule commented Sep 11, 2017

Review comments addressed. Thanks!

#include <QTextOption>

#include "base/unicodestrings.h"
#include "base/utils/misc.h"

StatusSpeedButton::Section::Section(const QString& templateText, int minDigits,
Copy link
Member

Choose a reason for hiding this comment

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

const QString &templateText

}
}

QStaticText StatusSpeedButton::emptyText()
QChar StatusSpeedButton::widestDecimalDigit()
Copy link
Member

Choose a reason for hiding this comment

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

I would add const even used internally.

res.setTextFormat(Qt::PlainText);
res.setTextOption({Qt::AlignRight});
return res;
const QString digits = QLocale().toString(1234567890);
Copy link
Member

Choose a reason for hiding this comment

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

why QLocale here, does it do anything special?

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 need localised digits as would be produced by QString::arg(), but here I don't need the template string.

Copy link
Member

@Chocobo1 Chocobo1 Sep 12, 2017

Choose a reason for hiding this comment

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

I understand it now.
Not related to this PR, just my opinion, do you really expect to see a localized number string in the button? I mean I prefer plain number, commas or anything else for separator is redundant IMO.

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'm weak in locale-related things. Just wanted to avoid any assumptions that might fail.

qreal maxWidth = 0.;
QChar digit;
QFontMetricsF fm {font(), this};
for (int i = 0; i < digits.size(); ++i) {
Copy link
Member

Choose a reason for hiding this comment

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

minor thing, you can use range based for loop here.

@Chocobo1
Copy link
Member

Chocobo1 commented Sep 12, 2017

Asking a naive question here: in git master code, what about recording the largest width of the speed limit button and set it every time when it updates, well... assuming the width size don't explode.

@zeule
Copy link
Contributor Author

zeule commented Sep 12, 2017

what about recording the largest width of the speed limit button and set it every time when it updates,

I actually do exactly that for speed label, just allocate that space a bit in advance. But to get a stable position of the label (each of them), you also have to right-alight it. From there we are only a step away from the approach of this PR. Namely: should we try to predict the possible widest label or not.

Perhaps we simply measure width of the unit strings (once on initialisation), select the widest and just allocate space for "1023.99 "? But that labels will look quite strangely spaced most of the time.

@Chocobo1
Copy link
Member

Chocobo1 commented Sep 12, 2017

Thanks for the explain!
I've a bit more concerns:

  • what about RTL locales? will it work?
  • I think maybe the overall approach is a bit complex for such a UI element (both code & memory), I hope there could be a simpler solution
    Although you mentioned jitter and I understand what it means, I cannot observe it on my system (Sans Regular 10pt font here), can you describe it a bit more?
    So the jitter is caused by different glyph widths in font, so instead of using fixed-width spaces for separating fields, maybe you should use tabs instead, but I cannot verify this as I didn't experience the jitter symptom.
  • another bug found: the up arrow icon & the down arrow icon is shifted a few pixels down:
    pic

@zeule
Copy link
Contributor Author

zeule commented Sep 12, 2017

what about RTL locales? will it work?

Oh, thanks! Need to use left-alignment for them.

I think maybe the overall approach is a bit complex

Agree with you. But can't help myself, want smooth UI so much :)

Although you mentioned jitter and I understand what it means, I cannot observe it on my system (Sans Regular 10pt font here), can you describe it a bit more?

Here is a screen record, please: https://streamable.com/jhsqz

another bug found:

What QStyle do you use, please? I don't see anything like that.

@Chocobo1
Copy link
Member

Agree with you. But can't help myself, want smooth UI so much :)

Let me experiment a little...

Here is a screen record, please: https://streamable.com/jhsqz

OK, thanks!

What QStyle do you use, please? I don't see anything like that.

Fusion I guess.

@zeule
Copy link
Contributor Author

zeule commented Sep 12, 2017

What QStyle do you use, please? I don't see anything like that.

Fusion I guess.

Wrong metric was used. Should be correct now.

@zeule
Copy link
Contributor Author

zeule commented Sep 14, 2017

Do I correctly understand from your comments, that this PR contains too much of code and is too complicated for the task?

Since a proportional font is used usually for GUI texts, the width
of speed status labels can fluctuate significantly due to speed changes
and digit variability. Because of that the download speed button jitters
in the status bar from left to right, creating unpleasant visual
experience.

Here we replace it with a custom widget, that attempts to allocate
constatn-sized placeholders for its text labels, thus eliminating the
jitter.
@d-s-x
Copy link
Contributor

d-s-x commented Oct 13, 2017

@evsh,

this PR contains too much of code and is too complicated for the task?

Here is a screen record, please: https://streamable.com/jhsqz

When no limit is set there is a plenty of free space for both download and upload speeds.
That means that there is a minimal width applied to the labels.
When a limit is enabled (easy to reproduce with 100 KiB/s upload limit) width of the text exceeds the minimal width and thus the status bar "jitters".

Simplest solution is to increase width for the labels and made it fixed (not dependent on content).
This usually requires 2 lines changed (not 372 as in this PR)

@glassez
Copy link
Member

glassez commented Dec 10, 2019

@Chocobo1, @sledgehammer999, are we interested in this feature? (given the fact that the author has been inactive for a long time)

@Chocobo1
Copy link
Member

@Chocobo1, @sledgehammer999, are we interested in this feature? (given the fact that the author has been inactive for a long time)

IIRC I did still see some resizing quirks, although much less often. And I think the implementation is maybe a little bit too complex.

@glassez
Copy link
Member

glassez commented Dec 12, 2019

And I think the implementation is maybe a little bit too complex.

As I said before the implementation is too complex for this job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
GUI GUI-related issues/changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants