mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 14:50:03 -04:00
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).
This commit is contained in:
@@ -99,7 +99,7 @@ fn menu_close_on_click_outside() {
|
||||
harness.run();
|
||||
|
||||
harness
|
||||
.get_by_label("Submenu C (CloseOnClickOutside)")
|
||||
.get_by_label_contains("Submenu C (CloseOnClickOutside)")
|
||||
.hover();
|
||||
harness.run();
|
||||
|
||||
@@ -133,7 +133,7 @@ fn menu_close_on_click() {
|
||||
harness.get_by_label("Menu A").simulate_click();
|
||||
harness.run();
|
||||
|
||||
harness.get_by_label("Submenu B with icon").hover();
|
||||
harness.get_by_label_contains("Submenu B with icon").hover();
|
||||
harness.run();
|
||||
|
||||
// Clicking the button should close the menu (even if ui.close() is not called by the button)
|
||||
@@ -154,7 +154,9 @@ fn clicking_submenu_button_should_never_close_menu() {
|
||||
harness.run();
|
||||
|
||||
// Clicking the submenu button should not close the menu
|
||||
harness.get_by_label("Submenu B with icon").simulate_click();
|
||||
harness
|
||||
.get_by_label_contains("Submenu B with icon")
|
||||
.simulate_click();
|
||||
harness.run();
|
||||
|
||||
harness.get_by_label("Button in Submenu B").simulate_click();
|
||||
@@ -177,12 +179,12 @@ fn menu_snapshots() {
|
||||
results.add(harness.try_snapshot("menu/opened"));
|
||||
|
||||
harness
|
||||
.get_by_label("Submenu C (CloseOnClickOutside)")
|
||||
.get_by_label_contains("Submenu C (CloseOnClickOutside)")
|
||||
.hover();
|
||||
harness.run();
|
||||
results.add(harness.try_snapshot("menu/submenu"));
|
||||
|
||||
harness.get_by_label("Submenu D").hover();
|
||||
harness.get_by_label_contains("Submenu D").hover();
|
||||
harness.run();
|
||||
results.add(harness.try_snapshot("menu/subsubmenu"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user