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