Improve GraphicLayers: always paint all layers

This commit is contained in:
Emil Ernerfeldt 2020-10-24 10:06:11 +02:00
parent 211d70b4f3
commit c96a929713
3 changed files with 50 additions and 20 deletions

View file

@ -223,6 +223,17 @@ impl Context {
if !same_as_current {
self.fonts = Some(Arc::new(Fonts::from_definitions(font_definitions)));
}
// 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,
},
);
}
/// Call at the end of each frame.
@ -268,17 +279,6 @@ impl Context {
fn fullscreen_ui(self: &Arc<Self>) -> Ui {
let rect = self.input.screen_rect();
let layer_id = LayerId::background();
// Ensure we register the background area so it is painted
// and so we handle interactions properly (clicks on it etc).
// TODO: we shouldn't need to register areas. Maybe GraphicLayers should take care of it?
self.memory().areas.set_state(
layer_id,
containers::area::State {
pos: rect.min,
size: rect.size(),
interactable: true,
},
);
Ui::new(self.clone(), layer_id, layer_id.id, rect, rect)
}

View file

@ -17,6 +17,16 @@ pub enum Order {
/// Debug layer, always painted last / on top
Debug,
}
impl Order {
const COUNT: usize = 5;
const ALL: [Order; Self::COUNT] = [
Self::Background,
Self::Middle,
Self::Foreground,
Self::Tooltip,
Self::Debug,
];
}
/// An identifier for a paint layer.
/// Also acts as an identifier for `Area`:s.
@ -52,6 +62,10 @@ pub struct PaintCmdIdx(usize);
pub struct PaintList(Vec<(Rect, PaintCmd)>);
impl PaintList {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Returns the index of the new command that can be used with `PaintList::set`.
pub fn add(&mut self, clip_rect: Rect, cmd: PaintCmd) -> PaintCmdIdx {
let idx = PaintCmdIdx(self.0.len());
@ -76,13 +90,14 @@ impl PaintList {
}
}
// TODO: improve GraphicLayers
#[derive(Clone, Default)]
pub struct GraphicLayers(AHashMap<LayerId, PaintList>);
pub struct GraphicLayers([AHashMap<Id, PaintList>; Order::COUNT]);
impl GraphicLayers {
pub fn list(&mut self, layer_id: LayerId) -> &mut PaintList {
self.0.entry(layer_id).or_default()
self.0[layer_id.order as usize]
.entry(layer_id.id)
.or_default()
}
pub fn drain(
@ -91,15 +106,28 @@ impl GraphicLayers {
) -> impl ExactSizeIterator<Item = (Rect, PaintCmd)> {
let mut all_commands: Vec<_> = Default::default();
for &order in &Order::ALL {
let order_map = &mut self.0[order as usize];
// If a layer is empty at the start of the frame
// the nobody has added to it, and it is old and defunct.
// Free it to save memory:
order_map.retain(|_, list| !list.is_empty());
// First do the layers part of area_order:
for layer_id in area_order {
if let Some(commands) = self.0.get_mut(layer_id) {
if layer_id.order == order {
if let Some(commands) = order_map.get_mut(&layer_id.id) {
all_commands.extend(commands.0.drain(..));
}
}
}
if let Some(commands) = self.0.get_mut(&LayerId::debug()) {
// Also draw areas that are missing in `area_order`:
for commands in order_map.values_mut() {
all_commands.extend(commands.0.drain(..));
}
}
all_commands.into_iter()
}

View file

@ -113,6 +113,8 @@ impl Interaction {
}
}
/// Keeps track of `Area`s, which are free-floating `Ui`s.
/// These `Area`s can be in any `Order`.
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]