Floem

repository·main·Indexed 26 days ago

https://github.com/lapce/floem

A native Rust UI library featuring fine-grained reactivity and a declarative API. It supports cross-platform rendering (Windows, macOS, Linux) via wgpu or Skia, Flexbox and Grid layouts via Taffy, and high-performance components like VirtualList. Floem implements a two-phase event dispatch model (capturing and bubbling) and provides reactive primitives such as RwSignal for state management.

Tokens
27.4K
Snippets
57
Records
178
Agent score
88%

What's inside floem

  1. Overview of the Timer example

    main
    The Timer example demonstrates how Floem handles concurrency between background processes (like a timer updating elapsed time) and user interactions with the GUI. It specifically tests the responsiveness of the application when handling competing signals, such as simultaneous timer ticks and slider adjustments, ensuring that UI updates like slider movements are reflected immediately.
  2. Overview of Floem features

    main

    Floem is a high-performance, declarative UI library for Rust with the following core capabilities:

    • Cross-platform rendering: Supports Windows, macOS, and Linux. It uses wgpu via vger or vello, or Skia via AnyRender. It includes a tiny-skia CPU fallback if a GPU is unavailable.
    • Fine-grained reactivity: Built around reactive primitives (inspired by leptos_reactive) to keep the UI updated with minimal effort.
    • Layout Engines: Supports both Flexbox and Grid layout systems via Taffy.
    • Styling & Animation: Highly customizable widgets with a styling API supporting classes, themes, transitions (CSS-like), and keyframe animations with spring easing.
    • Developer Tools: Includes an Element Inspector for debugging layouts.
    • Localization: Supports the Fluent crate for runtime language switching and fallbacks.
    • Performance: The view tree is constructed only once, preventing bottlenecks during view generation. Supports virtual lists for efficient large-scale data rendering.
  3. Overview of the Flight Booker example

    main

    The flight_booker example emulates a flight booking application based on the 7gui tasks. It is designed to demonstrate how to model two types of constraints in Floem:

    1. Constraints between widgets: Managing interactions and dependencies between different UI components.
    2. Constraints within a widget: Managing internal logic and state validation within a single component.

    The goal of this example is to show how to make these constraints clear, succinct, and explicit in the source code without excessive scaffolding.

  4. Use the Pan Zoom View for visual editors

    main
    The pan-zoom example provides a simple pan-zoom area that supports translation and scaling. It is designed to serve as a foundational component for building visual editors that require a central pan-zoom interface, or for testing and debugging rendering and event handling when using transformations like scale and translation.
  5. Bridge Winit events to the ui-events model

    main

    The ui-events-winit crate provides a bridge between winit's native input events (such as mouse, touch, and keyboard) and the ui-events model. This allows you to process native windowing events as high-level UI events.

    The primary entry point for this integration is the WindowEventReducer struct.

  6. Quickstart with Floem

    main

    Floem is a native Rust UI library featuring fine-grained reactivity. To get started, use floem::launch to run your application and RwSignal to manage reactive state. Views are constructed using a declarative API where components like Stack, Button, and Label can be composed.

    Key reactive primitives include:

    • RwSignal: A reactive signal that allows for reading and writing state.
    • Label::derived: Creates a label that automatically updates when its dependencies (signals) change.
    • .action(): Attaches a closure to a widget (like a Button) to handle user interactions.
    use floem::prelude::*;
    
    fn main() {
        floem::launch(counter_view);
    }
    
    fn counter_view() -> impl IntoView {
        let mut counter = RwSignal::new(0);
    
        Stack::horizontal((
            Button::new("Increment").action(move || counter += 1),
            Label::derived(move || format!("Value: {counter}")),
            Button::new("Decrement").action(move || counter -= 1),
        ))
        .style(|s| s.size_full().items_center().justify_center().gap(10))
    }
  7. Understand the two-phase event dispatch model

    main

    Floem implements a two-phase event dispatch system similar to the W3C DOM standard:

    1. Capturing Phase (Root → Target): Events are dispatched from the root view down toward the target. For each view in the path, event_before_children() is called. This phase applies coordinate transformations (absolute to local) and can be halted if a view returns EventPropagation::Stop.
    2. Bubbling Phase (Target → Root): Events are dispatched from the target view back up toward the root. For each view in the path, event_after_children() is called. This phase processes built-in behaviors and registered event listeners. If a handler returns EventPropagation::Stop, bubbling ceases.
  8. Verify Minimum Supported Rust Version (MSRV)

    main
    This crate requires Rust 1.81 or later to compile. If you encounter compilation errors related to dependencies, you may need to upgrade your toolchain or use cargo update to pin a dependency to a specific version compatible with your current Rust version.
  9. Handle keyboard navigation and focus

    main

    Keyboard events are routed based on the current focus state:

    • Dispatch: Events are sent to the focused view first via dispatch_to_view(focused_id, event, directed: true). If the focused view does not process the event, it falls back to the main view.
    • Built-in Navigation: Floem supports standard navigation patterns:
      • Tab / Shift+Tab: Forward and backward navigation.
      • Alt+Arrow keys: Arrow navigation.
      • Enter / Space: Triggers click events on the currently focused element.
    • Focus Requirements: Only views where computed_style.get(Focusable) is true can receive focus. Focus changes trigger FocusGained and FocusLost events.
  10. Implement drag and drop functionality

    main

    Drag and drop operations in Floem are managed through specific state transitions:

    1. Initiation: A drag is tracked via drag_start: Option<(ViewId, Point)>. An actual drag operation begins when the pointer moves more than 1px from the start point. This triggers the DragStart event and sets the window_state.active flag.
    2. Dragging: During movement, the dragging state (containing position and timing) is updated, and dragging_over is used to highlight potential drop targets.
    3. Dropping: When the pointer is released over a valid target, a Drop event is fired at the target, and a DragEnd event is fired for the originating view.