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
qquickpaletteproviderprivatebase_p.h
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4#ifndef QQUICKPALETTEPROVIDERPRIVATEBASE_H
5#define QQUICKPALETTEPROVIDERPRIVATEBASE_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtQuick/private/qquickpalette_p.h>
19#include <QtQuick/private/qquickabstractpaletteprovider_p.h>
20#include <QtGui/qwindow.h>
21#include <QtQml/private/qlazilyallocated_p.h>
22
23QT_BEGIN_NAMESPACE
24
25class QWindow;
26class QQuickWindow;
27class QQuickWindowPrivate;
28class QQuickItem;
29class QQuickItemPrivate;
30class QQuickPopup;
31class QQuickPopupPrivate;
32
33/*!
34 \internal
35
36 Implements all required operations with palette.
37
38 I -- is interface class (e.g. QQuickItem).
39 Impl -- is implementation class (e.g. QQuickItemPrivate).
40
41 To use this class you need to inherit implementation class from it.
42 */
43template <class I, class Impl>
45{
46 static_assert(std::is_base_of<QObject, I>{}, "The interface class must inherit QObject");
47
48public:
50
51 /*!
52 \internal
53
54 Get current palette.
55
56 \note Palette might be lazily allocated. Signal \p paletteCreated()
57 will be emitted by an object of interface class in this case.
58
59 \note This function doesn't ask an object of interface class to emit
60 paletteChanged() signal in order to avoid problems with
61 property bindigns.
62 */
63 virtual QQuickPalette *palette() const;
64
65 /*!
66 \internal
67
68 Set new palette. Doesn't transfer ownership.
69 */
70 virtual void setPalette(QQuickPalette *p);
71
72 /*!
73 \internal
74
75 Reset palette to the default one.
76 */
77 virtual void resetPalette();
78
79 /*!
80 \internal
81
82 Check if everything is internally allocated and palette exists.
83
84 Use before call \p palette() to avoid unnecessary allocations.
85 */
86 virtual bool providesPalette() const;
87
88 /*!
89 \internal
90
91 The default palette for this component.
92 */
93 QPalette defaultPalette() const override;
94
95 /*!
96 \internal
97
98 The parent palette for this component. Can be null.
99 */
100 QPalette parentPalette(const QPalette &fallbackPalette) const override;
101
102 /*!
103 \internal
104
105 Inherit from \p parentPalette. This function is also called when
106 either parent or window of this item is changed.
107 */
108 void inheritPalette(const QPalette &parentPalette);
109
110 /*!
111 \internal
112
113 Updates children palettes. The default implementation invokes
114 inheritPalette for all visual children.
115
116 This function is also called when palette is changed
117 (signal changed() is emitted).
118 */
119 virtual void updateChildrenPalettes(const QPalette &parentPalette);
120
121protected:
123
124private:
126 using Self = QQuickPaletteProviderPrivateBase<I, Impl>;
127
128 void registerPalette(PalettePtr palette);
129
130 bool isValidPalette(const QQuickPalette *palette) const;
131
132 QQuickPalette *windowPalette() const;
133
134
135 void connectItem();
136
137 const I *itemWithPalette() const;
138 I *itemWithPalette();
139
140 QQuickPalette *paletteData() const;
141
142 QPalette toQPalette() const;
143
144private:
145 PalettePtr m_palette;
146};
147
148template<class I, class Impl>
150{
151 if (!providesPalette()) {
152 // It's required to create a new palette without parent,
153 // because this method can be called from the rendering thread
154 const_cast<Self*>(this)->registerPalette(std::make_unique<QQuickPalette>());
155 Q_EMIT const_cast<Self*>(this)->itemWithPalette()->paletteCreated();
156 }
157
158 return paletteData();
159}
160
161template<class I, class Impl>
162bool QQuickPaletteProviderPrivateBase<I, Impl>::isValidPalette(const QQuickPalette *palette) const
163{
164 if (!palette) {
165 qWarning("Palette cannot be null.");
166 return false;
167 }
168
169 if (providesPalette() && paletteData() == palette) {
170 qWarning("Self assignment makes no sense.");
171 return false;
172 }
173
174 return true;
175}
176
177template<class I, class Impl>
178void QQuickPaletteProviderPrivateBase<I, Impl>::setPalette(QQuickPalette *p)
179{
180 if (isValidPalette(p)) {
181 palette()->fromQPalette(p->toQPalette());
182 }
183}
184
185template<class I, class Impl>
187{
188 paletteData()->reset();
189}
190
191template<class I, class Impl>
193{
194 return !!m_palette;
195}
196
197template<class I, class Impl>
199{
200 return QPalette();
201}
202
203template <class Window>
204inline constexpr bool isRootWindow() { return std::is_base_of_v<QWindow, Window>; }
205
206template<class I, class Impl>
207void QQuickPaletteProviderPrivateBase<I, Impl>::registerPalette(PalettePtr palette)
208{
209 if constexpr (!isRootWindow<I>()) {
210 // Connect item only once, before initial data allocation
211 if (!providesPalette()) {
212 connectItem();
213 }
214 }
215
216 m_palette = std::move(palette);
217 m_palette->setPaletteProvider(this);
218 m_palette->inheritPalette(parentPalette(defaultPalette()));
219
221
222 // In order to avoid extra noise, we should connect
223 // the following signals only after everything is already setup
224 I::connect(paletteData(), &QQuickPalette::changed, itemWithPalette(), &I::paletteChanged);
225 I::connect(paletteData(), &QQuickPalette::changed, itemWithPalette(), [this]{ updateChildrenPalettes(toQPalette()); });
226}
227
228template<class T> struct dependent_false : std::false_type {};
229template<class Impl, class I> decltype(auto) getPrivateImpl(I &t) { return Impl::get(&t); }
230
231template <class T>
232decltype(auto) getPrivate(T &item)
233{
234 if constexpr (std::is_base_of_v<T, QQuickWindow>) {
235 return getPrivateImpl<QQuickWindowPrivate>(item);
236 } else if constexpr (std::is_base_of_v<T, QQuickItem>) {
237 return getPrivateImpl<QQuickItemPrivate>(item);
238 } else {
239 static_assert (dependent_false<T>::value, "Extend please.");
240 }
241}
242
243template<class I, class Impl>
244QQuickPalette *QQuickPaletteProviderPrivateBase<I, Impl>::windowPalette() const
245{
246 if constexpr (!isRootWindow<I>()) {
247 if (auto window = itemWithPalette()->window()) {
248 if (getPrivate(*window)->providesPalette()) {
249 return getPrivate(*window)->palette();
250 }
251 }
252 }
253
254 return nullptr;
255}
256
257template<class I, class Impl>
258QPalette QQuickPaletteProviderPrivateBase<I, Impl>::parentPalette(const QPalette &fallbackPalette) const
259{
260 if constexpr (!isRootWindow<I>()) {
261 // Popups should always inherit from their window, even child popups: QTBUG-115707.
262 if (!std::is_base_of_v<QQuickPopup, I>) {
263 for (auto parentItem = itemWithPalette()->parentItem(); parentItem;
264 parentItem = parentItem->parentItem()) {
265
266 // Don't allocate a new palette here. Use only if it's already pre allocated
267 if (parentItem && getPrivate(*parentItem)->providesPalette()) {
268 return getPrivate(*parentItem)->palette()->toQPalette();
269 }
270 }
271 }
272
273 if (auto wp = windowPalette()) {
274 return wp->toQPalette();
275 }
276 }
277
278 return fallbackPalette;
279}
280
281template<class I>
282const QQuickItem* rootItem(const I &item)
283{
284 if constexpr (isRootWindow<I>()) {
285 return item.contentItem();
286 } else if constexpr (std::is_base_of_v<QQuickPopup, I>) {
287 return nullptr;
288 } else {
289 return &item;
290 }
291}
292
293template<class I, class Impl>
294void QQuickPaletteProviderPrivateBase<I, Impl>::inheritPalette(const QPalette &parentPalette)
295{
296 if (providesPalette()) {
297 // If palette is changed, then this function will be invoked
298 // for all children because of connection with signal changed()
299 palette()->inheritPalette(parentPalette);
300 } else {
301 // Otherwise, just propagate parent palette to all children
302 updateChildrenPalettes(parentPalette);
303 }
304}
305
306template<class I, class Impl>
308{
309 if constexpr (!isRootWindow<I>()) {
310 if (providesPalette()) {
311 const bool enabled = itemWithPalette()->isEnabled();
312 const auto window = itemWithPalette()->window();
313 const bool active = window ? window->isActive() : true;
314 palette()->setCurrentGroup(enabled ? (active ? QPalette::Active : QPalette::Inactive)
315 : QPalette::Disabled);
316 }
317 }
318}
319
320template<class I, class Impl>
321void QQuickPaletteProviderPrivateBase<I, Impl>::updateChildrenPalettes(const QPalette &parentPalette)
322{
323 if constexpr (std::is_same_v<QQuickWindow, I> && std::is_same_v<QQuickWindowPrivate, Impl>) {
324 /* QQuickWindowPrivate instantiates this template, but does not include QQuickItemPrivate
325 * This causes an error with the QQuickItemPrivate::inheritPalette call below on MSVC in
326 * static builds, as QQuickItemPrivate is incomplete. To work around this situation, we do
327 * nothing in this instantiation of updateChildrenPalettes and instead add an override in
328 * QQuickWindowPrivate, which does the correct thing.
329 */
330 Q_UNREACHABLE_RETURN(); // You are not supposed to call this function
331 } else {
332 if (auto root = rootItem(*itemWithPalette())) {
333 for (auto &&child : root->childItems()) {
334 if (Q_LIKELY(child)) {
335 getPrivate(*child)->inheritPalette(parentPalette);
336 }
337 }
338 }
339 }
340}
341
342template<class I, class Impl>
343void QQuickPaletteProviderPrivateBase<I, Impl>::connectItem()
344{
345 Q_ASSERT(itemWithPalette());
346
347 if constexpr (!isRootWindow<I>()) {
348 // Item with palette has the same lifetime as its implementation that inherits this class
349 I::connect(itemWithPalette(), &I::parentChanged,
350 itemWithPalette(), [this]() { inheritPalette(parentPalette(defaultPalette())); });
351 I::connect(itemWithPalette(), &I::windowChanged,
352 itemWithPalette(), [this]() { inheritPalette(parentPalette(defaultPalette())); });
353 I::connect(itemWithPalette(), &I::enabledChanged,
354 itemWithPalette(), [this]() { setCurrentColorGroup(); });
355 }
356}
357
358template<class I, class Impl>
359const I *QQuickPaletteProviderPrivateBase<I, Impl>::itemWithPalette() const
360{
361 static_assert(std::is_base_of<QObjectData, Impl>{},
362 "The Impl class must inherit QObjectData");
363
364 return static_cast<const I*>(static_cast<const Impl*>(this)->q_ptr);
365}
366
367template<class I, class Impl>
368I *QQuickPaletteProviderPrivateBase<I, Impl>::itemWithPalette()
369{
370 return const_cast<I*>(const_cast<const Self*>(this)->itemWithPalette());
371}
372
373template<class I, class Impl>
374QQuickPalette *QQuickPaletteProviderPrivateBase<I, Impl>::paletteData() const
375{
376 Q_ASSERT(m_palette); return m_palette.get();
377}
378
379template<class I, class Impl>
380QPalette QQuickPaletteProviderPrivateBase<I, Impl>::toQPalette() const
381{
382 return palette()->toQPalette();
383}
384
385QT_END_NAMESPACE
386
387#endif // QQUICKPALETTEPROVIDERPRIVATEBASE_H
void inheritPalette(const QPalette &parentPalette)
virtual void updateChildrenPalettes(const QPalette &parentPalette)
virtual ~QQuickPaletteProviderPrivateBase()=default
QPalette parentPalette(const QPalette &fallbackPalette) const override
const QQuickItem * rootItem(const I &item)
decltype(auto) getPrivate(T &item)
constexpr bool isRootWindow()
decltype(auto) getPrivateImpl(I &t)