status bar
git clone https://git.lucas.co/cce-status-interface.git
feat: text_halo — full white outline around module text
Four diagonal white text_faded copies (±0.75px) around each non-boxed
run: a true outline readable over any backdrop, for when the single
letterpress edge isn't enough. Takes precedence over text_relief.
Co-Authored-By: Claude Fable 5 <[email protected]>
CLAUDE.md | 4 +++-
src/config.rs | 8 ++++++++
src/main.rs | 19 +++++++++++++++----
3 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index a3a6069..a8b0c80 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -150,7 +150,9 @@ and `module { text_raise }` (lifts module text above vertical center, logical
px, bar-side only — every module funnels through `centered_text_y`) and
`module { text_relief }` (letterpress underlay strength 0-1: a translucent
white copy 0.75px down-right beneath each non-boxed text run — engraved text,
-guaranteed contrast on dark backdrops). Everything is read through
+guaranteed contrast on dark backdrops) and `module { text_halo }` (full white
+outline 0-1: FOUR diagonal white copies around each run; beats text_relief
+when set). Everything is read through
`cce_ui::config::cached_config()`; KDL is converted to JSON
(`cce_ui::config::parse_kdl_to_json`) and looked up by **explicit JSON
pointer only**: every key names its canonical nesting
diff --git a/src/config.rs b/src/config.rs
index 6a12e74..3bbafc3 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -227,6 +227,14 @@ pub(crate) fn read_text_relief_from_config() -> f32 {
cfg_f32("/module/text_relief").unwrap_or(0.0).clamp(0.0, 1.0)
}
+/// `module { text_halo }` — full white outline strength (0 = off, 1 = opaque):
+/// four translucent white copies at the diagonal offsets ±0.75px around each
+/// module text run, a true halo readable over any backdrop. When set it
+/// replaces the single-offset `text_relief` underlay.
+pub(crate) fn read_text_halo_from_config() -> f32 {
+ cfg_f32("/module/text_halo").unwrap_or(0.0).clamp(0.0, 1.0)
+}
+
pub(crate) fn read_status_box_corner_radius_from_config() -> f32 {
// App-native ONLY (~/.config/cce/cce-status-interface/config.kdl,
// merged over the shared config by cce-ui): `module { corner_radius }`.
diff --git a/src/main.rs b/src/main.rs
index 6db6fd0..c148bc5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -263,6 +263,9 @@ struct StatusApp {
/// Letterpress underlay strength for module text (0 = off) — see
/// `read_text_relief_from_config`.
text_relief: f32,
+ /// Full white outline strength (0 = off); beats `text_relief` when set —
+ /// see `read_text_halo_from_config`.
+ text_halo: f32,
text_prims: Vec<TextPrim>,
scale_factor: f64,
@@ -371,6 +374,7 @@ impl StatusApp {
self.droplet = read_droplet_from_config();
self.droplet_boxes.clear();
self.text_relief = read_text_relief_from_config();
+ self.text_halo = read_text_halo_from_config();
self.status_bar.set_rect(0.0, 0.0, self.width as f32, self.height as f32);
// The surface itself is transparent: every StatusApp is a single
@@ -1121,6 +1125,7 @@ impl cce_ui::engine::Application for StatusApp {
droplet_boxes: Vec::new(),
droplet: None,
text_relief: 0.0,
+ text_halo: 0.0,
text_prims: Vec::new(),
scale_factor: 1.0,
width: if selected_module.is_some() { 120 } else { 1920 },
@@ -1418,10 +1423,16 @@ impl cce_ui::engine::Application for StatusApp {
match layout {
Some(l) => pc.text_boxed(text.clone(), *x, *y, *tsize, *color, font.clone(), *bounds, cce_ui::scene::paint::TextAttrs::default(), *l),
None => {
- // Letterpress underlay: a translucent white copy offset
- // down-right BENEATH the glyphs — dark text keeps a lit
- // edge on dark backdrops (the engraved-text treatment).
- if self.text_relief > 0.0 {
+ if self.text_halo > 0.0 {
+ // Full halo: four diagonal white copies — a true
+ // outline, readable over any backdrop.
+ for (dx, dy) in [(-0.75, -0.75), (0.75, -0.75), (-0.75, 0.75), (0.75, 0.75)] {
+ pc.text_faded(text.clone(), *x + dx, *y + dy, *tsize, [255, 255, 255], self.text_halo, font.clone(), *bounds);
+ }
+ } else if self.text_relief > 0.0 {
+ // Letterpress underlay: a translucent white copy offset
+ // down-right BENEATH the glyphs — dark text keeps a lit
+ // edge on dark backdrops (the engraved-text treatment).
pc.text_faded(text.clone(), *x + 0.75, *y + 0.75, *tsize, [255, 255, 255], self.text_relief, font.clone(), *bounds);
}
pc.text_with(text.clone(), *x, *y, *tsize, *color, font.clone(), *bounds)