1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <qstylehints.h>
41 #include <qpa/qplatformintegration.h>
42 #include <qpa/qplatformtheme.h>
43 #include <private/qguiapplication_p.h>
44 #include <qdebug.h>
45 
46 QT_BEGIN_NAMESPACE
47 
hint(QPlatformIntegration::StyleHint h)48 static inline QVariant hint(QPlatformIntegration::StyleHint h)
49 {
50     return QGuiApplicationPrivate::platformIntegration()->styleHint(h);
51 }
52 
themeableHint(QPlatformTheme::ThemeHint th,QPlatformIntegration::StyleHint ih)53 static inline QVariant themeableHint(QPlatformTheme::ThemeHint th,
54                                      QPlatformIntegration::StyleHint ih)
55 {
56     if (!QCoreApplication::instance()) {
57         qWarning("Must construct a QGuiApplication before accessing a platform theme hint.");
58         return QVariant();
59     }
60     if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
61         const QVariant themeHint = theme->themeHint(th);
62         if (themeHint.isValid())
63             return themeHint;
64     }
65     return QGuiApplicationPrivate::platformIntegration()->styleHint(ih);
66 }
67 
themeableHint(QPlatformTheme::ThemeHint th)68 static inline QVariant themeableHint(QPlatformTheme::ThemeHint th)
69 {
70     if (!QCoreApplication::instance()) {
71         qWarning("Must construct a QGuiApplication before accessing a platform theme hint.");
72         return QVariant();
73     }
74     if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
75         const QVariant themeHint = theme->themeHint(th);
76         if (themeHint.isValid())
77             return themeHint;
78     }
79     return QPlatformTheme::defaultThemeHint(th);
80 }
81 
82 class QStyleHintsPrivate : public QObjectPrivate
83 {
84     Q_DECLARE_PUBLIC(QStyleHints)
85 public:
86     int m_mouseDoubleClickInterval = -1;
87     int m_mousePressAndHoldInterval = -1;
88     int m_startDragDistance = -1;
89     int m_startDragTime = -1;
90     int m_keyboardInputInterval = -1;
91     int m_cursorFlashTime = -1;
92     int m_tabFocusBehavior = -1;
93     int m_uiEffects = -1;
94     int m_showShortcutsInContextMenus = -1;
95     int m_wheelScrollLines = -1;
96     int m_mouseQuickSelectionThreshold = -1;
97     int m_mouseDoubleClickDistance = -1;
98     int m_touchDoubleTapDistance = -1;
99 };
100 
101 /*!
102     \class QStyleHints
103     \since 5.0
104     \brief The QStyleHints class contains platform specific hints and settings.
105     \inmodule QtGui
106 
107     An object of this class, obtained from QGuiApplication, provides access to certain global
108     user interface parameters of the current platform.
109 
110     Access is read only; typically the platform itself provides the user a way to tune these
111     parameters.
112 
113     Access to these parameters are useful when implementing custom user interface components, in that
114     they allow the components to exhibit the same behaviour and feel as other components.
115 
116     \sa QGuiApplication::styleHints()
117  */
QStyleHints()118 QStyleHints::QStyleHints()
119     : QObject(*new QStyleHintsPrivate(), nullptr)
120 {
121 }
122 
123 /*!
124     Sets the \a mouseDoubleClickInterval.
125     \internal
126     \sa mouseDoubleClickInterval()
127     \since 5.3
128 */
setMouseDoubleClickInterval(int mouseDoubleClickInterval)129 void  QStyleHints::setMouseDoubleClickInterval(int mouseDoubleClickInterval)
130 {
131     Q_D(QStyleHints);
132     if (d->m_mouseDoubleClickInterval == mouseDoubleClickInterval)
133         return;
134     d->m_mouseDoubleClickInterval = mouseDoubleClickInterval;
135     emit mouseDoubleClickIntervalChanged(mouseDoubleClickInterval);
136 }
137 
138 /*!
139     \property QStyleHints::mouseDoubleClickInterval
140     \brief the time limit in milliseconds that distinguishes a double click
141     from two consecutive mouse clicks.
142 */
mouseDoubleClickInterval() const143 int QStyleHints::mouseDoubleClickInterval() const
144 {
145     Q_D(const QStyleHints);
146     return d->m_mouseDoubleClickInterval >= 0 ?
147            d->m_mouseDoubleClickInterval :
148            themeableHint(QPlatformTheme::MouseDoubleClickInterval, QPlatformIntegration::MouseDoubleClickInterval).toInt();
149 }
150 
151 /*!
152     \property QStyleHints::mouseDoubleClickDistance
153     \brief the maximum distance, in pixels, that the mouse can be moved between
154     two consecutive mouse clicks and still have it detected as a double-click
155     \since 5.14
156 */
mouseDoubleClickDistance() const157 int QStyleHints::mouseDoubleClickDistance() const
158 {
159     Q_D(const QStyleHints);
160     return d->m_mouseDoubleClickDistance >= 0 ?
161                 d->m_mouseDoubleClickDistance :
162                 themeableHint(QPlatformTheme::MouseDoubleClickDistance).toInt();
163 }
164 
165 /*!
166     \property QStyleHints::touchDoubleTapDistance
167     \brief the maximum distance, in pixels, that a finger can be moved between
168     two consecutive taps and still have it detected as a double-tap
169     \since 5.14
170 */
touchDoubleTapDistance() const171 int QStyleHints::touchDoubleTapDistance() const
172 {
173     Q_D(const QStyleHints);
174     return d->m_touchDoubleTapDistance >= 0 ?
175                 d->m_touchDoubleTapDistance :
176                 themeableHint(QPlatformTheme::TouchDoubleTapDistance).toInt();
177 }
178 
179 /*!
180     Sets the \a mousePressAndHoldInterval.
181     \internal
182     \sa mousePressAndHoldInterval()
183     \since 5.7
184 */
setMousePressAndHoldInterval(int mousePressAndHoldInterval)185 void QStyleHints::setMousePressAndHoldInterval(int mousePressAndHoldInterval)
186 {
187     Q_D(QStyleHints);
188     if (d->m_mousePressAndHoldInterval == mousePressAndHoldInterval)
189         return;
190     d->m_mousePressAndHoldInterval = mousePressAndHoldInterval;
191     emit mousePressAndHoldIntervalChanged(mousePressAndHoldInterval);
192 }
193 
194 /*!
195     \property QStyleHints::mousePressAndHoldInterval
196     \brief the time limit in milliseconds that activates
197     a press and hold.
198 
199     \since 5.3
200 */
mousePressAndHoldInterval() const201 int QStyleHints::mousePressAndHoldInterval() const
202 {
203     Q_D(const QStyleHints);
204     return d->m_mousePressAndHoldInterval >= 0 ?
205            d->m_mousePressAndHoldInterval :
206            themeableHint(QPlatformTheme::MousePressAndHoldInterval, QPlatformIntegration::MousePressAndHoldInterval).toInt();
207 }
208 
209 /*!
210     Sets the \a startDragDistance.
211     \internal
212     \sa startDragDistance()
213     \since 5.3
214 */
setStartDragDistance(int startDragDistance)215 void QStyleHints::setStartDragDistance(int startDragDistance)
216 {
217     Q_D(QStyleHints);
218     if (d->m_startDragDistance == startDragDistance)
219         return;
220     d->m_startDragDistance = startDragDistance;
221     emit startDragDistanceChanged(startDragDistance);
222 }
223 
224 /*!
225     \property QStyleHints::startDragDistance
226     \brief the distance, in pixels, that the mouse must be moved with a button
227     held down before a drag and drop operation will begin.
228 
229     If you support drag and drop in your application, and want to start a drag
230     and drop operation after the user has moved the cursor a certain distance
231     with a button held down, you should use this property's value as the
232     minimum distance required.
233 
234     For example, if the mouse position of the click is stored in \c startPos
235     and the current position (e.g. in the mouse move event) is \c currentPos,
236     you can find out if a drag should be started with code like this:
237 
238     \snippet code/src_gui_kernel_qapplication.cpp 6
239 
240     \sa startDragTime, QPoint::manhattanLength(), {Drag and Drop}
241 */
startDragDistance() const242 int QStyleHints::startDragDistance() const
243 {
244     Q_D(const QStyleHints);
245     return d->m_startDragDistance >= 0 ?
246            d->m_startDragDistance :
247            themeableHint(QPlatformTheme::StartDragDistance, QPlatformIntegration::StartDragDistance).toInt();
248 }
249 
250 /*!
251     Sets the \a startDragDragTime.
252     \internal
253     \sa startDragTime()
254     \since 5.3
255 */
setStartDragTime(int startDragTime)256 void QStyleHints::setStartDragTime(int startDragTime)
257 {
258     Q_D(QStyleHints);
259     if (d->m_startDragTime == startDragTime)
260         return;
261     d->m_startDragTime = startDragTime;
262     emit startDragTimeChanged(startDragTime);
263 }
264 
265 /*!
266     \property QStyleHints::startDragTime
267     \brief the time, in milliseconds, that a mouse button must be held down
268     before a drag and drop operation will begin.
269 
270     If you support drag and drop in your application, and want to start a drag
271     and drop operation after the user has held down a mouse button for a
272     certain amount of time, you should use this property's value as the delay.
273 
274     \sa startDragDistance, {Drag and Drop}
275 */
startDragTime() const276 int QStyleHints::startDragTime() const
277 {
278     Q_D(const QStyleHints);
279     return d->m_startDragTime >= 0 ?
280            d->m_startDragTime :
281            themeableHint(QPlatformTheme::StartDragTime, QPlatformIntegration::StartDragTime).toInt();
282 }
283 
284 /*!
285     \property QStyleHints::startDragVelocity
286     \brief the limit for the velocity, in pixels per second, that the mouse may
287     be moved, with a button held down, for a drag and drop operation to begin.
288     A value of 0 means there is no such limit.
289 
290     \sa startDragDistance, {Drag and Drop}
291 */
startDragVelocity() const292 int QStyleHints::startDragVelocity() const
293 {
294     return themeableHint(QPlatformTheme::StartDragVelocity, QPlatformIntegration::StartDragVelocity).toInt();
295 }
296 
297 /*!
298     Sets the \a keyboardInputInterval.
299     \internal
300     \sa keyboardInputInterval()
301     \since 5.3
302 */
setKeyboardInputInterval(int keyboardInputInterval)303 void QStyleHints::setKeyboardInputInterval(int keyboardInputInterval)
304 {
305     Q_D(QStyleHints);
306     if (d->m_keyboardInputInterval == keyboardInputInterval)
307         return;
308     d->m_keyboardInputInterval = keyboardInputInterval;
309     emit keyboardInputIntervalChanged(keyboardInputInterval);
310 }
311 
312 /*!
313     \property QStyleHints::keyboardInputInterval
314     \brief the time limit, in milliseconds, that distinguishes a key press
315     from two consecutive key presses.
316 */
keyboardInputInterval() const317 int QStyleHints::keyboardInputInterval() const
318 {
319     Q_D(const QStyleHints);
320     return d->m_keyboardInputInterval >= 0 ?
321            d->m_keyboardInputInterval :
322            themeableHint(QPlatformTheme::KeyboardInputInterval, QPlatformIntegration::KeyboardInputInterval).toInt();
323 }
324 
325 /*!
326     \property QStyleHints::keyboardAutoRepeatRate
327     \brief the rate, in events per second,  in which additional repeated key
328     presses will automatically be generated if a key is being held down.
329 */
keyboardAutoRepeatRate() const330 int QStyleHints::keyboardAutoRepeatRate() const
331 {
332     return themeableHint(QPlatformTheme::KeyboardAutoRepeatRate, QPlatformIntegration::KeyboardAutoRepeatRate).toInt();
333 }
334 
335 /*!
336     Sets the \a cursorFlashTime.
337     \internal
338     \sa cursorFlashTime()
339     \since 5.3
340 */
setCursorFlashTime(int cursorFlashTime)341 void QStyleHints::setCursorFlashTime(int cursorFlashTime)
342 {
343     Q_D(QStyleHints);
344     if (d->m_cursorFlashTime == cursorFlashTime)
345         return;
346     d->m_cursorFlashTime = cursorFlashTime;
347     emit cursorFlashTimeChanged(cursorFlashTime);
348 }
349 
350 /*!
351     \property QStyleHints::cursorFlashTime
352     \brief the text cursor's flash (blink) time in milliseconds.
353 
354     The flash time is the time used to display, invert and restore the
355     caret display. Usually the text cursor is displayed for half the cursor
356     flash time, then hidden for the same amount of time.
357 */
cursorFlashTime() const358 int QStyleHints::cursorFlashTime() const
359 {
360     Q_D(const QStyleHints);
361     return d->m_cursorFlashTime >= 0 ?
362            d->m_cursorFlashTime :
363            themeableHint(QPlatformTheme::CursorFlashTime, QPlatformIntegration::CursorFlashTime).toInt();
364 }
365 
366 /*!
367     \property QStyleHints::showIsFullScreen
368     \brief whether the platform defaults to fullscreen windows.
369 
370     This property is \c true if the platform defaults to windows being fullscreen,
371     otherwise \c false.
372 
373     \note The platform may still choose to show certain windows non-fullscreen,
374     such as popups or dialogs. This property only reports the default behavior.
375 
376     \sa QWindow::show(), showIsMaximized()
377 */
showIsFullScreen() const378 bool QStyleHints::showIsFullScreen() const
379 {
380     return hint(QPlatformIntegration::ShowIsFullScreen).toBool();
381 }
382 
383 /*!
384     \property QStyleHints::showIsMaximized
385     \brief whether the platform defaults to maximized windows.
386 
387     This property is \c true if the platform defaults to windows being maximized,
388     otherwise \c false.
389 
390     \note The platform may still choose to show certain windows non-maximized,
391     such as popups or dialogs. This property only reports the default behavior.
392 
393     \sa QWindow::show(), showIsFullScreen()
394     \since 5.6
395 */
showIsMaximized() const396 bool QStyleHints::showIsMaximized() const
397 {
398     return hint(QPlatformIntegration::ShowIsMaximized).toBool();
399 }
400 
401 /*!
402     \property QStyleHints::showShortcutsInContextMenus
403     \since 5.10
404     \brief \c true if the platform normally shows shortcut key sequences in
405     context menus, otherwise \c false.
406 
407     Since Qt 5.13, the setShowShortcutsInContextMenus() function can be used to
408     override the platform default.
409 */
showShortcutsInContextMenus() const410 bool QStyleHints::showShortcutsInContextMenus() const
411 {
412     Q_D(const QStyleHints);
413     return d->m_showShortcutsInContextMenus >= 0
414         ? d->m_showShortcutsInContextMenus != 0
415         : themeableHint(QPlatformTheme::ShowShortcutsInContextMenus, QPlatformIntegration::ShowShortcutsInContextMenus).toBool();
416 }
417 
setShowShortcutsInContextMenus(bool s)418 void QStyleHints::setShowShortcutsInContextMenus(bool s)
419 {
420     Q_D(QStyleHints);
421     if (s != showShortcutsInContextMenus()) {
422         d->m_showShortcutsInContextMenus = s ? 1 : 0;
423         emit showShortcutsInContextMenusChanged(s);
424     }
425 }
426 
427 /*!
428     \property QStyleHints::passwordMaskDelay
429     \brief the time, in milliseconds, a typed letter is displayed unshrouded
430     in a text input field in password mode.
431 */
passwordMaskDelay() const432 int QStyleHints::passwordMaskDelay() const
433 {
434     return themeableHint(QPlatformTheme::PasswordMaskDelay, QPlatformIntegration::PasswordMaskDelay).toInt();
435 }
436 
437 /*!
438     \property QStyleHints::passwordMaskCharacter
439     \brief the character used to mask the characters typed into text input
440     fields in password mode.
441 */
passwordMaskCharacter() const442 QChar QStyleHints::passwordMaskCharacter() const
443 {
444     return themeableHint(QPlatformTheme::PasswordMaskCharacter, QPlatformIntegration::PasswordMaskCharacter).toChar();
445 }
446 
447 /*!
448     \property QStyleHints::fontSmoothingGamma
449     \brief the gamma value used in font smoothing.
450 */
fontSmoothingGamma() const451 qreal QStyleHints::fontSmoothingGamma() const
452 {
453     return hint(QPlatformIntegration::FontSmoothingGamma).toReal();
454 }
455 
456 /*!
457     \property QStyleHints::useRtlExtensions
458     \brief the writing direction.
459 
460     This property is \c true if right-to-left writing direction is enabled,
461     otherwise \c false.
462 */
useRtlExtensions() const463 bool QStyleHints::useRtlExtensions() const
464 {
465     return hint(QPlatformIntegration::UseRtlExtensions).toBool();
466 }
467 
468 /*!
469     \property QStyleHints::setFocusOnTouchRelease
470     \brief the event that should set input focus on focus objects.
471 
472     This property is \c true if focus objects (line edits etc) should receive
473     input focus after a touch/mouse release. This is normal behavior on
474     touch platforms. On desktop platforms, the standard is to set
475     focus already on touch/mouse press.
476 */
setFocusOnTouchRelease() const477 bool QStyleHints::setFocusOnTouchRelease() const
478 {
479     return hint(QPlatformIntegration::SetFocusOnTouchRelease).toBool();
480 }
481 
482 /*!
483     \property QStyleHints::tabFocusBehavior
484     \since 5.5
485     \brief The focus behavior on press of the tab key.
486 
487     \note Do not bind this value in QML because the change notifier
488     signal is not implemented yet.
489 */
490 
tabFocusBehavior() const491 Qt::TabFocusBehavior QStyleHints::tabFocusBehavior() const
492 {
493     Q_D(const QStyleHints);
494     return Qt::TabFocusBehavior(d->m_tabFocusBehavior >= 0 ?
495                                 d->m_tabFocusBehavior :
496                                 themeableHint(QPlatformTheme::TabFocusBehavior, QPlatformIntegration::TabFocusBehavior).toInt());
497 }
498 
499 /*!
500     Sets the \a tabFocusBehavior.
501     \internal
502     \sa tabFocusBehavior()
503     \since 5.7
504 */
setTabFocusBehavior(Qt::TabFocusBehavior tabFocusBehavior)505 void QStyleHints::setTabFocusBehavior(Qt::TabFocusBehavior tabFocusBehavior)
506 {
507     Q_D(QStyleHints);
508     if (d->m_tabFocusBehavior == tabFocusBehavior)
509         return;
510     d->m_tabFocusBehavior = tabFocusBehavior;
511     emit tabFocusBehaviorChanged(tabFocusBehavior);
512 }
513 
514 /*!
515     \property QStyleHints::singleClickActivation
516     \brief whether items are activated by single or double click.
517 
518     This property is \c true if items should be activated by single click, \c false
519     if they should be activated by double click instead.
520 
521     \since 5.5
522 */
singleClickActivation() const523 bool QStyleHints::singleClickActivation() const
524 {
525     return themeableHint(QPlatformTheme::ItemViewActivateItemOnSingleClick, QPlatformIntegration::ItemViewActivateItemOnSingleClick).toBool();
526 }
527 
528 /*!
529     \property QStyleHints::useHoverEffects
530     \brief whether UI elements use hover effects.
531 
532     This property is \c true if UI elements should use hover effects. This is the
533     standard behavior on desktop platforms with a mouse pointer, whereas
534     on touch platforms the overhead of hover event delivery can be avoided.
535 
536     \since 5.8
537 */
useHoverEffects() const538 bool QStyleHints::useHoverEffects() const
539 {
540     Q_D(const QStyleHints);
541     return (d->m_uiEffects >= 0 ?
542             d->m_uiEffects :
543             themeableHint(QPlatformTheme::UiEffects, QPlatformIntegration::UiEffects).toInt()) & QPlatformTheme::HoverEffect;
544 }
545 
setUseHoverEffects(bool useHoverEffects)546 void QStyleHints::setUseHoverEffects(bool useHoverEffects)
547 {
548     Q_D(QStyleHints);
549     if (d->m_uiEffects >= 0 && useHoverEffects == bool(d->m_uiEffects & QPlatformTheme::HoverEffect))
550         return;
551     if (d->m_uiEffects == -1)
552         d->m_uiEffects = 0;
553     if (useHoverEffects)
554         d->m_uiEffects |= QPlatformTheme::HoverEffect;
555     else
556         d->m_uiEffects &= ~QPlatformTheme::HoverEffect;
557     emit useHoverEffectsChanged(useHoverEffects);
558 }
559 
560 /*!
561     \property QStyleHints::wheelScrollLines
562     \brief Number of lines to scroll by default for each wheel click.
563 
564     \since 5.9
565 */
wheelScrollLines() const566 int QStyleHints::wheelScrollLines() const
567 {
568     Q_D(const QStyleHints);
569     if (d->m_wheelScrollLines > 0)
570         return d->m_wheelScrollLines;
571     return themeableHint(QPlatformTheme::WheelScrollLines, QPlatformIntegration::WheelScrollLines).toInt();
572 }
573 
574 /*!
575     Sets the \a wheelScrollLines.
576     \internal
577     \sa wheelScrollLines()
578     \since 5.9
579 */
setWheelScrollLines(int scrollLines)580 void QStyleHints::setWheelScrollLines(int scrollLines)
581 {
582     Q_D(QStyleHints);
583     if (d->m_wheelScrollLines == scrollLines)
584         return;
585     d->m_wheelScrollLines = scrollLines;
586     emit wheelScrollLinesChanged(scrollLines);
587 }
588 
589 /*!
590     Sets the mouse quick selection threshold.
591     \internal
592     \sa mouseQuickSelectionThreshold()
593     \since 5.11
594 */
setMouseQuickSelectionThreshold(int threshold)595 void QStyleHints::setMouseQuickSelectionThreshold(int threshold)
596 {
597     Q_D(QStyleHints);
598     if (d->m_mouseQuickSelectionThreshold == threshold)
599         return;
600     d->m_mouseQuickSelectionThreshold = threshold;
601     emit mouseQuickSelectionThresholdChanged(threshold);
602 }
603 
604 /*!
605     \property QStyleHints::mouseQuickSelectionThreshold
606     \brief Quick selection mouse threshold in QLineEdit.
607 
608     This property defines how much the mouse cursor should be moved along the y axis
609     to trigger a quick selection during a normal QLineEdit text selection.
610 
611     If the property value is less than or equal to 0, the quick selection feature is disabled.
612 
613     \since 5.11
614 */
mouseQuickSelectionThreshold() const615 int QStyleHints::mouseQuickSelectionThreshold() const
616 {
617     Q_D(const QStyleHints);
618     if (d->m_mouseQuickSelectionThreshold >= 0)
619         return d->m_mouseQuickSelectionThreshold;
620     return themeableHint(QPlatformTheme::MouseQuickSelectionThreshold, QPlatformIntegration::MouseQuickSelectionThreshold).toInt();
621 }
622 
623 QT_END_NAMESPACE
624