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 | |
24 | namespace Kirigami |
25 | { |
26 | namespace Platform |
27 | { |
28 | |
29 | class UnitsPrivate |
30 | { |
31 | Q_DISABLE_COPY(UnitsPrivate) |
32 | |
33 | public: |
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 | |
77 | Units::~Units() = default; |
78 | |
79 | Units::Units(QObject *parent) |
80 | : QObject(parent) |
81 | , d(std::make_unique<UnitsPrivate>(args: this)) |
82 | { |
83 | qGuiApp->installEventFilter(filterObj: this); |
84 | } |
85 | |
86 | int Units::gridUnit() const |
87 | { |
88 | return d->gridUnit; |
89 | } |
90 | |
91 | void 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 | |
102 | int Units::smallSpacing() const |
103 | { |
104 | return d->smallSpacing; |
105 | } |
106 | |
107 | void 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 | |
118 | int Units::mediumSpacing() const |
119 | { |
120 | return d->mediumSpacing; |
121 | } |
122 | |
123 | void 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 | |
134 | int Units::largeSpacing() const |
135 | { |
136 | return d->largeSpacing; |
137 | } |
138 | |
139 | void 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 | |
150 | int Units::veryLongDuration() const |
151 | { |
152 | return d->veryLongDuration; |
153 | } |
154 | |
155 | void Units::setVeryLongDuration(int duration) |
156 | { |
157 | if (d->veryLongDuration == duration) { |
158 | return; |
159 | } |
160 | |
161 | d->veryLongDuration = duration; |
162 | Q_EMIT veryLongDurationChanged(); |
163 | } |
164 | |
165 | int Units::longDuration() const |
166 | { |
167 | return d->longDuration; |
168 | } |
169 | |
170 | void Units::setLongDuration(int duration) |
171 | { |
172 | if (d->longDuration == duration) { |
173 | return; |
174 | } |
175 | |
176 | d->longDuration = duration; |
177 | Q_EMIT longDurationChanged(); |
178 | } |
179 | |
180 | int Units::shortDuration() const |
181 | { |
182 | return d->shortDuration; |
183 | } |
184 | |
185 | void Units::setShortDuration(int duration) |
186 | { |
187 | if (d->shortDuration == duration) { |
188 | return; |
189 | } |
190 | |
191 | d->shortDuration = duration; |
192 | Q_EMIT shortDurationChanged(); |
193 | } |
194 | |
195 | int Units::veryShortDuration() const |
196 | { |
197 | return d->veryShortDuration; |
198 | } |
199 | |
200 | void Units::setVeryShortDuration(int duration) |
201 | { |
202 | if (d->veryShortDuration == duration) { |
203 | return; |
204 | } |
205 | |
206 | d->veryShortDuration = duration; |
207 | Q_EMIT veryShortDurationChanged(); |
208 | } |
209 | |
210 | int Units::humanMoment() const |
211 | { |
212 | return d->humanMoment; |
213 | } |
214 | |
215 | void Units::setHumanMoment(int duration) |
216 | { |
217 | if (d->humanMoment == duration) { |
218 | return; |
219 | } |
220 | |
221 | d->humanMoment = duration; |
222 | Q_EMIT humanMomentChanged(); |
223 | } |
224 | |
225 | int Units::toolTipDelay() const |
226 | { |
227 | return d->toolTipDelay; |
228 | } |
229 | |
230 | void Units::setToolTipDelay(int delay) |
231 | { |
232 | if (d->toolTipDelay == delay) { |
233 | return; |
234 | } |
235 | |
236 | d->toolTipDelay = delay; |
237 | Q_EMIT toolTipDelayChanged(); |
238 | } |
239 | |
240 | qreal Units::cornerRadius() const |
241 | { |
242 | return d->cornerRadius; |
243 | } |
244 | |
245 | void Units::setcornerRadius(qreal cornerRadius) |
246 | { |
247 | if (d->cornerRadius == cornerRadius) { |
248 | return; |
249 | } |
250 | |
251 | d->cornerRadius = cornerRadius; |
252 | Q_EMIT cornerRadiusChanged(); |
253 | } |
254 | |
255 | Units *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 | |
273 | bool 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 | |
289 | IconSizes *Units::iconSizes() const |
290 | { |
291 | return d->iconSizes; |
292 | } |
293 | |
294 | IconSizes::IconSizes(Units *units) |
295 | : QObject(units) |
296 | , m_units(units) |
297 | { |
298 | } |
299 | |
300 | int 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 | |
325 | int IconSizes::sizeForLabels() const |
326 | { |
327 | // gridUnit is the height of textMetrics |
328 | return roundedIconSize(size: m_units->d->fontMetrics.height()); |
329 | } |
330 | |
331 | int IconSizes::small() const |
332 | { |
333 | return 16; |
334 | } |
335 | |
336 | int IconSizes::smallMedium() const |
337 | { |
338 | return 22; |
339 | } |
340 | |
341 | int IconSizes::medium() const |
342 | { |
343 | return 32; |
344 | } |
345 | |
346 | int IconSizes::large() const |
347 | { |
348 | return 48; |
349 | } |
350 | |
351 | int IconSizes::huge() const |
352 | { |
353 | return 64; |
354 | } |
355 | |
356 | int IconSizes::enormous() const |
357 | { |
358 | return 128; |
359 | } |
360 | } |
361 | } |
362 | |
363 | #include "moc_units.cpp" |
364 | |