From 238581c65e4b0880a2bc5d0858e4dfe3e48e8899 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 28 Dec 2021 20:54:26 +0100 Subject: [PATCH] wip --- egui/src/context.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++- egui/src/layout.rs | 12 +++++++++ egui/src/lib.rs | 2 ++ egui/src/ui.rs | 7 +++++- 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/egui/src/context.rs b/egui/src/context.rs index f9617848..27f3ad8e 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -19,6 +19,15 @@ use epaint::{stats::*, text::Fonts, *}; // ---------------------------------------------------------------------------- +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum PassState { + SinglePass, + SizePass, + LayoutPass, +} + +// ---------------------------------------------------------------------------- + /// A wrapper around [`Arc`](std::sync::Arc)`<`[`Context`]`>`. /// This is how you will normally create and access a [`Context`]. /// @@ -103,7 +112,7 @@ impl CtxRef { pub fn run( &mut self, new_raw_input: RawInput, - mut run_ui: impl FnMut(&CtxRef), + run_ui: impl Fn(&CtxRef), ) -> (Output, Vec) { self.memory().begin_frame(&self.input, &new_raw_input); @@ -126,6 +135,48 @@ impl CtxRef { }, ); + if self.memory().options.multi_pass { + self.frame_state.lock().begin_pass(&self.input); + self.mutate(|context| { + context.pass_state = Some(PassState::SizePass); + }); + + run_ui(self); + + self.drain_paint_lists(); + self.mutate(|context| { + context.input.on_events(new_raw_input); + context.pass_state = Some(PassState::LayoutPass); + }); + + self.frame_state.lock().begin_pass(&self.input); + run_ui(self); + } else { + self.mutate(|context| { + context.input.on_events(new_raw_input); + context.pass_state = Some(PassState::SinglePass); + }); + } + + self.mutate(|context| { + if let Some(new_pixels_per_point) = context.memory.lock().new_pixels_per_point.take() { + context.input.pixels_per_point = new_pixels_per_point; + } + context.input.begin_frame(&new_raw_input); + context.update_fonts(context.input.pixels_per_point()); + }); + + // Ensure we register the background area so panels and background ui can catch clicks: + let screen_rect = self.input.screen_rect(); + self.memory().areas.set_state( + LayerId::background(), + containers::area::State { + pos: screen_rect.min, + size: screen_rect.size(), + interactable: true, + }, + ); + if self.memory().options.multi_pass { self.frame_state.lock().begin_pass(&self.input); run_ui(self); @@ -142,6 +193,10 @@ impl CtxRef { run_ui(self); } + self.mutate(|context| { + context.pass_state = None; + }); + self.end_frame() } @@ -392,6 +447,8 @@ pub struct Context { /// While positive, keep requesting repaints. Decrement at the end of each frame. repaint_requests: AtomicU32, + + pub(crate) pass_state: Option, } impl Clone for Context { @@ -407,6 +464,7 @@ impl Clone for Context { output: self.output.clone(), paint_stats: self.paint_stats.clone(), repaint_requests: self.repaint_requests.load(SeqCst).into(), + pass_state: None, } } } diff --git a/egui/src/layout.rs b/egui/src/layout.rs index 433242ca..9f3ebf67 100644 --- a/egui/src/layout.rs +++ b/egui/src/layout.rs @@ -230,6 +230,18 @@ impl Layout { } } + /// change layout to one suitable for size pass + pub(crate) fn for_size_pass(self) -> Self { + Self { + main_dir: self.main_dir, + main_wrap: self.main_wrap, + main_align: Align::Min, + main_justify: false, + cross_align: Align::Min, + cross_justify: false, + } + } + #[inline(always)] pub fn with_main_wrap(self, main_wrap: bool) -> Self { Self { main_wrap, ..self } diff --git a/egui/src/lib.rs b/egui/src/lib.rs index dc9cc561..aeebc906 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -396,6 +396,8 @@ pub mod text { }; } +pub(crate) use context::PassState; + pub use { containers::*, context::{Context, CtxRef}, diff --git a/egui/src/ui.rs b/egui/src/ui.rs index cbaba6f6..27fff8be 100644 --- a/egui/src/ui.rs +++ b/egui/src/ui.rs @@ -92,10 +92,15 @@ impl Ui { pub fn child_ui_with_id_source( &mut self, max_rect: Rect, - layout: Layout, + mut layout: Layout, id_source: impl Hash, ) -> Self { crate::egui_assert!(!max_rect.any_nan()); + + if self.ctx().pass_state == Some(PassState::SizePass) { + layout = layout.for_size_pass(); + } + let next_auto_id_source = Id::new(self.next_auto_id_source).with("child").value(); self.next_auto_id_source = self.next_auto_id_source.wrapping_add(1); let menu_state = self.get_menu_state();