Skip to main content

qtbridge/
lib.rs

1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4#![doc = include_str!("../README.md")]
5
6#[doc(hidden)]
7pub use qtbridge_runtime;
8pub use qtbridge_runtime::QModelItem;
9pub use qtbridge_runtime::invoke_method;
10pub use qtbridge_runtime::QVariantConvertible;
11pub use qtbridge_runtime::QMetaTypeCompatible;
12pub use qtbridge_runtime::QPropertyMember;
13pub use qtbridge_runtime::registry::collect_garbage;
14#[doc(hidden)]
15pub use qtbridge_interfaces;
16#[doc(hidden)]
17pub use qtbridge_type_lib;
18
19pub mod special_traits {
20      //! Traits that enable Rust types to fulfill specific QML roles.
21      //!
22      //! Implement one of these on your struct and pass it as `Base = ...`
23      //! to [`qobject`](crate::qobject).
24      //!
25      //! Note that only one of these traits can be implemented for the same
26      //! type.
27      //!
28      //! - [`QListModel`](crate::QListModel) exposes a list to QML ListView / Repeater
29      //! - [`QTableModel`](crate::QTableModel) exposes a table to QML TableView
30      //! - [`QParserStatus`](crate::QParserStatus) receives notifications during component construction
31}
32
33/// Annotate an `impl` or `mod` block to make its struct accessible from QML.
34///
35/// The macro implements a range of traits that enable bridging from Rust
36/// to QML. The mechanism is based on the implementation of various traits with
37/// some code generated at macro expansion time. You should not implement these
38/// traits yourself. As a user, you should only interact with:
39///
40/// * [`QmlObject`]
41/// * [`QmlElement`] (only non-generic types)
42///
43/// This macro makes it possible to declare the following items within the
44/// `impl` block:
45///
46/// * signals with the [`qsignal`] attribute macro
47/// * invokable functions with the [`qslot`] attribute macro
48/// * struct properties with the [`qproperty`] macro
49///
50/// Further, it allows the struct to implement traits to fulfill specific QML purposes.
51/// These are called `Base` traits. The available base traits are:
52///
53/// * [`QParserStatus`] to receive notifications during QML component construction.
54/// * [`QListModel`] to make a `struct` accessible by QML ListView, QML Repeater, or similar.
55/// * [`QTableModel`] to make a `struct` accessible by QML TableView.
56///
57/// Only one of those traits can be implemented at the same time.
58///
59/// # Usage
60///
61/// The [`qobject`] macro can be applied to a `impl` block of the
62/// target `struct`. Only a single `impl` block can be annotated with this macro and
63/// all applications of [`qsignal`], [`qslot`] and [`qproperty`] have to be limited to
64/// this block.
65///
66/// Alternatively, it may be applied to the `mod` block that contains the `struct`
67/// definition and its associated `impl` blocks.
68///
69/// In order to communicate with QML, the macro creates bridging objects that are attached
70/// to the respective structs. Therefore, objects created with [`qobject`] should be
71/// created with [`default_with_attached_qobject`](QmlObject::default_with_attached_qobject)
72/// or expanded with [`attach_qobject`](QmlObject::attach_qobject). This is not necessary if
73/// the struct is instantiated in QML.
74///
75/// When [`register`](QmlElement::register) is called, the macro creates a QML
76/// module whose name matches your Cargo package name. So for a `Cargo.toml` with
77/// ```toml
78/// [package]
79/// name = "hello_world"
80///
81/// [dependencies]
82/// qtbridge
83/// ```
84/// the QML file has to contain
85///
86/// ```qml
87/// import hello_world
88/// ```
89///
90/// ## Requirements
91///
92/// A `struct` using [`qobject`] must implement the [`Default`] trait when it
93/// is registered as a QML element; `NoQmlElement` types need no `Default`.
94/// The static function [`register`](QmlElement::register) has to be called at the start of the
95/// main function to make this `struct` instantiable from QML.
96///
97/// ## Parameters
98///
99/// Parameters to adjust the macro behavior are passed as comma-separated keywords or keyword-value pairs.
100///
101/// **Base = BaseTrait**
102///
103/// Set the base trait. Must be one of the [`special_traits`] and must be
104/// implemented for the corresponding `struct`. Only one base trait can be set
105/// per type.
106///
107/// **ConvertToCamelCase**
108///
109/// Rust uses snake_case for function names, while in QML camelCase is more common. Use this option
110/// to convert function names to camelCase when exposed to QML.
111///
112/// **NoQmlElement**
113///
114/// Do not implement [`QmlElement`]. [`QmlElement`] registers the `struct` in the QML type system,
115/// allowing you to instantiate this type in QML. The `NoQmlElement` option can be useful to turn off
116/// instantiatability within QML or to provide a manual implementation of this trait with better control
117/// over naming and versioning.
118///
119/// **Singleton**
120///
121/// Implement [`QmlElement`] as a [singleton](https://doc.qt.io/qt-6/qml-singleton.html). A singleton
122/// is accessed from QML as a single shared instance of the type, using the type name as identifier.
123/// This is useful for application-wide data, global settings, or service objects.
124///
125/// ## Automatic registration
126///
127/// When the `linkme` cargo feature is enabled, [`register`](QmlElement::register) is called at
128/// application start for every annotated type without any additional code. The crate
129/// [`Linkme`](https://crates.io/crates/linkme) is used for this purpose:
130///
131/// ```toml
132/// qtbridge = { version = "0.2", features = ["linkme"] }
133/// ```
134///
135/// The feature applies to every type annotated with [`qobject`] in the whole application,
136/// including its dependencies. Types annotated with `NoQmlElement` are exempt, as they do
137/// not implement [`QmlElement`].
138///
139/// ## Example
140///
141/// ```rust
142/// use qtbridge::{QApp, qobject};
143///
144/// #[derive(Default)]
145/// pub struct Counter {
146///    value: i32,
147/// }
148///
149/// #[qobject(Singleton)]
150/// impl Counter {
151///     qproperty!("value", Member = value, Notify = value_changed);
152///
153///     #[qsignal]
154///     fn value_changed(&mut self);
155///
156///     #[qslot]
157///     fn change_value(&mut self, inc: bool) {
158///         self.value = match inc {
159///             true => self.value.saturating_add(1),
160///             false => self.value.saturating_sub(1),
161///         };
162///         self.value_changed();
163///     }
164/// }
165///
166/// const QML_CODE: &str =
167/// r#"
168///     import QtQuick
169///     import QtQuick.Controls
170///     import QtQuick.Layouts
171///     import qtbridge // must match your cargo package name
172///
173///     ApplicationWindow {
174///         visible: true
175///         title: qsTr("Counter QML app")
176/// #       Component.onCompleted: closeTimer.start()
177/// #       Timer {
178/// #           id: closeTimer
179/// #           interval: 1
180/// #           onTriggered: Qt.quit()
181/// #       }
182///         RowLayout {
183///             anchors.centerIn: parent
184///             Button {
185///                 text: "-"
186///                 onClicked: Counter.changeValue(false)
187///             }
188///             Button {
189///                 text: "+"
190///                 onClicked: Counter.changeValue(true)
191///             }
192///         }
193///     }
194/// "#;
195///
196/// fn main() {
197///     QApp::new()
198///         .register::<Counter>()
199///         .load_qml(QML_CODE.as_bytes())
200///         .run();
201/// }
202/// ```
203///
204#[doc(inline)]
205pub use qtbridge_gen::qobject;
206
207
208/// Annotates a function as a signal that can be handled in QML.
209///
210/// Signals can be called from Rust and the signal handler can be defined in QML. This is the
211/// recommended way to invoke QML code from Rust.
212///
213/// ### Requirements
214///
215/// - The signal must be defined within a `mod` or `impl` block, annotated with [`qobject`].
216/// - The first argument of the annotated function must be `&mut self`.
217/// - All other parameter types and the return type must implement [`QMetaTypeCompatible`].
218/// - The function must not have a body (end with a semicolon or empty curly braces `{}`).
219///
220/// ```rust
221/// # use qtbridge::qobject;
222/// # #[derive(Default)]
223/// # pub struct Backend {
224/// # }
225/// #
226/// #[qobject]
227/// impl Backend {
228///     #[qsignal]
229///     fn value_changed(&mut self, new_value: i32);
230///     #[qsignal]
231///     fn event_triggered(&mut self){}
232/// }
233/// ```
234///
235/// To receive a notification on the QML side, the object definition has to declare a signal handler named
236/// `on<Signal>`, where `<Signal>` is the name of the signal, with the first letter capitalized. Note that
237/// the rest of the function name is not affected and the signal handler for e.g. `value_changed` will be
238/// `onValue_changed`.
239///
240/// ```qml,ignore
241/// Backend {
242///     onValue_changed: console.log("Value changed");
243/// }
244/// ```
245/// Alternatively you can instantiate a `Connection` object with the respective signal handler.
246/// ```qml,ignore
247/// Connection {
248///     target: backend
249///     function onValue_changed() {
250///         console.log("Value changed");
251///     }
252/// }
253/// ```
254///
255/// For more details see <https://doc.qt.io/qt-6/qtqml-syntax-signals.html>
256///
257/// ### Parameters
258///
259/// ***qml_name***
260///
261/// The signal name as seen in QML. Defaults to the Rust function name.
262///
263#[doc(inline)]
264pub use qtbridge_gen::qsignal;
265
266/// Annotates a function as invokable from QML.
267///
268/// Such a function is also registered as a Qt slot, so it can be the target of a
269/// [signal-slot connection](https://doc.qt.io/qt-6/signalsandslots.html), or be
270/// invoked by name from Rust through a [`QmlMethodInvoker`].
271///
272/// ### Requirements
273///
274/// - Has to be defined within a `mod` or `impl` block, annotated with [`qobject`].
275/// - The annotated function must have a body.
276/// - The first argument of the annotated function must be `&self` or `&mut self`.
277/// - All other parameter types and the return type must implement [`QMetaTypeCompatible`].
278///
279/// ### Example
280/// ```rust
281/// # use qtbridge::qobject;
282/// # #[derive(Default)]
283/// # pub struct Backend {
284/// #     value: i32,
285/// # }
286/// #
287/// # #[qobject]
288/// # impl Backend {
289/// #[qslot]
290/// fn set_value(&mut self, new_value: i32) {
291///     self.value = new_value;
292/// }
293/// # }
294/// ```
295///
296/// ### Parameters
297///
298/// **qml_name**
299///
300/// The function name as seen from QML. Defaults to the Rust function name.
301#[doc(inline)]
302pub use qtbridge_gen::qslot;
303
304// TODO: Remove name mangling from doc snippets.
305/// Registers a property to be accessible from QML.
306///
307/// ### Requirements
308///
309/// - The property must be defined within a `mod` or `impl` block, annotated with [`qobject`].
310/// - The first parameter is the property name. It must begin with a lower case letter and
311///   can only contain letters, numbers and underscores.
312/// - The property type must implement [`QPropertyMember`].
313/// - The return value of the getter (specified via `Read` parameter) must match the property type.
314/// - The value parameter of the setter (specified via `Write` parameter) must match the property type.
315/// - The member of the `struct` (specified via `Member` parameter) must match the property type.
316/// - A signal indicating any property changes (specified via `Notify` parameter) must be
317///   emitted explicitly by any code that changes the property. The framework does not emit
318///   it automatically.
319/// - Getter and setter methods must be defined within the same `impl` block in which the property
320///   is declared.
321///
322/// A property may be **accessor-based** or **member-based** or a mix of both (see the
323/// [syntax](#qproperty-syntax) section for details).
324///
325/// ### Accessor based property
326///
327/// A pure accessor-based property can be declared together with a range of functions:
328/// ```rust
329/// # use qtbridge::qobject;
330/// # #[derive(Default)]
331/// # pub struct Backend {
332/// #     value: i32,
333/// # }
334/// #
335/// # #[qobject]
336/// # impl Backend {
337/// qproperty!("myProperty", Read = get_value, Write = set_value, Notify = my_property_changed);
338///
339/// pub fn get_value(&self) -> i32 { self.value }
340/// pub fn set_value(&mut self, value: i32) {
341///     self.value = value;
342///     self.my_property_changed();
343/// }
344/// #[qsignal]
345/// pub fn my_property_changed(&mut self);
346/// # }
347/// ```
348/// The getter method that returns the current value of the property, the setter (if provided) must
349/// take the input value of the property as its first argument (after `&mut self`).
350///
351/// ### Member based property
352///
353/// Member based properties do not require a setter or getter and QML will directly read and write
354/// to the member. A `Notify` signal must be provided. Qt emits it automatically when QML writes
355/// the property, but when Rust code changes the member directly the notify signal must be emitted
356/// explicitly.
357///
358/// A `struct` containing a member-based property may look like:
359/// ```rust
360/// # use qtbridge::qobject;
361/// #[derive(Default)]
362/// struct Text {
363///     msg: String
364/// }
365///
366/// #[qobject]
367/// impl Text {
368///     qproperty!("message", Member = msg, Notify = message_changed);
369///
370///     #[qsignal]
371///     fn message_changed(&mut self);
372/// }
373/// ```
374///
375/// More information about Qt properties: <https://doc.qt.io/qt-6/properties.html>.
376///
377/// ### Parameters of `qproperty!`
378///
379/// **Name**
380///
381/// The first argument is a string literal specifying the name of the Qt property.
382/// This is the name under which the property is exposed to QML and should follow the
383/// naming rules from [requirements](#requirements-2).
384///
385/// **Read**
386///
387/// Specifies the getter method for the property in the format `Read = getter_name`.
388///
389/// **Write**
390///
391/// Specifies the setter method for the property in the format `Write = setter_name`.
392///
393/// **Member**
394///
395/// Specifies the struct member variable that will be accessed if no getter or setter
396/// are provided. Expected format: `Member = var_name`.
397///
398/// **Notify**
399///
400/// Specifies the name of the signal that has to be emitted when the property changes.
401/// Expected format: `Notify = signal_name`.
402///
403/// **Constant**
404///
405/// A constant property is not allowed to have `Write` or `Notify` parameters. If no
406/// `Notify` is provided in combination with member, `Constant` is required.
407/// Expected as a single keyword without an assignment expression.
408///
409/// **Default**
410///
411/// Marks this as the QML default property. Content placed inside an object literal
412/// without an explicit property assignment is written to it.
413/// Expected as a single keyword without an assignment expression.
414///
415#[doc(inline)]
416pub use qtbridge_gen::qproperty;
417
418pub use qtbridge_runtime::QApp;
419pub use qtbridge_runtime::qresource;
420pub use qtbridge_runtime::QmlMethodInvoker;
421
422#[doc(hidden)]
423pub use qtbridge_runtime::QObjectHolder;
424
425/// Basic functionality for `#[qobject]` types.
426///
427/// This trait connects structs to QML and manages their lifetime under
428/// QML usage. This trait is available on every `#[qobject]` type.
429/// Do not implement this trait manually.
430///
431/// # Object lifetime and ownership
432///
433/// A `#[qobject]` value is a plain Rust value that you can interact normally
434/// with. In order to allow the QML engine to interact with it, it needs to be
435/// wrapped in an `Rc<RefCell<_>>`. QtBridge clones this shared reference,
436/// keeps it alive while in use by QML and borrows references to call into
437/// Rust code.
438///
439/// QtBridge requires all `#[qobject]` types to have a proxy `QObject` on
440/// the QML side. It is attached lazily on its first exposure, or eagerly
441/// with [`QmlObject::default_with_attached_qobject`] and
442/// [`QmlObject::attach_qobject`].
443///
444/// The `QObject` proxy has to follow the Qt lifetime concept: Parents and
445/// Components delete their children in their destructor.
446///
447/// An object whose `QObject` was deleted remains a fully usable Rust value.
448/// The interactions with Qt (emitting signals, updating model views) become
449/// a no-op. On its next exposure to QML a fresh `QObject` is attached.
450/// Connections, bindings and QML references to the old `QObject` are not
451/// restored.
452///
453/// An object no longer referenced from Rust or reachable from QML is freed
454/// by [`collect_garbage`], which runs automatically after each QML
455/// garbage collection and during allocation pressure.
456#[doc(inline)]
457pub use qtbridge_runtime::QmlObject;
458
459/// QmlElement enables QML to instantiate types of this trait.
460///
461/// The trait is usually implemented by [`qobject`]. If you
462/// want to implement this trait manually, you have to add the `NoQmlElement`
463/// option.
464///
465/// [`QmlElement`] defines the [`ELEMENT_NAME`](QmlElement::ELEMENT_NAME)
466/// with which the `struct` can be instantiated in QML and the module name,
467/// [`URI`](QmlElement::URI), which has to be used as import in QML to
468/// use this `struct`.
469///
470/// [`QmlElement`] knows two ways of registering a type. The ordinary way
471/// is to register as an element that can be instantiated in QML:
472///
473/// ```rust
474/// # use qtbridge::qobject;
475/// # #[derive(Default)]
476/// # pub struct Backend {
477/// # }
478/// #
479/// #[qobject(NoQmlElement)]
480/// impl Backend {
481///     #[qslot]
482///     fn say_hello(&self) {
483///         println!("Hello World!")
484///     }
485/// }
486/// impl qtbridge::qtbridge_runtime::QmlElement for Backend {
487///     const URI: &str = "rust_backend";
488///     const ELEMENT_NAME: &str = "Backend";
489///     const MINOR_VERSION: u8 = 0u8;
490///     const MAJOR_VERSION: u8 = 1u8;
491///     const IS_SINGLETON: bool = false;
492/// }
493/// ```
494///
495/// ```qml
496/// import rust_backend
497/// Backend {
498///     id: backend
499/// }
500/// Button {
501///     anchors.centerIn: parent
502///     text: "Hello World!"
503///     onClicked: backend.sayHello()
504/// }
505/// ```
506///
507/// Alternatively, by setting [`IS_SINGLETON`](QmlElement::IS_SINGLETON)
508/// to true, the type is registered as a singleton. That means that only
509/// one instance can be created. It can be accessed with the
510/// [`ELEMENT_NAME`](QmlElement::ELEMENT_NAME):
511///
512/// ```rust
513/// # use qtbridge::qobject;
514/// # #[derive(Default)]
515/// # pub struct Backend {
516/// # }
517/// #
518/// #[qobject(NoQmlElement)]
519/// impl Backend {
520///     #[qslot]
521///     fn say_hello(&self) {
522///         println!("Hello World!")
523///     }
524/// }
525/// impl qtbridge::qtbridge_runtime::QmlElement for Backend {
526///     const URI: &str = "rust_backend";
527///     const ELEMENT_NAME: &str = "Backend";
528///     const MINOR_VERSION: u8 = 0u8;
529///     const MAJOR_VERSION: u8 = 1u8;
530///     const IS_SINGLETON: bool = true;
531/// }
532/// ```
533///
534/// ```qml
535/// import rust_backend
536/// Button {
537///     anchors.centerIn: parent
538///     text: "Hello World!"
539///     onClicked: Backend.sayHello()
540/// }
541/// ```
542///
543/// Further, [`MAJOR_VERSION`](QmlElement::MAJOR_VERSION) and
544/// [`MINOR_VERSION`](QmlElement::MINOR_VERSION) define the version of the
545/// QML module. These fields are mandatory but QML can load a module without
546/// specifying the version
547///
548#[doc(inline)]
549pub use qtbridge_runtime::QmlElement;
550
551pub use qtbridge_gen::QModelItem;
552
553pub use qtbridge_gen::include_bytes_qml;
554
555pub use qtbridge_interfaces::QParserStatus;
556pub use qtbridge_interfaces::{QListModel, QListModelBase};
557pub use qtbridge_interfaces::{QTableModel, QTableModelBase};
558
559#[doc(hidden)]
560pub use qtbridge_interfaces::{QAbstractItemModel, QAbstractItemModelBase};