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 "qqstylekitcontrolstate_p.h"
#include "qqstylekitcontrol_p.h"
QT_BEGIN_NAMESPACE
// ************* ControlStateStyle ****************
/*!
\qmltype ControlStateStyle
\inqmlmodule Qt.labs.StyleKit
\inherits ControlStyleProperties
\brief Describes the style of a control in a given state.
ControlStateStyle describes the style of a control in a particular state.
A \l ControlStyle inherits ControlStateStyle, since it represents the
\e normal state — properties set directly on a \l ControlStyle describe
how the control looks when no other state is active. State-specific
overrides are then set through nested states such as \l pressed,
\l hovered, and \l checked.
Nested states are not mutually exclusive. Multiple states can be active at
the same time — for example, a button can be both hovered and
pressed simultaneously. When several states are active, all matching
state overrides are applied. If the same property is set in multiple
active states, conflicts are resolved using the following priority
order: \l pressed, \l hovered, \l highlighted, \l focused,
\l checked, \l vertical. So for example \c {pressed.background.color}
wins over \c {checked.background.color} if the control is both
\l pressed and \l checked.
The \l disabled state is an exception: a disabled control cannot
be interacted with, so the \l pressed, \l hovered, \l highlighted,
and \l focused states will not apply. However, \l disabled can
still be combined with states like \l checked and \l vertical.
The more deeply nested a state is, the more qualified it is.
For example, \c {hovered.pressed.background.color} takes precedence over
\c {hovered.background.color} when both \l hovered and \l pressed are
active. The nesting order does not matter:
\c {hovered.pressed} and \c {pressed.hovered} are equivalent.
However, if both forms are used at the same time, which one wins is
undefined.
Deeper nesting of states can also be used to resolve conflicts. If the same property
is set in both \l hovered and \l checked, the priority order means
the \l hovered value wins. If you would rather have the checked value win, or
use an altogether different value in that situation, you can override
the property in \c {hovered.checked}, which then takes precedence over both.
The following snippet shows how to style a button differently
depending on its state:
\snippet ControlStateStyle_states.qml States
\labs
\sa ControlStyle, DelegateStyle, {StyleKit Property Resolution},
{Reference Fallback Style}
*/
/*!
\qmlproperty ControlStateStyle ControlStateStyle::pressed
Style overrides applied when the control is \l {StyleReader::}{pressed}.
\sa hovered, highlighted, focused, checked, vertical, disabled,
{StyleReader::pressed}{StyleReader.pressed}
*/
/*!
\qmlproperty ControlStateStyle ControlStateStyle::hovered
Style overrides applied when the control is \l {StyleReader::}{hovered}.
\sa pressed, highlighted, focused, checked, vertical, disabled,
{StyleReader::hovered}{StyleReader.hovered}
*/
/*!
\qmlproperty ControlStateStyle ControlStateStyle::highlighted
Style overrides applied when the control is \l {StyleReader::}{highlighted}.
\sa pressed, hovered, focused, checked, vertical, disabled,
{StyleReader::highlighted}{StyleReader.highlighted}
*/
/*!
\qmlproperty ControlStateStyle ControlStateStyle::focused
Style overrides applied when the control is \l {StyleReader::}{focused}.
\sa pressed, hovered, highlighted, checked, vertical, disabled,
{StyleReader::focused}{StyleReader.focused}
*/
/*!
\qmlproperty ControlStateStyle ControlStateStyle::checked
Style overrides applied when the control is \l {StyleReader::}{checked}.
\sa pressed, hovered, highlighted, focused, vertical, disabled,
{StyleReader::checked}{StyleReader.checked}
*/
/*!
\qmlproperty ControlStateStyle ControlStateStyle::vertical
Style overrides applied when the control is \l {StyleReader::}{vertical}
(for example, a vertical \l Slider or \l ScrollBar).
\sa pressed, hovered, highlighted, focused, checked, disabled,
{StyleReader::vertical}{StyleReader.vertical}
*/
/*!
\qmlproperty ControlStateStyle ControlStateStyle::disabled
Style overrides applied when the control is not \l {StyleReader::}{enabled}.
A disabled control cannot be interacted with, so \l pressed,
\l hovered, \l highlighted, and \l focused will not be applied
at the same time as disabled.
\sa pressed, hovered, highlighted, focused, checked, vertical,
{StyleReader::enabled}{StyleReader.enabled}
*/
QQStyleKitControlState::QQStyleKitControlState(QObject *parent)
: QQStyleKitControlProperties(QQSK::PropertyGroup::Control, parent)
{
}
QQStyleKitControl *QQStyleKitControlState::control() const
{
if (m_nestedState == QQSK::StateFlag::Normal) {
Q_ASSERT(qobject_cast<const QQStyleKitControl *>(this));
auto *self = const_cast<QQStyleKitControlState *>(this);
return static_cast<QQStyleKitControl *>(self);
}
Q_ASSERT(qobject_cast<const QQStyleKitControl *>(parent()));
return static_cast<QQStyleKitControl *>(parent());
}
QQStyleKitControlState *QQStyleKitControlState::lazyCreateState(QQSK::StateFlag state) const
{
if (m_nestedStateObjects.contains(state))
return m_nestedStateObjects.value(state);
QQStyleKitControlState *stateObj = new QQStyleKitControlState(control());
stateObj->m_nestedState = m_nestedState;
stateObj->m_nestedState.setFlag(state);
stateObj->m_nestedState.setFlag(QQSK::StateFlag::Normal, false);
auto *self = const_cast<QQStyleKitControlState *>(this);
self->m_nestedStateObjects.insert(state, stateObj);
return stateObj;
}
QQStyleKitControlState *QQStyleKitControlState::pressed() const
{
return lazyCreateState(QQSK::StateFlag::Pressed);
}
QQStyleKitControlState *QQStyleKitControlState::hovered() const
{
return lazyCreateState(QQSK::StateFlag::Hovered);
}
QQStyleKitControlState *QQStyleKitControlState::highlighted() const
{
return lazyCreateState(QQSK::StateFlag::Highlighted);
}
QQStyleKitControlState *QQStyleKitControlState::focused() const
{
return lazyCreateState(QQSK::StateFlag::Focused);
}
QQStyleKitControlState *QQStyleKitControlState::checked() const
{
return lazyCreateState(QQSK::StateFlag::Checked);
}
QQStyleKitControlState *QQStyleKitControlState::vertical() const
{
return lazyCreateState(QQSK::StateFlag::Vertical);
}
QQStyleKitControlState *QQStyleKitControlState::disabled() const
{
return lazyCreateState(QQSK::StateFlag::Disabled);
}
QT_END_NAMESPACE
#include "moc_qqstylekitcontrolstate_p.cpp"