egui/crates/egui_demo_lib
Lucas Meurer 6eb7bb6e08
Add `AtomLayout`, abstracing layouting within widgets (#5830)
Today each widget does its own custom layout, which has some drawbacks:
- not very flexible
- you can add an `Image` to `Button` but it will always be shown on the
left side
  - you can't add a `Image` to a e.g. a `SelectableLabel`
- a lot of duplicated code

This PR introduces `Atoms` and `AtomLayout` which abstracts over "widget
content" and layout within widgets, so it'd be possible to add images /
text / custom rendering (for e.g. the checkbox) to any widget.

A simple custom button implementation is now as easy as this:
```rs
pub struct ALButton<'a> {
    al: AtomicLayout<'a>,
}

impl<'a> ALButton<'a> {
    pub fn new(content: impl IntoAtomics) -> Self {
        Self { al: content.into_atomics() }
    }
}

impl<'a> Widget for ALButton<'a> {
    fn ui(mut self, ui: &mut Ui) -> Response {
        let response = ui.ctx().read_response(ui.next_auto_id());

        let visuals = response.map_or(&ui.style().visuals.widgets.inactive, |response| {
            ui.style().interact(&response)
        });

        self.al.frame = self
            .al
            .frame
            .inner_margin(ui.style().spacing.button_padding)
            .fill(visuals.bg_fill)
            .stroke(visuals.bg_stroke)
            .corner_radius(visuals.corner_radius);

        self.al.show(ui)
    }
}

```

The initial implementation only does very basic layout, just enough to
be able to implement most current egui widgets, so:
- only horizontal layout
- everything is centered
- a single item may grow/shrink based on the available space
- everything can be contained in a Frame


There is a trait `IntoAtoms` that conveniently allows you to construct
`Atoms` from a tuple
```
   ui.button((Image::new("image.png"), "Click me!"))
```
to get a button with image and text.


This PR reimplements three egui widgets based on the new AtomLayout:
 - Button
   - matches the old button pixel-by-pixel
- Button with image is now [properly
aligned](https://github.com/emilk/egui/pull/5830/files#diff-962ce2c68ab50724b01c6b64c683c4067edd9b79fcdcb39a6071021e33ebe772)
in justified layouts
   - selected button style now matches SelecatbleLabel look
- For some reason the DragValue text seems shifted by a pixel almost
everywhere, but I think it's more centered now, yay?
 - Checkbox
- basically pixel-perfect but apparently the check mesh is very slightly
different so I had to update the snapshot
   - somehow needs a bit more space in some snapshot tests?
 - RadioButton
   - pixel-perfect
   - somehow needs a bit more space in some snapshot tests?

I plan on updating TextEdit based on AtomLayout in a separate PR (so
you could use it to add a icon within the textedit frame).
2025-06-13 09:39:52 +02:00
..
benches Use mimalloc for benchmarks (#7029) 2025-05-06 17:54:06 +02:00
data Fix incorrect color fringe colors on SVG:s (#7069) 2025-05-21 17:18:36 +02:00
src Add `AtomLayout`, abstracing layouting within widgets (#5830) 2025-06-13 09:39:52 +02:00
tests/snapshots Add `AtomLayout`, abstracing layouting within widgets (#5830) 2025-06-13 09:39:52 +02:00
Cargo.toml Include test windows in `egui_demo_lib` snapshot tests (#7070) 2025-05-21 17:44:27 +02:00
README.md Add button benchmark (#6854) 2025-04-28 11:58:05 +02:00

README.md

egui demo library

Latest version Documentation unsafe forbidden MIT Apache

This crate contains example code for egui.

The demo library is a separate crate for three reasons:

This crate also contains benchmarks for egui. Run them with

# Run all benchmarks
cargo bench -p egui_demo_lib 

# Run a single benchmark
cargo bench -p egui_demo_lib "benchmark name"

# Profile benchmarks with cargo-flamegraph (--root flag is necessary for MacOS)
CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph --bench benchmark --root -p egui_demo_lib  -- --bench "benchmark name"

# Profile with cargo-instruments
CARGO_PROFILE_BENCH_DEBUG=true cargo instruments --profile bench --bench benchmark -p egui_demo_lib -t time -- --bench "benchmark name"