Compare commits
25 commits
master
...
emilk/zlay
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ce2d37d5d9 | ||
![]() |
cb051425ff | ||
![]() |
ac6344c104 | ||
![]() |
8fac6df249 | ||
![]() |
9ad5356cfa | ||
![]() |
f0d5b645f2 | ||
![]() |
95b318d3e0 | ||
![]() |
f87c789851 | ||
![]() |
494f5b3ef0 | ||
![]() |
9ca4d173c5 | ||
![]() |
9ee77aab84 | ||
![]() |
d2c7793370 | ||
![]() |
5473c0f8a0 | ||
![]() |
c29b80d41e | ||
![]() |
57f65b7be6 | ||
![]() |
45336eaf62 | ||
![]() |
3c2e669fe1 | ||
![]() |
191cc70362 | ||
![]() |
db46385073 | ||
![]() |
099e41bf3f | ||
![]() |
d0307417e1 | ||
![]() |
26c3fa22cb | ||
![]() |
7894cd4dfd | ||
![]() |
4560618d43 | ||
![]() |
1e770ae3bd |
20 changed files with 524 additions and 124 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -4999,6 +4999,15 @@ dependencies = [
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "z_order"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"eframe",
|
||||||
|
"log",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zbus"
|
name = "zbus"
|
||||||
version = "3.6.0"
|
version = "3.6.0"
|
||||||
|
|
|
@ -77,8 +77,8 @@ impl Area {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layer(&self) -> LayerId {
|
pub fn layer(&self) -> AreaLayerId {
|
||||||
LayerId::new(self.order, self.id)
|
AreaLayerId::new(self.order, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If false, no content responds to click
|
/// If false, no content responds to click
|
||||||
|
@ -187,7 +187,7 @@ impl Area {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Prepared {
|
pub(crate) struct Prepared {
|
||||||
layer_id: LayerId,
|
layer_id: AreaLayerId,
|
||||||
state: State,
|
state: State,
|
||||||
move_response: Response,
|
move_response: Response,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
|
@ -229,7 +229,7 @@ impl Area {
|
||||||
constrain,
|
constrain,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let layer_id = LayerId::new(order, id);
|
let layer_id = AreaLayerId::new(order, id);
|
||||||
|
|
||||||
let state = ctx.memory(|mem| mem.areas.get(id).copied());
|
let state = ctx.memory(|mem| mem.areas.get(id).copied());
|
||||||
let is_new = state.is_none();
|
let is_new = state.is_none();
|
||||||
|
@ -268,7 +268,7 @@ impl Area {
|
||||||
let move_response = ctx.interact(
|
let move_response = ctx.interact(
|
||||||
Rect::EVERYTHING,
|
Rect::EVERYTHING,
|
||||||
ctx.style().spacing.item_spacing,
|
ctx.style().spacing.item_spacing,
|
||||||
layer_id,
|
layers::ZLayer::from_area_layer(layer_id),
|
||||||
interact_id,
|
interact_id,
|
||||||
state.rect(),
|
state.rect(),
|
||||||
sense,
|
sense,
|
||||||
|
@ -328,7 +328,7 @@ impl Area {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let layer_id = LayerId::new(self.order, self.id);
|
let layer_id = AreaLayerId::new(self.order, self.id);
|
||||||
let area_rect = ctx.memory(|mem| mem.areas.get(self.id).map(|area| area.rect()));
|
let area_rect = ctx.memory(|mem| mem.areas.get(self.id).map(|area| area.rect()));
|
||||||
if let Some(area_rect) = area_rect {
|
if let Some(area_rect) = area_rect {
|
||||||
let clip_rect = ctx.available_rect();
|
let clip_rect = ctx.available_rect();
|
||||||
|
@ -416,7 +416,7 @@ impl Prepared {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pointer_pressed_on_area(ctx: &Context, layer_id: LayerId) -> bool {
|
fn pointer_pressed_on_area(ctx: &Context, layer_id: AreaLayerId) -> bool {
|
||||||
if let Some(pointer_pos) = ctx.pointer_interact_pos() {
|
if let Some(pointer_pos) = ctx.pointer_interact_pos() {
|
||||||
let any_pressed = ctx.input(|i| i.pointer.any_pressed());
|
let any_pressed = ctx.input(|i| i.pointer.any_pressed());
|
||||||
any_pressed && ctx.layer_id_at(pointer_pos) == Some(layer_id)
|
any_pressed && ctx.layer_id_at(pointer_pos) == Some(layer_id)
|
||||||
|
|
|
@ -237,7 +237,7 @@ impl SidePanel {
|
||||||
let we_are_on_top = ui
|
let we_are_on_top = ui
|
||||||
.ctx()
|
.ctx()
|
||||||
.layer_id_at(pointer)
|
.layer_id_at(pointer)
|
||||||
.map_or(true, |top_layer_id| top_layer_id == ui.layer_id());
|
.map_or(true, |top_layer_id| top_layer_id == ui.area_layer_id());
|
||||||
|
|
||||||
let resize_x = side.opposite().side_x(panel_rect);
|
let resize_x = side.opposite().side_x(panel_rect);
|
||||||
let mouse_over_resize_line = we_are_on_top
|
let mouse_over_resize_line = we_are_on_top
|
||||||
|
@ -306,12 +306,13 @@ impl SidePanel {
|
||||||
} else {
|
} else {
|
||||||
Stroke::NONE
|
Stroke::NONE
|
||||||
};
|
};
|
||||||
// TODO(emilk): draw line on top of all panels in this ui when https://github.com/emilk/egui/issues/1516 is done
|
let resize_x = side.opposite().side_x(rect);
|
||||||
// In the meantime: nudge the line so its inside the panel, so it won't be covered by neighboring panel
|
|
||||||
// (hence the shrink).
|
|
||||||
let resize_x = side.opposite().side_x(rect.shrink(1.0));
|
|
||||||
let resize_x = ui.painter().round_to_pixel(resize_x);
|
let resize_x = ui.painter().round_to_pixel(resize_x);
|
||||||
ui.painter().vline(resize_x, rect.y_range(), stroke);
|
ui.painter().clone().with_z(layers::ZOrder::FRONT).vline(
|
||||||
|
resize_x,
|
||||||
|
rect.y_range(),
|
||||||
|
stroke,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inner_response
|
inner_response
|
||||||
|
@ -332,7 +333,7 @@ impl SidePanel {
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||||
) -> InnerResponse<R> {
|
) -> InnerResponse<R> {
|
||||||
let layer_id = LayerId::background();
|
let layer_id = AreaLayerId::background();
|
||||||
let side = self.side;
|
let side = self.side;
|
||||||
let available_rect = ctx.available_rect();
|
let available_rect = ctx.available_rect();
|
||||||
let clip_rect = ctx.screen_rect();
|
let clip_rect = ctx.screen_rect();
|
||||||
|
@ -688,7 +689,7 @@ impl TopBottomPanel {
|
||||||
let we_are_on_top = ui
|
let we_are_on_top = ui
|
||||||
.ctx()
|
.ctx()
|
||||||
.layer_id_at(pointer)
|
.layer_id_at(pointer)
|
||||||
.map_or(true, |top_layer_id| top_layer_id == ui.layer_id());
|
.map_or(true, |top_layer_id| top_layer_id == ui.area_layer_id());
|
||||||
|
|
||||||
let resize_y = side.opposite().side_y(panel_rect);
|
let resize_y = side.opposite().side_y(panel_rect);
|
||||||
let mouse_over_resize_line = we_are_on_top
|
let mouse_over_resize_line = we_are_on_top
|
||||||
|
@ -757,12 +758,13 @@ impl TopBottomPanel {
|
||||||
} else {
|
} else {
|
||||||
Stroke::NONE
|
Stroke::NONE
|
||||||
};
|
};
|
||||||
// TODO(emilk): draw line on top of all panels in this ui when https://github.com/emilk/egui/issues/1516 is done
|
let resize_y = side.opposite().side_y(rect);
|
||||||
// In the meantime: nudge the line so its inside the panel, so it won't be covered by neighboring panel
|
|
||||||
// (hence the shrink).
|
|
||||||
let resize_y = side.opposite().side_y(rect.shrink(1.0));
|
|
||||||
let resize_y = ui.painter().round_to_pixel(resize_y);
|
let resize_y = ui.painter().round_to_pixel(resize_y);
|
||||||
ui.painter().hline(rect.x_range(), resize_y, stroke);
|
ui.painter().clone().with_z(layers::ZOrder::FRONT).hline(
|
||||||
|
rect.x_range(),
|
||||||
|
resize_y,
|
||||||
|
stroke,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inner_response
|
inner_response
|
||||||
|
@ -783,7 +785,7 @@ impl TopBottomPanel {
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||||
) -> InnerResponse<R> {
|
) -> InnerResponse<R> {
|
||||||
let layer_id = LayerId::background();
|
let layer_id = AreaLayerId::background();
|
||||||
let available_rect = ctx.available_rect();
|
let available_rect = ctx.available_rect();
|
||||||
let side = self.side;
|
let side = self.side;
|
||||||
|
|
||||||
|
@ -1041,7 +1043,7 @@ impl CentralPanel {
|
||||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||||
) -> InnerResponse<R> {
|
) -> InnerResponse<R> {
|
||||||
let available_rect = ctx.available_rect();
|
let available_rect = ctx.available_rect();
|
||||||
let layer_id = LayerId::background();
|
let layer_id = AreaLayerId::background();
|
||||||
let id = Id::new("central_panel");
|
let id = Id::new("central_panel");
|
||||||
|
|
||||||
let clip_rect = ctx.screen_rect();
|
let clip_rect = ctx.screen_rect();
|
||||||
|
|
|
@ -279,7 +279,7 @@ pub fn was_tooltip_open_last_frame(ctx: &Context, tooltip_id: Id) -> bool {
|
||||||
for (count, (individual_id, _size)) in &state.individual_ids_and_sizes {
|
for (count, (individual_id, _size)) in &state.individual_ids_and_sizes {
|
||||||
if *individual_id == tooltip_id {
|
if *individual_id == tooltip_id {
|
||||||
let area_id = common_id.with(count);
|
let area_id = common_id.with(count);
|
||||||
let layer_id = LayerId::new(Order::Tooltip, area_id);
|
let layer_id = AreaLayerId::new(Order::Tooltip, area_id);
|
||||||
if ctx.memory(|mem| mem.areas.visible_last_frame(&layer_id)) {
|
if ctx.memory(|mem| mem.areas.visible_last_frame(&layer_id)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,7 +510,7 @@ impl PossibleInteractions {
|
||||||
/// Either a move or resize
|
/// Either a move or resize
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub(crate) struct WindowInteraction {
|
pub(crate) struct WindowInteraction {
|
||||||
pub(crate) area_layer_id: LayerId,
|
pub(crate) area_layer_id: AreaLayerId,
|
||||||
pub(crate) start_rect: Rect,
|
pub(crate) start_rect: Rect,
|
||||||
pub(crate) left: bool,
|
pub(crate) left: bool,
|
||||||
pub(crate) right: bool,
|
pub(crate) right: bool,
|
||||||
|
@ -540,7 +540,7 @@ fn interact(
|
||||||
window_interaction: WindowInteraction,
|
window_interaction: WindowInteraction,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
margins: Vec2,
|
margins: Vec2,
|
||||||
area_layer_id: LayerId,
|
area_layer_id: AreaLayerId,
|
||||||
area: &mut area::Prepared,
|
area: &mut area::Prepared,
|
||||||
resize_id: Id,
|
resize_id: Id,
|
||||||
) -> Option<WindowInteraction> {
|
) -> Option<WindowInteraction> {
|
||||||
|
@ -607,7 +607,7 @@ fn move_and_resize_window(ctx: &Context, window_interaction: &WindowInteraction)
|
||||||
fn window_interaction(
|
fn window_interaction(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
possible: PossibleInteractions,
|
possible: PossibleInteractions,
|
||||||
area_layer_id: LayerId,
|
area_layer_id: AreaLayerId,
|
||||||
id: Id,
|
id: Id,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
) -> Option<WindowInteraction> {
|
) -> Option<WindowInteraction> {
|
||||||
|
@ -649,7 +649,7 @@ fn window_interaction(
|
||||||
fn resize_hover(
|
fn resize_hover(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
possible: PossibleInteractions,
|
possible: PossibleInteractions,
|
||||||
area_layer_id: LayerId,
|
area_layer_id: AreaLayerId,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
) -> Option<WindowInteraction> {
|
) -> Option<WindowInteraction> {
|
||||||
let pointer = ctx.input(|i| i.pointer.interact_pos())?;
|
let pointer = ctx.input(|i| i.pointer.interact_pos())?;
|
||||||
|
|
|
@ -64,9 +64,9 @@ struct ContextImpl {
|
||||||
requested_repaint_last_frame: bool,
|
requested_repaint_last_frame: bool,
|
||||||
|
|
||||||
/// Written to during the frame.
|
/// Written to during the frame.
|
||||||
layer_rects_this_frame: ahash::HashMap<LayerId, Vec<(Id, Rect)>>,
|
layer_rects_this_frame: ahash::HashMap<AreaLayerId, Vec<(Id, layers::ZOrder, Rect)>>,
|
||||||
/// Read
|
/// Read
|
||||||
layer_rects_prev_frame: ahash::HashMap<LayerId, Vec<(Id, Rect)>>,
|
layer_rects_prev_frame: ahash::HashMap<AreaLayerId, Vec<(Id, layers::ZOrder, Rect)>>,
|
||||||
|
|
||||||
#[cfg(feature = "accesskit")]
|
#[cfg(feature = "accesskit")]
|
||||||
is_accesskit_enabled: bool,
|
is_accesskit_enabled: bool,
|
||||||
|
@ -101,7 +101,7 @@ impl ContextImpl {
|
||||||
// Ensure we register the background area so panels and background ui can catch clicks:
|
// Ensure we register the background area so panels and background ui can catch clicks:
|
||||||
let screen_rect = self.input.screen_rect();
|
let screen_rect = self.input.screen_rect();
|
||||||
self.memory.areas.set_state(
|
self.memory.areas.set_state(
|
||||||
LayerId::background(),
|
AreaLayerId::background(),
|
||||||
containers::area::State {
|
containers::area::State {
|
||||||
pos: screen_rect.min,
|
pos: screen_rect.min,
|
||||||
size: screen_rect.size(),
|
size: screen_rect.size(),
|
||||||
|
@ -534,7 +534,7 @@ impl Context {
|
||||||
&self,
|
&self,
|
||||||
clip_rect: Rect,
|
clip_rect: Rect,
|
||||||
item_spacing: Vec2,
|
item_spacing: Vec2,
|
||||||
layer_id: LayerId,
|
layer: layers::ZLayer,
|
||||||
id: Id,
|
id: Id,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
|
@ -551,13 +551,13 @@ impl Context {
|
||||||
|
|
||||||
// Respect clip rectangle when interacting
|
// Respect clip rectangle when interacting
|
||||||
let interact_rect = clip_rect.intersect(interact_rect);
|
let interact_rect = clip_rect.intersect(interact_rect);
|
||||||
let mut hovered = self.rect_contains_pointer(layer_id, interact_rect);
|
let mut hovered = self.rect_contains_pointer(layer.area_layer, interact_rect);
|
||||||
|
|
||||||
// This solves the problem of overlapping widgets.
|
// This solves the problem of overlapping widgets.
|
||||||
// Whichever widget is added LAST (=on top) gets the input:
|
// Whichever widget is added LAST (=on top) gets the input:
|
||||||
if interact_rect.is_positive() && sense.interactive() {
|
if interact_rect.is_positive() && sense.interactive() {
|
||||||
if self.style().debug.show_interactive_widgets {
|
if self.style().debug.show_interactive_widgets {
|
||||||
Self::layer_painter(self, LayerId::debug()).rect(
|
Self::layer_painter(self, AreaLayerId::debug()).rect(
|
||||||
interact_rect,
|
interact_rect,
|
||||||
0.0,
|
0.0,
|
||||||
Color32::YELLOW.additive().linear_multiply(0.005),
|
Color32::YELLOW.additive().linear_multiply(0.005),
|
||||||
|
@ -567,16 +567,18 @@ impl Context {
|
||||||
|
|
||||||
self.write(|ctx| {
|
self.write(|ctx| {
|
||||||
ctx.layer_rects_this_frame
|
ctx.layer_rects_this_frame
|
||||||
.entry(layer_id)
|
.entry(layer.area_layer)
|
||||||
.or_default()
|
.or_default()
|
||||||
.push((id, interact_rect));
|
.push((id, layer.z, interact_rect));
|
||||||
|
|
||||||
if hovered {
|
if hovered {
|
||||||
let pointer_pos = ctx.input.pointer.interact_pos();
|
let pointer_pos = ctx.input.pointer.interact_pos();
|
||||||
if let Some(pointer_pos) = pointer_pos {
|
if let Some(pointer_pos) = pointer_pos {
|
||||||
if let Some(rects) = ctx.layer_rects_prev_frame.get(&layer_id) {
|
if let Some(rects) = ctx.layer_rects_prev_frame.get_mut(&layer.area_layer) {
|
||||||
for &(prev_id, prev_rect) in rects.iter().rev() {
|
rects.sort_by_key(|(_id, z, ..)| *z);
|
||||||
if prev_id == id {
|
|
||||||
|
for &(prev_id, prev_z, prev_rect) in rects.iter().rev() {
|
||||||
|
if prev_id == id && prev_z <= layer.z {
|
||||||
break; // there is no other interactive widget covering us at the pointer position.
|
break; // there is no other interactive widget covering us at the pointer position.
|
||||||
}
|
}
|
||||||
if prev_rect.contains(pointer_pos) {
|
if prev_rect.contains(pointer_pos) {
|
||||||
|
@ -584,12 +586,12 @@ impl Context {
|
||||||
// so we aren't hovered.
|
// so we aren't hovered.
|
||||||
|
|
||||||
if ctx.memory.options.style.debug.show_blocking_widget {
|
if ctx.memory.options.style.debug.show_blocking_widget {
|
||||||
Self::layer_painter(self, LayerId::debug()).debug_rect(
|
Self::layer_painter(self, AreaLayerId::debug()).debug_rect(
|
||||||
interact_rect,
|
interact_rect,
|
||||||
Color32::GREEN,
|
Color32::GREEN,
|
||||||
"Covered",
|
"Covered",
|
||||||
);
|
);
|
||||||
Self::layer_painter(self, LayerId::debug()).debug_rect(
|
Self::layer_painter(self, AreaLayerId::debug()).debug_rect(
|
||||||
prev_rect,
|
prev_rect,
|
||||||
Color32::LIGHT_BLUE,
|
Color32::LIGHT_BLUE,
|
||||||
"On top",
|
"On top",
|
||||||
|
@ -606,13 +608,13 @@ impl Context {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.interact_with_hovered(layer_id, id, rect, sense, enabled, hovered)
|
self.interact_with_hovered(layer.area_layer, id, rect, sense, enabled, hovered)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// You specify if a thing is hovered, and the function gives a [`Response`].
|
/// You specify if a thing is hovered, and the function gives a [`Response`].
|
||||||
pub(crate) fn interact_with_hovered(
|
pub(crate) fn interact_with_hovered(
|
||||||
&self,
|
&self,
|
||||||
layer_id: LayerId,
|
layer_id: AreaLayerId,
|
||||||
id: Id,
|
id: Id,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
|
@ -759,14 +761,14 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a full-screen painter for a new or existing layer
|
/// Get a full-screen painter for a new or existing layer
|
||||||
pub fn layer_painter(&self, layer_id: LayerId) -> Painter {
|
pub fn layer_painter(&self, layer_id: AreaLayerId) -> Painter {
|
||||||
let screen_rect = self.screen_rect();
|
let screen_rect = self.screen_rect();
|
||||||
Painter::new(self.clone(), layer_id, screen_rect)
|
Painter::new(self.clone(), layer_id, screen_rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Paint on top of everything else
|
/// Paint on top of everything else
|
||||||
pub fn debug_painter(&self) -> Painter {
|
pub fn debug_painter(&self) -> Painter {
|
||||||
Self::layer_painter(self, LayerId::debug())
|
Self::layer_painter(self, AreaLayerId::debug())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// What operating system are we running on?
|
/// What operating system are we running on?
|
||||||
|
@ -1322,14 +1324,14 @@ impl Context {
|
||||||
/// Move all the graphics at the given layer.
|
/// Move all the graphics at the given layer.
|
||||||
///
|
///
|
||||||
/// Can be used to implement drag-and-drop (see relevant demo).
|
/// Can be used to implement drag-and-drop (see relevant demo).
|
||||||
pub fn translate_layer(&self, layer_id: LayerId, delta: Vec2) {
|
pub fn translate_layer(&self, layer_id: AreaLayerId, delta: Vec2) {
|
||||||
if delta != Vec2::ZERO {
|
if delta != Vec2::ZERO {
|
||||||
self.graphics_mut(|g| g.list(layer_id).translate(delta));
|
self.graphics_mut(|g| g.list(layer_id).translate(delta));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Top-most layer at the given position.
|
/// Top-most layer at the given position.
|
||||||
pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> {
|
pub fn layer_id_at(&self, pos: Pos2) -> Option<AreaLayerId> {
|
||||||
self.memory(|mem| {
|
self.memory(|mem| {
|
||||||
mem.layer_id_at(pos, mem.options.style.interaction.resize_grab_radius_side)
|
mem.layer_id_at(pos, mem.options.style.interaction.resize_grab_radius_side)
|
||||||
})
|
})
|
||||||
|
@ -1338,11 +1340,11 @@ impl Context {
|
||||||
/// Moves the given area to the top in its [`Order`].
|
/// Moves the given area to the top in its [`Order`].
|
||||||
///
|
///
|
||||||
/// [`Area`]:s and [`Window`]:s also do this automatically when being clicked on or interacted with.
|
/// [`Area`]:s and [`Window`]:s also do this automatically when being clicked on or interacted with.
|
||||||
pub fn move_to_top(&self, layer_id: LayerId) {
|
pub fn move_to_top(&self, layer_id: AreaLayerId) {
|
||||||
self.memory_mut(|mem| mem.areas.move_to_top(layer_id));
|
self.memory_mut(|mem| mem.areas.move_to_top(layer_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn rect_contains_pointer(&self, layer_id: LayerId, rect: Rect) -> bool {
|
pub(crate) fn rect_contains_pointer(&self, layer_id: AreaLayerId, rect: Rect) -> bool {
|
||||||
rect.is_positive() && {
|
rect.is_positive() && {
|
||||||
let pointer_pos = self.input(|i| i.pointer.interact_pos());
|
let pointer_pos = self.input(|i| i.pointer.interact_pos());
|
||||||
if let Some(pointer_pos) = pointer_pos {
|
if let Some(pointer_pos) = pointer_pos {
|
||||||
|
@ -1599,7 +1601,7 @@ impl Context {
|
||||||
ui.indent("areas", |ui| {
|
ui.indent("areas", |ui| {
|
||||||
ui.label("Visible areas, ordered back to front.");
|
ui.label("Visible areas, ordered back to front.");
|
||||||
ui.label("Hover to highlight");
|
ui.label("Hover to highlight");
|
||||||
let layers_ids: Vec<LayerId> = self.memory(|mem| mem.areas.order().to_vec());
|
let layers_ids: Vec<AreaLayerId> = self.memory(|mem| mem.areas.order().to_vec());
|
||||||
for layer_id in layers_ids {
|
for layer_id in layers_ids {
|
||||||
let area = self.memory(|mem| mem.areas.get(layer_id.id).copied());
|
let area = self.memory(|mem| mem.areas.get(layer_id.id).copied());
|
||||||
if let Some(area) = area {
|
if let Some(area) = area {
|
||||||
|
|
|
@ -69,12 +69,16 @@ impl Order {
|
||||||
/// Also acts as an identifier for [`Area`]:s.
|
/// Also acts as an identifier for [`Area`]:s.
|
||||||
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct LayerId {
|
pub struct AreaLayerId {
|
||||||
pub order: Order,
|
pub order: Order,
|
||||||
pub id: Id,
|
pub id: Id,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayerId {
|
/// For backwards-compatibility with `AreaLayerId`
|
||||||
|
#[deprecated(note = "Use `AreaLayerId` instead")]
|
||||||
|
pub type LayerId = AreaLayerId;
|
||||||
|
|
||||||
|
impl AreaLayerId {
|
||||||
pub fn new(order: Order, id: Id) -> Self {
|
pub fn new(order: Order, id: Id) -> Self {
|
||||||
Self { order, id }
|
Self { order, id }
|
||||||
}
|
}
|
||||||
|
@ -98,6 +102,11 @@ impl LayerId {
|
||||||
self.order.allow_interaction()
|
self.order.allow_interaction()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_z(self, z: ZOrder) -> ZLayer {
|
||||||
|
ZLayer::from_area_layer_z(self, z)
|
||||||
|
}
|
||||||
|
|
||||||
/// Short and readable summary
|
/// Short and readable summary
|
||||||
pub fn short_debug_format(&self) -> String {
|
pub fn short_debug_format(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
|
@ -108,13 +117,163 @@ impl LayerId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Represents the relative order an element should be displayed.
|
||||||
|
///
|
||||||
|
/// Lower values render first, and therefore appear below higher values.
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
pub struct ZOrder(pub i32);
|
||||||
|
|
||||||
|
impl ZOrder {
|
||||||
|
/// The default layer 0.
|
||||||
|
pub const BASE: ZOrder = ZOrder(0);
|
||||||
|
|
||||||
|
/// In front of everything else.
|
||||||
|
pub const FRONT: ZOrder = ZOrder(i32::MAX);
|
||||||
|
|
||||||
|
/// Behind everything else.
|
||||||
|
pub const BACK: ZOrder = ZOrder(i32::MIN);
|
||||||
|
|
||||||
|
/// Directly above
|
||||||
|
pub fn in_front(self) -> Self {
|
||||||
|
self.in_front_by(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Directly behind
|
||||||
|
pub fn behind(self) -> Self {
|
||||||
|
self.behind_by(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// In front of by the number of levels given
|
||||||
|
pub fn in_front_by(self, levels: i32) -> Self {
|
||||||
|
Self(self.0.saturating_add(levels))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Behind by the number of levels given
|
||||||
|
pub fn behind_by(self, levels: i32) -> Self {
|
||||||
|
Self(self.0.saturating_sub(levels))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ZOrder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::BASE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Add<ZOffset> for ZOrder {
|
||||||
|
type Output = ZOrder;
|
||||||
|
|
||||||
|
fn add(self, offset: ZOffset) -> Self::Output {
|
||||||
|
Self(self.0.saturating_add(offset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::AddAssign<ZOffset> for ZOrder {
|
||||||
|
fn add_assign(&mut self, offset: ZOffset) {
|
||||||
|
self.0 = self.0.saturating_add(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Offset within a [`ZOrder`].
|
||||||
|
///
|
||||||
|
/// * Positive: more in front of.
|
||||||
|
/// * Negative: more behind.
|
||||||
|
pub type ZOffset = i32;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// An identifier for a paint layer which supports Z-indexing
|
||||||
|
///
|
||||||
|
/// This says: draw on [`AreaLayerId`] with index z. This only affects the display
|
||||||
|
/// order of elements on the same area layer. Order of area layers still takes
|
||||||
|
/// precedence over z-index.
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
pub struct ZLayer {
|
||||||
|
pub area_layer: AreaLayerId,
|
||||||
|
pub z: ZOrder,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZLayer {
|
||||||
|
pub fn new(order: Order, id: Id, z: ZOrder) -> Self {
|
||||||
|
Self {
|
||||||
|
area_layer: AreaLayerId { order, id },
|
||||||
|
z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use specified Z-level
|
||||||
|
pub fn from_area_layer_z(area_layer: AreaLayerId, z: ZOrder) -> Self {
|
||||||
|
Self { area_layer, z }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use base Z-level
|
||||||
|
pub fn from_area_layer(area_layer: AreaLayerId) -> Self {
|
||||||
|
Self::from_area_layer_z(area_layer, ZOrder::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug() -> Self {
|
||||||
|
Self::from_area_layer(AreaLayerId::debug())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn background() -> Self {
|
||||||
|
Self::from_area_layer(AreaLayerId::background())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_z(self, z: ZOrder) -> Self {
|
||||||
|
Self::from_area_layer_z(self.area_layer, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `ZLayer` directly in front of this one.
|
||||||
|
#[must_use]
|
||||||
|
pub fn in_front(self) -> Self {
|
||||||
|
self.with_z(self.z.in_front())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `ZLayer` in front of this one by `levels` levels.
|
||||||
|
#[must_use]
|
||||||
|
pub fn in_front_by(self, levels: i32) -> Self {
|
||||||
|
self.with_z(self.z.in_front_by(levels))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `ZLayer` directly behind this one.
|
||||||
|
#[must_use]
|
||||||
|
pub fn behind(self) -> Self {
|
||||||
|
self.with_z(self.z.behind())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `ZLayer` behind this one by `levels` levels.
|
||||||
|
#[must_use]
|
||||||
|
pub fn behind_by(self, levels: i32) -> Self {
|
||||||
|
self.with_z(self.z.behind_by(levels))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Id` of underlying area layer
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn id(&self) -> Id {
|
||||||
|
self.area_layer.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Order` of underlying area layer
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn order(&self) -> Order {
|
||||||
|
self.area_layer.order
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A unique identifier of a specific [`Shape`] in a [`PaintList`].
|
/// A unique identifier of a specific [`Shape`] in a [`PaintList`].
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct ShapeIdx(usize);
|
pub struct ShapeIdx(usize);
|
||||||
|
|
||||||
/// A list of [`Shape`]s paired with a clip rectangle.
|
/// A list of [`Shape`]s paired with a clip rectangle.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct PaintList(Vec<ClippedShape>);
|
pub struct PaintList(Vec<(ZOrder, ClippedShape)>);
|
||||||
|
|
||||||
impl PaintList {
|
impl PaintList {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -122,22 +281,37 @@ impl PaintList {
|
||||||
self.0.is_empty()
|
self.0.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the index of the new [`Shape`] that can be used with `PaintList::set`.
|
/// Returns the index of the new [`Shape`] at index `z` that can be used with `PaintList::set`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn add(&mut self, clip_rect: Rect, shape: Shape) -> ShapeIdx {
|
pub fn add_at_z(&mut self, clip_rect: Rect, shape: Shape, z: ZOrder) -> ShapeIdx {
|
||||||
let idx = ShapeIdx(self.0.len());
|
let idx = ShapeIdx(self.0.len());
|
||||||
self.0.push(ClippedShape(clip_rect, shape));
|
self.0.push((z, ClippedShape(clip_rect, shape)));
|
||||||
idx
|
idx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend<I: IntoIterator<Item = Shape>>(&mut self, clip_rect: Rect, shapes: I) {
|
/// Returns the index of the new [`Shape`] at base z-index that can be used with `PaintList::set`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn add(&mut self, clip_rect: Rect, shape: Shape) -> ShapeIdx {
|
||||||
|
self.add_at_z(clip_rect, shape, ZOrder::BASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend_at_z<I: IntoIterator<Item = Shape>>(
|
||||||
|
&mut self,
|
||||||
|
clip_rect: Rect,
|
||||||
|
shapes: I,
|
||||||
|
z: ZOrder,
|
||||||
|
) {
|
||||||
self.0.extend(
|
self.0.extend(
|
||||||
shapes
|
shapes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|shape| ClippedShape(clip_rect, shape)),
|
.map(|shape| (z, ClippedShape(clip_rect, shape))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extend<I: IntoIterator<Item = Shape>>(&mut self, clip_rect: Rect, shapes: I) {
|
||||||
|
self.extend_at_z(clip_rect, shapes, ZOrder::BASE);
|
||||||
|
}
|
||||||
|
|
||||||
/// Modify an existing [`Shape`].
|
/// Modify an existing [`Shape`].
|
||||||
///
|
///
|
||||||
/// Sometimes you want to paint a frame behind some contents, but don't know how large the frame needs to be
|
/// Sometimes you want to paint a frame behind some contents, but don't know how large the frame needs to be
|
||||||
|
@ -147,12 +321,12 @@ impl PaintList {
|
||||||
/// and then later setting it using `paint_list.set(idx, cr, frame);`.
|
/// and then later setting it using `paint_list.set(idx, cr, frame);`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set(&mut self, idx: ShapeIdx, clip_rect: Rect, shape: Shape) {
|
pub fn set(&mut self, idx: ShapeIdx, clip_rect: Rect, shape: Shape) {
|
||||||
self.0[idx.0] = ClippedShape(clip_rect, shape);
|
self.0[idx.0].1 = ClippedShape(clip_rect, shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translate each [`Shape`] and clip rectangle by this much, in-place
|
/// Translate each [`Shape`] and clip rectangle by this much, in-place
|
||||||
pub fn translate(&mut self, delta: Vec2) {
|
pub fn translate(&mut self, delta: Vec2) {
|
||||||
for ClippedShape(clip_rect, shape) in &mut self.0 {
|
for (.., ClippedShape(clip_rect, shape)) in &mut self.0 {
|
||||||
*clip_rect = clip_rect.translate(delta);
|
*clip_rect = clip_rect.translate(delta);
|
||||||
shape.translate(delta);
|
shape.translate(delta);
|
||||||
}
|
}
|
||||||
|
@ -163,18 +337,26 @@ impl PaintList {
|
||||||
pub(crate) struct GraphicLayers([IdMap<PaintList>; Order::COUNT]);
|
pub(crate) struct GraphicLayers([IdMap<PaintList>; Order::COUNT]);
|
||||||
|
|
||||||
impl GraphicLayers {
|
impl GraphicLayers {
|
||||||
pub fn list(&mut self, layer_id: LayerId) -> &mut PaintList {
|
pub fn list(&mut self, layer_id: AreaLayerId) -> &mut PaintList {
|
||||||
self.0[layer_id.order as usize]
|
self.0[layer_id.order as usize]
|
||||||
.entry(layer_id.id)
|
.entry(layer_id.id)
|
||||||
.or_default()
|
.or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drain(&mut self, area_order: &[LayerId]) -> impl ExactSizeIterator<Item = ClippedShape> {
|
pub fn drain(
|
||||||
|
&mut self,
|
||||||
|
area_order: &[AreaLayerId],
|
||||||
|
) -> impl ExactSizeIterator<Item = ClippedShape> {
|
||||||
let mut all_shapes: Vec<_> = Default::default();
|
let mut all_shapes: Vec<_> = Default::default();
|
||||||
|
|
||||||
for &order in &Order::ALL {
|
for &order in &Order::ALL {
|
||||||
let order_map = &mut self.0[order as usize];
|
let order_map = &mut self.0[order as usize];
|
||||||
|
|
||||||
|
// Sort by z-order
|
||||||
|
for list in order_map.values_mut() {
|
||||||
|
list.0.sort_by_key(|(z, ..)| *z);
|
||||||
|
}
|
||||||
|
|
||||||
// If a layer is empty at the start of the frame
|
// If a layer is empty at the start of the frame
|
||||||
// then nobody has added to it, and it is old and defunct.
|
// then nobody has added to it, and it is old and defunct.
|
||||||
// Free it to save memory:
|
// Free it to save memory:
|
||||||
|
@ -195,6 +377,6 @@ impl GraphicLayers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
all_shapes.into_iter()
|
all_shapes.into_iter().map(|(.., shape)| shape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,7 +361,7 @@ pub use {
|
||||||
grid::Grid,
|
grid::Grid,
|
||||||
id::{Id, IdMap},
|
id::{Id, IdMap},
|
||||||
input_state::{InputState, MultiTouchInfo, PointerState},
|
input_state::{InputState, MultiTouchInfo, PointerState},
|
||||||
layers::{LayerId, Order},
|
layers::{AreaLayerId, Order, ZOffset, ZOrder},
|
||||||
layout::*,
|
layout::*,
|
||||||
memory::{Memory, Options},
|
memory::{Memory, Options},
|
||||||
painter::Painter,
|
painter::Painter,
|
||||||
|
@ -374,6 +374,9 @@ pub use {
|
||||||
widgets::*,
|
widgets::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
|
pub use layers::LayerId;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Helper function that adds a label when compiling with debug assertions enabled.
|
/// Helper function that adds a label when compiling with debug assertions enabled.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{area, window, Id, IdMap, InputState, LayerId, Pos2, Rect, Style};
|
use crate::{area, window, AreaLayerId, Id, IdMap, InputState, Pos2, Rect, Style};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -358,12 +358,12 @@ impl Memory {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Top-most layer at the given position.
|
/// Top-most layer at the given position.
|
||||||
pub fn layer_id_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option<LayerId> {
|
pub fn layer_id_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option<AreaLayerId> {
|
||||||
self.areas.layer_id_at(pos, resize_interact_radius_side)
|
self.areas.layer_id_at(pos, resize_interact_radius_side)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over all layers. Back-to-front. Top is last.
|
/// An iterator over all layers. Back-to-front. Top is last.
|
||||||
pub fn layer_ids(&self) -> impl ExactSizeIterator<Item = LayerId> + '_ {
|
pub fn layer_ids(&self) -> impl ExactSizeIterator<Item = AreaLayerId> + '_ {
|
||||||
self.areas.order().iter().copied()
|
self.areas.order().iter().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,16 +530,16 @@ impl Memory {
|
||||||
pub struct Areas {
|
pub struct Areas {
|
||||||
areas: IdMap<area::State>,
|
areas: IdMap<area::State>,
|
||||||
/// Back-to-front. Top is last.
|
/// Back-to-front. Top is last.
|
||||||
order: Vec<LayerId>,
|
order: Vec<AreaLayerId>,
|
||||||
visible_last_frame: ahash::HashSet<LayerId>,
|
visible_last_frame: ahash::HashSet<AreaLayerId>,
|
||||||
visible_current_frame: ahash::HashSet<LayerId>,
|
visible_current_frame: ahash::HashSet<AreaLayerId>,
|
||||||
|
|
||||||
/// When an area want to be on top, it is put in here.
|
/// 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.
|
/// 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.
|
/// 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,
|
/// 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.
|
/// they will all be sent to the top, but keep their previous internal order.
|
||||||
wants_to_be_on_top: ahash::HashSet<LayerId>,
|
wants_to_be_on_top: ahash::HashSet<AreaLayerId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Areas {
|
impl Areas {
|
||||||
|
@ -552,11 +552,11 @@ impl Areas {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Back-to-front. Top is last.
|
/// Back-to-front. Top is last.
|
||||||
pub(crate) fn order(&self) -> &[LayerId] {
|
pub(crate) fn order(&self) -> &[AreaLayerId] {
|
||||||
&self.order
|
&self.order
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_state(&mut self, layer_id: LayerId, state: area::State) {
|
pub(crate) fn set_state(&mut self, layer_id: AreaLayerId, state: area::State) {
|
||||||
self.visible_current_frame.insert(layer_id);
|
self.visible_current_frame.insert(layer_id);
|
||||||
self.areas.insert(layer_id.id, state);
|
self.areas.insert(layer_id.id, state);
|
||||||
if !self.order.iter().any(|x| *x == layer_id) {
|
if !self.order.iter().any(|x| *x == layer_id) {
|
||||||
|
@ -565,7 +565,7 @@ impl Areas {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Top-most layer at the given position.
|
/// Top-most layer at the given position.
|
||||||
pub fn layer_id_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option<LayerId> {
|
pub fn layer_id_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option<AreaLayerId> {
|
||||||
for layer in self.order.iter().rev() {
|
for layer in self.order.iter().rev() {
|
||||||
if self.is_visible(layer) {
|
if self.is_visible(layer) {
|
||||||
if let Some(state) = self.areas.get(&layer.id) {
|
if let Some(state) = self.areas.get(&layer.id) {
|
||||||
|
@ -583,15 +583,15 @@ impl Areas {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visible_last_frame(&self, layer_id: &LayerId) -> bool {
|
pub fn visible_last_frame(&self, layer_id: &AreaLayerId) -> bool {
|
||||||
self.visible_last_frame.contains(layer_id)
|
self.visible_last_frame.contains(layer_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_visible(&self, layer_id: &LayerId) -> bool {
|
pub fn is_visible(&self, layer_id: &AreaLayerId) -> bool {
|
||||||
self.visible_last_frame.contains(layer_id) || self.visible_current_frame.contains(layer_id)
|
self.visible_last_frame.contains(layer_id) || self.visible_current_frame.contains(layer_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visible_layer_ids(&self) -> ahash::HashSet<LayerId> {
|
pub fn visible_layer_ids(&self) -> ahash::HashSet<AreaLayerId> {
|
||||||
self.visible_last_frame
|
self.visible_last_frame
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
|
@ -607,7 +607,7 @@ impl Areas {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_to_top(&mut self, layer_id: LayerId) {
|
pub fn move_to_top(&mut self, layer_id: AreaLayerId) {
|
||||||
self.visible_current_frame.insert(layer_id);
|
self.visible_current_frame.insert(layer_id);
|
||||||
self.wants_to_be_on_top.insert(layer_id);
|
self.wants_to_be_on_top.insert(layer_id);
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
emath::{Align2, Pos2, Rect, Vec2},
|
emath::{Align2, Pos2, Rect, Vec2},
|
||||||
layers::{LayerId, PaintList, ShapeIdx},
|
layers::{PaintList, ShapeIdx, ZLayer, ZOffset, ZOrder},
|
||||||
Color32, Context, FontId,
|
AreaLayerId, Color32, Context, FontId,
|
||||||
};
|
};
|
||||||
use epaint::{
|
use epaint::{
|
||||||
text::{Fonts, Galley},
|
text::{Fonts, Galley},
|
||||||
|
@ -20,7 +20,7 @@ pub struct Painter {
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
|
|
||||||
/// Where we paint
|
/// Where we paint
|
||||||
layer_id: LayerId,
|
z_layer: ZLayer,
|
||||||
|
|
||||||
/// Everything painted in this [`Painter`] will be clipped against this.
|
/// Everything painted in this [`Painter`] will be clipped against this.
|
||||||
/// This means nothing outside of this rectangle will be visible on screen.
|
/// This means nothing outside of this rectangle will be visible on screen.
|
||||||
|
@ -33,24 +33,34 @@ pub struct Painter {
|
||||||
|
|
||||||
impl Painter {
|
impl Painter {
|
||||||
/// Create a painter to a specific layer within a certain clip rectangle.
|
/// Create a painter to a specific layer within a certain clip rectangle.
|
||||||
pub fn new(ctx: Context, layer_id: LayerId, clip_rect: Rect) -> Self {
|
pub fn new(ctx: Context, area_layer: AreaLayerId, clip_rect: Rect) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ctx,
|
ctx,
|
||||||
layer_id,
|
z_layer: ZLayer::from_area_layer(area_layer),
|
||||||
clip_rect,
|
clip_rect,
|
||||||
fade_to_color: None,
|
fade_to_color: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Redirect where you are painting.
|
/// Redirect where you are painting with default z-index
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_layer_id(self, layer_id: LayerId) -> Self {
|
pub fn with_layer_id(mut self, layer: AreaLayerId) -> Self {
|
||||||
Self {
|
self.z_layer = ZLayer::from_area_layer(layer);
|
||||||
ctx: self.ctx,
|
self
|
||||||
layer_id,
|
}
|
||||||
clip_rect: self.clip_rect,
|
|
||||||
fade_to_color: None,
|
/// Redirect z-index
|
||||||
}
|
#[must_use]
|
||||||
|
pub fn with_z(mut self, z: ZOrder) -> Self {
|
||||||
|
self.z_layer.z = z;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify z-index
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_z_offset(mut self, z_offset: ZOffset) -> Self {
|
||||||
|
self.z_layer.z += z_offset;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a painter for a sub-region of this [`Painter`].
|
/// Create a painter for a sub-region of this [`Painter`].
|
||||||
|
@ -60,15 +70,25 @@ impl Painter {
|
||||||
pub fn with_clip_rect(&self, rect: Rect) -> Self {
|
pub fn with_clip_rect(&self, rect: Rect) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ctx: self.ctx.clone(),
|
ctx: self.ctx.clone(),
|
||||||
layer_id: self.layer_id,
|
z_layer: self.z_layer,
|
||||||
clip_rect: rect.intersect(self.clip_rect),
|
clip_rect: rect.intersect(self.clip_rect),
|
||||||
fade_to_color: self.fade_to_color,
|
fade_to_color: self.fade_to_color,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Redirect where you are painting.
|
/// Redirect what area layer you are painting.
|
||||||
pub fn set_layer_id(&mut self, layer_id: LayerId) {
|
pub fn set_layer_id(&mut self, area_layer: AreaLayerId) {
|
||||||
self.layer_id = layer_id;
|
self.z_layer.area_layer = area_layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Redirect at what z order you are drawing
|
||||||
|
pub fn set_z(&mut self, z: ZOrder) {
|
||||||
|
self.z_layer.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Redirect where you are drawing
|
||||||
|
pub fn set_layer(&mut self, layer: ZLayer) {
|
||||||
|
self.z_layer = layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If set, colors will be modified to look like this
|
/// If set, colors will be modified to look like this
|
||||||
|
@ -89,7 +109,7 @@ impl Painter {
|
||||||
pub fn sub_region(&self, rect: Rect) -> Self {
|
pub fn sub_region(&self, rect: Rect) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ctx: self.ctx.clone(),
|
ctx: self.ctx.clone(),
|
||||||
layer_id: self.layer_id,
|
z_layer: self.z_layer,
|
||||||
clip_rect: rect.intersect(self.clip_rect),
|
clip_rect: rect.intersect(self.clip_rect),
|
||||||
fade_to_color: self.fade_to_color,
|
fade_to_color: self.fade_to_color,
|
||||||
}
|
}
|
||||||
|
@ -114,8 +134,19 @@ impl Painter {
|
||||||
|
|
||||||
/// Where we paint
|
/// Where we paint
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn layer_id(&self) -> LayerId {
|
pub fn area_layer_id(&self) -> AreaLayerId {
|
||||||
self.layer_id
|
self.z_layer.area_layer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Where we paint, and on what Z-level
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn z_layer(&self) -> ZLayer {
|
||||||
|
self.z_layer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn z(&self) -> ZOrder {
|
||||||
|
self.z_layer.z
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Everything painted in this [`Painter`] will be clipped against this.
|
/// Everything painted in this [`Painter`] will be clipped against this.
|
||||||
|
@ -153,9 +184,9 @@ impl Painter {
|
||||||
|
|
||||||
/// ## Low level
|
/// ## Low level
|
||||||
impl Painter {
|
impl Painter {
|
||||||
#[inline]
|
|
||||||
fn paint_list<R>(&self, writer: impl FnOnce(&mut PaintList) -> R) -> R {
|
fn paint_list<R>(&self, writer: impl FnOnce(&mut PaintList) -> R) -> R {
|
||||||
self.ctx.graphics_mut(|g| writer(g.list(self.layer_id)))
|
self.ctx
|
||||||
|
.graphics_mut(|g| writer(g.list(self.z_layer.area_layer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_shape(&self, shape: &mut Shape) {
|
fn transform_shape(&self, shape: &mut Shape) {
|
||||||
|
@ -164,16 +195,28 @@ impl Painter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_to_paint_list(&self, shape: Shape) -> ShapeIdx {
|
||||||
|
self.paint_list(|l| l.add_at_z(self.clip_rect, shape, self.z_layer.z))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_paint_list(&self, shapes: impl IntoIterator<Item = Shape>) {
|
||||||
|
self.paint_list(|l| l.extend_at_z(self.clip_rect, shapes, self.z_layer.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_shape_in_paint_list(&self, idx: ShapeIdx, shape: Shape) {
|
||||||
|
self.paint_list(|l| l.set(idx, self.clip_rect, shape));
|
||||||
|
}
|
||||||
|
|
||||||
/// It is up to the caller to make sure there is room for this.
|
/// It is up to the caller to make sure there is room for this.
|
||||||
/// Can be used for free painting.
|
/// Can be used for free painting.
|
||||||
/// NOTE: all coordinates are screen coordinates!
|
/// NOTE: all coordinates are screen coordinates!
|
||||||
pub fn add(&self, shape: impl Into<Shape>) -> ShapeIdx {
|
pub fn add(&self, shape: impl Into<Shape>) -> ShapeIdx {
|
||||||
if self.fade_to_color == Some(Color32::TRANSPARENT) {
|
if self.fade_to_color == Some(Color32::TRANSPARENT) {
|
||||||
self.paint_list(|l| l.add(self.clip_rect, Shape::Noop))
|
self.add_to_paint_list(Shape::Noop)
|
||||||
} else {
|
} else {
|
||||||
let mut shape = shape.into();
|
let mut shape = shape.into();
|
||||||
self.transform_shape(&mut shape);
|
self.transform_shape(&mut shape);
|
||||||
self.paint_list(|l| l.add(self.clip_rect, shape))
|
self.add_to_paint_list(shape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,9 +232,9 @@ impl Painter {
|
||||||
self.transform_shape(&mut shape);
|
self.transform_shape(&mut shape);
|
||||||
shape
|
shape
|
||||||
});
|
});
|
||||||
self.paint_list(|l| l.extend(self.clip_rect, shapes));
|
self.extend_paint_list(shapes);
|
||||||
} else {
|
} else {
|
||||||
self.paint_list(|l| l.extend(self.clip_rect, shapes));
|
self.extend_paint_list(shapes);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +245,7 @@ impl Painter {
|
||||||
}
|
}
|
||||||
let mut shape = shape.into();
|
let mut shape = shape.into();
|
||||||
self.transform_shape(&mut shape);
|
self.transform_shape(&mut shape);
|
||||||
self.paint_list(|l| l.set(idx, self.clip_rect, shape));
|
self.set_shape_in_paint_list(idx, shape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
emath::{Align, Pos2, Rect, Vec2},
|
emath::{Align, Pos2, Rect, Vec2},
|
||||||
menu, Context, CursorIcon, Id, LayerId, PointerButton, Sense, Ui, WidgetText,
|
menu, AreaLayerId, Context, CursorIcon, Id, PointerButton, Sense, Ui, WidgetText,
|
||||||
NUM_POINTER_BUTTONS,
|
NUM_POINTER_BUTTONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ pub struct Response {
|
||||||
|
|
||||||
// IN:
|
// IN:
|
||||||
/// Which layer the widget is part of.
|
/// Which layer the widget is part of.
|
||||||
pub layer_id: LayerId,
|
pub layer_id: AreaLayerId,
|
||||||
|
|
||||||
/// The [`Id`] of the widget/area this response pertains.
|
/// The [`Id`] of the widget/area this response pertains.
|
||||||
pub id: Id,
|
pub id: Id,
|
||||||
|
|
|
@ -6,8 +6,8 @@ use std::sync::Arc;
|
||||||
use epaint::mutex::RwLock;
|
use epaint::mutex::RwLock;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
containers::*, ecolor::*, epaint::text::Fonts, layout::*, menu::MenuState, placer::Placer,
|
containers::*, ecolor::*, epaint::text::Fonts, layers::ZLayer, layout::*, menu::MenuState,
|
||||||
util::IdTypeMap, widgets::*, *,
|
placer::Placer, util::IdTypeMap, widgets::*, *,
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -71,7 +71,13 @@ impl Ui {
|
||||||
///
|
///
|
||||||
/// Normally you would not use this directly, but instead use
|
/// Normally you would not use this directly, but instead use
|
||||||
/// [`SidePanel`], [`TopBottomPanel`], [`CentralPanel`], [`Window`] or [`Area`].
|
/// [`SidePanel`], [`TopBottomPanel`], [`CentralPanel`], [`Window`] or [`Area`].
|
||||||
pub fn new(ctx: Context, layer_id: LayerId, id: Id, max_rect: Rect, clip_rect: Rect) -> Self {
|
pub fn new(
|
||||||
|
ctx: Context,
|
||||||
|
layer_id: AreaLayerId,
|
||||||
|
id: Id,
|
||||||
|
max_rect: Rect,
|
||||||
|
clip_rect: Rect,
|
||||||
|
) -> Self {
|
||||||
let style = ctx.style();
|
let style = ctx.style();
|
||||||
Ui {
|
Ui {
|
||||||
id,
|
id,
|
||||||
|
@ -310,8 +316,19 @@ impl Ui {
|
||||||
|
|
||||||
/// Use this to paint stuff within this [`Ui`].
|
/// Use this to paint stuff within this [`Ui`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn layer_id(&self) -> LayerId {
|
pub fn area_layer_id(&self) -> AreaLayerId {
|
||||||
self.painter().layer_id()
|
self.painter().area_layer_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated = "Rename area_layer_id"]
|
||||||
|
#[inline]
|
||||||
|
pub fn layer_id(&self) -> AreaLayerId {
|
||||||
|
self.area_layer_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn z_layer(&self) -> ZLayer {
|
||||||
|
self.painter().z_layer()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The height of text of this text style
|
/// The height of text of this text style
|
||||||
|
@ -616,7 +633,7 @@ impl Ui {
|
||||||
self.ctx().interact(
|
self.ctx().interact(
|
||||||
self.clip_rect(),
|
self.clip_rect(),
|
||||||
self.spacing().item_spacing,
|
self.spacing().item_spacing,
|
||||||
self.layer_id(),
|
self.z_layer(),
|
||||||
id,
|
id,
|
||||||
rect,
|
rect,
|
||||||
sense,
|
sense,
|
||||||
|
@ -636,8 +653,14 @@ impl Ui {
|
||||||
id: Id,
|
id: Id,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
self.ctx()
|
self.ctx().interact_with_hovered(
|
||||||
.interact_with_hovered(self.layer_id(), id, rect, sense, self.enabled, hovered)
|
self.area_layer_id(),
|
||||||
|
id,
|
||||||
|
rect,
|
||||||
|
sense,
|
||||||
|
self.enabled,
|
||||||
|
hovered,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the pointer (mouse/touch) above this rectangle in this [`Ui`]?
|
/// Is the pointer (mouse/touch) above this rectangle in this [`Ui`]?
|
||||||
|
@ -646,7 +669,7 @@ impl Ui {
|
||||||
/// if this [`Ui`] is behind some other window, this will always return `false`.
|
/// if this [`Ui`] is behind some other window, this will always return `false`.
|
||||||
pub fn rect_contains_pointer(&self, rect: Rect) -> bool {
|
pub fn rect_contains_pointer(&self, rect: Rect) -> bool {
|
||||||
self.ctx()
|
self.ctx()
|
||||||
.rect_contains_pointer(self.layer_id(), self.clip_rect().intersect(rect))
|
.rect_contains_pointer(self.area_layer_id(), self.clip_rect().intersect(rect))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the pointer (mouse/touch) above this [`Ui`]?
|
/// Is the pointer (mouse/touch) above this [`Ui`]?
|
||||||
|
@ -942,7 +965,7 @@ impl Ui {
|
||||||
pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) {
|
pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) {
|
||||||
let response = self.allocate_response(desired_size, sense);
|
let response = self.allocate_response(desired_size, sense);
|
||||||
let clip_rect = self.clip_rect().intersect(response.rect); // Make sure we don't paint out of bounds
|
let clip_rect = self.clip_rect().intersect(response.rect); // Make sure we don't paint out of bounds
|
||||||
let painter = Painter::new(self.ctx().clone(), self.layer_id(), clip_rect);
|
let painter = Painter::new(self.ctx().clone(), self.area_layer_id(), clip_rect);
|
||||||
(response, painter)
|
(response, painter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1734,10 +1757,10 @@ impl Ui {
|
||||||
InnerResponse::new(ret, response)
|
InnerResponse::new(ret, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Redirect shapes to another paint layer.
|
/// Redirect shapes to another area layer.
|
||||||
pub fn with_layer_id<R>(
|
pub fn with_layer_id<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
layer_id: LayerId,
|
layer_id: AreaLayerId,
|
||||||
add_contents: impl FnOnce(&mut Self) -> R,
|
add_contents: impl FnOnce(&mut Self) -> R,
|
||||||
) -> InnerResponse<R> {
|
) -> InnerResponse<R> {
|
||||||
self.scope(|ui| {
|
self.scope(|ui| {
|
||||||
|
@ -1746,6 +1769,33 @@ impl Ui {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set z-index and layer id at the same time
|
||||||
|
pub fn with_z_layer<R>(
|
||||||
|
&mut self,
|
||||||
|
layer: ZLayer,
|
||||||
|
add_contents: impl FnOnce(&mut Self) -> R,
|
||||||
|
) -> InnerResponse<R> {
|
||||||
|
self.scope(|ui| {
|
||||||
|
ui.painter.set_layer(layer);
|
||||||
|
add_contents(ui)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set z-index for all shapes drawn on the current layer
|
||||||
|
///
|
||||||
|
/// Note that this z-index is for this layer only. The draw order of area
|
||||||
|
/// layers takes precedence over this z-index.
|
||||||
|
pub fn with_z<R>(
|
||||||
|
&mut self,
|
||||||
|
z: layers::ZOrder,
|
||||||
|
add_contents: impl FnOnce(&mut Self) -> R,
|
||||||
|
) -> InnerResponse<R> {
|
||||||
|
self.scope(|ui| {
|
||||||
|
ui.painter.set_z(z);
|
||||||
|
add_contents(ui)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// A [`CollapsingHeader`] that starts out collapsed.
|
/// A [`CollapsingHeader`] that starts out collapsed.
|
||||||
pub fn collapsing<R>(
|
pub fn collapsing<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl FractalClock {
|
||||||
|
|
||||||
let painter = Painter::new(
|
let painter = Painter::new(
|
||||||
ui.ctx().clone(),
|
ui.ctx().clone(),
|
||||||
ui.layer_id(),
|
ui.area_layer_id(),
|
||||||
ui.available_rect_before_wrap(),
|
ui.available_rect_before_wrap(),
|
||||||
);
|
);
|
||||||
self.paint(&painter);
|
self.paint(&painter);
|
||||||
|
|
|
@ -355,8 +355,10 @@ impl WrapApp {
|
||||||
text
|
text
|
||||||
});
|
});
|
||||||
|
|
||||||
let painter =
|
let painter = ctx.layer_painter(AreaLayerId::new(
|
||||||
ctx.layer_painter(LayerId::new(Order::Foreground, Id::new("file_drop_target")));
|
Order::Foreground,
|
||||||
|
Id::new("file_drop_target"),
|
||||||
|
));
|
||||||
|
|
||||||
let screen_rect = ctx.screen_rect();
|
let screen_rect = ctx.screen_rect();
|
||||||
painter.rect_filled(screen_rect, 0.0, Color32::from_black_alpha(192));
|
painter.rect_filled(screen_rect, 0.0, Color32::from_black_alpha(192));
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub fn drag_source(ui: &mut Ui, id: Id, body: impl FnOnce(&mut Ui)) {
|
||||||
ui.ctx().set_cursor_icon(CursorIcon::Grabbing);
|
ui.ctx().set_cursor_icon(CursorIcon::Grabbing);
|
||||||
|
|
||||||
// Paint the body to a new layer:
|
// Paint the body to a new layer:
|
||||||
let layer_id = LayerId::new(Order::Tooltip, id);
|
let layer_id = AreaLayerId::new(Order::Tooltip, id);
|
||||||
let response = ui.with_layer_id(layer_id, body).response;
|
let response = ui.with_layer_id(layer_id, body).response;
|
||||||
|
|
||||||
// Now we move the visuals of the body to where the mouse is.
|
// Now we move the visuals of the body to where the mouse is.
|
||||||
|
|
|
@ -93,8 +93,10 @@ fn preview_files_being_dropped(ctx: &egui::Context) {
|
||||||
text
|
text
|
||||||
});
|
});
|
||||||
|
|
||||||
let painter =
|
let painter = ctx.layer_painter(AreaLayerId::new(
|
||||||
ctx.layer_painter(LayerId::new(Order::Foreground, Id::new("file_drop_target")));
|
Order::Foreground,
|
||||||
|
Id::new("file_drop_target"),
|
||||||
|
));
|
||||||
|
|
||||||
let screen_rect = ctx.screen_rect();
|
let screen_rect = ctx.screen_rect();
|
||||||
painter.rect_filled(screen_rect, 0.0, Color32::from_black_alpha(192));
|
painter.rect_filled(screen_rect, 0.0, Color32::from_black_alpha(192));
|
||||||
|
|
16
examples/z_order/Cargo.toml
Normal file
16
examples/z_order/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "z_order"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Max Stoumen <max@mxs.dev>"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.65"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
eframe = { path = "../../crates/eframe", features = [
|
||||||
|
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||||
|
] }
|
||||||
|
log = "0.4.17"
|
||||||
|
tracing-subscriber = "0.3"
|
7
examples/z_order/README.md
Normal file
7
examples/z_order/README.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Example for how to set Z-order for drawing and interaction.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo run -p z_order
|
||||||
|
```
|
||||||
|
|
||||||
|

|
BIN
examples/z_order/screenshot.png
Normal file
BIN
examples/z_order/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
82
examples/z_order/src/main.rs
Normal file
82
examples/z_order/src/main.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
|
use eframe::{
|
||||||
|
egui::{self, layers::ZOrder, Sense, Ui},
|
||||||
|
epaint::{Color32, Rect, Rounding, Vec2},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), eframe::Error> {
|
||||||
|
// Log to stdout (if you run with `RUST_LOG=debug`).
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
let options = eframe::NativeOptions {
|
||||||
|
initial_window_size: Some(egui::vec2(220.0, 150.0)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
eframe::run_native(
|
||||||
|
"Z Order Test",
|
||||||
|
options,
|
||||||
|
Box::new(|_cc| Box::new(MyApp::default())),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct MyApp {}
|
||||||
|
|
||||||
|
impl eframe::App for MyApp {
|
||||||
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
ui.label("The left example should show blue over green. The right should show green over blue.");
|
||||||
|
|
||||||
|
egui::Frame::default()
|
||||||
|
.fill(ui.style().visuals.window_fill)
|
||||||
|
.inner_margin(10.0)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
const SIZE: Vec2 = Vec2::new(50.0, 50.0);
|
||||||
|
const DELTA: Vec2 = Vec2::new(20.0, 20.0);
|
||||||
|
|
||||||
|
fn draw_squares(
|
||||||
|
ui: &mut Ui,
|
||||||
|
shift: Vec2,
|
||||||
|
order1: ZOrder,
|
||||||
|
order2: ZOrder,
|
||||||
|
) {
|
||||||
|
let pos = ui.max_rect().left_top();
|
||||||
|
|
||||||
|
ui.with_z(order1, |ui| {
|
||||||
|
let response = ui.allocate_rect(
|
||||||
|
Rect::from_min_size(pos + shift, SIZE),
|
||||||
|
Sense::click(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let painter = ui.painter_at(response.rect);
|
||||||
|
painter.rect_filled(response.rect, Rounding::none(), Color32::GREEN);
|
||||||
|
|
||||||
|
if response.clicked() {
|
||||||
|
log::info!("Clicked green");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.with_z(order2, |ui| {
|
||||||
|
let response = ui.allocate_rect(
|
||||||
|
Rect::from_min_size(pos + DELTA + shift, SIZE),
|
||||||
|
Sense::click(),
|
||||||
|
);
|
||||||
|
let painter = ui.painter_at(response.rect);
|
||||||
|
painter.rect_filled(response.rect, Rounding::none(), Color32::BLUE);
|
||||||
|
|
||||||
|
if response.clicked() {
|
||||||
|
log::info!("Clicked blue");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let base = ZOrder::BASE;
|
||||||
|
let above = base.in_front();
|
||||||
|
|
||||||
|
draw_squares(ui, Vec2::new(0.0, 0.0), base, above);
|
||||||
|
draw_squares(ui, Vec2::new(100.0, 0.0), above, base);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue