Crate egui_taffy

Source
Expand description

§egui_taffy: Egui Taffy Ui

egui_version taffy_version Latest version Documentation unsafe forbidden License

Flexible egui layout library that supports CSS Block, Flexbox, Grid layouts. It uses high-performance taffy library under the hood.

This library is in active development and some breaking changes are expected, but they will be kept as small as possible.

§👉 Web Demo 👈 of the latest released version.

§Version compatibility

egui_taffyeguitaffyMSRV
0.70.310.7.31.81
0.60.300.7.31.81
0.50.300.71.83
0.40.300.71.83
0.30.290.71.83
0.20.290.71.83
0.1.20.290.61.83
0.10.290.61.83 (nightly)

To use add egui_taffy to your project dependencies in Cargo.toml file.

See CHANGELOG for changes between versions.

§Examples

Check out ./examples/demo.rs (cargo run –example demo).

§Flex wrap demo example:

egui::Window::new("Flex wrap demo").show(ctx, |ui| {
    tui(ui, ui.id().with("demo"))
        .reserve_available_space() // Reserve full space of this window for layout
        .style(Style {
            flex_direction: taffy::FlexDirection::Column,
            align_items: Some(taffy::AlignItems::Stretch),
            ..default_style()
        })
        .show(|tui| {
            // Add egui ui as node
            tui.ui(|ui| {
                ui.label("Hello from egui ui!");
                ui.button("Egui button");
            });

            // Add egui widgets directly to UI that implements [`TuiWidget`] trait
            tui.ui_add(egui::Label::new("label"));
            tui.ui_add(egui::Button::new("button"));
            // Or use couple of supported helper function
            tui.separator();
            tui.label("Text");

            // You can add custom style or unique id to every element that is added to the ui
            // by calling id, style, mut_style methods on it first using builder pattern

            // Provide full style
            tui.style(Style {
                align_self: Some(taffy::AlignItems::Center),
                ..Default::default()
            })
            .label("Centered text");

            tui.style(default_style())
                .mut_style(|style| {
                    // Modify one field of the style
                    style.align_self = Some(taffy::AlignItems::End);
                })
                .label("Right aligned text");

            // You can add elements with custom background using add_with_ family of methods
            tui.add_with_border(|tui| {
                tui.label("Text with border");
            });

            tui.separator();

            tui.style(Style {
                flex_wrap: taffy::FlexWrap::Wrap,
                justify_items: Some(taffy::AlignItems::Stretch),
                ..default_style()
            })
            .add(|tui| {
                for word in FLEX_ITEMS {
                    tui.style(default_style()).add_with_border(|tui| {
                        tui.label(word);
                    });
                }
            });
        });
});

Preview:

flex_wrap_demo

§Button example

button_demo

§Grid example

grid_demo

§Flex example

flex_demo

§Grow demo

grow_demo

§Overflow demo

Supports scrollable elements!

overflow_demo

§Sticky elements (Sticky row and column in scrollable grid)

https://github.com/user-attachments/assets/07546146-7a90-422b-b291-99b758fd7704

§Virtual grid (virtual table rows)

Support grids with equal virtual row height. Rows can contain merged cells (colspan).

https://github.com/user-attachments/assets/a3c8ebba-e72f-44c2-9233-29004b97d070

§Egui options

§Max passes

For best visual look you should enable egui multiple passes support so layout can be immediately recalculated upon some changes.

ctx.options_mut(|options| {
    options.max_passes = std::num::NonZeroUsize::new(2).unwrap();
});

If integrating with egui implementations such as bevy_egui, for egui multipass (request_discard) functionality to work you need to use special approach. See bevy_egui simple_multipass example for such case.

§Text wrapping

By default egui text wrapping tries to utilize as less width as possible. In dynamic layouts it results in text where letters are placed in a column.

Instead you should use one of the following options:

  1. Specify minimal width or width for the elements, set text elements to fill width of the parent.
  2. Set custom egui wrap mode when necessary.
    tui.wrap_mode(egui::TextWrapMode::Truncate).add(|tui| { ... })
  3. Disable text wrapping:
    ctx.style_mut(|style| {
      style.wrap_mode = Some(egui::TextWrapMode::Extend);
    });

§Inspiration

This crate is inspired by lucasmerlin previous exploration in this direction by such crates as:

It combines ideas from both crates and builds upon them to provide easy to use egui like API to write your UI with modern layout support.

Library uses intrinsic size and request_discard egui functionality to measure layout and request immediate frame redraw (without even drawing the current frame) if layout has changed.

§Contributing

Contributions are welcome. Please add your improvements to examples so that it is easy to see and validate.

Re-exports§

pub use taffy;

Modules§

virtual_tui
Helper functionality for virtual elements
widgets
Widgets built combining multiple taffy nodes

Structs§

Context
Sizing context retrieved from Tui layout leaf nodes (egui widgets or child egui::Ui)
TaffyContainerUi
Helper to show the inner content of a container.
TaffyMainBackgroundReturnValues
Return values from Main, Background closures
TaffyReturn
Tui returned information about final layout of the Tui
TaffyState
Egui taffy layout state which stores calculated taffy node layout and hiarchy
Tui
Tui (Egui Taffy UI) is used to place ui nodes and set their id, style configuration
TuiBuilder
Helper structure to provide more egonomic API for child ui container creation
TuiBuilderParams
Parameters for creating child element in Tui layout
TuiContainerResponse
Describes information about used space when laying out elements
TuiInitializer
Egui tui initialization helper to reserve/allocate necessary space
TuiInnerResponse
Helper structure to return: 1. egui::Response of the surrounding element, 2. return value of the inner closure.

Enums§

TuiId
Id type to simplify defining layout node ids

Traits§

AsTuiBuilder
Helper trait to reduce code boilerplate
TuiBuilderLogic
Trait that implements TuiBuilder logic for child node creation in Tui UI.
TuiWidget
Implement this trait for a widget to make it usable in a tui container.

Functions§

setup_tui_visuals
Helper function to set up tui visuals based on background response interaction state
tid
Helper function to generate TuiID that takes into account element hiarchy to avoid duplicated ids
tui
Helper function to initialize taffy layout