GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
refactor: a graph's cells have no colour, and its lines are grid_color
The graph filled itself with style.surface.graph.cell_color when a host
set uniform_background, and drew its lattice in gap_color, the cell
model's name for it. The fill is gone: the cells are whatever the graph
is painted on. The lines are graph.grid_color. cell_color and gap_color
are retired, reported by path at load and not read.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
src/color.rs | 46 +++++++++++++++++++++++----------------------
src/layout.rs | 8 ++------
src/widget/display/graph.rs | 37 +++++++++++++++---------------------
3 files changed, 41 insertions(+), 50 deletions(-)
diff --git a/src/color.rs b/src/color.rs
index 5f4109d..9feb8cf 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -182,8 +182,7 @@ static TREE_SEPARATOR_COLOR: RwLock<[f32; 4]> = RwLock::new([0.15, 0.15, 0.19, 1
static SCROLLBAR_TRACK_COLOR: RwLock<[f32; 4]> = RwLock::new([0.15, 0.15, 0.20, 0.3]);
static SCROLLBAR_THUMB_COLOR: RwLock<[f32; 4]> = RwLock::new([0.60, 0.60, 0.65, 0.4]);
-static GRAPH_CELL_COLOR: RwLock<[f32; 3]> = RwLock::new([0.13, 0.13, 0.16]);
-static GRAPH_GAP_COLOR: RwLock<[f32; 3]> = RwLock::new([0.07, 0.07, 0.09]);
+static GRAPH_GRID_COLOR: RwLock<[f32; 3]> = RwLock::new([0.07, 0.07, 0.09]);
static GRAPH_OPACITY: RwLock<f32> = RwLock::new(0.95);
/// Opacity of the graph's NODE-domain content (node bodies, wires, connectors,
/// node text) — `style.surface.graph.node.opacity`, deliberately independent of
@@ -550,11 +549,11 @@ fn parse_and_set_colors(content: &str) {
}
}
- if let Some(c) = get_color("/style/surface/graph/cell_color") {
- if let Ok(mut lock) = GRAPH_CELL_COLOR.write() { *lock = [c[0], c[1], c[2]]; }
- }
- if let Some(c) = get_color("/style/surface/graph/gap_color") {
- if let Ok(mut lock) = GRAPH_GAP_COLOR.write() { *lock = [c[0], c[1], c[2]]; }
+ // The lattice's lines. The cells between them have no colour of their
+ // own: a graph shows whatever it is painted on. `cell_color` and
+ // `gap_color`, the cell model's pair, are retired (`retired_surface_keys`).
+ if let Some(c) = get_color("/style/surface/graph/grid_color") {
+ if let Ok(mut lock) = GRAPH_GRID_COLOR.write() { *lock = [c[0], c[1], c[2]]; }
}
if let Some(c) = get_color("/style/surface/graph/node/color") {
if let Ok(mut lock) = GRAPH_NODE_COLOR.write() { *lock = c; }
@@ -683,7 +682,7 @@ fn parse_and_set_colors(content: &str) {
let retired = retired_surface_keys(&val);
if !retired.is_empty() {
log::warn!(
- "retired style.surface keys in config: {} — the frost is `plate {{ frost radius= compression= refraction= }}` (a material's `frost` child spells `compression`), every roll's width is `relief width=`, the light strength is `relief light=` (a material's `finish light=`), and the relief's geometry is `relief {{ wall height= profile= ; edge height= profile= }}` (the window_manager bevel_* spellings are the same relief keys, and its bevel_shader is `relief shader=`)",
+ "retired style.surface keys in config: {} — the frost is `plate {{ frost radius= compression= refraction= }}` (a material's `frost` child spells `compression`), every roll's width is `relief width=`, the light strength is `relief light=` (a material's `finish light=`), and the relief's geometry is `relief {{ wall height= profile= ; edge height= profile= }}` (the window_manager bevel_* spellings are the same relief keys, and its bevel_shader is `relief shader=`); a graph's lines are `graph {{ grid_color }}` and its cells take no colour",
retired.join(", ")
);
}
@@ -781,7 +780,9 @@ fn parse_and_set_colors(content: &str) {
/// / `bevel_width` / `bevel_shader`, the block the relief keys were born in
/// before `style.surface.relief` existed (the compositor never read them;
/// the shader toggle is `relief.shader` now). Each was an alias for part
-/// of 2026-09-28 and is not read now. Empty for a clean config.
+/// of 2026-09-28 and is not read now. And the graph's `cell_color` and
+/// `gap_color` (2026-09-29): a graph's cells have no colour, and its lines
+/// are `graph.grid_color`. Empty for a clean config.
pub fn retired_surface_keys(val: &serde_json::Value) -> Vec<String> {
let mut found = Vec::new();
for k in ["blur", "radius", "backdrop_compression", "refraction", "bevel_width"] {
@@ -812,6 +813,11 @@ pub fn retired_surface_keys(val: &serde_json::Value) -> Vec<String> {
}
}
}
+ for k in ["cell_color", "gap_color"] {
+ if val.pointer(&format!("/style/surface/graph/{k}")).is_some() {
+ found.push(format!("style.surface.graph.{k}"));
+ }
+ }
found
}
@@ -941,22 +947,14 @@ pub fn set_graph_node_drag_color(color: [f32; 4]) {
style_write(&GRAPH_NODE_DRAG_COLOR, color);
}
-pub fn graph_cell_color() -> [f32; 3] {
- load_colors_once();
- style_read(&GRAPH_CELL_COLOR)
-}
-
-pub fn set_graph_cell_color(color: [f32; 3]) {
- style_write(&GRAPH_CELL_COLOR, color);
-}
-
-pub fn graph_gap_color() -> [f32; 3] {
+/// The colour of a graph's grid lines (`style.surface.graph.grid_color`).
+pub fn graph_grid_color() -> [f32; 3] {
load_colors_once();
- style_read(&GRAPH_GAP_COLOR)
+ style_read(&GRAPH_GRID_COLOR)
}
-pub fn set_graph_gap_color(color: [f32; 3]) {
- style_write(&GRAPH_GAP_COLOR, color);
+pub fn set_graph_grid_color(color: [f32; 3]) {
+ style_write(&GRAPH_GRID_COLOR, color);
}
pub fn graph_opacity() -> f32 {
@@ -2275,6 +2273,8 @@ mod tests {
"relief": { "depth": 0.15, "height": 1.0, "profile": "a", "edge_height": 2.0, "edge_profile": "b" },
"material": { "glass": { "frost": { "backdrop_compression": 0.6 }, "finish": { "depth": 0.2 } } }
} }, "window_manager": { "bevel_depth": 0.15, "bevel_width": 9.3, "bevel_shader": 0 } });
+ let mut old = old;
+ old["style"]["surface"]["graph"] = serde_json::json!({ "cell_color": "#545467", "gap_color": "#48485b", "grid_color": "#48485b" });
assert_eq!(retired_surface_keys(&old), vec![
"style.surface.plate.blur",
"style.surface.plate.radius",
@@ -2292,6 +2292,8 @@ mod tests {
"window_manager.bevel_shader",
"style.surface.material.glass.frost.backdrop_compression",
"style.surface.material.glass.finish.depth",
+ "style.surface.graph.cell_color",
+ "style.surface.graph.gap_color",
]);
assert!(retired_surface_keys(&serde_json::json!({})).is_empty());
}
diff --git a/src/layout.rs b/src/layout.rs
index 952fc29..0ccbaf3 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -348,8 +348,7 @@ fn flatten_json_to_flat_props(val: &serde_json::Value, prefix: &str, flat_props:
"style.surface.statusbar.font" => "statusbar_font",
"style.surface.page.opacity" => "page_opacity",
"style.surface.page.margin" => "page_margin",
- "style.surface.graph.cell_color" => "graph_cell_color",
- "style.surface.graph.gap_color" => "graph_gap_color",
+ "style.surface.graph.grid_color" => "graph_grid_color",
"style.surface.graph.opacity" => "graph_opacity",
"style.surface.graph.node.opacity" => "graph_node_opacity",
"style.surface.graph.spacing_x" => "graph_spacing_x",
@@ -7108,10 +7107,7 @@ mod tests {
// module's reach; what is checkable without writing them is that each
// resolves to a real, in-gamut colour rather than an unparsed or
// uninitialised one.
- let rgb: [(&str, [f32; 3]); 2] = [
- ("graph_cell", crate::color::graph_cell_color()),
- ("graph_gap", crate::color::graph_gap_color()),
- ];
+ let rgb: [(&str, [f32; 3]); 1] = [("graph_grid", crate::color::graph_grid_color())];
for (name, c) in rgb {
assert!(c.iter().all(|v| v.is_finite() && (0.0..=1.0).contains(v)), "{name}: {c:?}");
}
diff --git a/src/widget/display/graph.rs b/src/widget/display/graph.rs
index 8213e80..c1b901f 100644
--- a/src/widget/display/graph.rs
+++ b/src/widget/display/graph.rs
@@ -106,8 +106,7 @@ pub struct Graph {
/// Node-domain opacity (bodies, wires, connectors) — independent of
/// `network_opacity`, which fades the pane surface (grid cells/gaps).
node_opacity: f32,
- cell_color: [f32; 3],
- gap_color: [f32; 3],
+ grid_color: [f32; 3],
// Connection state
connecting_from: Option<(usize, PortType, usize)>,
@@ -138,8 +137,7 @@ impl Graph {
let node_h = crate::layout::graph_node_height();
let grid_snap_enabled = crate::layout::graph_grid_snap();
- let cell_col = crate::color::graph_cell_color();
- let gap_col = crate::color::graph_gap_color();
+ let grid_col = crate::color::graph_grid_color();
Adapted::new(Graph {
show_network_grid: false,
@@ -166,8 +164,7 @@ impl Graph {
uniform_background: false,
network_opacity: crate::color::graph_opacity(),
node_opacity: crate::color::graph_node_opacity(),
- cell_color: cell_col,
- gap_color: gap_col,
+ grid_color: grid_col,
connecting_from: None,
current_mouse_pos: (0.0, 0.0),
pending_connection: None,
@@ -215,11 +212,8 @@ impl Graph {
pub fn grid_snap_enabled(&self) -> bool {
self.grid_snap_enabled
}
- pub fn set_cell_color(&mut self, color: [f32; 3]) {
- self.cell_color = color;
- }
- pub fn set_gap_color(&mut self, color: [f32; 3]) {
- self.gap_color = color;
+ pub fn set_grid_color(&mut self, color: [f32; 3]) {
+ self.grid_color = color;
}
/// The top-left corner of a node body centred on lattice cell (col, row).
@@ -378,17 +372,16 @@ impl Graph {
}
}
- /// The graph's plate, as the colour-typed host paints it: the cell
- /// colour (or a near-transparent black) at the network opacity, and
- /// under `graph_blur` a frosted material whose tint alpha IS the blur
- /// value — the knob doubles as the frost's opacity.
+ /// The graph's plate, as the colour-typed host paints it: a
+ /// near-transparent black, so the cells between the grid lines are
+ /// whatever the graph is painted on, and under `graph_blur` a frosted
+ /// material whose tint alpha IS the blur value — the knob doubles as
+ /// the frost's opacity. Until 2026-09-29 a `uniform_background` graph
+ /// filled itself with a cell colour of its own (`graph.cell_color`);
+ /// the flag is kept for the hosts that set it and chooses nothing here.
fn bg_color(&self) -> [f32; 4] {
use crate::scene::{Frost, Material, PlateRole};
- let c = if self.uniform_background {
- [self.cell_color[0], self.cell_color[1], self.cell_color[2], self.network_opacity]
- } else {
- [0.0, 0.0, 0.0, 0.01 * self.network_opacity]
- };
+ let c = [0.0, 0.0, 0.0, 0.01 * self.network_opacity];
let blur_val = crate::layout::graph_blur();
let m = if blur_val > 0.0 {
Material::opaque([c[0], c[1], c[2], blur_val.abs() * self.network_opacity]).with_frost(Frost::from_style())
@@ -416,7 +409,7 @@ impl Graph {
}
/// The grid lines, flat, over whatever the graph is painted on — the
- /// pane plate. A lattice of lines one pitch apart in the gap colour at
+ /// pane plate. A lattice of lines one pitch apart in the grid colour at
/// the network opacity, each centred on its coordinate (the pitch is
/// measured centre to centre, and `graph_line_width` only thickens
/// them), so the intersections are exactly where the node centres go.
@@ -445,7 +438,7 @@ impl Graph {
let line = crate::layout::graph_line_width().max(0.0);
if self.show_network_grid && line > 0.0 && self.pitch_x >= 4.0 && self.pitch_y >= 4.0 {
- let color = [self.gap_color[0], self.gap_color[1], self.gap_color[2], self.network_opacity];
+ let color = [self.grid_color[0], self.grid_color[1], self.grid_color[2], self.network_opacity];
// The line indices that can cross the rect, one past each edge so
// a line's own width never pops at the boundary.
let c0 = ((min_x - self.grid_origin_x) / self.pitch_x).floor() as i32 - 1;