Skip to content

Commit cd70ffc

Browse files
committed
Update digital clock display
1 parent 080a798 commit cd70ffc

8 files changed

Lines changed: 150 additions & 57 deletions

File tree

‎src/libs/application/uishell/src/DigitalClockLabel.cpp‎

Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,120 @@
33

44
#include "DigitalClockLabel_p.h"
55

6+
#include <algorithm>
7+
8+
#include <QFontMetricsF>
9+
#include <QTextLayout>
10+
611
#include <QtQuick/private/qquicktext_p_p.h>
712

813
namespace UIShell {
914

1015
DigitalClockLabel::DigitalClockLabel(QQuickItem *parent) : QQuickText(parent) {
1116
}
17+
1218
DigitalClockLabel::~DigitalClockLabel() = default;
1319

1420
QString DigitalClockLabel::text() const {
15-
return m_fullText;
21+
return m_text;
1622
}
1723

1824
void DigitalClockLabel::setText(const QString &text) {
19-
if (m_fullText == text)
25+
if (text == m_text) {
2026
return;
21-
22-
m_fullText = text;
27+
}
28+
m_text = text;
2329
updateDigitalFormat();
24-
Q_EMIT textChanged();
2530
}
2631

27-
bool DigitalClockLabel::fineTuneEnabled() const {
28-
return m_fineTuneEnabled;
32+
QFont DigitalClockLabel::font() const {
33+
return m_font;
2934
}
3035

31-
void DigitalClockLabel::setFineTuneEnabled(bool enabled) {
32-
if (m_fineTuneEnabled == enabled)
36+
void DigitalClockLabel::setFont(const QFont &font) {
37+
if (font == m_font) {
3338
return;
34-
35-
m_fineTuneEnabled = enabled;
39+
}
40+
m_font = font;
3641
updateDigitalFormat();
42+
Q_EMIT fontChanged();
43+
}
3744

38-
if (isComponentComplete())
39-
forceLayout();
40-
41-
Q_EMIT fineTuneEnabledChanged();
45+
DigitalClockLabel::FineTuneMode DigitalClockLabel::fineTuneMode() const {
46+
return m_fineTuneMode;
4247
}
4348

44-
static inline QTextLayout::FormatRange fixedPitchRange(int start, int length) {
45-
QTextLayout::FormatRange range;
46-
range.start = start;
47-
range.length = length;
48-
range.format.setFontFixedPitch(true);
49-
return range;
49+
void DigitalClockLabel::setFineTuneMode(FineTuneMode mode) {
50+
if (m_fineTuneMode == mode) {
51+
return;
52+
}
53+
m_fineTuneMode = mode;
54+
updateDigitalFormat();
55+
Q_EMIT fineTuneModeChanged();
5056
}
5157

52-
static constexpr bool isIncludedChar(QChar c) {
53-
return c.isDigit();
58+
static QList<QTextLayout::FormatRange> makeTabularDigitFormats(const QString &text, const QFont &font) {
59+
QFontMetricsF fm(font);
60+
61+
qreal digitWidth = 0.0;
62+
for (int i = 0; i <= 9; i++) {
63+
const QChar ch(static_cast<uchar>('0' + i));
64+
digitWidth = std::max(digitWidth, fm.horizontalAdvance(ch));
65+
}
66+
67+
QList<QTextLayout::FormatRange> formats;
68+
formats.reserve(text.size());
69+
70+
for (qsizetype i = 0; i < text.size(); ++i) {
71+
const QChar ch = text[i];
72+
73+
if (!ch.isDigit())
74+
continue;
75+
76+
const qreal width = fm.horizontalAdvance(ch);
77+
const qreal extraSpacing = digitWidth - width;
78+
79+
QTextCharFormat format;
80+
81+
format.setFontKerning(false);
82+
83+
format.setFontLetterSpacingType(QFont::AbsoluteSpacing);
84+
format.setFontLetterSpacing(extraSpacing);
85+
86+
QTextLayout::FormatRange range;
87+
range.start = static_cast<int>(i);
88+
range.length = 1;
89+
range.format = format;
90+
91+
formats.append(range);
92+
}
93+
94+
return formats;
5495
}
5596

5697
void DigitalClockLabel::updateDigitalFormat() {
57-
// FIXME
58-
QString text = m_fullText;
98+
auto font = m_font;
99+
switch (m_fineTuneMode) {
100+
case None:
101+
font.unsetFeature("tnum");
102+
break;
103+
case TabularFiguresFontFeature:
104+
font.setFeature("tnum", 1);
105+
break;
106+
case LayoutSimulation:
107+
font.unsetFeature("tnum");
108+
break;
109+
}
110+
QQuickText::setFont(font);
111+
QQuickText::setText(m_text);
59112
QList<QTextLayout::FormatRange> formats;
60-
if (m_fineTuneEnabled) {
61-
formats += fixedPitchRange(0, m_fullText.length());
113+
if (m_fineTuneMode == LayoutSimulation) {
114+
formats = makeTabularDigitFormats(m_text, font);
62115
}
63116
QQuickTextPrivate::get(this)->layout.setFormats(formats);
64-
QQuickText::setText(text);
117+
if (isComponentComplete()) {
118+
forceLayout();
119+
}
65120
}
66121

67122
}

‎src/libs/application/uishell/src/DigitalClockLabel_p.h‎

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
#include <qqmlintegration.h>
88

9+
#include <QFont>
910
#include <QObject>
11+
#include <QString>
1012

1113
#include <QtQuick/private/qquicktext_p.h>
1214

@@ -17,27 +19,41 @@ namespace UIShell {
1719
QML_ELEMENT
1820

1921
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
20-
Q_PROPERTY(bool fineTuneEnabled READ fineTuneEnabled WRITE setFineTuneEnabled NOTIFY fineTuneEnabledChanged)
22+
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
23+
Q_PROPERTY(FineTuneMode fineTuneMode READ fineTuneMode WRITE setFineTuneMode NOTIFY fineTuneModeChanged)
2124

2225
public:
26+
enum FineTuneMode {
27+
None,
28+
TabularFiguresFontFeature,
29+
LayoutSimulation,
30+
};
31+
Q_ENUM(FineTuneMode)
32+
2333
explicit DigitalClockLabel(QQuickItem *parent = nullptr);
2434
~DigitalClockLabel() override;
2535

2636
QString text() const;
2737
void setText(const QString &text);
2838

29-
bool fineTuneEnabled() const;
30-
void setFineTuneEnabled(bool enabled);
39+
QFont font() const;
40+
void setFont(const QFont &font);
41+
42+
FineTuneMode fineTuneMode() const;
43+
void setFineTuneMode(FineTuneMode mode);
3144

3245
Q_SIGNALS:
3346
void textChanged();
34-
void fineTuneEnabledChanged();
47+
void fontChanged();
48+
void fineTuneModeChanged();
3549

3650
private:
3751
void updateDigitalFormat();
3852

39-
bool m_fineTuneEnabled = true;
40-
QString m_fullText;
53+
QString m_text;
54+
QFont m_font;
55+
FineTuneMode m_fineTuneMode = TabularFiguresFontFeature;
56+
4157
};
4258

4359
}

‎src/libs/application/uishell/src/qml/DigitalClock.qml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import SVSCraft.UIComponents
1111
T.Button {
1212
id: control
1313
property bool backgroundVisible: true
14+
property int fineTuneMode: DigitalClockLabel.TabularFiguresFontFeature
1415

1516
implicitWidth: Math.max(backgroundVisible ? 108 : 0, timeLabel.width + 16)
1617
implicitHeight: 24
@@ -32,5 +33,6 @@ T.Button {
3233
color: Theme.foregroundPrimaryColor
3334
font.family: Theme.font.family
3435
font.pixelSize: 16
36+
fineTuneMode: control.fineTuneMode
3537
}
3638
}

‎src/plugins/coreplugin/internal/BehaviorPreference.cpp‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace Core::Internal {
4343
BehaviorPreference::TimeIndicatorInteractionBehavior timeIndicatorClickAction{};
4444
BehaviorPreference::TimeIndicatorInteractionBehavior timeIndicatorDoubleClickAction{};
4545
BehaviorPreference::TimeIndicatorInteractionBehavior timeIndicatorPressAndHoldAction{};
46-
bool timeIndicatorTextFineTuneEnabled{};
46+
BehaviorPreference::TimeIndicatorTextFineTuneMode timeIndicatorTextFineTuneMode{};
4747
bool timeIndicatorShowSliderOnHover{};
4848
};
4949

@@ -131,8 +131,8 @@ namespace Core::Internal {
131131
emit timeIndicatorDoubleClickActionChanged();
132132
d->timeIndicatorPressAndHoldAction = settings->value("timeIndicatorPressAndHoldAction", QVariant::fromValue(TIIB_ShowGoTo)).value<TimeIndicatorInteractionBehavior>();
133133
emit timeIndicatorPressAndHoldActionChanged();
134-
d->timeIndicatorTextFineTuneEnabled = settings->value("timeIndicatorTextFineTuneEnabled", true).toBool();
135-
emit timeIndicatorTextFineTuneEnabledChanged();
134+
d->timeIndicatorTextFineTuneMode = settings->value("timeIndicatorTextFineTuneMode", QVariant::fromValue(TITFTM_TabularFiguresFontFeature)).value<TimeIndicatorTextFineTuneMode>();
135+
emit timeIndicatorTextFineTuneModeChanged();
136136
d->timeIndicatorShowSliderOnHover = settings->value("timeIndicatorShowSliderOnHover", true).toBool();
137137
emit timeIndicatorShowSliderOnHoverChanged();
138138
settings->endGroup();
@@ -170,7 +170,7 @@ namespace Core::Internal {
170170
settings->setValue("timeIndicatorClickAction", static_cast<int>(d->timeIndicatorClickAction));
171171
settings->setValue("timeIndicatorDoubleClickAction", static_cast<int>(d->timeIndicatorDoubleClickAction));
172172
settings->setValue("timeIndicatorPressAndHoldAction", static_cast<int>(d->timeIndicatorPressAndHoldAction));
173-
settings->setValue("timeIndicatorTextFineTuneEnabled", d->timeIndicatorTextFineTuneEnabled);
173+
settings->setValue("timeIndicatorTextFineTuneMode", static_cast<int>(d->timeIndicatorTextFineTuneMode));
174174
settings->setValue("timeIndicatorShowSliderOnHover", d->timeIndicatorShowSliderOnHover);
175175
settings->endGroup();
176176
}
@@ -505,16 +505,16 @@ namespace Core::Internal {
505505
d->timeIndicatorPressAndHoldAction = timeIndicatorPressAndHoldAction;
506506
emit m_instance->timeIndicatorPressAndHoldActionChanged();
507507
}
508-
bool BehaviorPreference::timeIndicatorTextFineTuneEnabled() {
508+
BehaviorPreference::TimeIndicatorTextFineTuneMode BehaviorPreference::timeIndicatorTextFineTuneMode() {
509509
M_INSTANCE_D;
510-
return d->timeIndicatorTextFineTuneEnabled;
510+
return d->timeIndicatorTextFineTuneMode;
511511
}
512-
void BehaviorPreference::setTimeIndicatorTextFineTuneEnabled(bool timeIndicatorTextFineTuneEnabled) {
512+
void BehaviorPreference::setTimeIndicatorTextFineTuneMode(TimeIndicatorTextFineTuneMode timeIndicatorTextFineTuneMode) {
513513
M_INSTANCE_D;
514-
if (d->timeIndicatorTextFineTuneEnabled == timeIndicatorTextFineTuneEnabled)
514+
if (d->timeIndicatorTextFineTuneMode == timeIndicatorTextFineTuneMode)
515515
return;
516-
d->timeIndicatorTextFineTuneEnabled = timeIndicatorTextFineTuneEnabled;
517-
emit m_instance->timeIndicatorTextFineTuneEnabledChanged();
516+
d->timeIndicatorTextFineTuneMode = timeIndicatorTextFineTuneMode;
517+
emit m_instance->timeIndicatorTextFineTuneModeChanged();
518518
}
519519
bool BehaviorPreference::timeIndicatorShowSliderOnHover() {
520520
M_INSTANCE_D;

‎src/plugins/coreplugin/internal/BehaviorPreference.h‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ namespace Core::Internal {
5151
Q_PROPERTY(BehaviorPreference::TimeIndicatorInteractionBehavior timeIndicatorClickAction READ timeIndicatorClickAction WRITE setTimeIndicatorClickAction NOTIFY timeIndicatorClickActionChanged)
5252
Q_PROPERTY(BehaviorPreference::TimeIndicatorInteractionBehavior timeIndicatorDoubleClickAction READ timeIndicatorDoubleClickAction WRITE setTimeIndicatorDoubleClickAction NOTIFY timeIndicatorDoubleClickActionChanged)
5353
Q_PROPERTY(BehaviorPreference::TimeIndicatorInteractionBehavior timeIndicatorPressAndHoldAction READ timeIndicatorPressAndHoldAction WRITE setTimeIndicatorPressAndHoldAction NOTIFY timeIndicatorPressAndHoldActionChanged)
54-
Q_PROPERTY(bool timeIndicatorTextFineTuneEnabled READ timeIndicatorTextFineTuneEnabled WRITE setTimeIndicatorTextFineTuneEnabled NOTIFY timeIndicatorTextFineTuneEnabledChanged)
54+
Q_PROPERTY(BehaviorPreference::TimeIndicatorTextFineTuneMode timeIndicatorTextFineTuneMode READ timeIndicatorTextFineTuneMode WRITE setTimeIndicatorTextFineTuneMode NOTIFY timeIndicatorTextFineTuneModeChanged)
5555
Q_PROPERTY(bool timeIndicatorShowSliderOnHover READ timeIndicatorShowSliderOnHover WRITE setTimeIndicatorShowSliderOnHover NOTIFY timeIndicatorShowSliderOnHoverChanged)
5656

5757
public:
@@ -199,6 +199,13 @@ namespace Core::Internal {
199199
};
200200
Q_ENUM(TimeIndicatorInteractionBehavior)
201201

202+
enum TimeIndicatorTextFineTuneMode {
203+
TITFTM_None,
204+
TITFTM_TabularFiguresFontFeature,
205+
TITFTM_LayoutSimulation,
206+
};
207+
Q_ENUM(TimeIndicatorTextFineTuneMode)
208+
202209
static bool timeIndicatorBackgroundVisible();
203210
static void setTimeIndicatorBackgroundVisible(bool timeIndicatorBackgroundVisible);
204211

@@ -211,8 +218,8 @@ namespace Core::Internal {
211218
static TimeIndicatorInteractionBehavior timeIndicatorPressAndHoldAction();
212219
static void setTimeIndicatorPressAndHoldAction(TimeIndicatorInteractionBehavior timeIndicatorPressAndHoldAction);
213220

214-
static bool timeIndicatorTextFineTuneEnabled();
215-
static void setTimeIndicatorTextFineTuneEnabled(bool timeIndicatorTextFineTuneEnabled);
221+
static TimeIndicatorTextFineTuneMode timeIndicatorTextFineTuneMode();
222+
static void setTimeIndicatorTextFineTuneMode(TimeIndicatorTextFineTuneMode timeIndicatorTextFineTuneMode);
216223

217224
static bool timeIndicatorShowSliderOnHover();
218225
static void setTimeIndicatorShowSliderOnHover(bool timeIndicatorShowSliderOnHover);
@@ -247,7 +254,7 @@ namespace Core::Internal {
247254
void timeIndicatorClickActionChanged();
248255
void timeIndicatorDoubleClickActionChanged();
249256
void timeIndicatorPressAndHoldActionChanged();
250-
void timeIndicatorTextFineTuneEnabledChanged();
257+
void timeIndicatorTextFineTuneModeChanged();
251258
void timeIndicatorShowSliderOnHoverChanged();
252259

253260
void commandPaletteClearHistoryRequested();

‎src/plugins/coreplugin/internal/settings/TimeIndicatorPage.cpp‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ namespace Core::Internal {
5757
qCDebug(lcTimeIndicatorPage) << "timeIndicatorDoubleClickAction" << m_widget->property("timeIndicatorDoubleClickAction");
5858
m_widget->setProperty("timeIndicatorPressAndHoldAction", BehaviorPreference::instance()->property("timeIndicatorPressAndHoldAction"));
5959
qCDebug(lcTimeIndicatorPage) << "timeIndicatorPressAndHoldAction" << m_widget->property("timeIndicatorPressAndHoldAction");
60-
m_widget->setProperty("timeIndicatorTextFineTuneEnabled", BehaviorPreference::instance()->property("timeIndicatorTextFineTuneEnabled"));
61-
qCDebug(lcTimeIndicatorPage) << "timeIndicatorTextFineTuneEnabled" << m_widget->property("timeIndicatorTextFineTuneEnabled");
60+
m_widget->setProperty("timeIndicatorTextFineTuneMode", BehaviorPreference::instance()->property("timeIndicatorTextFineTuneMode"));
61+
qCDebug(lcTimeIndicatorPage) << "timeIndicatorTextFineTuneMode" << m_widget->property("timeIndicatorTextFineTuneMode");
6262
m_widget->setProperty("timeIndicatorShowSliderOnHover", BehaviorPreference::instance()->property("timeIndicatorShowSliderOnHover"));
6363
qCDebug(lcTimeIndicatorPage) << "timeIndicatorShowSliderOnHover" << m_widget->property("timeIndicatorShowSliderOnHover");
6464
m_widget->setProperty("started", true);
@@ -75,8 +75,8 @@ namespace Core::Internal {
7575
BehaviorPreference::instance()->setProperty("timeIndicatorDoubleClickAction", m_widget->property("timeIndicatorDoubleClickAction"));
7676
qCDebug(lcTimeIndicatorPage) << "timeIndicatorPressAndHoldAction" << m_widget->property("timeIndicatorPressAndHoldAction");
7777
BehaviorPreference::instance()->setProperty("timeIndicatorPressAndHoldAction", m_widget->property("timeIndicatorPressAndHoldAction"));
78-
qCDebug(lcTimeIndicatorPage) << "timeIndicatorTextFineTuneEnabled" << m_widget->property("timeIndicatorTextFineTuneEnabled");
79-
BehaviorPreference::instance()->setProperty("timeIndicatorTextFineTuneEnabled", m_widget->property("timeIndicatorTextFineTuneEnabled"));
78+
qCDebug(lcTimeIndicatorPage) << "timeIndicatorTextFineTuneMode" << m_widget->property("timeIndicatorTextFineTuneMode");
79+
BehaviorPreference::instance()->setProperty("timeIndicatorTextFineTuneMode", m_widget->property("timeIndicatorTextFineTuneMode"));
8080
qCDebug(lcTimeIndicatorPage) << "timeIndicatorShowSliderOnHover" << m_widget->property("timeIndicatorShowSliderOnHover");
8181
BehaviorPreference::instance()->setProperty("timeIndicatorShowSliderOnHover", m_widget->property("timeIndicatorShowSliderOnHover"));
8282
BehaviorPreference::instance()->save();

‎src/plugins/coreplugin/qml/actions/TimelineAddOnActions.qml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ ActionCollection {
4040
DigitalClock {
4141
id: digitalClock
4242
backgroundVisible: BehaviorPreference.timeIndicatorBackgroundVisible
43+
fineTuneMode: BehaviorPreference.timeIndicatorTextFineTuneMode
4344
text: d.addOn.showMusicTime ? d.addOn.musicTimeText : d.addOn.longTimeText
4445
DescriptiveText.activated: hovered
4546
DescriptiveText.statusTip: qsTr("Current project time")

‎src/plugins/coreplugin/qml/settings/TimeIndicatorPage.qml‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ ScrollView {
1919
property int timeIndicatorClickAction
2020
property int timeIndicatorDoubleClickAction
2121
property int timeIndicatorPressAndHoldAction
22-
property bool timeIndicatorTextFineTuneEnabled
22+
property int timeIndicatorTextFineTuneMode
2323
property bool timeIndicatorShowSliderOnHover
2424

2525
readonly property var interactionBehaviorModel: [
@@ -32,7 +32,7 @@ ScrollView {
3232
onTimeIndicatorClickActionChanged: if (started) pageHandle.markDirty()
3333
onTimeIndicatorDoubleClickActionChanged: if (started) pageHandle.markDirty()
3434
onTimeIndicatorPressAndHoldActionChanged: if (started) pageHandle.markDirty()
35-
onTimeIndicatorTextFineTuneEnabledChanged: if (started) pageHandle.markDirty()
35+
onTimeIndicatorTextFineTuneModeChanged: if (started) pageHandle.markDirty()
3636
onTimeIndicatorShowSliderOnHoverChanged: if (started) pageHandle.markDirty()
3737

3838
anchors.fill: parent
@@ -63,9 +63,10 @@ ScrollView {
6363
}
6464
}
6565
CheckBox {
66+
id: fineTuneCharacterSpacingCheckBox
6667
text: qsTr("Fine-tune character spacing")
67-
checked: page.timeIndicatorTextFineTuneEnabled
68-
onClicked: page.timeIndicatorTextFineTuneEnabled = checked
68+
checked: page.timeIndicatorTextFineTuneMode !== BehaviorPreference.TITFTM_None
69+
onClicked: page.timeIndicatorTextFineTuneMode = checked ? layoutSimulationCheckBox.checked ? BehaviorPreference.TITFTM_LayoutSimulation : BehaviorPreference.TITFTM_TabularFiguresFontFeature : BehaviorPreference.TITFTM_None
6970
TextMatcherItem on text {
7071
matcher: page.matcher
7172
}
@@ -74,7 +75,18 @@ ScrollView {
7475
ThemedItem.foregroundLevel: SVS.FL_Secondary
7576
Layout.fillWidth: true
7677
wrapMode: Text.Wrap
77-
text: qsTr("Enabling fine-tuning of character spacing can prevent text width changes caused by timecode changes")
78+
text: qsTr("Enabling fine-tuning of character spacing can prevent text width changes caused by timecode changes.\nBy default, OpenType's Tabular Figures feature is used. If the widths of numeric characters are still inconsistent after enabling this, please try using text layout simulation.")
79+
}
80+
CheckBox {
81+
id: layoutSimulationCheckBox
82+
Layout.leftMargin: 22
83+
enabled: fineTuneCharacterSpacingCheckBox.checked
84+
text: qsTr("Use text layout simulation (advanced)")
85+
checked: page.timeIndicatorTextFineTuneMode === BehaviorPreference.TITFTM_LayoutSimulation
86+
onClicked: page.timeIndicatorTextFineTuneMode = checked ? BehaviorPreference.TITFTM_LayoutSimulation : BehaviorPreference.TITFTM_TabularFiguresFontFeature
87+
TextMatcherItem on text {
88+
matcher: page.matcher
89+
}
7890
}
7991
}
8092
}

0 commit comments

Comments
 (0)