diff --git a/crates/ui/src/docking/iconic_tests.rs b/crates/ui/src/docking/iconic_tests.rs index 58a85fa5..0a353f2c 100644 --- a/crates/ui/src/docking/iconic_tests.rs +++ b/crates/ui/src/docking/iconic_tests.rs @@ -273,6 +273,27 @@ fn group_dropped_on_an_iconic_column_joins_as_an_icon_group() { assert!(first_column(&d.layout).iconic); } +/// A group dropped on the window edge beside an iconic column at that edge docks in a new column +/// there: the preview is the edge line alone, without the column's outline. +#[test] +fn an_edge_drop_next_to_an_iconic_column_highlights_only_the_edge() { + let mut layout = docked(&[&[1], &[2]], true); + layout.floating.push(Floating::single(vec![5, 6], 0, [300.0, 200.0, 240.0, 200.0])); + let mut d = DockDriver::new(layout, Content); + let bar = hit(&d, Hit::DragBar(5)).center(); + let target = pos2(2.0, 300.0); + d.hold(bar, target); + let column = Rect::from_min_max(pos2(0.0, 14.0), pos2(36.0, 600.0)); + assert!(d.filled(Rect::from_x_y_ranges(0.0..=4.0, 0.0..=600.0)), "the edge line"); + assert!(!d.outlined(column.shrink(1.0)), "the iconic column is not outlined"); + d.release(target); + let Some(Node::Split { first, .. }) = &d.layout.root else { panic!("{:?}", d.layout.root) }; + let Node::Dock { columns, .. } = first.as_ref() else { panic!("{first:?}") }; + let panels: Vec> = columns.iter().map(|c| c.groups.iter().flat_map(|g| g.panels.clone()).collect()).collect(); + assert_eq!(panels, vec![vec![5, 6], vec![1, 2]]); + assert!(!columns[0].iconic && columns[1].iconic); +} + /// Every kind of gesture source has a rect, and dragging from it does something. #[test] fn hit_rects_cover_every_gesture_source() { diff --git a/crates/ui/src/docking/render/dock.rs b/crates/ui/src/docking/render/dock.rs index 4eaab778..878d909e 100644 --- a/crates/ui/src/docking/render/dock.rs +++ b/crates/ui/src/docking/render/dock.rs @@ -789,11 +789,15 @@ impl Renderer<'_, P> { } /// The line of a drop that shows no result rect: on the window edge, into an iconic column, - /// or any dock drop with [`DockStyle::side_edge_zones`]. - pub(super) fn paint_drop_line(&self, ctx: &Context, line: Rect) { + /// or any dock drop with [`DockStyle::side_edge_zones`]. A line inside an iconic column also + /// outlines the column, unless it is on the window edge (`outer`): a column at that edge holds + /// the line, but the drop docks beside the column, not into it. + pub(super) fn paint_drop_line(&self, ctx: &Context, line: Rect, outer: bool) { if usable(line) { let painter = self.preview_painter(ctx); - self.iconic.outline(&painter, line, self.style); + if !outer { + self.iconic.outline(&painter, line, self.style); + } painter.rect_filled(line, 1.0, self.style.accent); } } diff --git a/crates/ui/src/docking/render/preview.rs b/crates/ui/src/docking/render/preview.rs index 65c15fd3..5404984e 100644 --- a/crates/ui/src/docking/render/preview.rs +++ b/crates/ui/src/docking/render/preview.rs @@ -599,12 +599,12 @@ impl Renderer<'_, P> { if self.style.side_edge_zones { drop_preview(painter, proposal.preview.shrink(1.0), self.style.accent, filled); } else if matches!(proposal.placement, Placement::Edge(_)) { - self.paint_drop_line(ctx, proposal.preview); + self.paint_drop_line(ctx, proposal.preview, true); } else if beside { let to = Target::At { anchor: proposal.anchor.clone(), placement: proposal.placement.clone() }; match self.result_rect(action(to), members) { Some(rect) => tab_outline(painter, rect.shrink(1.0), self.style.accent), - None => self.paint_drop_line(ctx, proposal.preview), + None => self.paint_drop_line(ctx, proposal.preview, false), } } else { tab_outline(painter, proposal.preview.shrink(1.0), self.style.accent); @@ -621,7 +621,7 @@ impl Renderer<'_, P> { let rect = (!self.style.side_edge_zones && !drop.outer).then_some(action).and_then(|action| self.result_rect(action, members)); match rect { Some(rect) => tab_outline(painter, rect.shrink(1.0), self.style.accent), - None => self.paint_drop_line(ctx, drop.line), + None => self.paint_drop_line(ctx, drop.line, drop.outer), } }