From e097e53a8527e51a601d2ff0af14478cd1ba2b6e Mon Sep 17 00:00:00 2001 From: Skkeye Date: Thu, 1 Oct 2026 01:40:24 -0400 Subject: [PATCH] Make branch lines take their parent's color A node's color now flows down the lines to its children, mind-map style: Watering's teal colors the lines to Rain barrel and Drip line. It used to color the line from the root down to Watering itself, which also left the shared bus of a parent's branches in whichever child's color was drawn last. Branches follow their parent by default, and stay dim when the parent has no color. Co-Authored-By: Claude Opus 5.5 --- DESIGN.md | 4 +++- examples/garden.cum | 3 --- src/model/look.rs | 5 +++-- src/ui/theme.rs | 36 ++++++++++++++++++++++++++---------- src/view/canvas/render.rs | 16 ++++++++++++++++ src/view/canvas/scene.rs | 2 +- 6 files changed, 49 insertions(+), 17 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 6c252f4..108478f 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -77,7 +77,9 @@ lines. - Connections can set arrowheads (off, end, start, both), a line (solid, dashed, dotted, thick, double), a color (a palette color or the node's own) and a label, or use a named style. Branches start solid without arrowheads, - cross-links as dashed arrows. + in their parent's color, so a node's color flows down the lines to its + children (dim when the parent has no color). Cross-links start as dim + dashed arrows. **Keys** - Medium vim: counts, operators with node targets, registers (with `"+` for the diff --git a/examples/garden.cum b/examples/garden.cum index 3076cab..b5c9b20 100644 --- a/examples/garden.cum +++ b/examples/garden.cum @@ -43,9 +43,6 @@ title: "Watering", pos: (22, 12), color: "teal", - branch: ( - color: "node", - ), ), ( id: 7, diff --git a/src/model/look.rs b/src/model/look.rs index efe062f..886e0d9 100644 --- a/src/model/look.rs +++ b/src/model/look.rs @@ -49,8 +49,9 @@ pub enum Arrows { pub enum LineColor { /// A color from the theme's palette. Named(ColorName), - /// The color of the node the line comes from (for a branch: the child), - /// so each branch takes its node's color, mind-map style. + /// The color of the node the line comes from: a branch takes its + /// parent's (so a node's color flows down the lines to its children, + /// mind-map style), a cross-link its start's. FollowNode, } diff --git a/src/ui/theme.rs b/src/ui/theme.rs index c740905..e6ffd70 100644 --- a/src/ui/theme.rs +++ b/src/ui/theme.rs @@ -87,7 +87,14 @@ impl Default for Theme { palette, node: NodeLook { border: Some(Border::Square), ..NodeLook::default() }, root: NodeLook { border: Some(Border::Rounded), ..NodeLook::default() }, - branch: LineLook { line: Some(Stroke::Solid), arrows: Some(Arrows::Off), ..LineLook::default() }, + // Branches take their parent's color: a node's color flows down + // the lines to its children (dim when the parent has no color). + branch: LineLook { + line: Some(Stroke::Solid), + arrows: Some(Arrows::Off), + color: Some(LineColor::FollowNode), + style: None, + }, link: LineLook { line: Some(Stroke::Dashed), arrows: Some(Arrows::End), ..LineLook::default() }, node_styles: BTreeMap::new(), line_styles: BTreeMap::new(), @@ -128,9 +135,9 @@ impl Theme { } /// How to draw a branch line, given the look it has and the color of - /// its child (for lines that follow their node's color). - pub fn branch_style(&self, look: &LineLook, child_color: Color) -> LineStyle { - self.line_style(&self.branch, look, child_color) + /// its parent (for lines that follow their node's color). + pub fn branch_style(&self, look: &LineLook, parent_color: Color) -> LineStyle { + self.line_style(&self.branch, look, parent_color) } /// How to draw a cross-link, given the look it has and the color of the @@ -211,12 +218,21 @@ mod tests { } #[test] - fn lines_can_follow_their_node() { + fn branches_take_their_parents_color() { let theme = Theme::default(); - let follow = LineLook { color: Some(LineColor::FollowNode), ..LineLook::default() }; - assert_eq!(theme.branch_style(&follow, Color::Indexed(71)).color, Color::Indexed(71)); - assert_eq!(theme.branch_style(&follow, Color::Reset).color, theme.muted); - let link = theme.link_style(&LineLook::default(), Color::Reset); - assert_eq!((link.stroke, link.arrows), (Stroke::Dashed, Arrows::End)); + let teal = Color::Indexed(37); + assert_eq!(theme.branch_style(&LineLook::default(), teal).color, teal, "by default"); + assert_eq!( + theme.branch_style(&LineLook::default(), Color::Reset).color, + theme.muted, + "no color: dim" + ); + let red = LineLook { + color: Some(LineColor::Named(ColorName::parse("red").unwrap())), + ..LineLook::default() + }; + assert_eq!(theme.branch_style(&red, teal).color, theme.color(&ColorName::parse("red").unwrap())); + let link = theme.link_style(&LineLook::default(), teal); + assert_eq!((link.stroke, link.arrows, link.color), (Stroke::Dashed, Arrows::End, theme.muted)); } } diff --git a/src/view/canvas/render.rs b/src/view/canvas/render.rs index 1e16980..405d056 100644 --- a/src/view/canvas/render.rs +++ b/src/view/canvas/render.rs @@ -244,6 +244,22 @@ mod tests { assert_eq!(scene.node_at(crate::view::canvas::ScreenPos::new(30, 5)), Some(g.beds)); } + #[test] + fn branch_lines_take_their_parents_color() { + let (mut doc, g) = garden(); + let orange = crate::model::ColorName::parse("orange").unwrap(); + doc.edit(|e| e.update(g.beds, |node| node.look.color = Some(orange.clone()))).unwrap(); + let theme = Theme::default(); + let scene = + Scene::build(&doc, g.soil, Camera::default(), Size::new(52, 8), &theme, SceneOptions::default()); + let area = Rect::new(0, 0, 52, 8); + let mut buf = Buffer::empty(area); + scene.render(area, &mut buf); + let color = |col: u16, row: u16| buf[(col, row)].fg; + assert_eq!(color(38, 5), theme.color(&orange), "Raised beds → Cedar: orange, the parent's"); + assert_eq!(color(17, 5), theme.muted, "Garden plans → Raised beds: dim, the root has no color"); + } + #[test] fn folded_branches_links_and_far_zoom() { let (mut doc, g) = garden(); diff --git a/src/view/canvas/scene.rs b/src/view/canvas/scene.rs index b26737f..a74d711 100644 --- a/src/view/canvas/scene.rs +++ b/src/view/canvas/scene.rs @@ -190,7 +190,7 @@ impl Scene { let child = &self.nodes[child_index]; let Some(Place::Child { parent, branch }) = doc.place(child.id) else { continue }; let Some(&parent_index) = self.index.get(parent) else { continue }; - let style = theme.branch_style(branch, child.color); + let style = theme.branch_style(branch, self.nodes[parent_index].color); let owner = LineOwner::Branch(child.id); self.connect(parent_index, child_index, Bend::NearStart, style, owner, None); }