Revision control

Copy as Markdown

// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqstylekitcontrol_p.h"
#include "qqstylekitcontrols_p.h"
#include "qqstylekitpropertyresolver_p.h"
QT_BEGIN_NAMESPACE
/*!
\qmltype ControlStyle
\inqmlmodule Qt.labs.StyleKit
\inherits ControlStateStyle
\brief Defines the style for a control in the \c normal state.
A ControlStyle describes how a \l Control should be styled. Its API
largely mirrors that of a Qt Quick Control: it provides grouped
properties for delegates such as
\l {ControlStateStyle::background}{background},
\l {ControlStateStyle::indicator}{indicator},
\l {ControlStateStyle::handle}{handle}, and
\l {ControlStateStyle::text}{text}, along with layout
properties such as
\l {ControlStateStyle::padding}{padding} and
\l {ControlStateStyle::spacing}{spacing}.
If you are familiar with the API of a \l Control in Qt Quick Controls,
you should find the ControlStyle API easy to follow.
ControlStyle inherits \l ControlStateStyle because it represents the
\e normal state: properties set directly on a ControlStyle describe
how the control looks when no other state is active. State-specific
overrides are set through nested states, such as \l {ControlStateStyle::}{hovered}
\l {ControlStateStyle::}{pressed}, and \l {ControlStateStyle::}{checked}.
\l {StylableControls}{Each stylable control} in a \l Style, \l Theme, or \l StyleVariation is a ControlStyle.
For example, in the snippet below, \l {StylableControls::}{control},
\l {StylableControls::}{button} and \l {StylableControls::}{radioButton}
are all ControlStyles:
\snippet ControlStyleSnippets.qml ControlStyle
\sa {StylableControls}{All stylable controls}, Style, Theme,
StyleVariation, ControlStateStyle, DelegateStyle
*/
/*!
\qmlproperty list<StyleVariation> ControlStyle::variations
A list of \l {StyleVariation}{type variations} for this control type.
A type variation provides alternate styling for controls that are
children (or descendants) of this control type. For example, you
can use it to style all \l {Button}{buttons} inside a \l {Frame}{frame}
differently from buttons elsewhere:
\snippet TypeVariationSnippets.qml frame with variation
Unlike instance variations — which are applied to specific control
instances from the application via the
\l {StyleVariation::variations} attached property — type
variations are applied to \e{all} instances of a control type from
the \l Style, without requiring the application to opt in.
\sa StyleVariation
*/
QQStyleKitControl::QQStyleKitControl(QObject *parent)
: QQStyleKitControlState(parent)
{
}
QQmlListProperty<QQStyleKitVariation> QQStyleKitControl::variations()
{
const bool isWrite = subclass() == QQSK::Subclass::QQStyleKitState;
if (isWrite) {
if (!QQStyleKitPropertyResolver::hasLocalStyleProperty(this, QQSK::Property::Variations)) {
/* We need to handle both the setter and the getter in the getter, since QML doesn't
* use a separate setter for QQmlListProperty. This means that we need to initialize
* the storage with an empty QList, since we need to be prepared for the QML engine
* inserting elements into it behind our back. A negative side-effect of this logic
* is that a simple read of the property for a QQStyleKitState will also accidentally
* populate the local storage of that QQStylKitState, and thereby affect propagation.
* Note: since Variations is not a part of QQStyleKitProperties, it's not possible,
* and there is also no point, in emitting a changed signal globally, since a
* QQuickStyleKitReader inherits QQStyleKitProperties and not QQStyleKitControl,
* and as such, doesn't have a 'variations' property. */
auto *newList = new QList<QQStyleKitVariation *>();
setStyleProperty(QQSK::Property::Variations, newList);
}
}
/* Read the property, taking propagation into account. Note that since QQmlListProperty takes
* a pointer to a QList as argument, we need to store the list as a pointer as well */
const QVariant variant = QQStyleKitPropertyResolver::readStyleProperty(this, QQSK::Property::Variations);
if (!variant.isValid()) {
// Return a read-only list. Trying to change this list from the app has no effect.
static auto *emptyList = new QList<QQStyleKitVariation *>();
return QQmlListProperty<QQStyleKitVariation>(this, emptyList);
}
const auto value = qvariant_cast<QList<QQStyleKitVariation *> *>(variant);
return QQmlListProperty<QQStyleKitVariation>(this, value);
}
QVariant QQStyleKitControl::readStyleProperty(PropertyStorageId key) const
{
return m_storage.value(key);
}
void QQStyleKitControl::writeStyleProperty(PropertyStorageId key, const QVariant &value)
{
m_storage.insert(key, value);
}
QQStyleKitControls *QQStyleKitControl::controls() const
{
Q_ASSERT(qobject_cast<QQStyleKitControls *>(parent()));
return static_cast<QQStyleKitControls *>(parent());
}
QQStyleKitExtendableControlType QQStyleKitControl::controlType() const
{
const auto &controlsMap = controls()->m_controls;
Q_ASSERT(std::find(controlsMap.begin(), controlsMap.end(), this) != controlsMap.end());
return controlsMap.key(const_cast<QQStyleKitControl *>(this));
}
QT_END_NAMESPACE
#include "moc_qqstylekitcontrol_p.cpp"