diff --git a/emigui/src/containers/area.rs b/emigui/src/containers/area.rs index 3eff3ad6..17e45d29 100644 --- a/emigui/src/containers/area.rs +++ b/emigui/src/containers/area.rs @@ -155,7 +155,10 @@ impl Area { // &format!("Area size: {:?}", state.size), // ); - if move_interact.active || mouse_pressed_on_area(ctx, layer) { + if move_interact.active + || mouse_pressed_on_area(ctx, layer) + || !ctx.memory().areas.visible_last_frame(&layer) + { ctx.memory().areas.move_to_top(layer); } ctx.memory().areas.set_state(layer, state); diff --git a/emigui/src/context.rs b/emigui/src/context.rs index 197d3b9c..8a693270 100644 --- a/emigui/src/context.rs +++ b/emigui/src/context.rs @@ -161,7 +161,6 @@ impl Context { if !self.last_raw_input.mouse_down || self.last_raw_input.mouse_pos.is_none() { self.memory().active_id = None; } - self.memory().begin_frame(); self.used_ids.lock().clear(); @@ -180,6 +179,7 @@ impl Context { } pub fn end_frame(&self) -> (Output, PaintBatches) { + self.memory().end_frame(); let output: Output = std::mem::take(&mut self.output()); let paint_batches = self.paint(); (output, paint_batches) diff --git a/emigui/src/examples/app.rs b/emigui/src/examples/app.rs index 02e0fc05..bac95b97 100644 --- a/emigui/src/examples/app.rs +++ b/emigui/src/examples/app.rs @@ -112,9 +112,6 @@ fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows) { ui.add(Button::new("Don't Quit")); }); menu::menu(ui, "Windows", |ui| { - // TODO: open on top when clicking a new. - // Maybe an Window or Area can detect that: if wasn't open last frame, but is now, - // then automatically go to front? ui.add(Checkbox::new(&mut windows.examples, "Examples")); ui.add(Checkbox::new(&mut windows.settings, "Settings")); ui.add(Checkbox::new(&mut windows.inspection, "Inspection")); diff --git a/emigui/src/memory.rs b/emigui/src/memory.rs index 42d708e3..6915809f 100644 --- a/emigui/src/memory.rs +++ b/emigui/src/memory.rs @@ -33,11 +33,18 @@ pub struct Areas { order: Vec, visible_last_frame: HashSet, visible_current_frame: HashSet, + + /// When an area want to be on top, it is put in here. + /// At the end of the frame, this is used to reorder the layers. + /// This means if several layers want to be on top, they will keep their relative order. + /// So if you close three windows and then reopen them all in one frame, + /// they will all be sent to the top, but keep their previous internal order. + wants_to_be_on_top: HashSet, } impl Memory { - pub(crate) fn begin_frame(&mut self) { - self.areas.begin_frame() + pub(crate) fn end_frame(&mut self) { + self.areas.end_frame() } /// TODO: call once at the start of the frame for the current mouse pos @@ -64,7 +71,6 @@ impl Areas { let did_insert = self.areas.insert(layer.id, state).is_none(); if did_insert { self.order.push(layer); - self.order.sort_by_key(|layer| layer.order); } } @@ -85,25 +91,34 @@ impl Areas { None } + pub fn visible_last_frame(&self, layer: &Layer) -> bool { + self.visible_last_frame.contains(layer) + } + pub fn is_visible(&self, layer: &Layer) -> bool { self.visible_last_frame.contains(layer) || self.visible_current_frame.contains(layer) } pub fn move_to_top(&mut self, layer: Layer) { self.visible_current_frame.insert(layer); + self.wants_to_be_on_top.insert(layer); - if self.order.last() == Some(&layer) { - return; // common case early-out + if self.order.iter().find(|x| **x == layer).is_none() { + self.order.push(layer); } - if let Some(index) = self.order.iter().position(|x| *x == layer) { - self.order.remove(index); - } - self.order.push(layer); - - self.order.sort_by_key(|layer| layer.order); } - pub(crate) fn begin_frame(&mut self) { - self.visible_last_frame = std::mem::take(&mut self.visible_current_frame); + pub(crate) fn end_frame(&mut self) { + let Self { + visible_last_frame, + visible_current_frame, + order, + wants_to_be_on_top, + .. + } = self; + + *visible_last_frame = std::mem::take(visible_current_frame); + order.sort_by_key(|layer| (layer.order, wants_to_be_on_top.contains(layer))); + wants_to_be_on_top.clear(); } }