1/*
2 * SPDX-FileCopyrightText: 2020 Jonah BrĂ¼chert <jbb@kaidan.im>
3 * SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "units.h"
9
10#include <QFont>
11#include <QFontMetrics>
12#include <QGuiApplication>
13#include <QQmlComponent>
14#include <QQuickStyle>
15#include <QStyleHints>
16
17#include <chrono>
18#include <cmath>
19
20#include "kirigamiplatform_logging.h"
21#include "platformpluginfactory.h"
22
23namespace Kirigami
24{
25namespace Platform
26{
27
28class UnitsPrivate
29{
30 Q_DISABLE_COPY(UnitsPrivate)
31
32public:
33 explicit UnitsPrivate(Units *units)
34 // Cache font so we don't have to go through QVariant and property every time
35 : fontMetrics(QFontMetricsF(QGuiApplication::font()))
36 , gridUnit(18)
37 , smallSpacing(4)
38 , mediumSpacing(6)
39 , largeSpacing(8)
40 , veryLongDuration(400)
41 , longDuration(200)
42 , shortDuration(100)
43 , veryShortDuration(50)
44 , humanMoment(2000)
45 , toolTipDelay(700)
46 , cornerRadius(5)
47 , iconSizes(new IconSizes(units))
48 {
49 }
50
51 // Font metrics used for Units.
52 // TextMetrics uses QFontMetricsF internally, so this should do the same
53 QFontMetricsF fontMetrics;
54
55 // units
56 int gridUnit;
57 int smallSpacing;
58 int mediumSpacing;
59 int largeSpacing;
60
61 // durations
62 int veryLongDuration;
63 int longDuration;
64 int shortDuration;
65 int veryShortDuration;
66 int humanMoment;
67 int toolTipDelay;
68 qreal cornerRadius;
69
70 IconSizes *const iconSizes;
71
72 // To prevent overriding custom set units if the font changes
73 bool customUnitsSet = false;
74};
75
76Units::~Units() = default;
77
78Units::Units(QObject *parent)
79 : QObject(parent)
80 , d(std::make_unique<UnitsPrivate>(args: this))
81{
82 qGuiApp->installEventFilter(filterObj: this);
83}
84
85int Units::gridUnit() const
86{
87 return d->gridUnit;
88}
89
90void Units::setGridUnit(int size)
91{
92 if (d->gridUnit == size) {
93 return;
94 }
95
96 d->gridUnit = size;
97 d->customUnitsSet = true;
98 Q_EMIT gridUnitChanged();
99}
100
101int Units::smallSpacing() const
102{
103 return d->smallSpacing;
104}
105
106void Units::setSmallSpacing(int size)
107{
108 if (d->smallSpacing == size) {
109 return;
110 }
111
112 d->smallSpacing = size;
113 d->customUnitsSet = true;
114 Q_EMIT smallSpacingChanged();
115}
116
117int Units::mediumSpacing() const
118{
119 return d->mediumSpacing;
120}
121
122void Units::setMediumSpacing(int size)
123{
124 if (d->mediumSpacing == size) {
125 return;
126 }
127
128 d->mediumSpacing = size;
129 d->customUnitsSet = true;
130 Q_EMIT mediumSpacingChanged();
131}
132
133int Units::largeSpacing() const
134{
135 return d->largeSpacing;
136}
137
138void Units::setLargeSpacing(int size)
139{
140 if (d->largeSpacing) {
141 return;
142 }
143
144 d->largeSpacing = size;
145 d->customUnitsSet = true;
146 Q_EMIT largeSpacingChanged();
147}
148
149int Units::veryLongDuration() const
150{
151 return d->veryLongDuration;
152}
153
154void Units::setVeryLongDuration(int duration)
155{
156 if (d->veryLongDuration == duration) {
157 return;
158 }
159
160 d->veryLongDuration = duration;
161 Q_EMIT veryLongDurationChanged();
162}
163
164int Units::longDuration() const
165{
166 return d->longDuration;
167}
168
169void Units::setLongDuration(int duration)
170{
171 if (d->longDuration == duration) {
172 return;
173 }
174
175 d->longDuration = duration;
176 Q_EMIT longDurationChanged();
177}
178
179int Units::shortDuration() const
180{
181 return d->shortDuration;
182}
183
184void Units::setShortDuration(int duration)
185{
186 if (d->shortDuration == duration) {
187 return;
188 }
189
190 d->shortDuration = duration;
191 Q_EMIT shortDurationChanged();
192}
193
194int Units::veryShortDuration() const
195{
196 return d->veryShortDuration;
197}
198
199void Units::setVeryShortDuration(int duration)
200{
201 if (d->veryShortDuration == duration) {
202 return;
203 }
204
205 d->veryShortDuration = duration;
206 Q_EMIT veryShortDurationChanged();
207}
208
209int Units::humanMoment() const
210{
211 return d->humanMoment;
212}
213
214void Units::setHumanMoment(int duration)
215{
216 if (d->humanMoment == duration) {
217 return;
218 }
219
220 d->humanMoment = duration;
221 Q_EMIT humanMomentChanged();
222}
223
224int Units::toolTipDelay() const
225{
226 return d->toolTipDelay;
227}
228
229void Units::setToolTipDelay(int delay)
230{
231 if (d->toolTipDelay == delay) {
232 return;
233 }
234
235 d->toolTipDelay = delay;
236 Q_EMIT toolTipDelayChanged();
237}
238
239qreal Units::cornerRadius() const
240{
241 return d->cornerRadius;
242}
243
244void Units::setcornerRadius(qreal cornerRadius)
245{
246 if (d->cornerRadius == cornerRadius) {
247 return;
248 }
249
250 d->cornerRadius = cornerRadius;
251 Q_EMIT cornerRadiusChanged();
252}
253
254Units *Units::create(QQmlEngine *qmlEngine, [[maybe_unused]] QJSEngine *jsEngine)
255{
256#ifndef KIRIGAMI_BUILD_TYPE_STATIC
257 const QString pluginName = qmlEngine->property(name: "_kirigamiTheme").toString();
258
259 auto plugin = PlatformPluginFactory::findPlugin(pluginName);
260 if (!plugin && !pluginName.isEmpty()) {
261 plugin = PlatformPluginFactory::findPlugin();
262 }
263
264 if (plugin) {
265 return plugin->createUnits(parent: qmlEngine);
266 }
267#endif
268 // Fall back to the default units implementation
269 return new Units(qmlEngine);
270}
271
272bool Units::eventFilter([[maybe_unused]] QObject *watched, QEvent *event)
273{
274 if (event->type() == QEvent::ApplicationFontChange) {
275 d->fontMetrics = QFontMetricsF(qGuiApp->font());
276
277 if (d->customUnitsSet) {
278 return false;
279 }
280
281 Q_EMIT d->iconSizes->sizeForLabelsChanged();
282 }
283 return false;
284}
285
286IconSizes *Units::iconSizes() const
287{
288 return d->iconSizes;
289}
290
291IconSizes::IconSizes(Units *units)
292 : QObject(units)
293 , m_units(units)
294{
295}
296
297int IconSizes::roundedIconSize(int size) const
298{
299 if (size < 16) {
300 return size;
301 }
302
303 if (size < 22) {
304 return 16;
305 }
306
307 if (size < 32) {
308 return 22;
309 }
310
311 if (size < 48) {
312 return 32;
313 }
314
315 if (size < 64) {
316 return 48;
317 }
318
319 return size;
320}
321
322int IconSizes::sizeForLabels() const
323{
324 // gridUnit is the height of textMetrics
325 return roundedIconSize(size: m_units->d->fontMetrics.height());
326}
327
328int IconSizes::small() const
329{
330 return 16;
331}
332
333int IconSizes::smallMedium() const
334{
335 return 22;
336}
337
338int IconSizes::medium() const
339{
340 return 32;
341}
342
343int IconSizes::large() const
344{
345 return 48;
346}
347
348int IconSizes::huge() const
349{
350 return 64;
351}
352
353int IconSizes::enormous() const
354{
355 return 128;
356}
357}
358}
359
360#include "moc_units.cpp"
361

source code of kirigami/src/platform/units.cpp