Skip to main content

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}