mirror of
https://github.com/storytold/craft-libs.git
synced 2026-10-31 07:39:23 +00:00
docking: content that fills its body floats at floating_size or 320
A panel body that reaches the bottom of its rect has no height of its own, so a floated panel or group falls back to floating_size, else 320 points, instead of the whole frame height. A body in a window fitted to its recorded height keeps that height. Panels leaving a frame fit their content like panels leaving a dock.
This commit is contained in:
1 parent
b94df6c8b6
commit
30cebdc0f2
5 files changed
+63
-16
No files matched your search
@@ -54,10 +54,16 @@ struct TestContent {
|
||||
whole_group: bool,
|
||||
/// Height every body takes; `None` draws a one-line label.
|
||||
body_height: Option<f32>,
|
||||
/// Every body takes its whole rect.
|
||||
fill: bool,
|
||||
}
|
||||
|
||||
impl DockContent<u32> for TestContent {
|
||||
fn body(&mut self, ui: &mut egui::Ui, _: &u32) {
|
||||
if self.fill {
|
||||
ui.allocate_rect(ui.max_rect(), egui::Sense::hover());
|
||||
return;
|
||||
}
|
||||
match self.body_height {
|
||||
Some(height) => _ = ui.allocate_exact_size(vec2(10.0, height), egui::Sense::hover()),
|
||||
None => _ = ui.label("Body"),
|
||||
@@ -593,6 +599,27 @@ fn a_short_docked_panel_floats_at_its_content_height_up_to_its_floating_size() {
|
||||
assert_eq!(*height, title + strip + 150.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_panel_that_fills_its_frame_floats_at_its_floating_size_or_320() {
|
||||
let float = |floating_size: Option<Vec2>| {
|
||||
let content = TestContent { fill: true, floating_size, ..Default::default() };
|
||||
let mut d = Driver::with(frames(), content, Rect::from_min_size(pos2(0.0, 0.0), vec2(600.0, 600.0)));
|
||||
let target = pos2(400.0, 300.0);
|
||||
d.hold(d.tab(3).center(), target);
|
||||
d.modifiers = Modifiers::COMMAND;
|
||||
let out = d.step(vec![button(target, false)]);
|
||||
out.actions
|
||||
.iter()
|
||||
.find_map(|a| match a {
|
||||
Action::Float { panel: 3, rect } => Some(rect[3]),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_else(|| panic!("{:?}", out.actions))
|
||||
};
|
||||
assert_eq!(float(None), 320.0);
|
||||
assert_eq!(float(Some(vec2(300.0, 400.0))), 400.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_focus_follows_only_the_users_input() {
|
||||
let mut d = Driver::new(docked());
|
||||
|
||||
@@ -218,7 +218,7 @@ impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
|
||||
ui.new_child(UiBuilder::new().id(self.id.with(("body", panel))).max_rect(rect).layout(egui::Layout::top_down(egui::Align::Min)));
|
||||
child.set_clip_rect(rect.intersect(ui.clip_rect()));
|
||||
self.content.body(&mut child, panel);
|
||||
self.float_space.record_content(panel.clone(), child.min_rect().height());
|
||||
self.float_space.record_content(panel.clone(), child.min_rect().height(), rect.height());
|
||||
// Any button: a canvas pans with the middle button and opens menus with the secondary.
|
||||
if child.rect_contains_pointer(rect) && child.input(|i| i.pointer.any_pressed()) {
|
||||
self.output.focused = Some(panel.clone());
|
||||
|
||||
@@ -279,16 +279,21 @@ impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
|
||||
}
|
||||
|
||||
/// Size of a panel floated by a drag or the Float menu: the host's floating size, else the
|
||||
/// source size within the panel limits. Out of a dock column, or with a floating size, the
|
||||
/// height fits the content the panel last drew, up to that height (320 in a dock).
|
||||
/// source size within the panel limits. Out of a dock or frame, or with a floating size, the
|
||||
/// height fits the content the panel last drew, up to that height (else 320). Content that
|
||||
/// filled its body floats at that height.
|
||||
pub(super) fn float_size(&self, panel: &P, source: Vec2) -> Vec2 {
|
||||
let chrome = self.style.title_height + self.style.tab_height;
|
||||
if let Some(size) = self.content.floating_size(panel).filter(|s| s.is_finite() && s.x > 0.0 && s.y > 0.0) {
|
||||
return vec2(size.x, self.fitted_height(panel, chrome, size.y).unwrap_or(size.y));
|
||||
}
|
||||
let mut size = self.iconic.float_width(panel).map_or(source, |width| vec2(width, DOCKED_FLOAT_HEIGHT));
|
||||
if matches!(self.layout.place(panel), Some(Place::Dock { .. })) {
|
||||
size.y = self.fitted_height(panel, chrome, DOCKED_FLOAT_HEIGHT).unwrap_or(size.y.min(DOCKED_FLOAT_HEIGHT));
|
||||
if matches!(self.layout.place(panel), Some(Place::Dock { .. } | Place::Node(_))) {
|
||||
size.y = match self.fitted_height(panel, chrome, DOCKED_FLOAT_HEIGHT) {
|
||||
Some(height) => height,
|
||||
None if self.float_space.filled(panel) => DOCKED_FLOAT_HEIGHT,
|
||||
None => size.y.min(DOCKED_FLOAT_HEIGHT),
|
||||
};
|
||||
}
|
||||
let limits = self.limits(panel);
|
||||
let header = vec2(0.0, self.style.tab_height);
|
||||
|
||||
@@ -255,8 +255,8 @@ pub struct FloatSpace<P> {
|
||||
pub(super) groups: Vec<(P, Vec2)>,
|
||||
pub(super) columns: Vec<(P, Vec2)>,
|
||||
/// The height each panel's content used when it was last drawn, which fits a floated group
|
||||
/// to its content.
|
||||
pub(super) contents: Vec<(P, f32)>,
|
||||
/// to its content; `None` for content that filled its body.
|
||||
pub(super) contents: Vec<(P, Option<f32>)>,
|
||||
}
|
||||
|
||||
impl<P: PartialEq> FloatSpace<P> {
|
||||
@@ -275,9 +275,16 @@ impl<P: PartialEq> FloatSpace<P> {
|
||||
}
|
||||
|
||||
impl<P: PartialEq> FloatSpace<P> {
|
||||
pub(super) fn record_content(&mut self, panel: P, height: f32) {
|
||||
let height = if height.is_finite() { height.max(0.0) } else { 0.0 };
|
||||
match self.contents.iter_mut().find(|(p, _)| *p == panel) {
|
||||
/// Record the height `panel`'s content used in a body `available` tall. Content that
|
||||
/// reaches the body's bottom filled it and has no height of its own, unless the body was
|
||||
/// sized to the height recorded before (a fitted window).
|
||||
pub(super) fn record_content(&mut self, panel: P, used: f32, available: f32) {
|
||||
const TOLERANCE: f32 = 1.0;
|
||||
let used = if used.is_finite() { used.max(0.0) } else { 0.0 };
|
||||
let recorded = self.contents.iter_mut().find(|(p, _)| *p == panel);
|
||||
let fitted = recorded.as_ref().and_then(|(_, height)| *height).is_some_and(|height| height >= available - TOLERANCE);
|
||||
let height = (used < available - TOLERANCE || fitted).then_some(used);
|
||||
match recorded {
|
||||
Some((_, recorded)) => *recorded = height,
|
||||
None => self.contents.push((panel, height)),
|
||||
}
|
||||
@@ -299,8 +306,13 @@ impl<P: PartialEq> FloatSpace<P> {
|
||||
Self::find(&self.columns, panel)
|
||||
}
|
||||
|
||||
/// Whether `panel`'s content filled its body when it was last drawn.
|
||||
pub(super) fn filled(&self, panel: &P) -> bool {
|
||||
self.contents.iter().any(|(p, height)| p == panel && height.is_none())
|
||||
}
|
||||
|
||||
pub(super) fn content(&self, panel: &P) -> Option<f32> {
|
||||
self.contents.iter().find(|(p, _)| p == panel).map(|(_, height)| *height)
|
||||
self.contents.iter().find(|(p, _)| p == panel).and_then(|(_, height)| *height)
|
||||
}
|
||||
|
||||
/// The first record wins: an iconic panel is recorded at its icon before its flyout.
|
||||
@@ -513,8 +525,9 @@ pub trait DockContent<P> {
|
||||
/// Preferred floating size, independent of the current dock geometry: the width of a
|
||||
/// floated panel and the most height it takes. A floated panel or group, and a flyout, fit
|
||||
/// their height to the content the active panel last drew (at least 120 points), up to this
|
||||
/// height, or up to 320 out of a dock when this is `None`. A rect a command gives and a
|
||||
/// window the user resized keep their size.
|
||||
/// height, or up to 320 out of a dock when this is `None`. Content that filled its body
|
||||
/// takes this height, else 320. A rect a command gives and a window the user resized keep
|
||||
/// their size.
|
||||
fn floating_size(&self, _panel: &P) -> Option<Vec2> {
|
||||
None
|
||||
}
|
||||
|
||||
+5
-3
@@ -156,9 +156,11 @@ the bar itself shrinks it. A tab dropped on the "…" button goes to the end of
|
||||
A panel or group floated by a drag, a menu or a command without a rect takes its content height:
|
||||
the title bar, the tab strip and the height the active panel's content used when it was last
|
||||
drawn (the content ui's `min_rect`), at least 120 points. The most it takes is the height of
|
||||
`DockContent::floating_size`, or 320 points for a panel or group leaving a dock. A short panel
|
||||
therefore floats as a short window. A panel's width is its `floating_size` width, else its docked
|
||||
width; a group keeps its docked width.
|
||||
`DockContent::floating_size`, or 320 points for a panel leaving a dock or frame and a group
|
||||
leaving a dock. A short panel therefore floats as a short window. Content that reaches the bottom
|
||||
of its body (a panel that allocates its whole rect) has no height of its own: it floats at the
|
||||
`floating_size` height, else at 320 points. A panel's width is its `floating_size` width, else
|
||||
its docked width; a group keeps its docked width.
|
||||
A flyout fits its content the same way, without the title bar.
|
||||
|
||||
- A panel the area has not drawn floats at the `floating_size` height, else the docked height
|
||||
|
||||
Reference in new issue
Block a user