1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpalette_p.h"
5#include "qguiapplication_p.h"
6#include "qdatastream.h"
7#include "qvariant.h"
8#include "qdebug.h"
9
10#include <QtCore/qmetaobject.h>
11
12QT_BEGIN_NAMESPACE
13
14static_assert(QPalettePrivate::bitPosition(colorGroup: QPalette::ColorGroup(QPalette::NColorGroups - 1),
15 colorRole: QPalette::ColorRole(QPalette::NColorRoles - 1))
16 < sizeof(QPalette::ResolveMask) * CHAR_BIT,
17 "The resolve mask type is not wide enough to fit the entire bit mask.");
18
19static QColor qt_mix_colors(QColor a, QColor b)
20{
21 return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2,
22 (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2);
23}
24
25/*!
26 \internal
27
28 Derive undefined \l PlaceholderText colors from \l Text colors.
29 Unless already set, PlaceholderText colors will be derived from their Text pendents.
30 Colors of existing PlaceHolderText brushes will not be replaced.
31
32 \a alpha represents the dim factor as a percentage. By default, a PlaceHolderText color
33 becomes a 50% more transparent version of the corresponding Text color.
34*/
35static void qt_placeholder_from_text(QPalette &pal, int alpha = 50)
36{
37 if (alpha < 0 or alpha > 100)
38 return;
39
40 for (int cg = 0; cg < int(QPalette::NColorGroups); ++cg) {
41 const QPalette::ColorGroup group = QPalette::ColorGroup(cg);
42
43 // skip if the brush has been set already
44 if (!pal.isBrushSet(cg: group, cr: QPalette::PlaceholderText)) {
45 QColor c = pal.color(cg: group, cr: QPalette::Text);
46 const int a = (c.alpha() * alpha) / 100;
47 c.setAlpha(a);
48 pal.setColor(acg: group, acr: QPalette::PlaceholderText, acolor: c);
49 }
50 }
51}
52
53static void qt_ensure_default_accent_color(QPalette &pal)
54{
55 // have a lighter/darker factor handy, depending on dark/light heuristics
56 const int lighter = pal.base().color().lightness() > pal.text().color().lightness() ? 130 : 70;
57
58 // Act only for color groups where no accent color is set
59 for (int i = 0; i < QPalette::NColorGroups; ++i) {
60 const QPalette::ColorGroup group = static_cast<QPalette::ColorGroup>(i);
61 if (!pal.isBrushSet(cg: group, cr: QPalette::Accent)) {
62 // Default to highlight if available, otherwise use a shade of base
63 const QBrush accentBrush = pal.isBrushSet(cg: group, cr: QPalette::Highlight)
64 ? pal.brush(cg: group, cr: QPalette::Highlight)
65 : pal.brush(cg: group, cr: QPalette::Base).color().lighter(f: lighter);
66 pal.setBrush(cg: group, cr: QPalette::Accent, brush: accentBrush);
67 }
68 }
69}
70
71static void qt_palette_from_color(QPalette &pal, const QColor &button)
72{
73 int h, s, v;
74 button.getHsv(h: &h, s: &s, v: &v);
75 // inactive and active are the same..
76 const QBrush whiteBrush = QBrush(Qt::white);
77 const QBrush blackBrush = QBrush(Qt::black);
78 const QBrush baseBrush = v > 128 ? whiteBrush : blackBrush;
79 const QBrush foregroundBrush = v > 128 ? blackBrush : whiteBrush;
80 const QBrush buttonBrush = QBrush(button);
81 const QBrush buttonBrushDark = QBrush(button.darker());
82 const QBrush buttonBrushDark150 = QBrush(button.darker(f: 150));
83 const QBrush buttonBrushLight150 = QBrush(button.lighter(f: 150));
84 pal.setColorGroup(cr: QPalette::Active, windowText: foregroundBrush, button: buttonBrush, light: buttonBrushLight150,
85 dark: buttonBrushDark, mid: buttonBrushDark150, text: foregroundBrush, bright_text: whiteBrush,
86 base: baseBrush, window: buttonBrush);
87 pal.setColorGroup(cr: QPalette::Inactive, windowText: foregroundBrush, button: buttonBrush, light: buttonBrushLight150,
88 dark: buttonBrushDark, mid: buttonBrushDark150, text: foregroundBrush, bright_text: whiteBrush,
89 base: baseBrush, window: buttonBrush);
90 pal.setColorGroup(cr: QPalette::Disabled, windowText: buttonBrushDark, button: buttonBrush, light: buttonBrushLight150,
91 dark: buttonBrushDark, mid: buttonBrushDark150, text: buttonBrushDark,
92 bright_text: whiteBrush, base: buttonBrush, window: buttonBrush);
93
94 qt_placeholder_from_text(pal);
95 qt_ensure_default_accent_color(pal);
96}
97
98/*!
99 \fn QPalette &QPalette::operator=(QPalette &&other)
100
101 Move-assigns \a other to this QPalette instance.
102
103 \since 5.2
104*/
105
106/*!
107 \fn const QColor &QPalette::color(ColorRole role) const
108
109 \overload
110
111 Returns the color that has been set for the given color \a role in
112 the current ColorGroup.
113
114 \sa brush(), ColorRole
115 */
116
117/*!
118 \fn const QBrush &QPalette::brush(ColorRole role) const
119
120 \overload
121
122 Returns the brush that has been set for the given color \a role in
123 the current ColorGroup.
124
125 \sa color(), setBrush(), ColorRole
126*/
127
128/*!
129 \fn void QPalette::setColor(ColorRole role, const QColor &color)
130
131 \overload
132
133 Sets the color used for the given color \a role, in all color
134 groups, to the specified solid \a color.
135
136 \sa brush(), setColor(), ColorRole
137*/
138
139/*!
140 \fn void QPalette::setBrush(ColorRole role, const QBrush &brush)
141
142 Sets the brush for the given color \a role to the specified \a
143 brush for all groups in the palette.
144
145 \sa brush(), setColor(), ColorRole
146*/
147
148/*!
149 \fn const QBrush & QPalette::windowText() const
150
151 Returns the window text (general foreground) brush of the
152 current color group.
153
154 \sa ColorRole, brush()
155*/
156
157/*!
158 \fn const QBrush & QPalette::button() const
159
160 Returns the button brush of the current color group.
161
162 \sa ColorRole, brush()
163*/
164
165/*!
166 \fn const QBrush & QPalette::light() const
167
168 Returns the light brush of the current color group.
169
170 \sa ColorRole, brush()
171*/
172
173/*!
174 \fn const QBrush& QPalette::midlight() const
175
176 Returns the midlight brush of the current color group.
177
178 \sa ColorRole, brush()
179*/
180
181/*!
182 \fn const QBrush & QPalette::dark() const
183
184 Returns the dark brush of the current color group.
185
186 \sa ColorRole, brush()
187*/
188
189/*!
190 \fn const QBrush & QPalette::mid() const
191
192 Returns the mid brush of the current color group.
193
194 \sa ColorRole, brush()
195*/
196
197/*!
198 \fn const QBrush & QPalette::text() const
199
200 Returns the text foreground brush of the current color group.
201
202 \sa ColorRole, brush()
203*/
204
205/*!
206 \fn const QBrush & QPalette::brightText() const
207
208 Returns the bright text foreground brush of the current color group.
209
210 \sa ColorRole, brush()
211*/
212
213/*!
214 \fn const QBrush & QPalette::buttonText() const
215
216 Returns the button text foreground brush of the current color group.
217
218 \sa ColorRole, brush()
219*/
220
221/*!
222 \fn const QBrush & QPalette::base() const
223
224 Returns the base brush of the current color group.
225
226 \sa ColorRole, brush()
227*/
228
229/*!
230 \fn const QBrush & QPalette::alternateBase() const
231
232 Returns the alternate base brush of the current color group.
233
234 \sa ColorRole, brush()
235*/
236
237/*!
238 \fn const QBrush & QPalette::toolTipBase() const
239 \since 4.4
240
241 Returns the tool tip base brush of the current color group. This brush is
242 used by QToolTip and QWhatsThis.
243
244 \note Tool tips use the Inactive color group of QPalette, because tool
245 tips are not active windows.
246
247 \sa ColorRole, brush()
248*/
249
250/*!
251 \fn const QBrush & QPalette::toolTipText() const
252 \since 4.4
253
254 Returns the tool tip text brush of the current color group. This brush is
255 used by QToolTip and QWhatsThis.
256
257 \note Tool tips use the Inactive color group of QPalette, because tool
258 tips are not active windows.
259
260 \sa ColorRole, brush()
261*/
262
263/*!
264 \fn const QBrush & QPalette::window() const
265
266 Returns the window (general background) brush of the current
267 color group.
268
269 \sa ColorRole, brush()
270*/
271
272/*!
273 \fn const QBrush & QPalette::shadow() const
274
275 Returns the shadow brush of the current color group.
276
277 \sa ColorRole, brush()
278*/
279
280/*!
281 \fn const QBrush & QPalette::highlight() const
282
283 Returns the highlight brush of the current color group.
284
285 \sa ColorRole, brush()
286*/
287
288/*!
289 \fn const QBrush & QPalette::highlightedText() const
290
291 Returns the highlighted text brush of the current color group.
292
293 \sa ColorRole, brush()
294*/
295
296/*!
297 \fn const QBrush & QPalette::accent() const
298 \since 6.6
299
300 Returns the accent brush of the current color group.
301
302 \sa ColorRole, brush()
303*/
304
305/*!
306 \fn const QBrush & QPalette::link() const
307
308 Returns the unvisited link text brush of the current color group.
309
310 \sa ColorRole, brush()
311*/
312
313/*!
314 \fn const QBrush & QPalette::linkVisited() const
315
316 Returns the visited link text brush of the current color group.
317
318 \sa ColorRole, brush()
319*/
320
321/*!
322 \fn const QBrush & QPalette::placeholderText() const
323 \since 5.12
324
325 Returns the placeholder text brush of the current color group.
326
327 \note Before Qt 5.12, the placeholder text color was hard-coded as QPalette::text().color()
328 with an alpha of 128 applied. In Qt 6, it is an independent color.
329
330 \sa ColorRole, brush()
331*/
332
333/*!
334 \fn ColorGroup QPalette::currentColorGroup() const
335
336 Returns the palette's current color group.
337*/
338
339/*!
340 \fn void QPalette::setCurrentColorGroup(ColorGroup cg)
341
342 Set the palette's current color group to \a cg.
343*/
344
345/*!
346 \class QPalette
347
348 \brief The QPalette class contains color groups for each widget state.
349
350 \inmodule QtGui
351 \ingroup appearance
352 \ingroup shared
353
354 A palette consists of three color groups: \e Active, \e Disabled,
355 and \e Inactive. All widgets in Qt contain a palette and
356 use their palette to draw themselves. This makes the user
357 interface easily configurable and easier to keep consistent.
358
359
360 If you create a new widget we strongly recommend that you use the
361 colors in the palette rather than hard-coding specific colors.
362
363 The color groups:
364 \list
365 \li The Active group is used for the window that has keyboard focus.
366 \li The Inactive group is used for other windows.
367 \li The Disabled group is used for widgets (not windows) that are
368 disabled for some reason.
369 \endlist
370
371 Both active and inactive windows can contain disabled widgets.
372 (Disabled widgets are often called \e inaccessible or \e{grayed
373 out}.)
374
375 In most styles, Active and Inactive look the same.
376
377 Colors and brushes can be set for particular roles in any of a palette's
378 color groups with setColor() and setBrush(). A color group contains a
379 group of colors used by widgets for drawing themselves. We recommend that
380 widgets use color group roles from the palette such as "foreground" and
381 "base" rather than literal colors like "red" or "turquoise". The color
382 roles are enumerated and defined in the \l ColorRole documentation.
383
384 We strongly recommend that you use the default palette of the
385 current style (returned by QGuiApplication::palette()) and
386 modify that as necessary. This is done by Qt's widgets when they
387 are drawn.
388
389 To modify a color group you call the functions
390 setColor() and setBrush(), depending on whether you want a pure
391 color or a pixmap pattern.
392
393 There are also corresponding color() and brush() getters, and a
394 commonly used convenience function to get the ColorRole for the current ColorGroup:
395 window(), windowText(), base(), etc.
396
397
398 You can copy a palette using the copy constructor and test to see
399 if two palettes are \e identical using isCopyOf().
400
401 QPalette is optimized by the use of \l{implicit sharing},
402 so it is very efficient to pass QPalette objects as arguments.
403
404 \warning Some styles do not use the palette for all drawing, for
405 instance, if they make use of native theme engines. This is the
406 case for both the Windows Vista and the \macos
407 styles.
408
409 \sa QApplication::setPalette(), QWidget::setPalette(), QColor
410*/
411
412/*!
413 \enum QPalette::ColorGroup
414
415 \value Disabled
416 \value Active
417 \value Inactive
418 \value Normal synonym for Active
419
420 \omitvalue All
421 \omitvalue NColorGroups
422 \omitvalue Current
423*/
424
425/*!
426 \enum QPalette::ColorRole
427
428 \image palette.png Color Roles
429
430 The ColorRole enum defines the different symbolic color roles used
431 in current GUIs.
432
433 The central roles are:
434
435 \value Window A general background color.
436
437 \value WindowText A general foreground color.
438
439 \value Base Used mostly as the background color for text entry widgets,
440 but can also be used for other painting - such as the
441 background of combobox drop down lists and toolbar handles.
442 It is usually white or another light color.
443
444 \value AlternateBase Used as the alternate background color in views with
445 alternating row colors (see
446 QAbstractItemView::setAlternatingRowColors()).
447
448 \value ToolTipBase Used as the background color for QToolTip and
449 QWhatsThis. Tool tips use the Inactive color group
450 of QPalette, because tool tips are not active
451 windows.
452
453 \value ToolTipText Used as the foreground color for QToolTip and
454 QWhatsThis. Tool tips use the Inactive color group
455 of QPalette, because tool tips are not active
456 windows.
457
458 \value PlaceholderText Used as the placeholder color for various text input widgets.
459 This enum value has been introduced in Qt 5.12
460
461 \value Text The foreground color used with \c Base. This is usually
462 the same as the \c WindowText, in which case it must provide
463 good contrast with \c Window and \c Base.
464
465 \value Button The general button background color. This background can be different from
466 \c Window as some styles require a different background color for buttons.
467
468 \value ButtonText A foreground color used with the \c Button color.
469
470 \value BrightText A text color that is very different from
471 \c WindowText, and contrasts well with e.g. \c
472 Dark. Typically used for text that needs to be
473 drawn where \c Text or \c WindowText would give
474 poor contrast, such as on pressed push buttons.
475 Note that text colors can be used for things
476 other than just words; text colors are \e
477 usually used for text, but it's quite common to
478 use the text color roles for lines, icons, etc.
479
480
481 There are some color roles used mostly for 3D bevel and shadow effects.
482 All of these are normally derived from \c Window, and used in ways that
483 depend on that relationship. For example, buttons depend on it to make the
484 bevels look attractive, and Motif scroll bars depend on \c Mid to be
485 slightly different from \c Window.
486
487 \value Light Lighter than \c Button color.
488
489 \value Midlight Between \c Button and \c Light.
490
491 \value Dark Darker than \c Button.
492
493 \value Mid Between \c Button and \c Dark.
494
495 \value Shadow A very dark color. By default, the shadow color is
496 Qt::black.
497
498
499 Selected (marked) items have two roles:
500
501 \value Highlight A color to indicate a selected item or the current
502 item. By default, the highlight color is
503 Qt::darkBlue.
504
505 \value [since 6.6] Accent
506 A color that typically contrasts or complements
507 Base, Window and Button colors. It usually represents
508 the users' choice of desktop personalisation.
509 Styling of interactive components is a typical use case.
510 Unless explicitly set, it defaults to Highlight.
511
512 \value HighlightedText A text color that contrasts with \c Highlight.
513 By default, the highlighted text color is Qt::white.
514
515 There are two color roles related to hyperlinks:
516
517 \value Link A text color used for unvisited hyperlinks.
518 By default, the link color is Qt::blue.
519
520 \value LinkVisited A text color used for already visited hyperlinks.
521 By default, the linkvisited color is Qt::magenta.
522
523 Note that we do not use the \c Link and \c LinkVisited roles when
524 rendering rich text in Qt, and that we recommend that you use CSS
525 and the QTextDocument::setDefaultStyleSheet() function to alter
526 the appearance of links. For example:
527
528 \snippet textdocument-css/main.cpp 0
529
530 \value NoRole No role; this special role is often used to indicate that a
531 role has not been assigned.
532
533 \omitvalue NColorRoles
534*/
535
536/*!
537 Constructs an empty palette object with no color roles set.
538
539 When used as the palette of a QWidget the colors are resolved
540 as described by QWidget::setPalette().
541
542 \sa QApplication::setPalette(), QApplication::palette()
543*/
544QPalette::QPalette()
545 : d(nullptr)
546{
547 // Initialize to application palette if present, else default to black.
548 // This makes it possible to instantiate QPalette outside QGuiApplication,
549 // for example in the platform plugins.
550 if (QGuiApplicationPrivate::app_pal) {
551 d = QGuiApplicationPrivate::app_pal->d;
552 d->ref.ref();
553 setResolveMask(0);
554 } else {
555 init();
556 qt_palette_from_color(pal&: *this, button: Qt::black);
557 d->resolveMask = 0;
558 }
559}
560
561/*!
562 Constructs a palette from the \a button color. The other colors are
563 automatically calculated, based on this color. \c Window will be
564 the button color as well.
565*/
566QPalette::QPalette(const QColor &button)
567{
568 init();
569 qt_palette_from_color(pal&: *this, button);
570}
571
572/*!
573 Constructs a palette from the \a button color. The other colors are
574 automatically calculated, based on this color. \c Window will be
575 the button color as well.
576*/
577QPalette::QPalette(Qt::GlobalColor button)
578{
579 init();
580 qt_palette_from_color(pal&: *this, button);
581}
582
583/*!
584 Constructs a palette. You can pass either brushes, pixmaps or
585 plain colors for \a windowText, \a button, \a light, \a dark, \a
586 mid, \a text, \a bright_text, \a base and \a window.
587
588 \sa QBrush
589*/
590QPalette::QPalette(const QBrush &windowText, const QBrush &button,
591 const QBrush &light, const QBrush &dark,
592 const QBrush &mid, const QBrush &text,
593 const QBrush &bright_text, const QBrush &base,
594 const QBrush &window)
595{
596 init();
597 setColorGroup(cr: All, windowText, button, light, dark, mid, text, bright_text,
598 base, window);
599
600 qt_placeholder_from_text(pal&: *this);
601 qt_ensure_default_accent_color(pal&: *this);
602}
603
604
605/*!
606 \deprecated
607
608 Constructs a palette with the specified \a windowText, \a
609 window, \a light, \a dark, \a mid, \a text, and \a base colors.
610 The button color will be set to the window color.
611*/
612QPalette::QPalette(const QColor &windowText, const QColor &window,
613 const QColor &light, const QColor &dark, const QColor &mid,
614 const QColor &text, const QColor &base)
615{
616 init();
617 const QBrush windowBrush(window);
618 const QBrush lightBrush(light);
619 setColorGroup(cr: All, windowText: QBrush(windowText), button: windowBrush, light: lightBrush,
620 dark: QBrush(dark), mid: QBrush(mid), text: QBrush(text), bright_text: lightBrush,
621 base: QBrush(base), window: windowBrush);
622}
623
624/*!
625 Constructs a palette from a \a button color and a \a window.
626 The other colors are automatically calculated, based on these
627 colors.
628*/
629QPalette::QPalette(const QColor &button, const QColor &window)
630{
631 init();
632 int h, s, v;
633 window.getHsv(h: &h, s: &s, v: &v);
634
635 const QBrush windowBrush = QBrush(window);
636 const QBrush whiteBrush = QBrush(Qt::white);
637 const QBrush blackBrush = QBrush(Qt::black);
638 const QBrush baseBrush = v > 128 ? whiteBrush : blackBrush;
639 const QBrush foregroundBrush = v > 128 ? blackBrush : whiteBrush;
640 const QBrush disabledForeground = QBrush(Qt::darkGray);
641
642 const QBrush buttonBrush = QBrush(button);
643 const QBrush buttonBrushDark = QBrush(button.darker());
644 const QBrush buttonBrushDark150 = QBrush(button.darker(f: 150));
645 const QBrush buttonBrushLight150 = QBrush(button.lighter(f: 150));
646
647 //inactive and active are identical
648 setColorGroup(cr: Inactive, windowText: foregroundBrush, button: buttonBrush, light: buttonBrushLight150, dark: buttonBrushDark,
649 mid: buttonBrushDark150, text: foregroundBrush, bright_text: whiteBrush, base: baseBrush,
650 window: windowBrush);
651 setColorGroup(cr: Active, windowText: foregroundBrush, button: buttonBrush, light: buttonBrushLight150, dark: buttonBrushDark,
652 mid: buttonBrushDark150, text: foregroundBrush, bright_text: whiteBrush, base: baseBrush,
653 window: windowBrush);
654 setColorGroup(cr: Disabled, windowText: disabledForeground, button: buttonBrush, light: buttonBrushLight150,
655 dark: buttonBrushDark, mid: buttonBrushDark150, text: disabledForeground,
656 bright_text: whiteBrush, base: baseBrush, window: windowBrush);
657
658 qt_placeholder_from_text(pal&: *this);
659 qt_ensure_default_accent_color(pal&: *this);
660}
661
662/*!
663 Constructs a copy of \a p.
664
665 This constructor is fast thanks to \l{implicit sharing}.
666*/
667QPalette::QPalette(const QPalette &p)
668 : d(p.d), currentGroup(p.currentGroup)
669{
670 d->ref.ref();
671}
672
673/*!
674 \fn QPalette::QPalette(QPalette &&other)
675 \since 5.4
676
677 Move-constructs a QPalette instance, making it point at the same
678 object that \a other was pointing to.
679
680 After being moved from, you can only assign to or destroy \a other.
681 Any other operation will result in undefined behavior.
682*/
683
684/*!
685 Destroys the palette.
686*/
687QPalette::~QPalette()
688{
689 if (d && !d->ref.deref())
690 delete d;
691}
692
693/*!\internal*/
694void QPalette::init()
695{
696 d = new QPalettePrivate;
697}
698
699/*!
700 Assigns \a p to this palette and returns a reference to this
701 palette.
702
703 This operation is fast thanks to \l{implicit sharing}.
704*/
705QPalette &QPalette::operator=(const QPalette &p)
706{
707 p.d->ref.ref();
708 currentGroup = p.currentGroup;
709 if (d && !d->ref.deref())
710 delete d;
711 d = p.d;
712 return *this;
713}
714
715/*!
716 \fn void QPalette::swap(QPalette &other)
717 \since 5.0
718
719 Swaps this palette instance with \a other. This function is very
720 fast and never fails.
721*/
722
723/*!
724 Returns the palette as a QVariant
725*/
726QPalette::operator QVariant() const
727{
728 return QVariant::fromValue(value: *this);
729}
730
731/*!
732 \fn const QColor &QPalette::color(ColorGroup group, ColorRole role) const
733
734 Returns the color in the specified color \a group, used for the
735 given color \a role.
736
737 \sa brush(), setColor(), ColorRole
738*/
739
740/*!
741 \fn const QBrush &QPalette::brush(ColorGroup group, ColorRole role) const
742
743 Returns the brush in the specified color \a group, used for the
744 given color \a role.
745
746 \sa color(), setBrush(), ColorRole
747*/
748const QBrush &QPalette::brush(ColorGroup gr, ColorRole cr) const
749{
750 Q_ASSERT(cr < NColorRoles);
751 if (gr >= (int)NColorGroups) {
752 if (gr == Current) {
753 gr = currentGroup;
754 } else {
755 qWarning(msg: "QPalette::brush: Unknown ColorGroup: %d", (int)gr);
756 gr = Active;
757 }
758 }
759 return d->data->br[gr][cr];
760}
761
762/*!
763 \fn void QPalette::setColor(ColorGroup group, ColorRole role, const QColor &color)
764
765 Sets the color in the specified color \a group, used for the given
766 color \a role, to the specified solid \a color.
767
768 \sa setBrush(), color(), ColorRole
769*/
770
771/*!
772 \fn void QPalette::setBrush(ColorGroup group, ColorRole role, const QBrush &brush)
773 \overload
774
775 Sets the brush in the specified color \a group, used for the given
776 color \a role, to \a brush.
777
778 \sa brush(), setColor(), ColorRole
779*/
780void QPalette::setBrush(ColorGroup cg, ColorRole cr, const QBrush &b)
781{
782 Q_ASSERT(cr < NColorRoles);
783
784 if (cg == All) {
785 for (uint i = 0; i < NColorGroups; i++)
786 setBrush(cg: ColorGroup(i), cr, b);
787 return;
788 }
789
790 if (cg == Current) {
791 cg = currentGroup;
792 } else if (cg >= NColorGroups) {
793 qWarning(msg: "QPalette::setBrush: Unknown ColorGroup: %d", cg);
794 cg = Active;
795 }
796
797 const auto newResolveMask = d->resolveMask | ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: cg, colorRole: cr);
798 const auto valueChanged = d->data->br[cg][cr] != b;
799
800 if (valueChanged) {
801 detach();
802 d->data.detach();
803 d->data->br[cg][cr] = b;
804 } else if (d->resolveMask != newResolveMask) {
805 detach();
806 }
807
808 d->resolveMask = newResolveMask;
809}
810
811/*!
812 \since 4.2
813
814 Returns \c true if the ColorGroup \a cg and ColorRole \a cr has been
815 set previously on this palette; otherwise returns \c false.
816
817 The ColorGroup \a cg should be less than QPalette::NColorGroups,
818 but you can use QPalette::Current. In this case, the previously
819 set current color group will be used.
820
821 The ColorRole \a cr should be less than QPalette::NColorRoles.
822
823 \sa setBrush(), currentColorGroup()
824*/
825bool QPalette::isBrushSet(ColorGroup cg, ColorRole cr) const
826{
827 // NoRole has no resolve mask and should never be set anyway
828 if (cr == NoRole)
829 return false;
830
831 if (cg == Current)
832 cg = currentGroup;
833
834 if (cg >= NColorGroups) {
835 qWarning() << "Wrong color group:" << cg;
836 return false;
837 }
838
839 if (cr >= NColorRoles) {
840 qWarning() << "Wrong color role:" << cr;
841 return false;
842 }
843
844 return d->resolveMask & (ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: cg, colorRole: cr));
845}
846
847/*!
848 \internal
849*/
850void QPalette::detach()
851{
852 if (d->ref.loadRelaxed() != 1) {
853 QPalettePrivate *x = new QPalettePrivate(d->data);
854 x->resolveMask = d->resolveMask;
855 if (!d->ref.deref())
856 delete d;
857 d = x;
858 } else {
859 d->detach_no = ++QPalettePrivate::qt_palette_private_count;
860 }
861}
862
863/*!
864 \fn bool QPalette::operator!=(const QPalette &p) const
865
866 Returns \c true (slowly) if this palette is different from \a p;
867 otherwise returns \c false (usually quickly).
868
869 \note The current ColorGroup is not taken into account when
870 comparing palettes
871
872 \sa operator==()
873*/
874
875/*!
876 Returns \c true (usually quickly) if this palette is equal to \a p;
877 otherwise returns \c false (slowly).
878
879 \note The following is not taken into account when comparing palettes:
880 \list
881 \li the \c current ColorGroup
882 \li ColorRole NoRole \since 6.6
883 \endlist
884
885 \sa operator!=()
886*/
887bool QPalette::operator==(const QPalette &p) const
888{
889 if (isCopyOf(p) || d->data == p.d->data)
890 return true;
891 for(int grp = 0; grp < (int)NColorGroups; grp++) {
892 for(int role = 0; role < (int)NColorRoles; role++) {
893 // Dont't verify NoRole, because it has no resolve bit
894 if (role == NoRole)
895 continue;
896 if (d->data->br[grp][role] != p.d->data->br[grp][role])
897 return false;
898 }
899 }
900 return true;
901}
902
903/*!
904 \fn bool QPalette::isEqual(ColorGroup cg1, ColorGroup cg2) const
905
906 Returns \c true (usually quickly) if color group \a cg1 is equal to
907 \a cg2; otherwise returns \c false.
908*/
909bool QPalette::isEqual(QPalette::ColorGroup group1, QPalette::ColorGroup group2) const
910{
911 if (group1 >= (int)NColorGroups) {
912 if (group1 == Current) {
913 group1 = currentGroup;
914 } else {
915 qWarning(msg: "QPalette::brush: Unknown ColorGroup(1): %d", (int)group1);
916 group1 = Active;
917 }
918 }
919 if (group2 >= (int)NColorGroups) {
920 if (group2 == Current) {
921 group2 = currentGroup;
922 } else {
923 qWarning(msg: "QPalette::brush: Unknown ColorGroup(2): %d", (int)group2);
924 group2 = Active;
925 }
926 }
927 if (group1 == group2)
928 return true;
929 for(int role = 0; role < (int)NColorRoles; role++) {
930 if (d->data->br[group1][role] != d->data->br[group2][role])
931 return false;
932 }
933 return true;
934}
935
936/*!
937 Returns a number that identifies the contents of this QPalette
938 object. Distinct QPalette objects can have the same key if
939 they refer to the same contents.
940
941 The cacheKey() will change when the palette is altered.
942*/
943qint64 QPalette::cacheKey() const
944{
945 return (((qint64) d->data->ser_no) << 32) | ((qint64) (d->detach_no));
946}
947
948static constexpr QPalette::ResolveMask allResolveMask()
949{
950 QPalette::ResolveMask mask = {0};
951 for (int role = 0; role < int(QPalette::NColorRoles); ++role) {
952 for (int grp = 0; grp < int(QPalette::NColorGroups); ++grp) {
953 mask |= (QPalette::ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: QPalette::ColorGroup(grp), colorRole: QPalette::ColorRole(role)));
954 }
955 }
956 return mask;
957}
958
959/*!
960 Returns a new QPalette that is a union of this instance and \a other.
961 Color roles set in this instance take precedence. Roles that are not
962 set in this instance will be taken from \a other.
963
964 \sa isBrushSet
965*/
966QPalette QPalette::resolve(const QPalette &other) const
967{
968 if ((*this == other && d->resolveMask == other.d->resolveMask)
969 || d->resolveMask == 0) {
970 QPalette o = other;
971 o.setResolveMask(d->resolveMask);
972 return o;
973 }
974
975 if (d->resolveMask == allResolveMask())
976 return *this;
977
978 QPalette palette(*this);
979 palette.detach();
980
981 for (int role = 0; role < int(NColorRoles); ++role) {
982 // Don't resolve NoRole, its bits are needed for Accent (see bitPosition)
983 if (role == NoRole)
984 continue;
985
986 for (int grp = 0; grp < int(NColorGroups); ++grp) {
987 if (!(d->resolveMask & (ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: ColorGroup(grp), colorRole: ColorRole(role))))) {
988 palette.d->data.detach();
989 palette.d->data->br[grp][role] = other.d->data->br[grp][role];
990 }
991 }
992 }
993
994 palette.d->resolveMask |= other.d->resolveMask;
995
996 return palette;
997}
998
999/*!
1000 \internal
1001*/
1002QPalette::ResolveMask QPalette::resolveMask() const
1003{
1004 return d->resolveMask;
1005}
1006
1007/*!
1008 \internal
1009*/
1010void QPalette::setResolveMask(QPalette::ResolveMask mask)
1011{
1012 if (mask == d->resolveMask)
1013 return;
1014
1015 detach();
1016 d->resolveMask = mask;
1017}
1018
1019/*!
1020 \typedef ResolveMask
1021 \internal
1022
1023 A bit mask that stores which colors the palette instance explicitly defines,
1024 and which ones are inherited from a parent.
1025*/
1026
1027/*****************************************************************************
1028 QPalette stream functions
1029 *****************************************************************************/
1030
1031#ifndef QT_NO_DATASTREAM
1032
1033static const int NumOldRoles = 7;
1034static const int oldRoles[7] = { QPalette::WindowText, QPalette::Window, QPalette::Light,
1035 QPalette::Dark, QPalette::Mid, QPalette::Text, QPalette::Base };
1036
1037/*!
1038 \relates QPalette
1039
1040 Writes the palette, \a p to the stream \a s and returns a
1041 reference to the stream.
1042
1043 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
1044*/
1045
1046QDataStream &operator<<(QDataStream &s, const QPalette &p)
1047{
1048 for (int grp = 0; grp < (int)QPalette::NColorGroups; grp++) {
1049 if (s.version() == 1) {
1050 // Qt 1.x
1051 for (int i = 0; i < NumOldRoles; ++i)
1052 s << p.d->data->br[grp][oldRoles[i]].color();
1053 } else {
1054 int max = (int)QPalette::NColorRoles;
1055 if (s.version() <= QDataStream::Qt_2_1)
1056 max = QPalette::HighlightedText + 1;
1057 else if (s.version() <= QDataStream::Qt_4_3)
1058 max = QPalette::AlternateBase + 1;
1059 else if (s.version() <= QDataStream::Qt_5_11)
1060 max = QPalette::ToolTipText + 1;
1061 else if (s.version() <= QDataStream::Qt_6_5)
1062 max = QPalette::PlaceholderText + 1;
1063
1064 for (int r = 0; r < max; r++)
1065 s << p.d->data->br[grp][r];
1066 }
1067 }
1068 return s;
1069}
1070
1071static void readV1ColorGroup(QDataStream &s, QPalette &pal, QPalette::ColorGroup grp)
1072{
1073 for (int i = 0; i < NumOldRoles; ++i) {
1074 QColor col;
1075 s >> col;
1076 pal.setColor(acg: grp, acr: (QPalette::ColorRole)oldRoles[i], acolor: col);
1077 }
1078}
1079
1080/*!
1081 \relates QPalette
1082
1083 Reads a palette from the stream, \a s into the palette \a p, and
1084 returns a reference to the stream.
1085
1086 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
1087*/
1088
1089QDataStream &operator>>(QDataStream &s, QPalette &p)
1090{
1091 if (s.version() == 1) {
1092 p = QPalette();
1093 readV1ColorGroup(s, pal&: p, grp: QPalette::Active);
1094 readV1ColorGroup(s, pal&: p, grp: QPalette::Disabled);
1095 readV1ColorGroup(s, pal&: p, grp: QPalette::Inactive);
1096 } else {
1097 int max = QPalette::NColorRoles;
1098 if (s.version() <= QDataStream::Qt_2_1) {
1099 p = QPalette();
1100 max = QPalette::HighlightedText + 1;
1101 } else if (s.version() <= QDataStream::Qt_4_3) {
1102 p = QPalette();
1103 max = QPalette::AlternateBase + 1;
1104 } else if (s.version() <= QDataStream::Qt_5_11) {
1105 p = QPalette();
1106 max = QPalette::ToolTipText + 1;
1107 } else if (s.version() <= QDataStream::Qt_6_5) {
1108 p = QPalette();
1109 max = QPalette::PlaceholderText + 1;
1110 }
1111
1112
1113 QBrush tmp;
1114 for(int grp = 0; grp < (int)QPalette::NColorGroups; ++grp) {
1115 const QPalette::ColorGroup group = static_cast<QPalette::ColorGroup>(grp);
1116 for(int role = 0; role < max; ++role) {
1117 s >> tmp;
1118 p.setBrush(cg: group, cr: (QPalette::ColorRole)role, b: tmp);
1119 }
1120
1121 // Accent defaults to Highlight for stream versions that don't have it.
1122 if (s.version() < QDataStream::Qt_6_6)
1123 p.setBrush(cg: group, cr: QPalette::Accent, b: p.brush(gr: group, cr: QPalette::Highlight));
1124 }
1125
1126 }
1127 return s;
1128}
1129#endif //QT_NO_DATASTREAM
1130
1131/*!
1132 Returns \c true if this palette and \a p are copies of each other,
1133 i.e. one of them was created as a copy of the other and neither
1134 was subsequently modified; otherwise returns \c false. This is much
1135 stricter than equality.
1136
1137 \sa operator=(), operator==()
1138*/
1139
1140bool QPalette::isCopyOf(const QPalette &p) const
1141{
1142 return d == p.d;
1143}
1144
1145/*!
1146
1147 Sets a the group at \a cg. You can pass either brushes, pixmaps or
1148 plain colors for \a windowText, \a button, \a light, \a dark, \a
1149 mid, \a text, \a bright_text, \a base and \a window.
1150
1151 \sa QBrush
1152*/
1153void QPalette::setColorGroup(ColorGroup cg, const QBrush &windowText, const QBrush &button,
1154 const QBrush &light, const QBrush &dark, const QBrush &mid,
1155 const QBrush &text, const QBrush &bright_text, const QBrush &base,
1156 const QBrush &window)
1157{
1158 QBrush alt_base = QBrush(qt_mix_colors(a: base.color(), b: button.color()));
1159 QBrush mid_light = QBrush(qt_mix_colors(a: button.color(), b: light.color()));
1160 QColor toolTipBase(255, 255, 220);
1161 QColor toolTipText(0, 0, 0);
1162
1163 setColorGroup(cr: cg, windowText, button, light, dark, mid, text, bright_text, base,
1164 alternate_base: alt_base, window, midlight: mid_light, button_text: text,
1165 shadow: QBrush(Qt::black), highlight: QBrush(Qt::darkBlue), highlighted_text: QBrush(Qt::white),
1166 link: QBrush(Qt::blue), link_visited: QBrush(Qt::magenta), toolTipBase: QBrush(toolTipBase),
1167 toolTipText: QBrush(toolTipText));
1168
1169 for (int cr = Highlight; cr <= LinkVisited; ++cr) {
1170 if (cg == All) {
1171 for (int group = Active; group < NColorGroups; ++group) {
1172 d->resolveMask &= ~(ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: ColorGroup(group), colorRole: ColorRole(cr)));
1173 }
1174 } else {
1175 d->resolveMask &= ~(ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: ColorGroup(cg), colorRole: ColorRole(cr)));
1176 }
1177 }
1178}
1179
1180
1181/*!\internal*/
1182void
1183QPalette::setColorGroup(ColorGroup cg, const QBrush &foreground, const QBrush &button,
1184 const QBrush &light, const QBrush &dark, const QBrush &mid,
1185 const QBrush &text, const QBrush &bright_text,
1186 const QBrush &base, const QBrush &alternate_base,
1187 const QBrush &background, const QBrush &midlight,
1188 const QBrush &button_text, const QBrush &shadow,
1189 const QBrush &highlight, const QBrush &highlighted_text,
1190 const QBrush &link, const QBrush &link_visited)
1191{
1192 setColorGroup(cr: cg, windowText: foreground, button, light, dark, mid,
1193 text, bright_text, base, alternate_base, window: background,
1194 midlight, button_text, shadow, highlight, highlighted_text,
1195 link, link_visited, toolTipBase: background, toolTipText: foreground);
1196}
1197
1198/*!\internal*/
1199void QPalette::setColorGroup(ColorGroup cg, const QBrush &foreground, const QBrush &button,
1200 const QBrush &light, const QBrush &dark, const QBrush &mid,
1201 const QBrush &text, const QBrush &bright_text,
1202 const QBrush &base, const QBrush &alternate_base,
1203 const QBrush &background, const QBrush &midlight,
1204 const QBrush &button_text, const QBrush &shadow,
1205 const QBrush &highlight, const QBrush &highlighted_text,
1206 const QBrush &link, const QBrush &link_visited,
1207 const QBrush &toolTipBase, const QBrush &toolTipText)
1208{
1209 setBrush(cg, cr: WindowText, b: foreground);
1210 setBrush(cg, cr: Button, b: button);
1211 setBrush(cg, cr: Light, b: light);
1212 setBrush(cg, cr: Dark, b: dark);
1213 setBrush(cg, cr: Mid, b: mid);
1214 setBrush(cg, cr: Text, b: text);
1215 setBrush(cg, cr: BrightText, b: bright_text);
1216 setBrush(cg, cr: Base, b: base);
1217 setBrush(cg, cr: AlternateBase, b: alternate_base);
1218 setBrush(cg, cr: Window, b: background);
1219 setBrush(cg, cr: Midlight, b: midlight);
1220 setBrush(cg, cr: ButtonText, b: button_text);
1221 setBrush(cg, cr: Shadow, b: shadow);
1222 setBrush(cg, cr: Highlight, b: highlight);
1223 setBrush(cg, cr: HighlightedText, b: highlighted_text);
1224 setBrush(cg, cr: Link, b: link);
1225 setBrush(cg, cr: LinkVisited, b: link_visited);
1226 setBrush(cg, cr: ToolTipBase, b: toolTipBase);
1227 setBrush(cg, cr: ToolTipText, b: toolTipText);
1228}
1229
1230#ifndef QT_NO_DEBUG_STREAM
1231static QString groupsToString(const QPalette &p, QPalette::ColorRole cr)
1232{
1233 const auto groupEnum = QMetaEnum::fromType<QPalette::ColorGroup>();
1234
1235 QString groupString;
1236 for (int group = 0; group < QPalette::NColorGroups; ++group) {
1237 const auto cg = QPalette::ColorGroup(group);
1238
1239 if (p.isBrushSet(cg, cr)) {
1240 const auto &color = p.color(cg, cr);
1241 groupString += QString::fromUtf8(utf8: groupEnum.valueToKey(value: cg)) + u':' +
1242 color.name(format: QColor::HexArgb) + u',';
1243 }
1244 }
1245 groupString.chop(n: 1);
1246
1247 return groupString;
1248}
1249
1250static QString rolesToString(const QPalette &p)
1251{
1252 const auto roleEnum = QMetaEnum::fromType<QPalette::ColorRole>();
1253
1254 QString roleString;
1255 for (int role = 0; role < QPalette::NColorRoles; ++role) {
1256 const auto cr = QPalette::ColorRole(role);
1257
1258 auto groupString = groupsToString(p, cr);
1259 if (!groupString.isEmpty())
1260 roleString += QString::fromUtf8(utf8: roleEnum.valueToKey(value: cr)) + QStringLiteral(":[") +
1261 groupString + QStringLiteral("],");
1262 }
1263 roleString.chop(n: 1);
1264
1265 return roleString;
1266}
1267
1268QDebug operator<<(QDebug dbg, const QPalette &p)
1269{
1270 QDebugStateSaver saver(dbg);
1271 dbg.nospace();
1272
1273 dbg << "QPalette(resolve=" << Qt::hex << Qt::showbase << p.resolveMask();
1274
1275 auto roleString = rolesToString(p);
1276 if (!roleString.isEmpty())
1277 dbg << ',' << roleString;
1278
1279 dbg << ')';
1280
1281 return dbg;
1282 }
1283#endif
1284
1285QT_END_NAMESPACE
1286
1287#include "moc_qpalette.cpp"
1288

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtbase/src/gui/kernel/qpalette.cpp