1 | // Copyright (C) 2020 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 | #include "qquickpalettecolorprovider_p.h" |
4 | |
5 | #include <QtQuick/private/qquickabstractpaletteprovider_p.h> |
6 | #include <QtGui/private/qpalette_p.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | static bool notEq(const QPalette &p1, const QPalette &p2) |
11 | { |
12 | return p1.resolveMask() != p2.resolveMask() || p1 != p2; |
13 | } |
14 | |
15 | static QPalette::ColorGroup adjustCg(QPalette::ColorGroup group) |
16 | { |
17 | return group == QPalette::All ? QPalette::Active : group; |
18 | } |
19 | |
20 | class DefaultPalettesProvider : public QQuickAbstractPaletteProvider |
21 | { |
22 | public: |
23 | QPalette defaultPalette() const override { static QPalette p; return p; } |
24 | }; |
25 | |
26 | static std::default_delete<const QQuickAbstractPaletteProvider> defaultDeleter() { return {}; } |
27 | |
28 | QQuickPaletteColorProvider::QQuickPaletteColorProvider() |
29 | : m_paletteProvider(ProviderPtr(new DefaultPalettesProvider, defaultDeleter())) |
30 | { |
31 | } |
32 | |
33 | const QColor &QQuickPaletteColorProvider::color(QPalette::ColorGroup group, QPalette::ColorRole role) const |
34 | { |
35 | return m_resolvedPalette.color(cg: adjustCg(group), cr: role); |
36 | } |
37 | |
38 | bool QQuickPaletteColorProvider::setColor(QPalette::ColorGroup g, QPalette::ColorRole r, QColor c) |
39 | { |
40 | ensureRequestedPalette(); |
41 | m_requestedPalette->setColor(acg: g, acr: r, acolor: c); |
42 | |
43 | return updateInheritedPalette(); |
44 | } |
45 | |
46 | bool QQuickPaletteColorProvider::resetColor(QPalette::ColorGroup group, QPalette::ColorRole role) |
47 | { |
48 | if (!m_requestedPalette.isAllocated()) |
49 | return false; |
50 | |
51 | QPalette::ResolveMask unsetResolveMask = 0; |
52 | |
53 | if (group == QPalette::Current) |
54 | group = m_requestedPalette->currentColorGroup(); |
55 | |
56 | if (group == QPalette::All) { |
57 | for (int g = QPalette::Active; g < QPalette::NColorGroups; ++g) |
58 | unsetResolveMask |= (QPalette::ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: QPalette::ColorGroup(g), colorRole: role)); |
59 | } else { |
60 | unsetResolveMask = (QPalette::ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: group, colorRole: role)); |
61 | } |
62 | |
63 | m_requestedPalette->setResolveMask(m_requestedPalette->resolveMask() & ~unsetResolveMask); |
64 | |
65 | return updateInheritedPalette(); |
66 | } |
67 | |
68 | bool QQuickPaletteColorProvider::resetColor(QPalette::ColorGroup group) |
69 | { |
70 | if (!m_requestedPalette.isAllocated()) |
71 | return false; |
72 | |
73 | QPalette::ResolveMask unsetResolveMask = 0; |
74 | |
75 | auto getResolveMask = [] (QPalette::ColorGroup group) { |
76 | QPalette::ResolveMask mask = 0; |
77 | for (int roleIndex = QPalette::WindowText; roleIndex < QPalette::NColorRoles; ++roleIndex) { |
78 | const auto cr = QPalette::ColorRole(roleIndex); |
79 | mask |= (QPalette::ResolveMask(1) << QPalettePrivate::bitPosition(colorGroup: group, colorRole: cr)); |
80 | } |
81 | return mask; |
82 | }; |
83 | |
84 | if (group == QPalette::Current) |
85 | group = m_requestedPalette->currentColorGroup(); |
86 | |
87 | if (group == QPalette::All) { |
88 | for (int g = QPalette::Active; g < QPalette::NColorGroups; ++g) |
89 | unsetResolveMask |= getResolveMask(QPalette::ColorGroup(g)); |
90 | } else { |
91 | unsetResolveMask = getResolveMask(group); |
92 | } |
93 | |
94 | m_requestedPalette->setResolveMask(m_requestedPalette->resolveMask() & ~unsetResolveMask); |
95 | |
96 | return updateInheritedPalette(); |
97 | } |
98 | |
99 | bool QQuickPaletteColorProvider::fromQPalette(QPalette p) |
100 | { |
101 | m_requestedPalette.value() = std::move(p); |
102 | return updateInheritedPalette(); |
103 | } |
104 | |
105 | QPalette QQuickPaletteColorProvider::palette() const |
106 | { |
107 | return m_resolvedPalette; |
108 | } |
109 | |
110 | const QQuickAbstractPaletteProvider *QQuickPaletteColorProvider::paletteProvider() const |
111 | { |
112 | Q_ASSERT(m_paletteProvider); |
113 | return m_paletteProvider.get(); |
114 | } |
115 | |
116 | void QQuickPaletteColorProvider::setPaletteProvider(const QQuickAbstractPaletteProvider *paletteProvider) |
117 | { |
118 | static const auto emptyDeleter = [](auto &&){}; |
119 | m_paletteProvider = ProviderPtr(paletteProvider, emptyDeleter); |
120 | } |
121 | |
122 | bool QQuickPaletteColorProvider::copyColorGroup(QPalette::ColorGroup cg, |
123 | const QQuickPaletteColorProvider &p) |
124 | { |
125 | ensureRequestedPalette(); |
126 | |
127 | auto srcPalette = p.palette(); |
128 | for (int roleIndex = QPalette::WindowText; roleIndex < QPalette::NColorRoles; ++roleIndex) { |
129 | const auto cr = QPalette::ColorRole(roleIndex); |
130 | if (srcPalette.isBrushSet(cg, cr)) { |
131 | m_requestedPalette->setBrush(cg, cr, brush: srcPalette.brush(cg, cr)); |
132 | } |
133 | } |
134 | |
135 | return updateInheritedPalette(); |
136 | } |
137 | |
138 | bool QQuickPaletteColorProvider::reset() |
139 | { |
140 | return fromQPalette(p: QPalette()); |
141 | } |
142 | |
143 | /*! \internal |
144 | Merge the given \a palette with the existing requested palette, remember |
145 | that it is the inherited palette (in case updateInheritedPalette() is |
146 | called later), and update the stored palette (to be returned from |
147 | \l palette()) if the result is different. Returns whether the stored |
148 | palette got changed. |
149 | */ |
150 | bool QQuickPaletteColorProvider::inheritPalette(const QPalette &palette) |
151 | { |
152 | m_lastInheritedPalette.value() = palette; |
153 | return doInheritPalette(palette); |
154 | } |
155 | |
156 | /*! \internal |
157 | Merge the given \a palette with the existing requested palette, and update |
158 | the stored palette (to be returned from \l palette()) if the result is |
159 | different. Returns whether the stored palette got changed. |
160 | */ |
161 | bool QQuickPaletteColorProvider::doInheritPalette(const QPalette &palette) |
162 | { |
163 | auto inheritedMask = m_requestedPalette.isAllocated() ? m_requestedPalette->resolveMask() | palette.resolveMask() |
164 | : palette.resolveMask(); |
165 | // If a palette was set on this item, it should always win over the palette to be inherited from. |
166 | QPalette parentPalette = m_requestedPalette.isAllocated() ? m_requestedPalette->resolve(other: palette) : palette; |
167 | parentPalette.setResolveMask(inheritedMask); |
168 | |
169 | auto tmpResolvedPalette = parentPalette.resolve(other: paletteProvider()->defaultPalette()); |
170 | tmpResolvedPalette.setResolveMask(tmpResolvedPalette.resolveMask() | inheritedMask); |
171 | |
172 | bool changed = notEq(p1: tmpResolvedPalette, p2: m_resolvedPalette); |
173 | if (changed) |
174 | std::swap(a&: tmpResolvedPalette, b&: m_resolvedPalette); |
175 | |
176 | return changed; |
177 | } |
178 | |
179 | /*! \internal |
180 | Update the stored palette (to be returned from \l palette()) from the |
181 | parent palette. Returns whether the stored palette got changed. |
182 | */ |
183 | bool QQuickPaletteColorProvider::updateInheritedPalette() |
184 | { |
185 | // Use last inherited palette as parentPalette's fallbackPalette: it's useful when parentPalette doesn't exist. |
186 | const QPalette &p = m_lastInheritedPalette.isAllocated() ? m_lastInheritedPalette.value() |
187 | : paletteProvider()->defaultPalette(); |
188 | return doInheritPalette(palette: paletteProvider()->parentPalette(fallbackPalette: p)); |
189 | } |
190 | |
191 | void QQuickPaletteColorProvider::ensureRequestedPalette() |
192 | { |
193 | if (m_requestedPalette.isAllocated()) |
194 | return; |
195 | |
196 | m_requestedPalette.value() = QPalette(); |
197 | } |
198 | |
199 | QT_END_NAMESPACE |
200 | |