mirror of
https://github.com/storytold/craft-libs.git
synced 2026-10-31 07:39:23 +00:00
docking: Floating::stack is public, and four-way handles take the pointer only
Floating::stack builds a window from groups stacked top to bottom, so an app's own stacked layouts migrate without building the split chain. The four-way handle no longer takes keyboard focus: it has no label or key action, and the two dividers it joins take arrow keys.
This commit is contained in:
1 parent
50f9c06aa7
commit
01ce7162a4
7 files changed
+16
-14
No files matched your search
@@ -38,7 +38,7 @@ fn workspace() -> Layout<u32> {
|
||||
second: Box::new(tabs(&[0], 0)),
|
||||
}),
|
||||
floating: vec![
|
||||
Floating::stack(vec![Group::new(vec![5], 0), Group::new(vec![6, 7], 1)], [300.0, 80.0, 240.0, 300.0]),
|
||||
Floating::stack(vec![Group::new(vec![5], 0), Group::new(vec![6, 7], 1)], [300.0, 80.0, 240.0, 300.0]).unwrap(),
|
||||
Floating::single(vec![8], 0, [560.0, 300.0, 200.0, 200.0]),
|
||||
],
|
||||
}
|
||||
@@ -678,7 +678,7 @@ fn undock_panel_group_floats_one_group_of_a_floating_window() {
|
||||
use egui_kittest::{Harness, kittest::Queryable};
|
||||
let stacked = || Layout {
|
||||
root: Some(tabs(&[1], 0)),
|
||||
floating: vec![Floating::stack(vec![Group::new(vec![5], 0), Group::new(vec![6, 7], 0)], [300.0, 80.0, 300.0, 400.0])],
|
||||
floating: vec![Floating::stack(vec![Group::new(vec![5], 0), Group::new(vec![6, 7], 0)], [300.0, 80.0, 300.0, 400.0]).unwrap()],
|
||||
};
|
||||
type State = (Content, Layout<u32>, Vec<Action<u32>>);
|
||||
let mut h = Harness::builder().with_size(vec2(800.0, 600.0)).build_ui_state(
|
||||
|
||||
@@ -551,7 +551,7 @@ fn drag_bar_menu_has_the_group_items_and_opens_from_the_keyboard() {
|
||||
|
||||
#[test]
|
||||
fn a_group_dragged_out_of_a_floating_stack_tears_out_alone() {
|
||||
let stack = Floating::stack(vec![Group::new(vec![5], 0), Group::new(vec![6, 7], 1)], [80.0, 70.0, 300.0, 400.0]);
|
||||
let stack = Floating::stack(vec![Group::new(vec![5], 0), Group::new(vec![6, 7], 1)], [80.0, 70.0, 300.0, 400.0]).unwrap();
|
||||
let layout = Layout { root: Some(tabs(&[1], 0)), floating: vec![stack] };
|
||||
let mut d = Driver::new(layout);
|
||||
let from = d.rect("drag-bar", 6).center();
|
||||
|
||||
@@ -283,7 +283,7 @@ fn hit_rects_cover_every_gesture_source() {
|
||||
first: Box::new(Node::Tabs { panels: vec![0], active: 0 }),
|
||||
second: Box::new(stack),
|
||||
};
|
||||
let window = Floating::stack(vec![Group::new(vec![12], 0), Group::new(vec![13], 0)], [500.0, 60.0, 220.0, 300.0]);
|
||||
let window = Floating::stack(vec![Group::new(vec![12], 0), Group::new(vec![13], 0)], [500.0, 60.0, 220.0, 300.0]).unwrap();
|
||||
let layout = Layout {
|
||||
root: Some(Node::Split { axis: SplitAxis::Horizontal, size: SplitSize::FixedFirst(200.0), first: Box::new(dock), second: Box::new(frames) }),
|
||||
floating: vec![window],
|
||||
|
||||
@@ -87,10 +87,10 @@ impl<P> Floating<P> {
|
||||
tree_panels(&self.root).into_iter()
|
||||
}
|
||||
|
||||
/// Groups stacked top to bottom, as a v1 layout stored them.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn stack(groups: Vec<Group<P>>, rect: [f32; 4]) -> Self {
|
||||
Self::new(super::dock_model::stack_tree(groups).expect("a group"), rect)
|
||||
/// Groups stacked top to bottom, as a v1 layout stored them: each group over a vertical
|
||||
/// split of the ones below it, sized by their heights. `None` without groups.
|
||||
pub fn stack(groups: Vec<Group<P>>, rect: [f32; 4]) -> Option<Self> {
|
||||
super::dock_model::stack_tree(groups).map(|root| Self::new(root, rect))
|
||||
}
|
||||
|
||||
/// The window's groups, first to last.
|
||||
|
||||
@@ -23,7 +23,7 @@ pub(super) fn docked() -> Layout<u32> {
|
||||
Node::Dock { side: Side::End, columns: vec![Column::new(vec![g(&[2, 3], 1), g(&[4], 0)], 180.0), Column::new(vec![g(&[5], 0)], 120.0)] };
|
||||
Layout {
|
||||
root: Some(hsplit(SplitSize::FixedSecond(300.0), middle, dock)),
|
||||
floating: vec![Floating::stack(vec![g(&[6, 7], 1), g(&[8], 0)], [100.0, 100.0, 300.0, 400.0])],
|
||||
floating: vec![Floating::stack(vec![g(&[6, 7], 1), g(&[8], 0)], [100.0, 100.0, 300.0, 400.0]).unwrap()],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ fn restore_into_a_column_group_seam_and_new_column_round_trips() {
|
||||
let start = Node::Dock { side: Side::Start, columns: vec![Column::new(vec![g(&[10], 0)], 200.0)] };
|
||||
let original = Layout {
|
||||
root: Some(hsplit(SplitSize::FixedFirst(200.0), start, hsplit(SplitSize::FixedSecond(300.0), tabs(&[1], 0), end))),
|
||||
floating: vec![Floating::stack(vec![g(&[6], 0), Group { height: Some(90.0), ..g(&[7], 0) }], [10.0, 10.0, 200.0, 300.0])],
|
||||
floating: vec![Floating::stack(vec![g(&[6], 0), Group { height: Some(90.0), ..g(&[7], 0) }], [10.0, 10.0, 200.0, 300.0]).unwrap()],
|
||||
};
|
||||
original.validate().unwrap();
|
||||
// 4: the seam between [2, 3] and [9]; 9: below [4]; 5: a new column after A; 10: alone in
|
||||
@@ -415,7 +415,7 @@ mod serde_tests {
|
||||
let plain = Floating::single(vec![4u32, 5], 1, rect);
|
||||
assert_eq!(serde_json::to_value(&plain).unwrap(), json!({"panels": [4, 5], "active": 1, "rect": rect}));
|
||||
let minimized = Floating { minimized: true, ..Floating::single(vec![4u32], 0, rect) };
|
||||
let stacked = Floating::stack(vec![g(&[4], 0), g(&[5], 0)], rect);
|
||||
let stacked = Floating::stack(vec![g(&[4], 0), g(&[5], 0)], rect).unwrap();
|
||||
let native = Floating { native: Some(rect), ..Floating::single(vec![4u32], 0, rect) };
|
||||
for window in [minimized, stacked, native] {
|
||||
let value = serde_json::to_value(&window).unwrap();
|
||||
|
||||
@@ -295,7 +295,8 @@ impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
|
||||
None => self.id.with(("intersection", outer, inner_layout)),
|
||||
Some((panel, _)) => self.id.with(("window-intersection", panel, outer, inner_layout)),
|
||||
};
|
||||
let response = ui.interact(hit, id, Sense::drag());
|
||||
// Pointer only: each of the two dividers it joins already takes keyboard focus.
|
||||
let response = ui.interact(hit, id, Sense::DRAG);
|
||||
self.register_interaction(ui.ctx(), id);
|
||||
if response.hovered() || response.dragged() {
|
||||
ui.ctx().set_cursor_icon(CursorIcon::Move);
|
||||
|
||||
+3
-2
@@ -39,8 +39,9 @@ their sides.
|
||||
|
||||
A `Floating` window holds a tree like the docked layout's (`root`: splits, tab groups and
|
||||
accordions, no docks), a rect, an optional native-window rect and `minimized`.
|
||||
`Floating::single` makes a window with one group and `Floating::new` one with a tree; `panels()`
|
||||
and `contains()` read it. Saved layouts keep loading: a window stored as one group (v1) or as a
|
||||
`Floating::single` makes a window with one group, `Floating::new` one with a tree, and
|
||||
`Floating::stack` one with groups stacked top to bottom (a vertical split sized by the groups'
|
||||
heights, as an app's own stacked layouts migrate); `panels()` and `contains()` read it. Saved layouts keep loading: a window stored as one group (v1) or as a
|
||||
stack of groups loads as that group or as a vertical split of the stacked groups, sized by their
|
||||
heights.
|
||||
|
||||
|
||||
Reference in new issue
Block a user