From df07f25a1827e7080968556c1d03acd15d4d1114 Mon Sep 17 00:00:00 2001 From: lucasmerlin Date: Fri, 11 Jul 2025 23:09:34 +0200 Subject: [PATCH] Fix wasm check --- crates/egui/src/atomics/atom_widget.rs | 111 +++++++++++++++++++++++++ crates/egui/src/atomics/mod.rs | 2 + 2 files changed, 113 insertions(+) create mode 100644 crates/egui/src/atomics/atom_widget.rs diff --git a/crates/egui/src/atomics/atom_widget.rs b/crates/egui/src/atomics/atom_widget.rs new file mode 100644 index 000000000..bfda09e7d --- /dev/null +++ b/crates/egui/src/atomics/atom_widget.rs @@ -0,0 +1,111 @@ +use crate::{AtomKind, AtomLayout, Atoms, Button, Context, Frame, Id, Response, Ui, Widget}; + +// We would rename AtomLayout to AtomElement or similar, and it would be the "container" element +type AtomElement<'a> = AtomLayout<'a>; + +trait AtomWidget { + fn show(self, ui: &mut AtomUi, response: Response) -> AtomElement; +} + +impl<'a> AtomWidget for Button<'a> { + // We could pass in the response via Context::read_response for convenience, + fn show(self, ui: &mut AtomUi, response: Response) -> AtomElement { + // self.atom_ui(ui) // this should return the AtomElement instead + } +} + +/// The [Ui] equivalent. Instead of producing a list of shapes to paint, it produces a tree of +/// [AtomElement]s to layout and paint +struct AtomUi<'a> { + // This would probably just be another AtomElement and there would be a AtomKind::Layout + content: AtomElement<'a>, + id: Id, + next_id: usize, + context: Context, +} + +impl AtomUi { + pub fn new(context: Context) -> Self { + AtomUi { + content: AtomElement::default(), + id: Id::new(0), + next_id: 0, + context, + } + } + + pub fn scope(&mut self, layout: AtomElement, content: impl FnOnce(&mut AtomUi)) {} + + pub fn horizontal(&mut self, content: impl FnOnce(&mut AtomUi)) { + let layout = AtomElement::default(); + //.direction(egui::Direction::LeftToRight); We don't have a Direction yet + self.scope(layout, content); + } + + pub fn vertical(&mut self, content: impl FnOnce(&mut AtomUi)) { + let layout = AtomElement::default(); + //.direction(egui::Direction::TopDown); We don't have a Direction yet + self.scope(layout, content); + } + + fn next_id(&mut self) -> Id { + let id = self.id.with(self.next_id); + self.next_id += 1; + id + } + + pub fn add(&mut self, widget: impl AtomWidget<'_>) { + let id = self.next_id(); + // It would be really convenient if this could return a "default" response instead of Option + let response = self.context.read_response(id); + + // TODO: We need a AtomKind::AtomElement or similar + self.content + .push_right(widget.show(self, response.unwrap())); + } +} + +impl Widget for AtomUi { + /// This is where the actual layout and rendering happens. + /// This could be a advanced version of our current `AtomLayout` + /// (we could draw inspiration from https://github.com/nicbarker/clay), + /// or could be based on e.g. `taffy`. + /// + /// Since we now have a tree of elements, we can do fancy multipass measuring and layouting. + /// Everything that `taffy` can do should be possible. + /// + /// We'd probably want to do some kind of caching here so we don't have to re-layout parts of the + /// tree that haven't changed. (Taffy has built in support for that, I believe.) + fn ui(self, ui: &mut Ui) -> Response { + self.content.show(ui).response + } +} + +pub fn my_single_pass_ui(ui: &mut Ui) { + // Ideally there would be something like this: + // let mut atom_ui = ui.atom_ui(AtomElement::default().vertical()); + // the atom ui should inherit the UiStack, Style, Id, etc... + let mut atom_ui = AtomUi::new(ui.ctx().clone()); + + // Then we can build our element tree + my_atom_ui(&mut atom_ui); + + // And add it to our classic ui + ui.add(atom_ui); +} + +/// The atom-based uis could feel very similar to the classic uis +pub fn my_atom_ui(ui: &mut AtomUi) { + ui.add(Button::new("Atom Widget Button!")); + + ui.horizontal(|ui| { + ui.add(Button::new("Button 2")); + }); + + // If we add a AtomKind::Ui(&dyn Widget) we could even integrate these both ways. Lifetimes + // could get baaad though, ideally we would evaluate closures as soon as they are added to the + // AtomElement. We could call the single pass ui based on the rect from last frame. + ui.add(AtomKind::ui(|ui: &mut Ui| { + my_single_pass_ui(ui); + })) +} diff --git a/crates/egui/src/atomics/mod.rs b/crates/egui/src/atomics/mod.rs index 7c8922c97..61ee5b78e 100644 --- a/crates/egui/src/atomics/mod.rs +++ b/crates/egui/src/atomics/mod.rs @@ -1,7 +1,9 @@ mod atom; +mod atom_element; mod atom_ext; mod atom_kind; mod atom_layout; +mod atom_widget; mod atoms; mod sized_atom; mod sized_atom_kind;