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 <[email protected]>
This commit is contained in:
skkeyeandClaude Opus 5.5 committed 2026-10-01 01:40:24 -04:00
1 parent 3b58d6494d
commit e097e53a85
6 files changed
+49 -17

No files matched your search

+3 -1
View File
@@ -77,7 +77,9 @@ lines.
- Connections can set arrowheads (off, end, start, both), a line (solid, - 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) 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, 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** **Keys**
- Medium vim: counts, operators with node targets, registers (with `"+` for the - Medium vim: counts, operators with node targets, registers (with `"+` for the
-3
View File
@@ -43,9 +43,6 @@
title: "Watering", title: "Watering",
pos: (22, 12), pos: (22, 12),
color: "teal", color: "teal",
branch: (
color: "node",
),
), ),
( (
id: 7, id: 7,
+3 -2
View File
@@ -49,8 +49,9 @@ pub enum Arrows {
pub enum LineColor { pub enum LineColor {
/// A color from the theme's palette. /// A color from the theme's palette.
Named(ColorName), Named(ColorName),
/// The color of the node the line comes from (for a branch: the child), /// The color of the node the line comes from: a branch takes its
/// so each branch takes its node's color, mind-map style. /// parent's (so a node's color flows down the lines to its children,
/// mind-map style), a cross-link its start's.
FollowNode, FollowNode,
} }
+26 -10
View File
@@ -87,7 +87,14 @@ impl Default for Theme {
palette, palette,
node: NodeLook { border: Some(Border::Square), ..NodeLook::default() }, node: NodeLook { border: Some(Border::Square), ..NodeLook::default() },
root: NodeLook { border: Some(Border::Rounded), ..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() }, link: LineLook { line: Some(Stroke::Dashed), arrows: Some(Arrows::End), ..LineLook::default() },
node_styles: BTreeMap::new(), node_styles: BTreeMap::new(),
line_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 /// 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). /// its parent (for lines that follow their node's color).
pub fn branch_style(&self, look: &LineLook, child_color: Color) -> LineStyle { pub fn branch_style(&self, look: &LineLook, parent_color: Color) -> LineStyle {
self.line_style(&self.branch, look, child_color) self.line_style(&self.branch, look, parent_color)
} }
/// How to draw a cross-link, given the look it has and the color of the /// How to draw a cross-link, given the look it has and the color of the
@@ -211,12 +218,21 @@ mod tests {
} }
#[test] #[test]
fn lines_can_follow_their_node() { fn branches_take_their_parents_color() {
let theme = Theme::default(); let theme = Theme::default();
let follow = LineLook { color: Some(LineColor::FollowNode), ..LineLook::default() }; let teal = Color::Indexed(37);
assert_eq!(theme.branch_style(&follow, Color::Indexed(71)).color, Color::Indexed(71)); assert_eq!(theme.branch_style(&LineLook::default(), teal).color, teal, "by default");
assert_eq!(theme.branch_style(&follow, Color::Reset).color, theme.muted); assert_eq!(
let link = theme.link_style(&LineLook::default(), Color::Reset); theme.branch_style(&LineLook::default(), Color::Reset).color,
assert_eq!((link.stroke, link.arrows), (Stroke::Dashed, Arrows::End)); 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));
} }
} }
+16
View File
@@ -244,6 +244,22 @@ mod tests {
assert_eq!(scene.node_at(crate::view::canvas::ScreenPos::new(30, 5)), Some(g.beds)); 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] #[test]
fn folded_branches_links_and_far_zoom() { fn folded_branches_links_and_far_zoom() {
let (mut doc, g) = garden(); let (mut doc, g) = garden();
+1 -1
View File
@@ -190,7 +190,7 @@ impl Scene {
let child = &self.nodes[child_index]; let child = &self.nodes[child_index];
let Some(Place::Child { parent, branch }) = doc.place(child.id) else { continue }; let Some(Place::Child { parent, branch }) = doc.place(child.id) else { continue };
let Some(&parent_index) = self.index.get(parent) 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); let owner = LineOwner::Branch(child.id);
self.connect(parent_index, child_index, Bend::NearStart, style, owner, None); self.connect(parent_index, child_index, Bend::NearStart, style, owner, None);
} }