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

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