2021-01-17 09:52:01 +00:00
|
|
|
//! Handles paint layers, i.e. how things
|
|
|
|
//! are sometimes painted behind or in front of other things.
|
|
|
|
|
2021-02-14 09:44:46 +00:00
|
|
|
use crate::{Id, *};
|
2021-03-31 15:03:20 +00:00
|
|
|
use epaint::mutex::Mutex;
|
2021-01-17 00:35:14 +00:00
|
|
|
use epaint::{ClippedShape, Shape};
|
2021-03-31 15:03:20 +00:00
|
|
|
use std::sync::Arc;
|
2020-04-17 12:26:36 +00:00
|
|
|
|
2020-05-10 12:27:02 +00:00
|
|
|
/// Different layer categories
|
2020-05-30 09:04:40 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
|
2021-09-29 06:45:13 +00:00
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
2020-05-10 12:27:02 +00:00
|
|
|
pub enum Order {
|
|
|
|
/// Painted behind all floating windows
|
2020-04-17 12:26:36 +00:00
|
|
|
Background,
|
2021-05-26 20:06:10 +00:00
|
|
|
/// Special layer between panels and windows
|
|
|
|
PanelResizeLine,
|
2020-05-10 12:27:02 +00:00
|
|
|
/// Normal moveable windows that you reorder by click
|
|
|
|
Middle,
|
|
|
|
/// Popups, menus etc that should always be painted on top of windows
|
2020-09-06 19:30:52 +00:00
|
|
|
/// Foreground objects can also have tooltips
|
2020-11-02 16:39:01 +00:00
|
|
|
Foreground,
|
|
|
|
/// Things floating on top of everything else, like tooltips.
|
|
|
|
/// You cannot interact with these.
|
2020-09-06 19:30:52 +00:00
|
|
|
Tooltip,
|
2020-05-10 12:27:02 +00:00
|
|
|
/// Debug layer, always painted last / on top
|
2020-04-27 14:53:14 +00:00
|
|
|
Debug,
|
2020-04-17 12:26:36 +00:00
|
|
|
}
|
2020-10-24 08:06:11 +00:00
|
|
|
impl Order {
|
2021-05-26 20:06:10 +00:00
|
|
|
const COUNT: usize = 6;
|
2020-10-24 08:06:11 +00:00
|
|
|
const ALL: [Order; Self::COUNT] = [
|
|
|
|
Self::Background,
|
2021-05-26 20:06:10 +00:00
|
|
|
Self::PanelResizeLine,
|
2020-10-24 08:06:11 +00:00
|
|
|
Self::Middle,
|
|
|
|
Self::Foreground,
|
|
|
|
Self::Tooltip,
|
|
|
|
Self::Debug,
|
|
|
|
];
|
2020-11-02 16:39:01 +00:00
|
|
|
|
2021-03-31 15:06:12 +00:00
|
|
|
#[inline(always)]
|
2020-11-02 16:39:01 +00:00
|
|
|
pub fn allow_interaction(&self) -> bool {
|
|
|
|
match self {
|
2021-05-26 20:06:10 +00:00
|
|
|
Self::Background
|
|
|
|
| Self::PanelResizeLine
|
|
|
|
| Self::Middle
|
|
|
|
| Self::Foreground
|
|
|
|
| Self::Debug => true,
|
2020-11-02 16:39:01 +00:00
|
|
|
Self::Tooltip => false,
|
|
|
|
}
|
|
|
|
}
|
2021-08-28 08:28:50 +00:00
|
|
|
|
|
|
|
/// Short and readable summary
|
|
|
|
pub fn short_debug_format(&self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
Self::Background => "backg",
|
|
|
|
Self::PanelResizeLine => "panel",
|
|
|
|
Self::Middle => "middl",
|
|
|
|
Self::Foreground => "foreg",
|
|
|
|
Self::Tooltip => "toolt",
|
|
|
|
Self::Debug => "debug",
|
|
|
|
}
|
|
|
|
}
|
2020-10-24 08:06:11 +00:00
|
|
|
}
|
2020-04-17 12:26:36 +00:00
|
|
|
|
2020-07-30 12:11:09 +00:00
|
|
|
/// An identifier for a paint layer.
|
2020-12-27 11:57:15 +00:00
|
|
|
/// Also acts as an identifier for [`Area`]:s.
|
2020-05-30 09:04:40 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
2021-09-29 06:45:13 +00:00
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
2020-10-21 12:39:08 +00:00
|
|
|
pub struct LayerId {
|
2020-05-10 12:27:02 +00:00
|
|
|
pub order: Order,
|
|
|
|
pub id: Id,
|
|
|
|
}
|
|
|
|
|
2020-10-21 12:39:08 +00:00
|
|
|
impl LayerId {
|
2020-11-02 16:39:01 +00:00
|
|
|
pub fn new(order: Order, id: Id) -> Self {
|
|
|
|
Self { order, id }
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:27:02 +00:00
|
|
|
pub fn debug() -> Self {
|
|
|
|
Self {
|
|
|
|
order: Order::Debug,
|
|
|
|
id: Id::new("debug"),
|
|
|
|
}
|
|
|
|
}
|
2020-10-21 20:10:55 +00:00
|
|
|
|
|
|
|
pub fn background() -> Self {
|
|
|
|
Self {
|
|
|
|
order: Order::Background,
|
|
|
|
id: Id::background(),
|
|
|
|
}
|
|
|
|
}
|
2020-11-02 16:39:01 +00:00
|
|
|
|
2021-03-31 15:06:12 +00:00
|
|
|
#[inline(always)]
|
2020-11-02 16:39:01 +00:00
|
|
|
pub fn allow_interaction(&self) -> bool {
|
|
|
|
self.order.allow_interaction()
|
|
|
|
}
|
2021-08-28 08:28:50 +00:00
|
|
|
|
|
|
|
/// Short and readable summary
|
|
|
|
pub fn short_debug_format(&self) -> String {
|
|
|
|
format!(
|
|
|
|
"{} {}",
|
|
|
|
self.order.short_debug_format(),
|
|
|
|
self.id.short_debug_format()
|
|
|
|
)
|
|
|
|
}
|
2020-05-10 12:27:02 +00:00
|
|
|
}
|
|
|
|
|
2021-01-10 10:43:01 +00:00
|
|
|
/// A unique identifier of a specific [`Shape`] in a [`PaintList`].
|
2020-07-30 12:11:09 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq)]
|
2021-01-10 10:43:01 +00:00
|
|
|
pub struct ShapeIdx(usize);
|
2020-07-30 12:11:09 +00:00
|
|
|
|
2021-01-10 10:43:01 +00:00
|
|
|
/// A list of [`Shape`]s paired with a clip rectangle.
|
2020-07-30 12:11:09 +00:00
|
|
|
#[derive(Clone, Default)]
|
2021-01-17 00:35:14 +00:00
|
|
|
pub struct PaintList(Vec<ClippedShape>);
|
2020-07-30 12:11:09 +00:00
|
|
|
|
|
|
|
impl PaintList {
|
2021-03-31 15:06:12 +00:00
|
|
|
#[inline(always)]
|
2020-10-24 08:06:11 +00:00
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.0.is_empty()
|
|
|
|
}
|
|
|
|
|
2021-01-10 10:43:01 +00:00
|
|
|
/// Returns the index of the new [`Shape`] that can be used with `PaintList::set`.
|
2021-03-31 15:06:12 +00:00
|
|
|
#[inline(always)]
|
2021-01-10 10:43:01 +00:00
|
|
|
pub fn add(&mut self, clip_rect: Rect, shape: Shape) -> ShapeIdx {
|
|
|
|
let idx = ShapeIdx(self.0.len());
|
2021-01-17 00:35:14 +00:00
|
|
|
self.0.push(ClippedShape(clip_rect, shape));
|
2020-07-30 12:11:09 +00:00
|
|
|
idx
|
|
|
|
}
|
|
|
|
|
2021-01-10 10:43:01 +00:00
|
|
|
pub fn extend(&mut self, clip_rect: Rect, mut shapes: Vec<Shape>) {
|
|
|
|
self.0
|
2021-10-20 14:43:40 +00:00
|
|
|
.extend(shapes.drain(..).map(|shape| ClippedShape(clip_rect, shape)));
|
2020-07-30 12:11:09 +00:00
|
|
|
}
|
|
|
|
|
2021-01-10 10:43:01 +00:00
|
|
|
/// Modify an existing [`Shape`].
|
2020-08-09 15:24:32 +00:00
|
|
|
///
|
|
|
|
/// Sometimes you want to paint a frame behind some contents, but don't know how large the frame needs to be
|
|
|
|
/// until the contents have been added, and therefor also painted to the `PaintList`.
|
|
|
|
///
|
2021-01-10 10:43:01 +00:00
|
|
|
/// The solution is to allocate a `Shape` using `let idx = paint_list.add(cr, Shape::Noop);`
|
2020-08-09 15:24:32 +00:00
|
|
|
/// and then later setting it using `paint_list.set(idx, cr, frame);`.
|
2021-03-31 15:06:12 +00:00
|
|
|
#[inline(always)]
|
2021-01-10 10:43:01 +00:00
|
|
|
pub fn set(&mut self, idx: ShapeIdx, clip_rect: Rect, shape: Shape) {
|
2021-01-17 00:35:14 +00:00
|
|
|
self.0[idx.0] = ClippedShape(clip_rect, shape);
|
2020-07-30 12:11:09 +00:00
|
|
|
}
|
2020-11-02 16:41:52 +00:00
|
|
|
|
2021-01-10 10:43:01 +00:00
|
|
|
/// Translate each [`Shape`] and clip rectangle by this much, in-place
|
2020-11-02 16:41:52 +00:00
|
|
|
pub fn translate(&mut self, delta: Vec2) {
|
2021-01-17 00:35:14 +00:00
|
|
|
for ClippedShape(clip_rect, shape) in &mut self.0 {
|
2020-11-02 16:41:52 +00:00
|
|
|
*clip_rect = clip_rect.translate(delta);
|
2021-01-10 10:43:01 +00:00
|
|
|
shape.translate(delta);
|
2020-11-02 16:41:52 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-30 12:11:09 +00:00
|
|
|
}
|
2020-04-17 12:26:36 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Default)]
|
2021-10-09 12:10:38 +00:00
|
|
|
pub(crate) struct GraphicLayers([IdMap<Arc<Mutex<PaintList>>>; Order::COUNT]);
|
2020-04-17 12:26:36 +00:00
|
|
|
|
|
|
|
impl GraphicLayers {
|
2021-03-31 15:03:20 +00:00
|
|
|
pub fn list(&mut self, layer_id: LayerId) -> &Arc<Mutex<PaintList>> {
|
2020-10-24 08:06:11 +00:00
|
|
|
self.0[layer_id.order as usize]
|
|
|
|
.entry(layer_id.id)
|
|
|
|
.or_default()
|
2020-04-17 12:26:36 +00:00
|
|
|
}
|
|
|
|
|
2021-01-17 00:35:14 +00:00
|
|
|
pub fn drain(&mut self, area_order: &[LayerId]) -> impl ExactSizeIterator<Item = ClippedShape> {
|
2021-01-10 10:43:01 +00:00
|
|
|
let mut all_shapes: Vec<_> = Default::default();
|
2020-04-17 12:26:36 +00:00
|
|
|
|
2020-10-24 08:06:11 +00:00
|
|
|
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
|
2021-05-02 20:02:26 +00:00
|
|
|
// then nobody has added to it, and it is old and defunct.
|
2020-10-24 08:06:11 +00:00
|
|
|
// Free it to save memory:
|
2021-03-31 15:03:20 +00:00
|
|
|
order_map.retain(|_, list| !list.lock().is_empty());
|
2020-10-24 08:06:11 +00:00
|
|
|
|
|
|
|
// First do the layers part of area_order:
|
|
|
|
for layer_id in area_order {
|
|
|
|
if layer_id.order == order {
|
2021-03-31 15:03:20 +00:00
|
|
|
if let Some(list) = order_map.get_mut(&layer_id.id) {
|
2021-08-20 20:31:20 +00:00
|
|
|
all_shapes.append(&mut list.lock().0);
|
2020-10-24 08:06:11 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-17 21:22:28 +00:00
|
|
|
}
|
2020-04-17 12:26:36 +00:00
|
|
|
|
2020-10-24 08:06:11 +00:00
|
|
|
// Also draw areas that are missing in `area_order`:
|
2021-01-10 10:43:01 +00:00
|
|
|
for shapes in order_map.values_mut() {
|
2021-08-20 20:31:20 +00:00
|
|
|
all_shapes.append(&mut shapes.lock().0);
|
2020-10-24 08:06:11 +00:00
|
|
|
}
|
2020-05-10 12:27:02 +00:00
|
|
|
}
|
|
|
|
|
2021-01-10 10:43:01 +00:00
|
|
|
all_shapes.into_iter()
|
2020-04-17 12:26:36 +00:00
|
|
|
}
|
|
|
|
}
|