mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 10:50:00 +00:00
docs: Rework the rust part of the documentation (#2240)
Co-authored-by: Simon Hausmann <hausmann@gmail.com>
This commit is contained in:
parent
daab51543f
commit
96f75bdd0c
3 changed files with 71 additions and 47 deletions
|
@ -10,6 +10,8 @@
|
|||
of what is generated from the `.slint` file
|
||||
*/
|
||||
|
||||
// cSpell: ignore rustdoc
|
||||
|
||||
pub mod recipes {
|
||||
#![doc = include_str!("docs/recipes/recipes.md")]
|
||||
|
||||
|
@ -30,10 +32,10 @@ pub mod generated_code {
|
|||
/// what functions you can call and how you can pass data in and out.
|
||||
/// This is the source code:
|
||||
/// ```slint
|
||||
/// SampleComponent := Window {
|
||||
/// property<int> counter;
|
||||
/// export component SampleComponent inherits Window {
|
||||
/// in-out property<int> counter;
|
||||
/// // note that dashes will be replaced by underscores in the generated code
|
||||
/// property<string> user-name;
|
||||
/// in-out property<string> user-name;
|
||||
/// callback hello();
|
||||
/// // ... maybe more elements here
|
||||
/// }
|
||||
|
@ -62,6 +64,7 @@ pub mod generated_code {
|
|||
}
|
||||
/// Assigns a new value to the `user_name` property.
|
||||
pub fn set_user_name(&self, value: crate::SharedString) {}
|
||||
|
||||
/// For each callback declared at the root of the component, a function to call that
|
||||
/// callback is generated. This is the function that calls the `hello` callback declared
|
||||
/// in the `.slint` design markup.
|
||||
|
|
|
@ -13,36 +13,29 @@ Writing an application in Rust that runs on a MCU requires several prerequisites
|
|||
* Install tools for flashing and debugging your code on the device.
|
||||
|
||||
We recommend reading the [Rust Embedded Book](https://docs.rust-embedded.org/book/),
|
||||
as well as the curated list of [Awesome Embedded Rust](https://github.com/rust-embedded/awesome-embedded-rust) for a wide range of different
|
||||
crates, tools and training materials. These resources should guide you through the initial setup and often come with "hello world" examples
|
||||
and the curated list of [Awesome Embedded Rust](https://github.com/rust-embedded/awesome-embedded-rust) for a wide range of
|
||||
crates, tools, and training materials. These resources should guide you through the initial setup. Many include a "hello world" example
|
||||
to get started with your device.
|
||||
|
||||
Slint requires a global memory allocator. That is currently only possible in the nightly version of Rust, because the support for using a custom global
|
||||
allocator in a bare metal environment with `#![no_std]` has not been stabilized yet (see [#51540](https://github.com/rust-lang/rust/issues/51540) or
|
||||
[#66741](https://github.com/rust-lang/rust/issues/66741) for tracking issues).
|
||||
Slint requires a custom global memory allocator in a bare metal environment with `#![no_std]`.
|
||||
The Rust team hasn't yet stabilized this feature, so only the nightly version
|
||||
of the Rust compiler will support it. See
|
||||
[#51540](https://github.com/rust-lang/rust/issues/51540) or
|
||||
[#66741](https://github.com/rust-lang/rust/issues/66741) for tracking issues.
|
||||
|
||||
Note: The rust compiler version 1.68 should have all features needed by Slint
|
||||
stabilized. We have not tested this setup extensively yet though.
|
||||
|
||||
The following sections assume that your setup is complete and you have a non-graphical skeleton Rust program running on your MCU.
|
||||
|
||||
## Changes to `Cargo.toml`
|
||||
|
||||
Start by adding a dependency to the `slint` and the `slint-build` crates to your `Cargo.toml`:
|
||||
Start by adding a dependency to the `slint` and the `slint-build` crates to your `Cargo.toml` using the `cargo` command:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
## ...
|
||||
## Edition 2021 or later enables the feature resolver version 2.
|
||||
edition = "2021"
|
||||
Start with the `slint` crate like this:
|
||||
|
||||
[dependencies]
|
||||
## ... your other dependencies
|
||||
|
||||
[dependencies.slint]
|
||||
version = "0.3.4"
|
||||
default-features = false
|
||||
features = ["compat-1-0", "unsafe-single-threaded", "libm"]
|
||||
|
||||
[build-dependencies]
|
||||
slint-build = "0.3.4"
|
||||
```sh
|
||||
cargo add slint@1.0.0 --no-default-features --features "compat-1-0 unsafe-single-threaded libm"
|
||||
```
|
||||
|
||||
The default features of the `slint` crate are tailored towards hosted environments and includes the "std" feature. In bare metal environments,
|
||||
|
@ -55,12 +48,38 @@ In the snippet above, three features are selected:
|
|||
This macro is only available in the Rust Standard Library (std), but not in bare metal environments. As a fallback, the `unsafe-single-threaded`
|
||||
feature changes Slint to use unsafe static for storage. This way, you guarantee to use Slint API only from a single thread, and not from interrupt handlers.
|
||||
* `libm`: We select this feature to enable the use of the [libm](https://crates.io/crates/libm) crate to provide traits and functions for floating point arithmetic.
|
||||
They are typically provided by the Rust Standard Library (std), but that is not available in bare metal environments.
|
||||
They're typically provided by the Rust Standard Library (std), but that's not available in bare metal environments.
|
||||
|
||||
It might be necessary to enable the [Feature resolver version 2](https://doc.rust-lang.org/cargo/reference/features.html#feature-resolver-version-2)
|
||||
in your Cargo.toml if you notice that your dependencies are attempting to build with `std` support even if it was disabled.
|
||||
in your Cargo.toml if you notice that your dependencies are attempting to build with `std` support even when disabled.
|
||||
This is the default when using the Rust 2021 Edition or later.
|
||||
|
||||
Then add the `slint-build` crate as a build dependency:
|
||||
|
||||
```sh
|
||||
cargo add --build slint-build@1.0.0
|
||||
```
|
||||
|
||||
For reference: These are the relevant parts of your `Cargo.toml` file,
|
||||
ready to use Slint:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
## ...
|
||||
## Edition 2021 or later enables the feature resolver version 2.
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
## ... your other dependencies
|
||||
|
||||
[dependencies.slint]
|
||||
version = "1.0.0"
|
||||
default-features = false
|
||||
features = ["compat-1-0", "unsafe-single-threaded", "libm"]
|
||||
[build-dependencies]
|
||||
slint-build = "1.0.0"
|
||||
```
|
||||
|
||||
## Changes to `build.rs`
|
||||
|
||||
Next, write a build script to compile the `.slint` files to Rust code for embedding into the program binary, using the `slint-build` crate:
|
||||
|
@ -80,23 +99,23 @@ in a format that's suitable for the software based renderer we're going to use.
|
|||
|
||||
## Application Structure
|
||||
|
||||
Typically, a graphical application in hosted environments is comprised of at least three different tasks:
|
||||
Typically, a graphical application in hosted environments has at least three different tasks:
|
||||
|
||||
* Receives user input from operation system APIs.
|
||||
* Reacts to the input by performing application specific computations.
|
||||
* Renders an updated user interface and presents it on the screen using device-independent operating system APIs.
|
||||
|
||||
The operating system provides an event loop to connect and schedule these tasks. Slint implements the
|
||||
task of receiving user input and forwarding it to the user interface layer, as well as rendering the user interface to the screen.
|
||||
task of receiving user input and forwarding it to the user interface layer, and rendering the user interface to the screen.
|
||||
|
||||
In bare metal environments it is your responsibility to substitute and connect functionality that is otherwise provided by the operating system:
|
||||
In bare metal environments it's your responsibility to substitute and connect functionality that's otherwise provided by the operating system:
|
||||
|
||||
* Select crates that allow you to initialize the chips that operate peripherals, such as a touch input or display controller.
|
||||
If there are no crates, you may have to to develop your own drivers.
|
||||
* Drive the event loop yourself by querying peripherals for input, forwarding that input into computational modules of your
|
||||
application and instructing Slint to render the user interface.
|
||||
|
||||
In Slint, the two primary APIs you need to use to accomplish these tasks are the [`slint::platform::Platform`] trait as well as the [`slint::Window`] struct.
|
||||
In Slint, the two primary APIs you need to use to accomplish these tasks are the [`slint::platform::Platform`] trait and the [`slint::Window`] struct.
|
||||
In the following sections we're going to cover how to use them and how they integrate into your event loop.
|
||||
|
||||
### The `Platform` Trait
|
||||
|
@ -114,8 +133,8 @@ This minimal implementation needs to cover two functions:
|
|||
how much time has elapsed between two rendered frames. In a bare metal environment you need to provide a source of time. Often the HAL crate of your
|
||||
device provides a system timer API for this, which you can query in your impementation.
|
||||
|
||||
There are additional functions in the trait that you can implement, for example to handle debug output, to delegate the event loop or to implement
|
||||
the interface to safely deliver events in multi-threaded environments.
|
||||
You may override more functions of this trait, for example to handle debug output, to delegate the event loop,
|
||||
or to deliver events in multi-threaded environments.
|
||||
|
||||
A typical minimal implementation of the [`Platform`] trait that uses the [`MinimalSoftwareWindow`] looks like this:
|
||||
|
||||
|
@ -233,13 +252,13 @@ loop {
|
|||
### The Renderer
|
||||
|
||||
In desktop and embedded environments, Slint typically uses operating system provided APIs to render the user interface using the GPU.
|
||||
In contrast, most MCUs don't have GPUs. Instead, the all the rendering is done by software on the CPU. This is called software rendering, and Slint provides a SoftwareRenderer for this task.
|
||||
In contrast, most MCUs don't have GPUs. Instead, software rendering is used where all rendering is done by software on the CPU.
|
||||
Slint provides a SoftwareRenderer for this task.
|
||||
|
||||
In the previous example, we've instantiated a [`slint::platform::software_renderer::MinimalSoftwareWindow`]. This struct implements the
|
||||
`slint::platform::WindowAdapter` trait and also holds an instance of a [`slint::platform::software_renderer::SoftwareRenderer`]. You obtain access to it
|
||||
In the earlier example, we've instantiated a [`slint::platform::software_renderer::MinimalSoftwareWindow`]. This struct implements the
|
||||
`slint::platform::WindowAdapter` trait and also holds an instance of a [`slint::platform::software_renderer::SoftwareRenderer`]. You access it
|
||||
through the callback parameter of the [`draw_if_needed()`](MinimalSoftwareWindow::draw_if_needed) function.
|
||||
|
||||
Depending on the amount of RAM your MCU is equipped with, and the kind of screen that is attached, you can choose between two different ways of using the renderer:
|
||||
Depending on the amount of RAM your MCU has, and the kind of screen attached, you can choose between two different ways of using the renderer:
|
||||
|
||||
* Use the [`SoftwareRenderer::render()`] function if you have enough RAM to allocate one, or even two, copies of the entire screen (also known as
|
||||
frame buffer).
|
||||
|
@ -247,14 +266,16 @@ Depending on the amount of RAM your MCU is equipped with, and the kind of screen
|
|||
typically via the SPI. This requires allocating at least enough RAM to store one single line of pixels.
|
||||
|
||||
With both methods Slint renders into a provided buffer, which is a slice of a type that implements the [`slint::platform::software_renderer::TargetPixel`] trait.
|
||||
For convenience, Slint provides an implementation for [`slint::Rgb8Pixel`] as well as [`slint::platform::software_renderer::Rgb565Pixel`].
|
||||
For convenience, Slint provides an implementation for [`slint::Rgb8Pixel`] and [`slint::platform::software_renderer::Rgb565Pixel`].
|
||||
|
||||
#### Rendering into a Buffer
|
||||
#### Rendering Into a Buffer
|
||||
|
||||
The following example uses double buffering and swaps between them. This requires a graphics driver that can be provided
|
||||
with the address of what should be the currently displayed frame buffer, also known as front buffer. A dedicated chip is then responsible for
|
||||
reading from RAM and transferring the contents to the attached screen, without any interference of the CPU. Meanwhile, Slint can render into
|
||||
the second buffer, the back buffer.
|
||||
The following example uses double buffering and swaps between two buffers. This
|
||||
requires a graphics driver that takes the address of the currently displayed
|
||||
frame buffer, also known as front buffer. A dedicated chip is then responsible
|
||||
for reading from RAM and transferring the contents to the attached screen,
|
||||
without any interference of the CPU. Meanwhile, Slint renders into the second
|
||||
buffer, the back buffer.
|
||||
|
||||
```rust,no_run
|
||||
use slint::platform::software_renderer::Rgb565Pixel;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue