A Window
may now cover an existing CentralPanel
This commit is contained in:
parent
82a3997188
commit
58f36eb6ef
3 changed files with 96 additions and 65 deletions
|
@ -22,10 +22,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
* Slight tweak of the default `Style` and font sizes.
|
* Slight tweak of the default `Style` and font sizes.
|
||||||
* `SidePanel::left` and `TopPanel::top` now takes `impl Hash` as first argument.
|
* `SidePanel::left` and `TopPanel::top` now takes `impl Hash` as first argument.
|
||||||
|
* A `Window` may now cover an existing `CentralPanel`.
|
||||||
* `ui.image` now takes `impl Into<Vec2>` as a `size` argument.
|
* `ui.image` now takes `impl Into<Vec2>` as a `size` argument.
|
||||||
* Made some more fields of `RawInput` optional.
|
* Made some more fields of `RawInput` optional.
|
||||||
* `Slider` and `DragValue` uses fewer decimals by default. See the full precision by hovering over the value.
|
* `Slider` and `DragValue` uses fewer decimals by default. See the full precision by hovering over the value.
|
||||||
* `egui::App`: added `fn name(&self)` and `fn clear_color(&self)`
|
* `egui::App`: added `fn name(&self)` and `fn clear_color(&self)`.
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
* Deprecated `RawInput::screen_size` - use `RawInput::screen_rect` instead.
|
* Deprecated `RawInput::screen_size` - use `RawInput::screen_rect` instead.
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl SidePanel {
|
||||||
let panel_rect = panel_ui.min_rect();
|
let panel_rect = panel_ui.min_rect();
|
||||||
let response = panel_ui.interact_hover(panel_rect);
|
let response = panel_ui.interact_hover(panel_rect);
|
||||||
|
|
||||||
ctx.allocate_left_panel(panel_rect);
|
ctx.frame_state().allocate_left_panel(panel_rect);
|
||||||
|
|
||||||
(r, response)
|
(r, response)
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ impl TopPanel {
|
||||||
let panel_rect = panel_ui.min_rect();
|
let panel_rect = panel_ui.min_rect();
|
||||||
let response = panel_ui.interact_hover(panel_rect);
|
let response = panel_ui.interact_hover(panel_rect);
|
||||||
|
|
||||||
ctx.allocate_top_panel(panel_rect);
|
ctx.frame_state().allocate_top_panel(panel_rect);
|
||||||
|
|
||||||
(r, response)
|
(r, response)
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ impl CentralPanel {
|
||||||
let panel_rect = panel_ui.min_rect();
|
let panel_rect = panel_ui.min_rect();
|
||||||
let response = panel_ui.interact_hover(panel_rect);
|
let response = panel_ui.interact_hover(panel_rect);
|
||||||
|
|
||||||
ctx.allocate_central_panel(panel_rect);
|
ctx.frame_state().allocate_central_panel(panel_rect);
|
||||||
|
|
||||||
(r, response)
|
(r, response)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,7 @@ use crate::{
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
// ----------------------------------------------------------------------------
|
||||||
struct SliceStats<T>(usize, std::marker::PhantomData<T>);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct Options {
|
struct Options {
|
||||||
|
@ -23,6 +22,85 @@ struct Options {
|
||||||
font_definitions: FontDefinitions,
|
font_definitions: FontDefinitions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// State that is collected during a frame and then cleared
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct FrameState {
|
||||||
|
/// Starts off as the screen_rect, shrinks as panels are added.
|
||||||
|
/// The `CentralPanel` does not change this.
|
||||||
|
/// This is the area avilable to Window's.
|
||||||
|
available_rect: Rect,
|
||||||
|
|
||||||
|
/// Starts off as the screen_rect, shrinks as panels are added.
|
||||||
|
/// The `CentralPanel` retracts from this.
|
||||||
|
unused_rect: Rect,
|
||||||
|
|
||||||
|
/// How much space is used by panels.
|
||||||
|
used_by_panels: Rect,
|
||||||
|
// TODO: move some things from `Memory` to here
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FrameState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
available_rect: Rect::invalid(),
|
||||||
|
unused_rect: Rect::invalid(),
|
||||||
|
used_by_panels: Rect::invalid(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameState {
|
||||||
|
pub fn begin_frame(&mut self, input: &InputState) {
|
||||||
|
self.available_rect = input.screen_rect();
|
||||||
|
self.unused_rect = input.screen_rect();
|
||||||
|
self.used_by_panels = Rect::nothing();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// How much space is still available after panels has been added.
|
||||||
|
/// This is the "background" area, what Egui doesn't cover with panels (but may cover with windows).
|
||||||
|
/// This is also the area to which windows are constrained.
|
||||||
|
pub fn available_rect(&self) -> Rect {
|
||||||
|
debug_assert!(
|
||||||
|
self.available_rect.is_finite(),
|
||||||
|
"Called `available_rect()` before `begin_frame()`"
|
||||||
|
);
|
||||||
|
self.available_rect
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shrink `available_rect`.
|
||||||
|
pub(crate) fn allocate_left_panel(&mut self, panel_rect: Rect) {
|
||||||
|
debug_assert!(
|
||||||
|
panel_rect.min == self.available_rect.min,
|
||||||
|
"Mismatching panels. You must not create a panel from within another panel."
|
||||||
|
);
|
||||||
|
self.available_rect.min.x = panel_rect.max.x;
|
||||||
|
self.unused_rect.min.x = panel_rect.max.x;
|
||||||
|
self.used_by_panels = self.used_by_panels.union(panel_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shrink `available_rect`.
|
||||||
|
pub(crate) fn allocate_top_panel(&mut self, panel_rect: Rect) {
|
||||||
|
debug_assert!(
|
||||||
|
panel_rect.min == self.available_rect.min,
|
||||||
|
"Mismatching panels. You must not create a panel from within another panel."
|
||||||
|
);
|
||||||
|
self.available_rect.min.y = panel_rect.max.y;
|
||||||
|
self.unused_rect.min.y = panel_rect.max.y;
|
||||||
|
self.used_by_panels = self.used_by_panels.union(panel_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn allocate_central_panel(&mut self, panel_rect: Rect) {
|
||||||
|
// Note: we do not shrink `available_rect`, because
|
||||||
|
// we alllow windows to cover the CentralPanel.
|
||||||
|
self.unused_rect = Rect::nothing(); // Nothing left unused after this
|
||||||
|
self.used_by_panels = self.used_by_panels.union(panel_rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Thi is the first thing you need when working with Egui.
|
/// Thi is the first thing you need when working with Egui.
|
||||||
///
|
///
|
||||||
/// Contains the input state, memory, options and output.
|
/// Contains the input state, memory, options and output.
|
||||||
|
@ -40,11 +118,8 @@ pub struct Context {
|
||||||
|
|
||||||
input: InputState,
|
input: InputState,
|
||||||
|
|
||||||
/// Starts off as the screen_rect, shrinks as panels are added.
|
/// State that is collected during a frame and then cleared
|
||||||
/// Becomes `Rect::nothing()` after a `CentralPanel` is finished.
|
frame_state: Mutex<FrameState>,
|
||||||
available_rect: Mutex<Option<Rect>>,
|
|
||||||
/// How much space is used by panels.
|
|
||||||
used_by_panels: Mutex<Option<Rect>>,
|
|
||||||
|
|
||||||
// The output of a frame:
|
// The output of a frame:
|
||||||
graphics: Mutex<GraphicLayers>,
|
graphics: Mutex<GraphicLayers>,
|
||||||
|
@ -64,8 +139,7 @@ impl Clone for Context {
|
||||||
memory: self.memory.clone(),
|
memory: self.memory.clone(),
|
||||||
animation_manager: self.animation_manager.clone(),
|
animation_manager: self.animation_manager.clone(),
|
||||||
input: self.input.clone(),
|
input: self.input.clone(),
|
||||||
available_rect: self.available_rect.clone(),
|
frame_state: self.frame_state.clone(),
|
||||||
used_by_panels: self.used_by_panels.clone(),
|
|
||||||
graphics: self.graphics.clone(),
|
graphics: self.graphics.clone(),
|
||||||
output: self.output.clone(),
|
output: self.output.clone(),
|
||||||
paint_stats: self.paint_stats.clone(),
|
paint_stats: self.paint_stats.clone(),
|
||||||
|
@ -88,9 +162,7 @@ impl Context {
|
||||||
/// This is the "background" area, what Egui doesn't cover with panels (but may cover with windows).
|
/// This is the "background" area, what Egui doesn't cover with panels (but may cover with windows).
|
||||||
/// This is also the area to which windows are constrained.
|
/// This is also the area to which windows are constrained.
|
||||||
pub fn available_rect(&self) -> Rect {
|
pub fn available_rect(&self) -> Rect {
|
||||||
self.available_rect
|
self.frame_state.lock().available_rect()
|
||||||
.lock()
|
|
||||||
.expect("Called `available_rect()` before `begin_frame()`")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn memory(&self) -> MutexGuard<'_, Memory> {
|
pub fn memory(&self) -> MutexGuard<'_, Memory> {
|
||||||
|
@ -105,6 +177,10 @@ impl Context {
|
||||||
self.output.lock()
|
self.output.lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn frame_state(&self) -> MutexGuard<'_, FrameState> {
|
||||||
|
self.frame_state.lock()
|
||||||
|
}
|
||||||
|
|
||||||
/// Call this if there is need to repaint the UI, i.e. if you are showing an animation.
|
/// Call this if there is need to repaint the UI, i.e. if you are showing an animation.
|
||||||
/// If this is called at least once in a frame, then there will be another frame right after this.
|
/// If this is called at least once in a frame, then there will be another frame right after this.
|
||||||
/// Call as many times as you wish, only one repaint will be issued.
|
/// Call as many times as you wish, only one repaint will be issued.
|
||||||
|
@ -225,8 +301,7 @@ impl Context {
|
||||||
self.memory().begin_frame(&self.input, &new_raw_input);
|
self.memory().begin_frame(&self.input, &new_raw_input);
|
||||||
|
|
||||||
self.input = std::mem::take(&mut self.input).begin_frame(new_raw_input);
|
self.input = std::mem::take(&mut self.input).begin_frame(new_raw_input);
|
||||||
*self.available_rect.lock() = Some(self.input.screen_rect());
|
self.frame_state.lock().begin_frame(&self.input);
|
||||||
*self.used_by_panels.lock() = Some(Rect::nothing());
|
|
||||||
|
|
||||||
let mut font_definitions = self.options.lock().font_definitions.clone();
|
let mut font_definitions = self.options.lock().font_definitions.clone();
|
||||||
font_definitions.pixels_per_point = self.input.pixels_per_point();
|
font_definitions.pixels_per_point = self.input.pixels_per_point();
|
||||||
|
@ -293,49 +368,9 @@ impl Context {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
/// Shrink `available_rect()`.
|
|
||||||
pub(crate) fn allocate_left_panel(&self, panel_rect: Rect) {
|
|
||||||
debug_assert!(
|
|
||||||
panel_rect.min == self.available_rect().min,
|
|
||||||
"Mismatching panels. You must not create a panel from within another panel."
|
|
||||||
);
|
|
||||||
let mut remainder = self.available_rect();
|
|
||||||
remainder.min.x = panel_rect.max.x;
|
|
||||||
*self.available_rect.lock() = Some(remainder);
|
|
||||||
self.register_panel(panel_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shrink `available_rect()`.
|
|
||||||
pub(crate) fn allocate_top_panel(&self, panel_rect: Rect) {
|
|
||||||
debug_assert!(
|
|
||||||
panel_rect.min == self.available_rect().min,
|
|
||||||
"Mismatching panels. You must not create a panel from within another panel."
|
|
||||||
);
|
|
||||||
let mut remainder = self.available_rect();
|
|
||||||
remainder.min.y = panel_rect.max.y;
|
|
||||||
*self.available_rect.lock() = Some(remainder);
|
|
||||||
self.register_panel(panel_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shrink `available_rect()`.
|
|
||||||
pub(crate) fn allocate_central_panel(&self, panel_rect: Rect) {
|
|
||||||
let mut available_rect = self.available_rect.lock();
|
|
||||||
debug_assert!(
|
|
||||||
*available_rect != Some(Rect::nothing()),
|
|
||||||
"You already created a `CentralPanel` this frame!"
|
|
||||||
);
|
|
||||||
*available_rect = Some(Rect::nothing()); // Nothing left after this
|
|
||||||
self.register_panel(panel_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_panel(&self, panel_rect: Rect) {
|
|
||||||
let mut used = self.used_by_panels.lock();
|
|
||||||
*used = Some(used.unwrap_or(Rect::nothing()).union(panel_rect));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// How much space is used by panels and windows.
|
/// How much space is used by panels and windows.
|
||||||
pub fn used_rect(&self) -> Rect {
|
pub fn used_rect(&self) -> Rect {
|
||||||
let mut used = self.used_by_panels.lock().unwrap_or(Rect::nothing());
|
let mut used = self.frame_state().used_by_panels;
|
||||||
for window in self.memory().areas.visible_windows() {
|
for window in self.memory().areas.visible_windows() {
|
||||||
used = used.union(window.rect());
|
used = used.union(window.rect());
|
||||||
}
|
}
|
||||||
|
@ -394,12 +429,7 @@ impl Context {
|
||||||
if let Some(mouse_pos) = self.input.mouse.pos {
|
if let Some(mouse_pos) = self.input.mouse.pos {
|
||||||
if let Some(layer) = self.layer_id_at(mouse_pos) {
|
if let Some(layer) = self.layer_id_at(mouse_pos) {
|
||||||
if layer.order == Order::Background {
|
if layer.order == Order::Background {
|
||||||
if let Some(available_rect) = *self.available_rect.lock() {
|
!self.frame_state().unused_rect.contains(mouse_pos)
|
||||||
// "available_rect" is the area that Egui is NOT using.
|
|
||||||
!available_rect.contains(mouse_pos)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue