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

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