diff --git a/crates/ui/src/docking/command.rs b/crates/ui/src/docking/command.rs index 3ae6d2ae..7a146f95 100644 --- a/crates/ui/src/docking/command.rs +++ b/crates/ui/src/docking/command.rs @@ -284,7 +284,7 @@ impl Unit { let panel = panel.clone(); Ok(match (self, to) { (Self::Panel, Target::At { anchor, placement }) => Action::Move { panel, anchor, placement }, - (Self::Panel, _) => return Err(DockError::InvalidPlacement), + (Self::Panel, to) => Action::MovePanel { panel, to }, (Self::Group, to) => Action::MoveGroup { panel, to }, (Self::Column, to) if floating => Action::MoveWindow { panel, to }, (Self::Column, to) => Action::MoveColumn { panel, to }, diff --git a/crates/ui/src/docking/command_tests.rs b/crates/ui/src/docking/command_tests.rs index e109a08c..905e1452 100644 --- a/crates/ui/src/docking/command_tests.rs +++ b/crates/ui/src/docking/command_tests.rs @@ -371,3 +371,13 @@ fn float_without_a_rect_takes_the_drag_size_inside_the_dock_area() { fn float_with(space: &FloatSpace
, panel: &str) -> Vec {
panel: P,
rect: Option<[f32; 4]>,
},
+ /// Move one panel, without the rest of its group. `Target::At` is [`Action::Move`];
+ /// `NewDock` and `Float` give the panel a group of its own.
+ MovePanel {
+ panel: P,
+ to: Target ,
+ },
}
/// What may happen to a panel. [`Layout::apply_with_permissions`] enforces these for every
@@ -726,6 +732,18 @@ impl {
Action::Close { panel } if !permissions(panel).closable => return Err(DockError::NotAllowed),
Action::MoveFloating { panel, .. } if !permissions(panel).movable => return Err(DockError::NotAllowed),
Action::Open { anchor: Some(anchor), .. } if !permissions(anchor).accepts_tabs => return Err(DockError::NotAllowed),
+ Action::MovePanel { panel, to } => {
+ let policy = permissions(panel);
+ let allowed = policy.movable
+ && match to {
+ Target::Float { .. } => policy.floatable,
+ Target::At { anchor, placement } => placement_allowed(placement, permissions(anchor)),
+ Target::NewDock { .. } => true,
+ };
+ if !allowed {
+ return Err(DockError::NotAllowed);
+ }
+ }
Action::MoveGroup { panel, to } | Action::MoveColumn { panel, to } | Action::MoveWindow { panel, to } => {
let members = self.members(panel, unit_of(&action))?;
if members.iter().any(|p| !permissions(p).movable) {
@@ -899,6 +917,13 @@ impl {
let moving = self.take_unit(panel, unit)?;
self.insert_moving(moving, to.clone())
}
+ Action::MovePanel { panel, to } => match to {
+ Target::At { anchor, placement } => self.apply_inner(Action::Move { panel, anchor, placement }),
+ to => {
+ let entry = self.take(&panel).ok_or(DockError::MissingPanel)?;
+ self.insert_moving(Moving::group(Group::new(vec![entry.panel], 0)), to)
+ }
+ },
Action::CloseGroup { ref panel } | Action::CloseWindow { ref panel } => self.take_unit(panel, unit_of(&action)).map(|_| ()),
Action::CloseOthers { panel } => {
for other in self.members(&panel, Unit::Group)? {
diff --git a/docs/ui-docking.md b/docs/ui-docking.md
index 9705a620..336367e7 100644
--- a/docs/ui-docking.md
+++ b/docs/ui-docking.md
@@ -57,8 +57,8 @@ layout.apply(Action::Move {
# Ok::<(), craft_ui::docking::DockError>(())
```
-- `Move`, `Float` and `Close` act on one panel. `MoveGroup`, `MoveColumn` and `MoveWindow` move a
- group, a dock column or a floating window, named by any panel in it.
+- `Move`, `MovePanel`, `Float` and `Close` act on one panel. `MoveGroup`, `MoveColumn` and
+ `MoveWindow` move a group, a dock column or a floating window, named by any panel in it.
- A `Target` is `At { anchor, placement }`, `Float { rect }` or `NewDock { side }`.
- A `Placement` is a tab position, a split zone, a new group above or below (with an optional
preferred `height`), a new column, or a new frame on an outer edge.