1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
3
4// cSpell: ignore buildrs
5
6/*!
7# Slint
8
9This crate is the main entry point for embedding user interfaces designed with
10[Slint](https://slint.rs/) in Rust programs.
11*/
12#![doc = concat!("If you are new to Slint, start with the [Walk-through **tutorial**](https://slint.dev/releases/", env!("CARGO_PKG_VERSION"), "/docs/tutorial/rust)")]
13/*! If you are already familiar with Slint, the following topics provide related information.
14
15## Topics
16
17*/
18#![doc = concat!("- [The Slint Language Documentation](https://slint.dev/releases/", env!("CARGO_PKG_VERSION"), "/docs/slint)")]
19/*! - [Type mappings between .slint and Rust](docs::type_mappings)
20 - [Feature flags and backend selection](docs::cargo_features)
21 - [Slint on Microcontrollers](docs::mcu)
22
23## How to use this crate:
24
25Designs of user interfaces are described in the `.slint` design markup language. There are three ways
26of including them in Rust:
27
28 - The `.slint` code is [inline in a macro](#the-slint-code-in-a-macro).
29 - The `.slint` code in [external files compiled with `build.rs`](#the-slint-code-in-external-files-is-compiled-with-buildrs)
30*/
31#![doc = concat!(" - The `.slint` code is loaded dynamically at run-time from the file system, by using the [interpreter API](https://slint.dev/releases/", env!("CARGO_PKG_VERSION"), "/docs/rust/slint_interpreter/).")]
32/*!
33
34With the first two methods, the markup code is translated to Rust code and each component is turned into a Rust
35struct with functions. Use these functions to instantiate and show the component, and
36to access declared properties. Check out our [sample component](docs::generated_code::SampleComponent) for more
37information about the generation functions and how to use them.
38
39### The .slint code in a macro
40
41This method combines your Rust code with the `.slint` design markup in one file, using a macro:
42
43```rust
44slint::slint!{
45 export component HelloWorld {
46 Text {
47 text: "hello world";
48 color: green;
49 }
50 }
51}
52fn main() {
53# return; // Don't run a window in an example
54 HelloWorld::new().unwrap().run().unwrap();
55}
56```
57
58### The .slint code in external files is compiled with `build.rs`
59
60When your design becomes bigger in terms of markup code, you may want move it to a dedicated*/
61#![doc = concat!("`.slint` file. It's also possible to split a `.slint` file into multiple files using [modules](https://slint.dev/releases/", env!("CARGO_PKG_VERSION"), "/docs/slint/src/language/syntax/modules.html).")]
62/*!Use a [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html) to compile
63your main `.slint` file:
64
65In your Cargo.toml add a `build` assignment and use the `slint-build` crate in `build-dependencies`:
66
67```toml
68[package]
69...
70build = "build.rs"
71edition = "2021"
72
73[dependencies]
74slint = "1.5.0"
75...
76
77[build-dependencies]
78slint-build = "1.5.0"
79```
80
81Use the API of the slint-build crate in the `build.rs` file:
82
83```rust,no_run
84fn main() {
85 slint_build::compile("ui/hello.slint").unwrap();
86}
87```
88
89Finally, use the [`include_modules!`] macro in your `main.rs`:
90
91```ignore
92slint::include_modules!();
93fn main() {
94 HelloWorld::new().unwrap().run().unwrap();
95}
96```
97
98The [cargo-generate](https://github.com/cargo-generate/cargo-generate) tool is a great tool to up and running quickly with a new
99Rust project. You can use it in combination with our [Template Repository](https://github.com/slint-ui/slint-rust-template) to
100create a skeleton file hierarchy that uses this method:
101
102```bash
103cargo install cargo-generate
104cargo generate --git https://github.com/slint-ui/slint-rust-template
105```
106
107## Generated components
108
109Currently, only the last component in a `.slint` source file is mapped to a Rust structure that be instantiated. We are tracking the
110resolution of this limitation in <https://github.com/slint-ui/slint/issues/784>.
111
112The component is generated and re-exported to the location of the [`include_modules!`] or [`slint!`] macro. It is represented
113as a struct with the same name as the component.
114
115For example, if you have
116
117```slint,no-preview
118export component MyComponent inherits Window { /*...*/ }
119```
120
121in the .slint file, it will create a
122```rust
123struct MyComponent{ /*...*/ }
124```
125
126See also our [sample component](docs::generated_code::SampleComponent) for more information about the API of the generated struct.
127
128A component is instantiated using the [`fn new() -> Self`](docs::generated_code::SampleComponent::new) function. The following
129convenience functions are available through the [`ComponentHandle`] implementation:
130
131 - [`fn clone_strong(&self) -> Self`](docs::generated_code::SampleComponent::clone_strong): creates a strongly referenced clone of the component instance.
132 - [`fn as_weak(&self) -> Weak`](docs::generated_code::SampleComponent::as_weak): to create a [weak](Weak) reference to the component instance.
133 - [`fn show(&self)`](docs::generated_code::SampleComponent::show): to show the window of the component.
134 - [`fn hide(&self)`](docs::generated_code::SampleComponent::hide): to hide the window of the component.
135 - [`fn run(&self)`](docs::generated_code::SampleComponent::run): a convenience function that first calls `show()`,
136 followed by spinning the event loop, and `hide()` when returning from the event loop.
137 - [`fn global<T: Global<Self>>(&self) -> T`](docs::generated_code::SampleComponent::global): an accessor to the global singletons,
138
139For each top-level property
140 - A setter [`fn set_<property_name>(&self, value: <PropertyType>)`](docs::generated_code::SampleComponent::set_counter)
141 - A getter [`fn get_<property_name>(&self) -> <PropertyType>`](docs::generated_code::SampleComponent::get_counter)
142
143For each top-level callback
144 - [`fn invoke_<callback_name>(&self)`](docs::generated_code::SampleComponent::invoke_hello): to invoke the callback
145 - [`fn on_<callback_name>(&self, callback: impl Fn(<CallbackArgs>) + 'static)`](docs::generated_code::SampleComponent::on_hello): to set the callback handler.
146
147Note: All dashes (`-`) are replaced by underscores (`_`) in names of types or functions.
148
149After instantiating the component, call [`ComponentHandle::run()`] on show it on the screen and spin the event loop to
150react to input events. To show multiple components simultaneously, call [`ComponentHandle::show()`] on each instance.
151Call [`run_event_loop()`] when you're ready to enter the event loop.
152
153The generated component struct acts as a handle holding a strong reference (similar to an `Rc`). The `Clone` trait is
154not implemented. Instead you need to make explicit [`ComponentHandle::clone_strong`] and [`ComponentHandle::as_weak`]
155calls. A strong reference should not be captured by the closures given to a callback, as this would produce a reference
156loop and leak the component. Instead, the callback function should capture a weak component.
157
158## Threading and Event-loop
159
160For platform-specific reasons, the event loop must run in the main thread, in most backends, and all the components
161must be created in the same thread as the thread the event loop is running or is going to run.
162
163You should perform the minimum amount of work in the main thread and delegate the actual logic to another
164thread to avoid blocking animations. Use the [`invoke_from_event_loop`] function to communicate from your worker thread to the UI thread.
165
166To run a function with a delay or with an interval use a [`Timer`].
167
168To run an async function or a future, use [`spawn_local()`].
169
170## Exported Global singletons
171
172*/
173#![doc = concat!("When you export a [global singleton](https://slint.dev/releases/", env!("CARGO_PKG_VERSION"), "/docs/slint/src/language/syntax/globals.html) from the main file,")]
174/*! it is also generated with the exported name. Like the main component, the generated struct have
175inherent method to access the properties and callback:
176
177For each property
178 - A setter: `fn set_<property_name>(&self, value: <PropertyType>)`
179 - A getter: `fn get_<property_name>(&self) -> <PropertyType>`
180
181For each callback
182 - `fn invoke_<callback_name>(&self, <CallbackArgs>) -> <ReturnValue>` to invoke the callback
183 - `fn on_<callback_name>(&self, callback: impl Fn(<CallbackArgs>) + 'static)` to set the callback handler.
184
185The global can be accessed with the [`ComponentHandle::global()`] function, or with [`Global::get()`]
186
187See the [documentation of the `Global` trait](Global) for an example.
188*/
189
190#![warn(missing_docs)]
191#![deny(unsafe_code)]
192#![doc(html_logo_url = "https://slint.dev/logo/slint-logo-square-light.svg")]
193#![cfg_attr(not(feature = "std"), no_std)]
194#![allow(clippy::needless_doctest_main)] // We document how to write a main function
195
196extern crate alloc;
197
198#[cfg(not(feature = "compat-1-2"))]
199compile_error!(
200 "The feature `compat-1-2` must be enabled to ensure \
201 forward compatibility with future version of this crate"
202);
203
204pub use slint_macros::slint;
205
206pub use i_slint_core::api::*;
207#[doc(hidden)]
208#[deprecated(note = "Experimental type was made public by mistake")]
209pub use i_slint_core::component_factory::ComponentFactory;
210#[cfg(not(target_arch = "wasm32"))]
211pub use i_slint_core::graphics::{BorrowedOpenGLTextureBuilder, BorrowedOpenGLTextureOrigin};
212// keep in sync with internal/interpreter/api.rs
213pub use i_slint_core::graphics::{
214 Brush, Color, Image, LoadImageError, Rgb8Pixel, Rgba8Pixel, RgbaColor, SharedPixelBuffer,
215};
216pub use i_slint_core::model::{
217 FilterModel, MapModel, Model, ModelExt, ModelNotify, ModelPeer, ModelRc, ModelTracker,
218 ReverseModel, SortModel, StandardListViewItem, TableColumn, VecModel,
219};
220pub use i_slint_core::sharedvector::SharedVector;
221pub use i_slint_core::timers::{Timer, TimerMode};
222pub use i_slint_core::{format, string::SharedString};
223
224pub mod private_unstable_api;
225
226/// Enters the main event loop. This is necessary in order to receive
227/// events from the windowing system for rendering to the screen
228/// and reacting to user input.
229/// This function will run until the last window is closed or until
230/// [`quit_event_loop()`] is called.
231///
232/// See also [`run_event_loop_until_quit()`] to keep the event loop running until
233/// [`quit_event_loop()`] is called, even if all windows are closed.
234pub fn run_event_loop() -> Result<(), PlatformError> {
235 i_slint_backend_selector::with_platform(|b: &dyn Platform| b.run_event_loop())
236}
237
238/// Similar to [`run_event_loop()`], but this function enters the main event loop
239/// and continues to run even when the last window is closed, until
240/// [`quit_event_loop()`] is called.
241///
242/// This is useful for system tray applications where the application needs to stay alive
243/// even if no windows are visible.
244pub fn run_event_loop_until_quit() -> Result<(), PlatformError> {
245 i_slint_backend_selector::with_platform(|b: &dyn Platform| {
246 #[allow(deprecated)]
247 b.set_event_loop_quit_on_last_window_closed(false);
248 b.run_event_loop()
249 })
250}
251
252/// Include the code generated with the slint-build crate from the build script. After calling `slint_build::compile`
253/// in your `build.rs` build script, the use of this macro includes the generated Rust code and makes the exported types
254/// available for you to instantiate.
255///
256/// Check the documentation of the `slint-build` crate for more information.
257#[macro_export]
258macro_rules! include_modules {
259 () => {
260 include!(env!("SLINT_INCLUDE_GENERATED"));
261 };
262}
263
264/// Initialize translations when using the `gettext` feature.
265///
266/// Call this in your main function with the path where translations are located.
267/// This macro internally calls the [`bindtextdomain`](https://man7.org/linux/man-pages/man3/bindtextdomain.3.html) function from gettext.
268///
269/// The first argument of the macro must be an expression that implements `Into<std::path::PathBuf>`.
270/// It specifies the directory in which gettext should search for translations.
271///
272/// Translations are expected to be found at `<dirname>/<locale>/LC_MESSAGES/<crate>.mo`,
273/// where `dirname` is the directory passed as an argument to this macro,
274/// `locale` is a locale name (e.g., `en`, `en_GB`, `fr`), and
275/// `crate` is the package name obtained from the `CARGO_PKG_NAME` environment variable.
276///
277/// ### Example
278/// ```rust
279/// fn main() {
280/// slint::init_translations!(concat!(env!("CARGO_MANIFEST_DIR"), "/translations/"));
281/// // ...
282/// }
283/// ```
284///
285/// For example, assuming this is in a crate called `example` and the default locale
286/// is configured to be French, it will load translations at runtime from
287/// `/path/to/example/translations/fr/LC_MESSAGES/example.mo`.
288///
289/// Another example of loading translations relative to the executable:
290/// ```rust
291/// slint::init_translations!(std::env::current_exe().unwrap().parent().unwrap().join("translations"));
292/// ```
293#[cfg(feature = "gettext")]
294#[macro_export]
295macro_rules! init_translations {
296 ($dirname:expr) => {
297 $crate::private_unstable_api::init_translations(env!("CARGO_PKG_NAME"), $dirname);
298 };
299}
300
301/// This module contains items that you need to use or implement if you want use Slint in an environment without
302/// one of the supplied platform backends such as qt or winit.
303///
304/// The primary interface is the [`platform::Platform`] trait. Pass your implementation of it to Slint by calling
305/// [`platform::set_platform()`] early on in your application, before creating any Slint components.
306///
307/// The [Slint on Microcontrollers](crate::docs::mcu) documentation has additional examples.
308pub mod platform {
309 pub use i_slint_core::platform::*;
310
311 /// This module contains the [`femtovg_renderer::FemtoVGRenderer`] and related types.
312 ///
313 /// It is only enabled when the `renderer-femtovg` Slint feature is enabled.
314 #[cfg(all(feature = "renderer-femtovg", not(target_os = "android")))]
315 pub mod femtovg_renderer {
316 pub use i_slint_renderer_femtovg::FemtoVGRenderer;
317 pub use i_slint_renderer_femtovg::OpenGLInterface;
318 }
319}
320
321#[cfg(any(doc, all(target_os = "android", feature = "backend-android-activity-05")))]
322pub mod android;
323
324/// Helper type that helps checking that the generated code is generated for the right version
325#[doc(hidden)]
326#[allow(non_camel_case_types)]
327pub struct VersionCheck_1_5_1;
328
329#[cfg(doctest)]
330mod compile_fail_tests;
331
332#[cfg(doc)]
333pub mod docs;
334