Skip to main content

floem/
lib.rs

1//! # Floem
2//! Floem is a cross-platform GUI library for Rust. It aims to be extremely performant while providing world-class developer ergonomics.
3//!
4//! The following is a simple example to demonstrate Floem's API and capabilities.
5//!
6//! ## Example: Counter
7//! ```rust
8//! use floem::prelude::*;
9//!
10//! let mut counter = RwSignal::new(0);
11//!
12//! v_stack((
13//!     label(move || format!("Value: {counter}")),
14//!     h_stack((
15//!         button("Increment").action(move || counter += 1),
16//!         button("Decrement").action(move || counter -= 1),
17//!     )),
18//! ));
19//! ```
20//! This example demonstrates the core concepts of building a reactive GUI with Floem:
21//!
22//! - State Management: The `RwSignal` provides a reactive way to manage the counter's state.
23//! - Widgets: Common UI elements like `stack`, `label`, and `button` are easily implemented.
24//! - Reactivity: The label automatically updates when the counter changes.
25//! - Event Handling: Button clicks are handled with simple closures that modify the state.
26//!
27//! Floem's objectives prioritize simplicity and performance, enabling the development of complex graphical user interfaces with minimal boilerplate.
28//!
29//! ## Views
30//! Floem models the UI using a tree of [Views](view::View). Views, such as the `h_stack`, `label`, and
31//! `button` elements are the building blocks of UI in Floem.
32//!
33//! Floem's main view tree is constructed only once.
34//! This guards against unnecessary and expensive rebuilds of your views;
35//! however, even though the tree is built only once, views can still receive reactive updates.
36//!
37//! ### Composition and Flexibility
38//! Views in Floem are composable, allowing for the construction of complex user interfaces by integrating simpler components.
39//! In the counter example, label and button views were combined within vertical (`v_stack`) and horizontal (`h_stack`) layouts to create a more intricate interface.
40//!
41//! This compositional approach provides the following benefits:
42//! - Reusable UI components
43//! - Easy and consistent refactoring
44//!
45//! ### Learn More
46//! Floem provides a set of built-in views to help you create UIs quickly.
47//! To learn more about the built-in views, check out the [views module](crate::views) documentation.
48//!
49//! ## State management
50//!
51//! Floem uses a reactive system built on signals and effects for its state management.
52//!
53//! Floem uses its own reactive system with an API that is similar to the one in the [leptos_reactive](https://docs.rs/leptos_reactive/latest/leptos_reactive/index.html) crate.
54//!
55//! ### Signals as State
56//!
57//! You can create reactive state by creating a signal anywhere in the program using [`RwSignal::new()`](floem_reactive::RwSignal::new), [`RwSignal::new_split()`](floem_reactive::RwSignal::new_split), or use a [different signal type](floem_reactive).
58//!
59//! When you use a signal by calling the [`get`](floem_reactive::SignalGet::get) or [`with`](floem_reactive::SignalWith::with) methods, (which are also called when you use an operator such as `==`)
60//! the runtime will automatically subscribe the correct side effects
61//! to changes in that signal, creating reactivity. To the programmer this is transparent.
62//! By simply accessing the value where you want to use it, the reactivity will "just work" and
63//! your views will stay in sync with changes to that signal.
64//!
65//!
66//! #### Example: Changing Text
67//! ```rust
68//! # use floem::reactive::*;
69//! # use floem::views::*;
70//! # use floem::IntoView;
71//! fn app_view() -> impl IntoView {
72//!
73//!     // All signal types implement `Copy`, so they can be easily used without needing to manually clone them.
74//!     let text = RwSignal::new("Hello, World!".to_string());
75//!
76//!     let label_view = label(move || text.get());
77//!
78//!     let button = button("Change Text").action(move || text.set("Hello, Floem!".to_string()));
79//!
80//!     v_stack((button, label_view))
81//! }
82//! ```
83//!
84//! In this example, `text` is a signal containing a `String` that can be both read from and written to.
85//! The button, when clicked, changes the text in the signal.
86//! The label view is subscribed to changes in the `text` signal and will automatically trigger a re-render with the updated text value whenever the signal changes.
87//!
88//! ### Functions as a Primitive of Reactivity
89//!
90//! The most fundamental primitive of reactivity is a function that can be re-run in response to changes in a signal.
91//! For this reason, many of Floem's APIs accept functions as arguments (such as in the label view in the `Changing Text` example above).
92//! Most of the functions is Floem's API will
93//! update reactively, but not all of them do. For this reason, all arguments in Floem's API that are functions will
94//! be marked with a `# Reactivity` section that will inform you if the function will be re-run in response to reactive updates.
95//!
96//! ### Learn More
97//! To learn more about signals and
98//! effects, you may want to explore the Leptos [documentation](https://docs.rs/leptos_reactive/latest/leptos_reactive/index.html)
99//! and the [leptos book](https://leptos-rs.github.io/leptos/).
100//!
101//! ## Style: Customizing Appearance
102//!
103//! Floem has a powerful, built-in styling system that allows you to customize the appearance of your UI.
104//!
105//! Example:
106//! ```
107//! #  use floem::peniko::color::palette;
108//! #  use floem::reactive::*;
109//! #  use floem::style::Style;
110//! #  use floem::unit::UnitExt;
111//! #  use floem::View;
112//! #  use floem::views::{text, Decorators};
113//! #
114//! text("Some text").style(|s| s.font_size(21.).color(palette::css::DARK_GRAY));
115//! ```
116//!
117//! The text view is styled by calling the [`style`](crate::views::Decorators::style) method (you'll need to import the
118//! [`Decorators`](crate::views::Decorators) trait to use the it). The `style` method takes a closure that takes and returns a
119//! [`Style`](crate::style::Style) value using the builder pattern. Through this value, you can access methods that modify a variety
120//! of familiar properties such as width, padding, and background. Some `Style` properties
121//! such as font size are `inherited` and will apply to all of a view's children until overridden.
122// TODO: Add links on these
123//!
124//! In this same style value, floem supports:
125//! - themeing with [classes](style::Style::class)
126//! - [property transitions](style::Style::transition)
127//! - defining styles on different [interaction states](style::Style::hover)
128//! - reactive updates
129//! - applying styles [conditionally](style::Style::apply_if)
130//! - setting custom properties
131//! - and more
132//!
133//! For additional information about styling, [see here](crate::style).
134//!
135//! ## Animation
136//!
137//! In addition to [property transitions](style::Style::transition) that can be added to `Style`s,
138//! Floem has a full keyframe animation system that allows you to animate any property that can be [interpolated](style::StylePropValue::interpolate) and builds on the capabilities and ergonomics of the style system.
139//!
140//! Animations in Floem, by default, have keyframes ranging from 0-100.
141//!
142//! #### Example: Rectangle to Square
143//!
144//! ```
145//! #  use floem::peniko::color::palette;
146//! #  use floem::reactive::*;
147//! #  use floem::style::Style;
148//! #  use floem::unit::{UnitExt, DurationUnitExt};
149//! #  use floem::View;
150//! #  use floem::views::*;
151//! #
152//! empty()
153//!     .style(|s| s.background(palette::css::RED).size(500, 100))
154//!     .animation(move |a| {
155//!         a.duration(5.seconds())
156//!             .keyframe(0, |f| f.computed_style())
157//!             .keyframe(50, |f| {
158//!                 f.style(|s| s.background(palette::css::BLACK).size(30, 30))
159//!                     .ease_in()
160//!             })
161//!             .keyframe(100, |f| {
162//!                 f.style(|s| s.background(palette::css::AQUAMARINE).size(10, 300))
163//!                     .ease_out()
164//!             })
165//!             .auto_reverse(true)
166//!             .repeat(true)
167//!     });
168//! ```
169//! - The first keyframe will use the computed style, which will include the red background with size of 500x100.
170//! - At 50%, the animation will animate to a black square of 30x30 with a bezier easing of `ease_in`.
171//! - At 100% the animation will animate to an aquamarine rectangle of 10x300 with an bezier easing of `ease_out`.
172//! - The animation is also set to automatically reverse (the animation will run and reverse in 5 seconds) and repeat forever.
173//!
174//! You can add animations to a `View` instance by calling the [`animation`](crate::views::Decorators::animation) method from the `Decorators` trait.
175//! The `animation` method takes a closure that takes and returns an [`Animation`](crate::animate::Animation) value using the builder pattern.
176//!
177//! For additional information about animation, [see here](crate::animate::Animation).
178
179pub mod action;
180pub mod animate;
181mod app;
182pub mod context;
183pub mod event;
184pub mod ext_event;
185mod inspector;
186pub mod layout;
187mod message;
188pub mod paint;
189pub mod platform;
190/// Re-export easing module from animate for backward compatibility.
191pub use animate::easing;
192/// Re-export dropped_file module from event for backward compatibility.
193pub use event::dropped_file;
194/// Re-export responsive module from layout for backward compatibility.
195pub use layout::responsive;
196/// Re-export file module from platform for backward compatibility.
197pub use platform::file;
198/// Re-export menu module from platform for backward compatibility.
199pub use platform::menu;
200/// Re-export view_tuple module from view for backward compatibility.
201pub use view::tuple as view_tuple;
202pub mod headless;
203pub mod style;
204pub mod view;
205pub mod views;
206pub mod window;
207pub mod receiver_signal {
208    //! Signals from Channels, Futures, and Streams.
209    mod channel_signal;
210    mod common;
211    mod future_signal;
212    mod resource;
213    mod stream_signal;
214    pub use channel_signal::*;
215    pub use common::*;
216    pub use future_signal::*;
217    pub use resource::*;
218    pub use stream_signal::*;
219}
220
221pub use app::{AppConfig, AppEvent, Application, launch, quit_app, reopen};
222pub use floem_reactive as reactive;
223pub use floem_renderer::Renderer;
224pub use floem_renderer::Svg as RendererSvg;
225pub use floem_renderer::gpu_resources::GpuResources;
226pub use floem_renderer::text;
227pub use imbl;
228pub use layout::ScreenLayout;
229#[cfg(not(target_arch = "wasm32"))]
230pub use muda;
231pub use peniko;
232pub use peniko::kurbo;
233#[cfg(not(target_arch = "wasm32"))]
234pub use platform::open_file;
235#[cfg(not(target_arch = "wasm32"))]
236pub use platform::save_as;
237pub use platform::{Clipboard, ClipboardError, FileDialogOptions, FileInfo, FileSpec};
238pub use platform::{Menu, SubMenu};
239pub use taffy;
240pub use ui_events;
241pub use view::ViewId;
242pub use view::{
243    AnyView, HasViewId, IntoView, LazyView, ParentView, View, default_compute_layout,
244    recursively_layout_view,
245};
246pub use view::{Stack, StackOffset};
247pub use window::{Urgency, WindowIdExt, WindowState, close_window, new_window};
248
249/// Re-export unit and theme modules from style for backward compatibility.
250pub use style::{theme, unit};
251
252pub mod prelude {
253    pub use crate::Renderer;
254    pub use crate::unit::{DurationUnitExt, UnitExt};
255    pub use crate::view::IntoViewIter;
256    pub use crate::view::ViewTuple;
257    pub use crate::views::*;
258    pub use crate::{HasViewId, IntoView, ParentView, View};
259    #[allow(deprecated)]
260    pub use floem_reactive::{
261        RwSignal, SignalGet, SignalTrack, SignalUpdate, SignalWith, create_rw_signal, create_signal,
262    };
263    pub use peniko::Color;
264    pub use peniko::color::palette;
265    pub use ui_events::{
266        keyboard::{Code, Key, KeyState, KeyboardEvent, Modifiers, NamedKey},
267        pointer::{PointerButtonEvent, PointerEvent},
268    };
269}