Kirigami2

units.cpp
1 /*
2  * SPDX-FileCopyrightText: 2020 Jonah BrĂ¼chert <[email protected]>
3  * SPDX-FileCopyrightText: 2015 Marco Martin <[email protected]>
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 <QStyleHints>
16 
17 #include <chrono>
18 #include <cmath>
19 
20 #include "loggingcategory.h"
21 
22 namespace Kirigami {
23 using clock = std::chrono::steady_clock;
24 
25 const clock::duration rateLimit = std::chrono::seconds(1);
26 
27 /* Print a deprecation warning that is rate limited to only display once in
28  * every time period as determined by rateLimit. We keep track of how often this
29  * is called and display that if it is larger than 0.
30  *
31  * This is done to prevent flooding the logs with "X is deprecated" messages
32  * that are all the same and don't provide any new information after the first.
33  */
34 void rateLimitWarning(const char *method, const char *since, const char *message)
35 {
37 
38  auto methodString = QString::fromUtf8(method);
39 
40  if (!messages.contains(methodString)) {
41  messages.insert(methodString, qMakePair(clock::time_point{}, 0));
42  }
43 
44  auto entry = messages.value(methodString);
45  if (clock::now() - entry.first < rateLimit) {
46  messages[methodString].second += 1;
47  return;
48  }
49 
50  qCWarning(KirigamiLog).nospace() << method << " is deprecated (since " << since << "): " << message;
51 
52  if (entry.second > 0) {
53  qCWarning(KirigamiLog) << "Previous message repeats" << entry.second << "times.";
54  }
55 
56  messages[methodString] = qMakePair(clock::now(), 0);
57 }
58 
59 class UnitsPrivate
60 {
61  Q_DISABLE_COPY(UnitsPrivate)
62 
63 public:
64  explicit UnitsPrivate(Units *units)
65 #if KIRIGAMI2_BUILD_DEPRECATED_SINCE(5, 86)
66  : qmlFontMetrics(nullptr)
67 #endif
68  // Cache font so we don't have to go through QVariant and property every time
69  , fontMetrics(QFontMetricsF(QGuiApplication::font()))
70  , gridUnit(fontMetrics.height())
71  , smallSpacing(std::floor(gridUnit / 4))
72  , largeSpacing(smallSpacing * 2)
73  , veryLongDuration(400)
74  , longDuration(200)
75  , shortDuration(100)
76  , veryShortDuration(50)
77  , humanMoment(2000)
78  , toolTipDelay(700)
79 #if KIRIGAMI2_BUILD_DEPRECATED_SINCE(5, 86)
80  , wheelScrollLines(QGuiApplication::styleHints()->wheelScrollLines())
81 #endif
82  , iconSizes(new IconSizes(units))
83  {
84  }
85 
86  // Only stored for QML API compatiblity
87  // TODO KF6 drop
88 #if KIRIGAMI2_BUILD_DEPRECATED_SINCE(5, 86)
89  QObject *qmlFontMetrics;
90 #endif
91 
92  // Font metrics used for Units.
93  // TextMetrics uses QFontMetricsF internally, so this should do the same
94  QFontMetricsF fontMetrics;
95 
96  // units
97  int gridUnit;
98  int smallSpacing;
99  int largeSpacing;
100 
101  // durations
102  int veryLongDuration;
103  int longDuration;
104  int shortDuration;
105  int veryShortDuration;
106  int humanMoment;
107  int toolTipDelay;
108 
109 #if KIRIGAMI2_BUILD_DEPRECATED_SINCE(5, 86)
110  int wheelScrollLines;
111 #endif
112 
113  IconSizes *const iconSizes;
114 
115  // To prevent overriding custom set units if the font changes
116  bool customUnitsSet = false;
117  bool customWheelScrollLinesSet = false;
118 
119 #if KIRIGAMI2_BUILD_DEPRECATED_SINCE(5, 86)
120  QObject *createQmlFontMetrics(QQmlEngine *engine)
121  {
122  QQmlComponent component(engine);
123  component.setData(QByteArrayLiteral(
124  "import QtQuick 2.14\n"
125  "import org.kde.kirigami 2.0\n"
126  "FontMetrics {\n"
127  " function roundedIconSize(size) {\n"
128  R"( console.warn("Units.fontMetrics.roundedIconSize is deprecated, use Units.iconSizes.roundedIconSize instead.");)"
129  " return Units.iconSizes.roundedIconSize(size)\n"
130  " }\n"
131  "}\n"
132  ), QUrl(QStringLiteral("units.cpp")));
133 
134  return component.create();
135  }
136 #endif
137 };
138 
139 Units::~Units() = default;
140 
141 Units::Units(QObject *parent)
142  : QObject(parent)
143  , d(std::make_unique<UnitsPrivate>(this))
144 {
146  if (d->customWheelScrollLinesSet) {
147  return;
148  }
149 
150  setWheelScrollLines(scrollLines);
151  });
152  connect(qGuiApp, &QGuiApplication::fontChanged, this, [this](const QFont &font) {
153  d->fontMetrics = QFontMetricsF(font);
154 
155  if (d->customUnitsSet) {
156  return;
157  }
158 
159  d->gridUnit = d->fontMetrics.height();
160  Q_EMIT gridUnitChanged();
161  d->smallSpacing = std::floor(d->gridUnit / 4);
162  Q_EMIT smallSpacingChanged();
163  d->largeSpacing = d->smallSpacing * 2;
164  Q_EMIT largeSpacingChanged();
165  Q_EMIT d->iconSizes->sizeForLabelsChanged();
166  });
167 }
168 
169 qreal Units::devicePixelRatio() const
170 {
171  rateLimitWarning("Units.devicePixelRatio", "5.86", "This returns 1 when using Qt HiDPI scaling.");
172  const int pixelSize = QGuiApplication::font().pixelSize();
173  const qreal pointSize = QGuiApplication::font().pointSize();
174 
175  return std::fmax(1, (pixelSize * 0.75 / pointSize));
176 }
177 
178 int Units::gridUnit() const
179 {
180  return d->gridUnit;
181 }
182 
183 void Kirigami::Units::setGridUnit(int size)
184 {
185  if (d->gridUnit == size) {
186  return;
187  }
188 
189  d->gridUnit = size;
190  d->customUnitsSet = true;
191  Q_EMIT gridUnitChanged();
192 }
193 
194 int Units::smallSpacing() const
195 {
196  return d->smallSpacing;
197 }
198 
199 void Kirigami::Units::setSmallSpacing(int size)
200 {
201  if (d->smallSpacing == size) {
202  return;
203  }
204 
205  d->smallSpacing = size;
206  d->customUnitsSet = true;
207  Q_EMIT smallSpacingChanged();
208 }
209 
210 int Units::largeSpacing() const
211 {
212  return d->largeSpacing;
213 }
214 
215 void Kirigami::Units::setLargeSpacing(int size)
216 {
217  if (d->largeSpacing) {
218  return;
219  }
220 
221  d->largeSpacing = size;
222  d->customUnitsSet = true;
223  Q_EMIT largeSpacingChanged();
224 }
225 
226 int Units::veryLongDuration() const
227 {
228  return d->veryLongDuration;
229 }
230 
231 void Units::setVeryLongDuration(int duration)
232 {
233  if (d->veryLongDuration == duration) {
234  return;
235  }
236 
237  d->veryLongDuration = duration;
238  Q_EMIT veryLongDurationChanged();
239 }
240 
241 int Units::longDuration() const
242 {
243  return d->longDuration;
244 }
245 
246 void Units::setLongDuration(int duration)
247 {
248  if (d->longDuration == duration) {
249  return;
250  }
251 
252  d->longDuration = duration;
253  Q_EMIT longDurationChanged();
254 }
255 
256 int Units::shortDuration() const
257 {
258  return d->shortDuration;
259 }
260 
261 void Units::setShortDuration(int duration)
262 {
263  if (d->shortDuration == duration) {
264  return;
265  }
266 
267  d->shortDuration = duration;
268  Q_EMIT shortDurationChanged();
269 }
270 
271 int Units::veryShortDuration() const
272 {
273  return d->veryLongDuration;
274 }
275 
276 void Units::setVeryShortDuration(int duration)
277 {
278  if (d->veryLongDuration == duration) {
279  return;
280  }
281 
282  d->veryLongDuration = duration;
283  Q_EMIT veryShortDurationChanged();
284 }
285 
286 int Units::humanMoment() const
287 {
288  return d->humanMoment;
289 }
290 
291 void Units::setHumanMoment(int duration)
292 {
293  if (d->humanMoment == duration) {
294  return;
295  }
296 
297  d->humanMoment = duration;
298  Q_EMIT humanMomentChanged();
299 }
300 
301 int Units::toolTipDelay() const
302 {
303  return d->toolTipDelay;
304 }
305 
306 void Units::setToolTipDelay(int delay)
307 {
308  if (d->toolTipDelay == delay) {
309  return;
310  }
311 
312  d->toolTipDelay = delay;
313  Q_EMIT toolTipDelayChanged();
314 }
315 
316 #if KIRIGAMI2_BUILD_DEPRECATED_SINCE(5, 86)
317 int Units::wheelScrollLines() const
318 {
319  rateLimitWarning("Units.wheelScrollLines", "5.86", "Use Qt.styleHints.wheelScrollLines instead");
320  return d->wheelScrollLines;
321 }
322 
323 void Units::setWheelScrollLines(int lines)
324 {
325  if (d->wheelScrollLines == lines) {
326  return;
327  }
328 
329  d->wheelScrollLines = lines;
330  d->customWheelScrollLinesSet = true;
331  Q_EMIT wheelScrollLinesChanged();
332 }
333 #endif
334 
335 IconSizes *Units::iconSizes() const
336 {
337  return d->iconSizes;
338 }
339 
340 #if KIRIGAMI2_BUILD_DEPRECATED_SINCE(5, 86)
341 QObject *Units::fontMetrics() const
342 {
343  rateLimitWarning("Units.fontMetrics", "5.86", "Create your own FontMetrics object instead.");
344  if (!d->qmlFontMetrics) {
345  d->qmlFontMetrics = d->createQmlFontMetrics(qmlEngine(this));
346  }
347  return d->qmlFontMetrics;
348 }
349 #endif
350 
351 IconSizes::IconSizes(Units *units)
352  : QObject(units)
353  , m_units(units)
354 {
355 }
356 
357 int IconSizes::roundedIconSize(int size) const
358 {
359  if (size < 16) {
360  return size;
361  }
362 
363  if (size < 22) {
364  return 16;
365  }
366 
367  if (size < 32) {
368  return 22;
369  }
370 
371  if (size < 48) {
372  return 32;
373  }
374 
375  if (size < 64) {
376  return 48;
377  }
378 
379  return size;
380 }
381 
382 int IconSizes::sizeForLabels() const
383 {
384  // gridUnit is the height of textMetrics
385  return roundedIconSize(m_units->d->fontMetrics.height());
386 }
387 
388 int IconSizes::small() const
389 {
390  return 16;
391 }
392 
393 int IconSizes::smallMedium() const
394 {
395  return 22;
396 }
397 
398 int IconSizes::medium() const
399 {
400  return 32;
401 }
402 
403 int IconSizes::large() const
404 {
405  return 48;
406 }
407 
408 int IconSizes::huge() const
409 {
410  return 64;
411 }
412 
413 int IconSizes::enormous() const
414 {
415  return 128;
416 }
417 
418 }
int humanMoment
Definition: icon.h:18
bool contains(const Key &key) const const
int pixelSize() const const
int shortDuration
int gridUnit
int largeSpacing
int toolTipDelay
time in ms by which the display of tooltips will be delayed.
Definition: units.h:189
QSizeF size() const const
QStyleHints * styleHints()
QString fromUtf8(const char *str, int size)
void fontChanged(const QFont &font)
int smallSpacing
qreal devicePixelRatio
QQmlPropertyMap iconSizes
QMap::iterator insert(const Key &key, const T &value)
void wheelScrollLinesChanged(int scrollLines)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int veryShortDuration
int pointSize() const const
Q_EMITQ_EMIT
int veryLongDuration
int longDuration
const T value(const Key &key, const T &defaultValue) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:39:06 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.