Allow setting a layer as a sublayer of another (#4690)
When the layers are reordered at the end of the frame, the sublayers are placed directly above their respective parents. This allows having Areas inside Windows, e.g., for the pan-zoom container. * Closes <https://github.com/emilk/egui/issues/4128> --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
parent
8cef6fc872
commit
b1dc059ef3
|
|
@ -2374,6 +2374,17 @@ impl Context {
|
|||
self.memory_mut(|mem| mem.areas_mut().move_to_top(layer_id));
|
||||
}
|
||||
|
||||
/// Mark the `child` layer as a sublayer of `parent`.
|
||||
///
|
||||
/// Sublayers are moved directly above the parent layer at the end of the frame. This is mainly
|
||||
/// intended for adding a new [`Area`] inside a [`Window`].
|
||||
///
|
||||
/// This currently only supports one level of nesting. If `parent` is a sublayer of another
|
||||
/// layer, the behavior is unspecified.
|
||||
pub fn set_sublayer(&self, parent: LayerId, child: LayerId) {
|
||||
self.memory_mut(|mem| mem.areas_mut().set_sublayer(parent, child));
|
||||
}
|
||||
|
||||
/// Retrieve the [`LayerId`] of the top level windows.
|
||||
pub fn top_layer_id(&self) -> Option<LayerId> {
|
||||
self.memory(|mem| mem.areas().top_layer_id(Order::Middle))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![warn(missing_docs)] // Let's keep this file well-documented.` to memory.rs
|
||||
|
||||
use ahash::HashMap;
|
||||
use ahash::{HashMap, HashSet};
|
||||
use epaint::emath::TSTransform;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -951,6 +951,11 @@ pub struct Areas {
|
|||
/// 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: ahash::HashSet<LayerId>,
|
||||
|
||||
/// List of sublayers for each layer
|
||||
///
|
||||
/// When a layer has sublayers, they are moved directly above it in the ordering.
|
||||
sublayers: ahash::HashMap<LayerId, HashSet<LayerId>>,
|
||||
}
|
||||
|
||||
impl Areas {
|
||||
|
|
@ -1042,20 +1047,38 @@ impl Areas {
|
|||
}
|
||||
}
|
||||
|
||||
/// Mark the `child` layer as a sublayer of `parent`.
|
||||
///
|
||||
/// Sublayers are moved directly above the parent layer at the end of the frame. This is mainly
|
||||
/// intended for adding a new [Area](crate::Area) inside a [Window](crate::Window).
|
||||
///
|
||||
/// This currently only supports one level of nesting. If `parent` is a sublayer of another
|
||||
/// layer, the behavior is unspecified.
|
||||
pub fn set_sublayer(&mut self, parent: LayerId, child: LayerId) {
|
||||
self.sublayers.entry(parent).or_default().insert(child);
|
||||
}
|
||||
|
||||
pub fn top_layer_id(&self, order: Order) -> Option<LayerId> {
|
||||
self.order
|
||||
.iter()
|
||||
.filter(|layer| layer.order == order)
|
||||
.filter(|layer| layer.order == order && !self.is_sublayer(layer))
|
||||
.last()
|
||||
.copied()
|
||||
}
|
||||
|
||||
pub(crate) fn is_sublayer(&self, layer: &LayerId) -> bool {
|
||||
self.sublayers
|
||||
.iter()
|
||||
.any(|(_, children)| children.contains(layer))
|
||||
}
|
||||
|
||||
pub(crate) fn end_frame(&mut self) {
|
||||
let Self {
|
||||
visible_last_frame,
|
||||
visible_current_frame,
|
||||
order,
|
||||
wants_to_be_on_top,
|
||||
sublayers,
|
||||
..
|
||||
} = self;
|
||||
|
||||
|
|
@ -1063,6 +1086,23 @@ impl Areas {
|
|||
visible_current_frame.clear();
|
||||
order.sort_by_key(|layer| (layer.order, wants_to_be_on_top.contains(layer)));
|
||||
wants_to_be_on_top.clear();
|
||||
// For all layers with sublayers, put the sublayers directly after the parent layer:
|
||||
let sublayers = std::mem::take(sublayers);
|
||||
for (parent, children) in sublayers {
|
||||
let mut moved_layers = vec![parent];
|
||||
order.retain(|l| {
|
||||
if children.contains(l) {
|
||||
moved_layers.push(*l);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
let Some(parent_pos) = order.iter().position(|l| l == &parent) else {
|
||||
continue;
|
||||
};
|
||||
order.splice(parent_pos..=parent_pos, moved_layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,11 +110,10 @@ impl crate::View for PanZoom {
|
|||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
let window_layer = ui.layer_id();
|
||||
let id = egui::Area::new(id.with(("subarea", i)))
|
||||
.default_pos(pos)
|
||||
// Need to cover up the pan_zoom demo window,
|
||||
// but may also cover over other windows.
|
||||
.order(egui::Order::Foreground)
|
||||
.order(egui::Order::Middle)
|
||||
.show(ui.ctx(), |ui| {
|
||||
ui.set_clip_rect(transform.inverse() * rect);
|
||||
egui::Frame::default()
|
||||
|
|
@ -130,6 +129,7 @@ impl crate::View for PanZoom {
|
|||
.response
|
||||
.layer_id;
|
||||
ui.ctx().set_transform_layer(id, transform);
|
||||
ui.ctx().set_sublayer(window_layer, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue