1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::*;
use epaint::ahash;
/// State that is collected during a frame and then cleared.
/// Short-term (single frame) memory.
#[derive(Clone)]
pub(crate) struct FrameState {
/// All `Id`s that were used this frame.
/// Used to debug `Id` clashes of widgets.
pub(crate) used_ids: ahash::AHashMap<Id, Pos2>,
/// Starts off as the screen_rect, shrinks as panels are added.
/// The `CentralPanel` does not change this.
/// This is the area available to Window's.
pub(crate) available_rect: Rect,
/// Starts off as the screen_rect, shrinks as panels are added.
/// The `CentralPanel` retracts from this.
pub(crate) unused_rect: Rect,
/// How much space is used by panels.
pub(crate) used_by_panels: Rect,
/// If a tooltip has been shown this frame, where was it?
/// This is used to prevent multiple tooltips to cover each other.
/// Initialized to `None` at the start of each frame.
pub(crate) tooltip_rect: Option<(Id, Rect)>,
/// Cleared by the first `ScrollArea` that makes use of it.
pub(crate) scroll_delta: Vec2,
pub(crate) scroll_target: Option<(f32, Align)>,
}
impl Default for FrameState {
fn default() -> Self {
Self {
used_ids: Default::default(),
available_rect: Rect::NAN,
unused_rect: Rect::NAN,
used_by_panels: Rect::NAN,
tooltip_rect: None,
scroll_delta: Vec2::ZERO,
scroll_target: None,
}
}
}
impl FrameState {
pub(crate) fn begin_frame(&mut self, input: &InputState) {
let Self {
used_ids,
available_rect,
unused_rect,
used_by_panels,
tooltip_rect,
scroll_delta,
scroll_target,
} = self;
used_ids.clear();
*available_rect = input.screen_rect();
*unused_rect = input.screen_rect();
*used_by_panels = Rect::NOTHING;
*tooltip_rect = None;
*scroll_delta = input.scroll_delta;
*scroll_target = None;
}
/// 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(crate) fn available_rect(&self) -> Rect {
debug_assert!(
self.available_rect.is_finite(),
"Called `available_rect()` before `CtxRef::begin_frame()`"
);
self.available_rect
}
/// Shrink `available_rect`.
pub(crate) fn allocate_left_panel(&mut self, panel_rect: Rect) {
debug_assert!(
panel_rect.min.distance(self.available_rect.min) < 0.1,
"Mismatching left panel. 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.distance(self.available_rect.min) < 0.1,
"Mismatching top panel. 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 allow 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);
}
}