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
46QT_BEGIN_NAMESPACE
47
48static inline QVariant hint(QPlatformIntegration::StyleHint h)
49{
50 return QGuiApplicationPrivate::platformIntegration()->styleHint(h);
51}
52
53static 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
68static 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
82class QStyleHintsPrivate : public QObjectPrivate
83{
84 Q_DECLARE_PUBLIC(QStyleHints)
85public:
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 */
118QStyleHints::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*/
129void 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*/
143int 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*/
157int 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*/
171int 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*/
185void 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*/
201int 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*/
215void 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*/
242int 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*/
256void 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*/
276int 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*/
292int 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*/
303void 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*/
317int 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*/
330int 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*/
341void 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*/
358int 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*/
378bool 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*/
396bool 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*/
410bool 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
418void 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*/
432int 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*/
442QChar 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*/
451qreal 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*/
463bool 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*/
477bool 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
491Qt::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*/
505void 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*/
523bool 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*/
538bool 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
546void 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*/
566int 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*/
580void 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*/
595void 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*/
615int 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
623QT_END_NAMESPACE
624