mirror of
https://github.com/storytold/craft-libs.git
synced 2026-10-31 15:49:54 +00:00
docking: a floated group takes its content height
This commit is contained in:
1 parent
e1b7733a1d
commit
a014337eb2
9 files changed
+158
-28
No files matched your search
@@ -340,7 +340,8 @@ fn float_without_a_rect_takes_the_drag_size_inside_the_dock_area() {
|
||||
let float = |params: Value| parse(params).unwrap().to_actions(&workspace(), false, &space).unwrap();
|
||||
|
||||
let panel = float(json!({"command": "window.panel.float", "panel": "layers"}));
|
||||
assert_eq!(panel, vec![Action::Float { panel: s("layers"), rect: [24.0, 54.0, 200.0, 150.0] }], "floating_size, inset in the area");
|
||||
// The floating_size width, and an empty body's least fitted height under its 150 points.
|
||||
assert_eq!(panel, vec![Action::Float { panel: s("layers"), rect: [24.0, 54.0, 200.0, 120.0] }], "floating_size, inset in the area");
|
||||
let [Action::MoveGroup { to: Target::Float { rect: Some([x, y, width, height]) }, .. }] =
|
||||
float(json!({"command": "window.panel.float", "panel": "history", "group": true}))[..]
|
||||
else {
|
||||
@@ -365,7 +366,7 @@ fn float_without_a_rect_takes_the_drag_size_inside_the_dock_area() {
|
||||
let applied = parse(json!({"command": "window.panel.float", "panel": "layers"})).unwrap().to_actions(&workspace(), false, &seeded);
|
||||
assert_eq!(applied, Ok(vec![Action::Float { panel: s("layers"), rect: [24.0, 54.0, 180.0, 240.0] }]));
|
||||
let recorded = space.clone().with_panel_size(s("layers"), egui::vec2(180.0, 240.0));
|
||||
assert_eq!(float_with(&recorded, "layers"), vec![Action::Float { panel: s("layers"), rect: [24.0, 54.0, 200.0, 150.0] }]);
|
||||
assert_eq!(float_with(&recorded, "layers"), vec![Action::Float { panel: s("layers"), rect: [24.0, 54.0, 200.0, 120.0] }]);
|
||||
}
|
||||
|
||||
fn float_with(space: &FloatSpace<P>, panel: &str) -> Vec<Action<P>> {
|
||||
|
||||
@@ -50,11 +50,16 @@ struct TestContent {
|
||||
floating_size: Option<Vec2>,
|
||||
host_owned: bool,
|
||||
whole_group: bool,
|
||||
/// Height every body takes; `None` draws a one-line label.
|
||||
body_height: Option<f32>,
|
||||
}
|
||||
|
||||
impl DockContent<u32> for TestContent {
|
||||
fn body(&mut self, ui: &mut egui::Ui, _: &u32) {
|
||||
ui.label("Body");
|
||||
match self.body_height {
|
||||
Some(height) => _ = ui.allocate_exact_size(vec2(10.0, height), egui::Sense::hover()),
|
||||
None => _ = ui.label("Body"),
|
||||
}
|
||||
}
|
||||
fn logical_label(&self, panel: &u32) -> String {
|
||||
format!("Panel {panel}")
|
||||
@@ -349,12 +354,12 @@ fn group_drag_escape_focus_loss_pointer_exit_and_cancel_drag_leave_the_layout_un
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn floated_panel_uses_floating_size_not_the_column_height() {
|
||||
fn floated_panel_fits_its_content_up_to_floating_size_not_the_column_height() {
|
||||
for size in [Some(vec2(200.0, 150.0)), None] {
|
||||
let mut layout = docked();
|
||||
let Some(Node::Split { first, .. }) = &mut layout.root else { panic!() };
|
||||
**first = Node::Dock { side: Side::Start, columns: vec![Column::new(vec![Group::new(vec![2, 3], 1)], 240.0)] };
|
||||
let content = TestContent { protected: vec![0], floating_size: size, ..Default::default() };
|
||||
let content = TestContent { protected: vec![0], floating_size: size, body_height: Some(200.0), ..Default::default() };
|
||||
let mut d = Driver::with(layout, content, Rect::from_min_size(pos2(0.0, 0.0), vec2(600.0, 600.0)));
|
||||
let out = d.drag(d.tab(3).center(), pos2(700.0, 100.0));
|
||||
let Some([_, _, width, height]) = out.actions.iter().find_map(|a| match a {
|
||||
@@ -363,9 +368,10 @@ fn floated_panel_uses_floating_size_not_the_column_height() {
|
||||
}) else {
|
||||
panic!("{:?}", out.actions)
|
||||
};
|
||||
let fitted = crate::docking::chrome::TITLE_HEIGHT + d.rect("drag-bar", 2).height() + 200.0;
|
||||
match size {
|
||||
Some(size) => assert_eq!((width, height), (size.x, size.y)),
|
||||
None => assert!(height <= 320.0, "{height}"),
|
||||
None => assert_eq!(height, fitted),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -542,3 +548,43 @@ fn a_group_dragged_out_of_a_floating_stack_tears_out_alone() {
|
||||
assert_eq!(d.layout.floating[0].groups, vec![Group::new(vec![5], 0)]);
|
||||
assert_eq!(d.layout.floating[1].groups, vec![Group::new(vec![6, 7], 1)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_short_docked_panel_floats_at_its_content_height_up_to_its_floating_size() {
|
||||
let title = crate::docking::chrome::TITLE_HEIGHT;
|
||||
let float = |body: f32, floating_size: Option<Vec2>| {
|
||||
let content = TestContent { body_height: Some(body), floating_size, ..Default::default() };
|
||||
let mut d = Driver::with(docked(), content, Rect::from_min_size(pos2(0.0, 0.0), vec2(600.0, 600.0)));
|
||||
let strip = d.rect("drag-bar", 4).height();
|
||||
let recorded = crate::docking::float_space::<u32>(&d.ctx, Id::new(AREA)).unwrap().panel(&4).unwrap();
|
||||
let target = pos2(400.0, 300.0);
|
||||
d.hold(d.tab(4).center(), target);
|
||||
d.modifiers = Modifiers::COMMAND;
|
||||
let out = d.step(vec![button(target, false)]);
|
||||
let Some([_, _, width, height]) = out.actions.iter().find_map(|a| match a {
|
||||
Action::Float { panel: 4, rect } => Some(*rect),
|
||||
_ => None,
|
||||
}) else {
|
||||
panic!("{:?}", out.actions)
|
||||
};
|
||||
assert_eq!(recorded, vec2(width, height), "a command floats at the size a drag does");
|
||||
(strip, vec2(width, height))
|
||||
};
|
||||
let (strip, size) = float(150.0, None);
|
||||
assert_eq!(size.y, title + strip + 150.0);
|
||||
assert_eq!(float(0.0, None).1.y, 120.0, "an empty panel floats at the least fitted height");
|
||||
assert_eq!(float(600.0, None).1.y, 320.0, "a tall docked panel keeps the docked cap");
|
||||
// The host's floating size gives the width and the most height.
|
||||
assert_eq!(float(150.0, Some(vec2(300.0, 360.0))).1, vec2(300.0, title + strip + 150.0));
|
||||
assert_eq!(float(150.0, Some(vec2(300.0, 160.0))).1, vec2(300.0, 160.0));
|
||||
|
||||
// A group takes its active panel's content height.
|
||||
let content = TestContent { body_height: Some(150.0), ..Default::default() };
|
||||
let mut d = Driver::with(docked(), 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.rect("drag-bar", 2).center(), target);
|
||||
d.modifiers = Modifiers::COMMAND;
|
||||
let out = d.step(vec![button(target, false)]);
|
||||
let Some(Target::Float { rect: Some([_, _, _, height]) }) = moved_group(&out.actions) else { panic!("{:?}", out.actions) };
|
||||
assert_eq!(*height, title + strip + 150.0);
|
||||
}
|
||||
@@ -193,9 +193,13 @@ fn dragging_a_flyout_strip_floats_its_group() {
|
||||
let mut d = DockDriver::new(docked(&[&[1, 2], &[3]], true), Content);
|
||||
d.click(hit(&d, Hit::Icon(1)).center());
|
||||
d.settle();
|
||||
// A one-line body: the flyout and the floated group take the least fitted height.
|
||||
let flyout = d.ctx.memory(|m| m.area_rect(d.id.with("flyout"))).unwrap();
|
||||
assert_eq!(flyout.height(), 120.0);
|
||||
let bar = hit(&d, Hit::DragBar(1));
|
||||
let out = d.drag(bar.center(), CANVAS);
|
||||
assert!(matches!(out.actions.as_slice(), [Action::MoveGroup { panel: 1, to: Target::Float { .. } }]), "{:?}", out.actions);
|
||||
let [Action::MoveGroup { panel: 1, to: Target::Float { rect: Some(rect) } }] = out.actions.as_slice() else { panic!("{:?}", out.actions) };
|
||||
assert_eq!(rect[3], 120.0);
|
||||
assert_eq!(groups(&d.layout), vec![vec![3]]);
|
||||
assert_eq!(d.layout.floating.len(), 1);
|
||||
assert_eq!(d.layout.floating.first().map(|w| w.panels().copied().collect::<Vec<_>>()), Some(vec![1, 2]));
|
||||
|
||||
@@ -299,13 +299,17 @@ impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
|
||||
let screen = ctx.content_rect();
|
||||
let bounds = self.workspace.intersect(screen);
|
||||
let width = request.width.max(self.style.min_pane).min(bounds.width());
|
||||
let height = self
|
||||
let max = self
|
||||
.content
|
||||
.floating_size(&active)
|
||||
.map(|size| size.y)
|
||||
.or(request.group.height)
|
||||
.filter(|h| h.is_finite() && *h > 0.0)
|
||||
.unwrap_or(FLYOUT_HEIGHT)
|
||||
.unwrap_or(FLYOUT_HEIGHT);
|
||||
// A flyout fits the content its panel last drew, up to that height.
|
||||
let height = self
|
||||
.fitted_height(&active, self.style.tab_height, max)
|
||||
.unwrap_or(max)
|
||||
.max(self.style.tab_height + self.style.min_pane)
|
||||
.min(bounds.height());
|
||||
let left = match request.edge {
|
||||
|
||||
@@ -218,6 +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());
|
||||
// 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());
|
||||
|
||||
@@ -5,7 +5,9 @@ use egui::{Context, Key, Pos2, Rect, Ui, Vec2, pos2, vec2};
|
||||
use super::{Renderer, clamp_float, dock::group_action};
|
||||
use crate::docking::chrome::drop_preview;
|
||||
use crate::docking::{
|
||||
Action, Drag, DropProposal, DropRequest, GroupDrag, GroupGesture, Placement, Target, Zone, cancel_drag, dock_model::Place, resolve_drop,
|
||||
Action, Drag, DropProposal, DropRequest, GroupDrag, GroupGesture, Node, Placement, Target, Zone, cancel_drag,
|
||||
dock_model::{Place, node_at},
|
||||
resolve_drop,
|
||||
surface::TAB_PADDING,
|
||||
};
|
||||
|
||||
@@ -17,6 +19,9 @@ fn float_only(ctx: &Context) -> bool {
|
||||
/// Height of a panel floated out of a dock column when the host gives no floating size.
|
||||
const DOCKED_FLOAT_HEIGHT: f32 = 320.0;
|
||||
|
||||
/// Least height of a floating window or flyout fitted to a short panel's content.
|
||||
pub(super) const MIN_FITTED_HEIGHT: f32 = 120.0;
|
||||
|
||||
impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
|
||||
pub(in crate::docking) fn finish_group_drag(&mut self, ui: &Ui) {
|
||||
let ctx = ui.ctx();
|
||||
@@ -274,21 +279,30 @@ 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. A panel leaving a dock column does not take the
|
||||
/// column's height.
|
||||
/// 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).
|
||||
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 size;
|
||||
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 = size.y.min(DOCKED_FLOAT_HEIGHT);
|
||||
size.y = self.fitted_height(panel, chrome, DOCKED_FLOAT_HEIGHT).unwrap_or(size.y.min(DOCKED_FLOAT_HEIGHT));
|
||||
}
|
||||
let limits = self.limits(panel);
|
||||
let header = vec2(0.0, self.style.tab_height);
|
||||
size.max(limits.min + header).min(limits.max + header)
|
||||
}
|
||||
|
||||
/// Height of a window around `panel`'s group: `chrome` (title bar and tab strip) and the
|
||||
/// content height the panel last drew, at least [`MIN_FITTED_HEIGHT`] and at most `max`.
|
||||
/// `None` for a panel the area has not drawn.
|
||||
pub(super) fn fitted_height(&self, panel: &P, chrome: f32, max: f32) -> Option<f32> {
|
||||
let content = self.float_space.content(panel)?;
|
||||
Some((chrome + content).max(MIN_FITTED_HEIGHT).min(max))
|
||||
}
|
||||
|
||||
/// Record what a drag floats from `panels`, one group drawn at `group` whose panels drag
|
||||
/// from `panel` rects, for commands that float without a rect.
|
||||
pub(super) fn record_float(&mut self, panels: &[P], panel: Vec2, group: Vec2) {
|
||||
@@ -307,17 +321,33 @@ impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
|
||||
}
|
||||
|
||||
/// Size of a group or column floated by a drag or Float Tab Group: the source width, and the
|
||||
/// tallest member's floating size, else the source height capped like a panel leaving a
|
||||
/// dock column. A group that already floats keeps its size.
|
||||
/// tallest member's floating height, else the source height capped like a panel leaving a
|
||||
/// dock column. A group fits that height to its active panel's content. A group that already
|
||||
/// floats keeps its size.
|
||||
pub(super) fn group_float_size(&self, members: &[P], source: Vec2) -> Vec2 {
|
||||
let place = members.first().and_then(|panel| self.layout.place(panel));
|
||||
if matches!(place, Some(Place::Floating { .. }) | None) {
|
||||
let Some(place) = members.first().and_then(|panel| self.layout.place(panel)) else { return source };
|
||||
if matches!(place, Place::Floating { .. }) {
|
||||
return source;
|
||||
}
|
||||
let valid = |s: &Vec2| s.is_finite() && s.x > 0.0 && s.y > 0.0;
|
||||
let host = members.iter().filter_map(|panel| self.content.floating_size(panel).filter(valid)).map(|s| s.y).reduce(f32::max);
|
||||
let docked = matches!(place, Some(Place::Dock { .. }));
|
||||
vec2(source.x, host.unwrap_or(if docked { source.y.min(DOCKED_FLOAT_HEIGHT) } else { source.y }))
|
||||
let docked = matches!(place, Place::Dock { .. });
|
||||
let chrome = self.style.title_height + self.style.tab_height;
|
||||
let max = host.or(docked.then_some(DOCKED_FLOAT_HEIGHT));
|
||||
let fitted = max.and_then(|max| self.group_active(members, &place).and_then(|active| self.fitted_height(active, chrome, max)));
|
||||
vec2(source.x, fitted.or(host).unwrap_or(if docked { source.y.min(DOCKED_FLOAT_HEIGHT) } else { source.y }))
|
||||
}
|
||||
|
||||
/// The active panel of the group at `place` when `members` are that whole group.
|
||||
fn group_active<'a>(&'a self, members: &[P], place: &Place) -> Option<&'a P> {
|
||||
let (panels, active) = match place {
|
||||
Place::Node(path) => match self.layout.root.as_ref().and_then(|root| node_at(root, path)) {
|
||||
Some(Node::Tabs { panels, active }) => (panels, *active),
|
||||
_ => return None,
|
||||
},
|
||||
_ => self.layout.group(place).map(|group| (&group.panels, group.active))?,
|
||||
};
|
||||
(panels.len() == members.len() && members.iter().all(|m| panels.contains(m))).then(|| panels.get(active)).flatten()
|
||||
}
|
||||
|
||||
/// Where a group or column drag floats with the pointer at `pointer`, keeping the grab
|
||||
|
||||
@@ -237,13 +237,16 @@ pub struct FloatSpace<P> {
|
||||
pub(super) panels: Vec<(P, Vec2)>,
|
||||
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)>,
|
||||
}
|
||||
|
||||
impl<P: PartialEq> FloatSpace<P> {
|
||||
/// An area with no recorded sizes: commands float a panel at 260x320, and a group or
|
||||
/// column at its dock column's width (else 260) by 320.
|
||||
pub fn new(area: Rect) -> Self {
|
||||
Self { area, panels: Vec::new(), groups: Vec::new(), columns: Vec::new() }
|
||||
Self { area, panels: Vec::new(), groups: Vec::new(), columns: Vec::new(), contents: Vec::new() }
|
||||
}
|
||||
|
||||
/// Adds the size a command floats `panel` at alone when the area has not drawn it, such as
|
||||
@@ -254,6 +257,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) {
|
||||
Some((_, recorded)) => *recorded = height,
|
||||
None => self.contents.push((panel, height)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lookups for `DockCommand`, which needs feature `serde`.
|
||||
#[cfg_attr(not(feature = "serde"), allow(dead_code))]
|
||||
impl<P: PartialEq> FloatSpace<P> {
|
||||
@@ -269,6 +282,10 @@ impl<P: PartialEq> FloatSpace<P> {
|
||||
Self::find(&self.columns, panel)
|
||||
}
|
||||
|
||||
pub(super) fn content(&self, panel: &P) -> Option<f32> {
|
||||
self.contents.iter().find(|(p, _)| p == panel).map(|(_, height)| *height)
|
||||
}
|
||||
|
||||
/// The first record wins: an iconic panel is recorded at its icon before its flyout.
|
||||
fn find(sizes: &[(P, Vec2)], panel: &P) -> Option<Vec2> {
|
||||
sizes.iter().find(|(p, _)| p == panel).map(|(_, size)| *size)
|
||||
@@ -445,8 +462,11 @@ pub trait DockContent<P> {
|
||||
fn limits(&self, _panel: &P) -> PanelLimits {
|
||||
PanelLimits::default()
|
||||
}
|
||||
/// Preferred floating size, independent of the current dock geometry. `None` falls back
|
||||
/// to the panel limits.
|
||||
/// 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.
|
||||
fn floating_size(&self, _panel: &P) -> Option<Vec2> {
|
||||
None
|
||||
}
|
||||
@@ -759,7 +779,13 @@ impl<'a, P: Clone + Eq + Hash + Debug + Send + Sync + 'static> DockArea<'a, P> {
|
||||
output: DockOutput::default(),
|
||||
frame,
|
||||
iconic: super::render::Iconic::new(self.auto_collapse),
|
||||
float_space: FloatSpace::new(rect),
|
||||
float_space: FloatSpace {
|
||||
// A panel keeps the content height it last drew while hidden or minimized.
|
||||
contents: float_space::<P>(ui.ctx(), self.id)
|
||||
.map(|space| space.contents.into_iter().filter(|(panel, _)| layout.contains(panel)).collect())
|
||||
.unwrap_or_default(),
|
||||
..FloatSpace::new(rect)
|
||||
},
|
||||
};
|
||||
if let Some(root) = &view.root {
|
||||
renderer.node(ui, root, rect, &mut Vec::new());
|
||||
|
||||
@@ -50,14 +50,14 @@ fn a_full_height_docked_group_floats_at_the_host_or_capped_height_inside_the_win
|
||||
let mut layout = docked();
|
||||
let Some(Node::Split { first, .. }) = &mut layout.root else { panic!() };
|
||||
**first = Node::Dock { side: Side::Start, columns: vec![Column::new(vec![Group::new(vec![2, 3], 1)], 240.0)] };
|
||||
let content = TestContent { protected: vec![0], floating_size: size, ..Default::default() };
|
||||
let content = TestContent { protected: vec![0], floating_size: size, body_height: Some(600.0), ..Default::default() };
|
||||
let mut d = Driver::with(layout, content, Rect::from_min_size(pos2(0.0, 0.0), vec2(600.0, 600.0)));
|
||||
let bar = d.rect("drag-bar", 2);
|
||||
let out = d.drag(bar.center(), pos2(420.0, 300.0));
|
||||
let Some(Target::Float { rect: Some([x, y, width, height]) }) = moved_group(&out.actions) else { panic!("{:?}", out.actions) };
|
||||
match size {
|
||||
Some(size) => assert_eq!(*height, size.y),
|
||||
None => assert!(*height <= 320.0, "{height}"),
|
||||
None => assert_eq!(*height, 320.0),
|
||||
}
|
||||
assert!(*width > 100.0 && *width <= 240.0, "{width}");
|
||||
let window = Rect::from_min_size(pos2(0.0, 0.0), vec2(800.0, 600.0));
|
||||
|
||||
+20
-2
@@ -146,6 +146,24 @@ the last of them. Only an active tab wider than the strip alone is cut with "…
|
||||
names it in full. The drag bar keeps its reserved width until the tabs overflow. A tab dropped on
|
||||
the "…" button goes to the end of the group.
|
||||
|
||||
## Floating size
|
||||
|
||||
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.
|
||||
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
|
||||
capped at 320, or at a `FloatSpace::with_panel_size` size for commands.
|
||||
- A group from a frame without a `floating_size` keeps its frame size. A dock column of several
|
||||
groups floats at the tallest `floating_size` height, else its column height capped at 320.
|
||||
- A rect from a command and a window the user resized keep their size; floating windows are not
|
||||
refitted while open.
|
||||
- Docked layout does not change: a column's last group still fills the column.
|
||||
|
||||
## Gestures
|
||||
|
||||
- A tab drags one panel. A group's drag bar (the space beside its tabs) or its top border drags
|
||||
@@ -195,8 +213,8 @@ let closed = command.apply(&mut app.workspace, style.right_to_left, &space, |pan
|
||||
`to_actions` take the layout's `right_to_left` for that.
|
||||
- `group` moves the panel's whole group; `column` moves its dock column, or its whole window when
|
||||
it floats. `side` is `Start` or `End`.
|
||||
- `window.panel.float` without a rect floats what it moves at the size a drag floats it at: the
|
||||
panel's `floating_size`, else its docked group or column size, capped like a drag. It goes
|
||||
- `window.panel.float` without a rect floats what it moves at the size a drag floats it at (see
|
||||
Floating size). It goes
|
||||
inside the dock area, 24 points from its top-left corner, so it stays clear of the menu bar.
|
||||
The area records that geometry in a `FloatSpace` each frame; `float_space(ctx, id)` reads it
|
||||
and `apply` and `to_actions` take it. Before the area has drawn, `FloatSpace::new(area)` floats
|
||||
|
||||
Reference in new issue
Block a user