Shared types
#[qenum] - Support for Q_ENUM and Q_ENUM_NS
Qt allows exposing enums to Qt's meta-object system, and thereby QML, with a set of macros:
Q_ENUMis used to expose an enum that is a member of aQObjectQ_ENUM_NSis used to expose an enum that is in a namespace.
CXX-Qt has support for both of these macros through the #[qenum] attribute.
QObject class enum (Q_ENUM)
CXX-Qt relies on CXX to expose enums from Rust to C++ and vice-versa.
However, CXX only supports free enums that are not defined as part of a class.
CXX-Qt doesn't change this, it only additionally exposes the enum as part of a QObject type to the meta-object system.
So any #[qenum] in CXX-Qt is available as both a normal shared CXX enum and a Q_ENUM inside the associated QObject.
To expose a shared enum as a Q_ENUM inside a QObject class, add the #[qenum(...)] attribute to the enum definition.
The argument to #[qenum(...)] must be the name of a #[qobject] that is defined in a extern "RustQt" block.
It is currently not possible to add a #[qenum(...)] to any extern "C++Qt" QObjects or a QObject that is defined in another #[cxx_qt::bridge].
Example:
#[cxx_qt::bridge]
pub mod qobject {
#[qenum(CustomBaseClass)]
/// State of the CustomBaseClass list model
enum State {
/// Another item is being added in the background
Running,
/// No items are being added in the background
Idle,
}
extern "RustQt" {
#[qobject]
#[base = QAbstractListModel]
#[qml_element]
#[qproperty(State, state)]
type CustomBaseClass = super::CustomBaseClassRust;
}
}
Registering the class enum with QML
Note that Qt provides access to enum variants through the name of the class it is registered with, not the enum name itself.
A side effect of this behavior is that the enum itself doesn't have to be registered with QML.
Only the QObject class has to be registered.
In the previous example, the #[qml_element] attribute on the #[qobject] takes care of the registration.
Usage from QML:
BusyIndicator {
anchors {
right: content.right
bottom: content.bottom
margins: 15
}
running: root.activeModel.state === CustomBaseClass.Running
}
Namespaced enum (Q_ENUM_NS)
If there is no class that the enum should be associated with, Qt still allows exposing the enum to the meta-object system, as long as it is inside a namespace.
If there is a namespace associated with a shared enum simply add the #[qenum] attribute and CXX-Qt will expose it using Q_ENUM_NS.
Note that the namespace doesn't have to be specified on the enum directly, the enum can inherit the namespace from the surrounding bridge. This follows normal CXX namespacing rules.
Example:
#[cxx_qt::bridge]
pub mod qobject {
#[qenum]
#[namespace = "Colors"]
/// An enum of colors
enum Color {
/// Red
Red,
/// Green
Green,
/// Blue
Blue,
}
}
📝 Note: Unfortunately, an important Qt limitation also applies to CXX-Qt. Namely, for any given namespace, there must be at most one bridge that exposes
#[qenum]enums through that namespace. One bridge may expose enums through multiple namespaces, however.
Registering the namespaced enum with QML
Whilst Q_ENUM_NS creates the appropriate meta-objects, it doesn't add them to QML automatically.
Like with Q_ENUM, access to the enum variants also doesn't happen through the enum directly, but rather the surrounding namespace.
Therefore, the namespace must be registered with the meta-object system and then exposed to QML.
CXX-Qt automatically registers the namespace of a namespaced #[qenum] with the meta-object system.
Registration with QML can then be done by placing a qnamespace!("...") macro inside the bridge that defines the namespaced #[qenum] and adding a #[qml_element] attribute.
#[cxx_qt::bridge]
pub mod qobject {
#[qml_element]
qnamespace!("Colors");
#[qenum]
#[namespace = "Colors"]
/// An enum of colors
enum Color {
/// Red
Red,
/// Green
Green,
/// Blue
Blue,
}
}
Usage from QML:
ToolButton {
text: qsTr("Red")
onClicked: rustInvokables.storeColorWithEnum(Colors.Red);
}