abstracttui_graph/view_style.rs
1//! [`GraphStyle`] (resolved inks) + [`GraphAlgo`] (pass selection) —
2//! the configuration half of the view, split from `view.rs` for the
3//! file-size discipline.
4//!
5//! OWNER: CANVAS (view half of 0440).
6
7use abstracttui::base::Rgba;
8use abstracttui::theme::TokenSet;
9
10use crate::layout::{ForceOpts, LayeredOpts};
11
12/// Resolved ink set for the view (the widget token rule: callers
13/// resolve theme tokens into plain `Rgba`; the view invents no
14/// colors). Author-written, shape-stable: plain fields + [`Default`]
15/// (derived from the default theme) + FRU per ADR-0003 §2.
16#[derive(Clone, Debug, PartialEq)]
17pub struct GraphStyle {
18 /// Card fill.
19 pub card_bg: Rgba,
20 /// Card border ink.
21 pub card_border: Rgba,
22 /// Border ink of the SELECTED card (the restyle).
23 pub card_border_selected: Rgba,
24 /// Title ink.
25 pub card_title: Rgba,
26 /// Badge ink.
27 pub badge: Rgba,
28 /// Edge stroke ink.
29 pub edge: Rgba,
30 /// Ink of cycle-broken edges (the honesty marker; broken edges
31 /// also render dotted).
32 pub edge_broken: Rgba,
33 /// Edge midpoint-label ink.
34 pub edge_label: Rgba,
35 /// Fallback notice line ink.
36 pub notice: Rgba,
37 /// Kind -> accent ink for the card's left border column (exact
38 /// string match on `NodeDesc::kind`; unknown kinds stay plain).
39 pub kind_accents: Vec<(String, Rgba)>,
40}
41
42impl GraphStyle {
43 /// Derive the default ink set from a resolved token set.
44 pub fn from_tokens(t: &TokenSet) -> GraphStyle {
45 GraphStyle {
46 card_bg: t.surface_raised,
47 card_border: t.border,
48 card_border_selected: t.border_focus,
49 card_title: t.text,
50 badge: t.info,
51 edge: t.text_muted,
52 edge_broken: t.error,
53 edge_label: t.text_faint,
54 notice: t.warn,
55 kind_accents: Vec::new(),
56 }
57 }
58
59 /// Map a node kind to an accent ink (builder style).
60 pub fn kind_accent(mut self, kind: impl Into<String>, ink: Rgba) -> GraphStyle {
61 self.kind_accents.push((kind.into(), ink));
62 self
63 }
64
65 pub(crate) fn accent_of(&self, kind: Option<&str>) -> Option<Rgba> {
66 let kind = kind?;
67 self.kind_accents
68 .iter()
69 .find(|(k, _)| k == kind)
70 .map(|(_, ink)| *ink)
71 }
72}
73
74impl Default for GraphStyle {
75 fn default() -> Self {
76 GraphStyle::from_tokens(&abstracttui::theme::default_theme().tokens)
77 }
78}
79
80/// Layout pass selection. The vocabulary may grow with the crate's
81/// passes, hence `#[non_exhaustive]` (ADR-0003 §3); constructing the
82/// existing variants stays stable.
83#[non_exhaustive]
84#[derive(Clone, Debug, PartialEq)]
85pub enum GraphAlgo {
86 /// Sugiyama-lite (the workflow/DAG path) — the default.
87 Layered(LayeredOpts),
88 /// Bounded seeded force placement (the knowledge-graph path).
89 Force(ForceOpts),
90 /// Labeled near-square grid (the honest fallback, explicitly).
91 Grid,
92}
93
94impl Default for GraphAlgo {
95 fn default() -> Self {
96 GraphAlgo::Layered(LayeredOpts::default())
97 }
98}