From 8ccd937ea5daed87542978d68285fbe3f41ff0d7 Mon Sep 17 00:00:00 2001 From: Lucas Meurer Date: Thu, 28 Nov 2024 16:26:47 +0100 Subject: [PATCH] Fix area click handling ignoring the modal backdrop --- crates/egui/src/memory/mod.rs | 34 ++++++++++++------ crates/egui_demo_lib/src/demo/modals.rs | 35 +++++++++++++++++-- ...rop_should_prevent_focusing_lower_area.png | 3 ++ 3 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png diff --git a/crates/egui/src/memory/mod.rs b/crates/egui/src/memory/mod.rs index 32eccc4f211..e5ca8d42789 100644 --- a/crates/egui/src/memory/mod.rs +++ b/crates/egui/src/memory/mod.rs @@ -818,7 +818,15 @@ impl Memory { /// Top-most layer at the given position. pub fn layer_id_at(&self, pos: Pos2) -> Option { - self.areas().layer_id_at(pos, &self.layer_transforms) + self.areas() + .layer_id_at(pos, &self.layer_transforms) + .and_then(|layer_id| { + if self.is_above_modal_layer(layer_id) { + Some(layer_id) + } else { + self.top_modal_layer() + } + }) } /// An iterator over all layers. Back-to-front, top is last. @@ -893,20 +901,26 @@ impl Memory { } } + /// Returns true if + /// - this layer is the top-most modal layer or above it + /// - there is no modal layer + pub fn is_above_modal_layer(&self, layer_id: LayerId) -> bool { + if let Some(modal_layer) = self.focus().and_then(|f| f.top_modal_layer) { + matches!( + self.areas().compare_order(layer_id, modal_layer), + std::cmp::Ordering::Equal | std::cmp::Ordering::Greater + ) + } else { + true + } + } + /// Does this layer allow interaction? /// Returns true if /// - the layer is not behind a modal layer /// - the [`Order`] allows interaction pub fn allows_interaction(&self, layer_id: LayerId) -> bool { - let is_above_modal_layer = - if let Some(modal_layer) = self.focus().and_then(|f| f.top_modal_layer) { - matches!( - self.areas().compare_order(layer_id, modal_layer), - std::cmp::Ordering::Equal | std::cmp::Ordering::Greater - ) - } else { - true - }; + let is_above_modal_layer = self.is_above_modal_layer(layer_id); let ordering_allows_interaction = layer_id.order.allow_interaction(); is_above_modal_layer && ordering_allows_interaction } diff --git a/crates/egui_demo_lib/src/demo/modals.rs b/crates/egui_demo_lib/src/demo/modals.rs index c3b2dcdb8d6..989101b4d75 100644 --- a/crates/egui_demo_lib/src/demo/modals.rs +++ b/crates/egui_demo_lib/src/demo/modals.rs @@ -1,4 +1,4 @@ -use egui::{Align, ComboBox, Context, Id, Layout, Modal, ProgressBar, Ui, Widget, Window}; +use egui::{ComboBox, Context, Id, Modal, ProgressBar, Ui, Widget, Window}; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] @@ -90,7 +90,7 @@ impl crate::View for Modals { egui::Sides::new().show( ui, - |ui| {}, + |_ui| {}, |ui| { if ui.button("Save").clicked() { *save_modal_open = true; @@ -116,7 +116,7 @@ impl crate::View for Modals { egui::Sides::new().show( ui, - |ui| {}, + |_ui| {}, |ui| { if ui.button("Yes Please").clicked() { *save_progress = Some(0.0); @@ -255,4 +255,33 @@ mod tests { result.unwrap(); } } + + // This tests whether the backdrop actually prevents interaction with lower layers. + #[test] + fn backdrop_should_prevent_focusing_lower_area() { + let initial_state = Modals { + save_modal_open: true, + save_progress: Some(0.0), + ..Modals::default() + }; + + let mut harness = Harness::new_state( + |ctx, modals| { + modals.show(ctx, &mut true); + }, + initial_state, + ); + + // TODO(lucasmerlin): Remove these extra runs once run checks for repaint requests + harness.run(); + harness.run(); + harness.run(); + + harness.get_by_label("Yes Please").simulate_click(); + + harness.run(); + + // This snapshots should show the progress bar modal on top of the save modal. + harness.wgpu_snapshot("modals_backdrop_should_prevent_focusing_lower_area"); + } } diff --git a/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png b/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png new file mode 100644 index 00000000000..14d6fb9cbfc --- /dev/null +++ b/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e1a5d265470c36e64340ccceea4ade464b3c4a1177d60630b02ae8287934748f +size 44026