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 | |
4 | #include "qquickpalette_p.h" |
5 | |
6 | #include <QtQuick/private/qquickpalettecolorprovider_p.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | static constexpr bool is_valid(QPalette::ColorGroup cg) noexcept |
11 | { |
12 | // use a switch to enable "unhandled enum" warnings: |
13 | switch (cg) { |
14 | case QPalette::Active: |
15 | case QPalette::Disabled: |
16 | case QPalette::Inactive: |
17 | return true; |
18 | case QPalette::NColorGroups: |
19 | case QPalette::Current: |
20 | case QPalette::All: |
21 | return false; |
22 | } |
23 | |
24 | // GCC 8.x does not tread __builtin_unreachable() as constexpr |
25 | #if defined(Q_CC_INTEL) || defined(Q_CC_CLANG) || (defined(Q_CC_GNU) && Q_CC_GNU >= 900) |
26 | // NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8 |
27 | Q_UNREACHABLE(); |
28 | #endif |
29 | return false; |
30 | } |
31 | |
32 | /*! |
33 | \internal |
34 | |
35 | \class QQuickPalette |
36 | \brief Contains color groups for each QML item state. |
37 | \inmodule QtQuick |
38 | \since 6.0 |
39 | |
40 | This class is the wrapper around QPalette. |
41 | |
42 | \sa QQuickColorGroup, QQuickAbstractPaletteProvider, QPalette |
43 | */ |
44 | |
45 | /*! |
46 | \qmltype Palette |
47 | \instantiates QQuickPalette |
48 | \inherits QQuickColorGroup |
49 | \inqmlmodule QtQuick |
50 | \ingroup qtquick-visual |
51 | \brief Contains color groups for each QML item state. |
52 | |
53 | A palette consists of three color groups: \c active, \c disabled, and \c inactive. |
54 | The \c active color group is the default group: its colors are used for other groups |
55 | if colors of these groups aren't explicitly specified. |
56 | |
57 | In the following example, color is applied for all color groups: |
58 | \code |
59 | ApplicationWindow { |
60 | palette.buttonText: "salmon" |
61 | |
62 | ColumnLayout { |
63 | Button { |
64 | text: qsTr("Disabled button") |
65 | enabled: false |
66 | } |
67 | |
68 | Button { |
69 | text: qsTr("Enabled button") |
70 | } |
71 | } |
72 | } |
73 | \endcode |
74 | It means that text color will be the same for both buttons. |
75 | |
76 | In the following example, colors will be different for enabled and disabled states: |
77 | \code |
78 | ApplicationWindow { |
79 | palette.buttonText: "salmon" |
80 | palette.disabled.buttonText: "lavender" |
81 | |
82 | ColumnLayout { |
83 | Button { |
84 | text: qsTr("Disabled button") |
85 | enabled: false |
86 | } |
87 | |
88 | Button { |
89 | text: qsTr("Enabled button") |
90 | } |
91 | } |
92 | } |
93 | \endcode |
94 | |
95 | It is also possible to specify colors like this: |
96 | |
97 | \snippet qtquickcontrols-custom-palette-buttons.qml palette |
98 | |
99 | This approach is especially convenient when you need to specify a whole |
100 | palette with all color groups; but as with the other cases above, the |
101 | colors that are not specified are initialized from SystemPalette, or |
102 | potentially the \l {Styling Qt Quick Controls}{Qt Quick Controls style}, |
103 | if one is in use. |
104 | |
105 | \note Some Controls styles use some palette colors, but many styles use |
106 | independent colors. |
107 | |
108 | \sa Window::palette, Item::palette, Popup::palette, SystemPalette |
109 | */ |
110 | |
111 | /*! |
112 | \qmlproperty ColorGroup QtQuick::Palette::active |
113 | |
114 | The Active group is used for windows that are in focus. |
115 | |
116 | \sa QPalette::Active |
117 | */ |
118 | |
119 | /*! |
120 | \qmlproperty ColorGroup QtQuick::Palette::inactive |
121 | |
122 | The Inactive group is used for windows that have no keyboard focus. |
123 | |
124 | \sa QPalette::Inactive |
125 | */ |
126 | |
127 | /*! |
128 | \qmlproperty ColorGroup QtQuick::Palette::disabled |
129 | |
130 | The Disabled group is used for elements that are disabled for some reason. |
131 | |
132 | \sa QPalette::Disabled |
133 | */ |
134 | |
135 | QQuickPalette::QQuickPalette(QObject *parent) |
136 | : QQuickColorGroup(parent) |
137 | , m_currentGroup(defaultCurrentGroup()) |
138 | { |
139 | } |
140 | |
141 | QQuickColorGroup *QQuickPalette::active() const |
142 | { |
143 | return colorGroup(groupTag: QPalette::Active); |
144 | } |
145 | |
146 | QQuickColorGroup *QQuickPalette::inactive() const |
147 | { |
148 | return colorGroup(groupTag: QPalette::Inactive); |
149 | } |
150 | |
151 | QQuickColorGroup *QQuickPalette::disabled() const |
152 | { |
153 | return colorGroup(groupTag: QPalette::Disabled); |
154 | } |
155 | |
156 | /*! |
157 | \internal |
158 | |
159 | Returns the palette's current color group. |
160 | The default value is Active. |
161 | */ |
162 | QPalette::ColorGroup QQuickPalette::currentColorGroup() const |
163 | { |
164 | return m_currentGroup; |
165 | } |
166 | |
167 | /*! |
168 | \internal |
169 | |
170 | Sets \a currentGroup for this palette. |
171 | |
172 | The current color group is used when accessing colors of this palette. |
173 | For example, if color group is Disabled, color accessors will be |
174 | returning colors form the respective group. |
175 | \code |
176 | QQuickPalette palette; |
177 | |
178 | palette.setAlternateBase(Qt::green); |
179 | palette.disabled()->setAlternateBase(Qt::red); |
180 | |
181 | auto color = palette.alternateBase(); // Qt::green |
182 | |
183 | palette.setCurrentGroup(QPalette::Disabled); |
184 | color = palette.alternateBase(); // Qt::red |
185 | \endcode |
186 | |
187 | Emits QColorGroup::changed(). |
188 | */ |
189 | void QQuickPalette::setCurrentGroup(QPalette::ColorGroup currentGroup) |
190 | { |
191 | if (m_currentGroup != currentGroup) { |
192 | m_currentGroup = currentGroup; |
193 | Q_EMIT changed(); |
194 | } |
195 | } |
196 | |
197 | void QQuickPalette::fromQPalette(QPalette palette) |
198 | { |
199 | if (colorProvider().fromQPalette(p: std::move(palette))) { |
200 | Q_EMIT changed(); |
201 | } |
202 | } |
203 | |
204 | QPalette QQuickPalette::toQPalette() const |
205 | { |
206 | return colorProvider().palette(); |
207 | } |
208 | |
209 | const QQuickAbstractPaletteProvider *QQuickPalette::paletteProvider() const |
210 | { |
211 | return colorProvider().paletteProvider(); |
212 | } |
213 | |
214 | void QQuickPalette::setPaletteProvider(const QQuickAbstractPaletteProvider *paletteProvider) |
215 | { |
216 | colorProvider().setPaletteProvider(paletteProvider); |
217 | } |
218 | |
219 | void QQuickPalette::reset() |
220 | { |
221 | if (colorProvider().reset()) { |
222 | Q_EMIT changed(); |
223 | } |
224 | } |
225 | |
226 | void QQuickPalette::inheritPalette(const QPalette &palette) |
227 | { |
228 | if (colorProvider().inheritPalette(palette)) { |
229 | Q_EMIT changed(); |
230 | } |
231 | } |
232 | |
233 | void QQuickPalette::setActive(QQuickColorGroup *active) |
234 | { |
235 | setColorGroup(groupTag: QPalette::Active, group: active, notifier: &QQuickPalette::activeChanged); |
236 | } |
237 | |
238 | void QQuickPalette::setInactive(QQuickColorGroup *inactive) |
239 | { |
240 | setColorGroup(groupTag: QPalette::Inactive, group: inactive, notifier: &QQuickPalette::inactiveChanged); |
241 | } |
242 | |
243 | void QQuickPalette::setDisabled(QQuickColorGroup *disabled) |
244 | { |
245 | setColorGroup(groupTag: QPalette::Disabled, group: disabled, notifier: &QQuickPalette::disabledChanged); |
246 | } |
247 | |
248 | |
249 | void QQuickPalette::setColorGroup(QPalette::ColorGroup groupTag, |
250 | const QQuickColorGroup::GroupPtr &group, |
251 | void (QQuickPalette::*notifier)()) |
252 | { |
253 | if (isValidColorGroup(groupTag, colorGroup: group)) { |
254 | if (colorProvider().copyColorGroup(cg: groupTag, p: group->colorProvider())) { |
255 | Q_EMIT (this->*notifier)(); |
256 | Q_EMIT changed(); |
257 | } |
258 | } |
259 | } |
260 | |
261 | QQuickColorGroup::GroupPtr QQuickPalette::colorGroup(QPalette::ColorGroup groupTag) const |
262 | { |
263 | if (auto group = findColorGroup(groupTag)) { |
264 | return group; |
265 | } |
266 | |
267 | auto group = QQuickColorGroup::createWithParent(parent&: *const_cast<QQuickPalette*>(this)); |
268 | const_cast<QQuickPalette*>(this)->registerColorGroup(group, groupTag); |
269 | return group; |
270 | } |
271 | |
272 | QQuickColorGroup::GroupPtr QQuickPalette::findColorGroup(QPalette::ColorGroup groupTag) const |
273 | { |
274 | Q_ASSERT(is_valid(groupTag)); |
275 | return m_colorGroups[groupTag]; |
276 | } |
277 | |
278 | void QQuickPalette::registerColorGroup(QQuickColorGroup *group, QPalette::ColorGroup groupTag) |
279 | { |
280 | Q_ASSERT(is_valid(groupTag)); |
281 | auto &g = m_colorGroups[groupTag]; |
282 | if (g) { |
283 | Q_ASSERT(g != group); |
284 | g->deleteLater(); |
285 | } |
286 | g = group; |
287 | |
288 | group->setGroupTag(groupTag); |
289 | |
290 | QQuickColorGroup::connect(sender: group, signal: &QQuickColorGroup::changed, context: this, slot: &QQuickPalette::changed); |
291 | } |
292 | |
293 | bool QQuickPalette::isValidColorGroup(QPalette::ColorGroup groupTag, |
294 | const QQuickColorGroup::GroupPtr &colorGroup) const |
295 | { |
296 | if (!colorGroup) { |
297 | qWarning(msg: "Color group cannot be null." ); |
298 | return false; |
299 | } |
300 | |
301 | if (!colorGroup->parent()) { |
302 | qWarning(msg: "Color group should have a parent." ); |
303 | return false; |
304 | } |
305 | |
306 | if (colorGroup->parent() && !qobject_cast<QQuickPalette*>(object: colorGroup->parent())) { |
307 | qWarning(msg: "Color group should be a part of QQuickPalette." ); |
308 | return false; |
309 | } |
310 | |
311 | if (groupTag == defaultGroupTag()) { |
312 | qWarning(msg: "Register %i color group is not allowed." |
313 | " QQuickPalette is %i color group itself." , groupTag, groupTag); |
314 | return false; |
315 | } |
316 | |
317 | if (findColorGroup(groupTag) == colorGroup) { |
318 | qWarning(msg: "The color group is already a part of the current palette." ); |
319 | return false; |
320 | } |
321 | |
322 | return true; |
323 | } |
324 | |
325 | QT_END_NAMESPACE |
326 | |
327 | #include "moc_qquickpalette_p.cpp" |
328 | |