GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat(layout): control_relief is read live; set_control_relief switches it
Every control captured `control_relief()` once at construction into a
`raised` / `recessed` bool, so the DE's relief setting could only change
between runs, and a gallery had to build a second copy of each widget to show
its flat look. The flag is now `Option<bool>` on all fourteen widgets that
carry it — Button, Toggle, Dropdown, FontSelector, ButtonStrip,
KeybindRecorder, ColorSelector, TextBox, Trackpad, ProgressBar, UsageBar,
MenuBar, StatusBar — read through a `raised()` / `recessed()` accessor that
falls back to `control_relief()` at paint and layout; `with_raised` /
`with_recessed` / `with_recess` pin one widget either way, as before.
`layout::set_control_relief` writes the registry value so a process can
switch every unpinned control at once (the gallery's Style dropdown). Not
persisted; a config reload restores the configured value.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
src/layout.rs | 17 ++++++++++++++---
src/widget/container/menu.rs | 15 +++++++++++----
src/widget/display/progress_bar.rs | 15 +++++++++++----
src/widget/display/status_bar.rs | 15 +++++++++++----
src/widget/display/usage_bar.rs | 15 +++++++++++----
src/widget/input/button.rs | 15 +++++++++++----
src/widget/input/button_strip.rs | 21 ++++++++++++++-------
src/widget/input/checkbox.rs | 15 +++++++++++----
src/widget/input/color_selector.rs | 21 ++++++++++++++-------
src/widget/input/dropdown.rs | 17 ++++++++++++-----
src/widget/input/font_selector.rs | 15 +++++++++++----
src/widget/input/keybind_recorder.rs | 15 +++++++++++----
src/widget/input/text_box.rs | 17 ++++++++++++-----
src/widget/input/trackpad.rs | 15 +++++++++++----
14 files changed, 165 insertions(+), 63 deletions(-)
diff --git a/src/layout.rs b/src/layout.rs
index 3b82d03..a686bc9 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -1847,14 +1847,25 @@ pub fn bar_wall_width() -> f32 {
/// DE-wide default for the controls' relief styling (`window_manager.control_relief`
/// in config.kdl, default on): raised Button/Toggle/Dropdown plates, recessed
-/// TextBox/Slider wells, recessed MenuBar/StatusBar bands. Widgets read this at
-/// construction; the per-widget `with_raised` / `with_recessed` / `with_recess`
-/// builders override it either way. `0` reverts the whole DE to the flat look.
+/// TextBox/Slider wells, recessed MenuBar/StatusBar bands. Widgets read this
+/// LIVE, at paint and layout, so [`set_control_relief`] restyles every control
+/// in the process at once; the per-widget `with_raised` / `with_recessed` /
+/// `with_recess` builders pin one widget either way. `0` reverts the whole DE
+/// to the flat look.
pub fn control_relief() -> bool {
lazy_init_style_registry();
get_style_registry().read().unwrap().get_float("control_relief").map(|v| v != 0.0).unwrap_or(true)
}
+/// Switch the controls' relief styling at runtime — the gallery's Style
+/// dropdown. Every widget without a per-widget override follows on its next
+/// paint; the caller asks for a rebuild. Not persisted: a config reload puts
+/// the configured value back.
+pub fn set_control_relief(relief: bool) {
+ lazy_init_style_registry();
+ get_style_registry().write().unwrap().set_float("control_relief", if relief { 1.0 } else { 0.0 });
+}
+
pub fn toggle_corner_radius() -> f32 {
lazy_init_style_registry();
get_style_registry().read().unwrap().get_float("toggle_corner_radius").unwrap_or_else(control_corner_radius)
diff --git a/src/widget/container/menu.rs b/src/widget/container/menu.rs
index 63a101e..f161b97 100644
--- a/src/widget/container/menu.rs
+++ b/src/widget/container/menu.rs
@@ -36,7 +36,7 @@ pub struct MenuBar {
/// Draw as a recess carved into the window root plate instead of as an opaque bar:
/// no background fill of its own, just shaded edges, so the plate shows through.
/// `color` is ignored while this is set — see [`Adapted::<MenuBar>::with_recess`].
- pub recessed: bool,
+ pub recessed: Option<bool>,
pub title: String,
pub menus: Adapted<ButtonStrip>,
pub menu_items: Vec<String>,
@@ -65,6 +65,13 @@ pub struct MenuBar {
}
impl MenuBar {
+ /// The style in force: the per-widget override (`with_recess`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(x: f32, y: f32, w: f32, h: f32) -> Adapted<MenuBar> {
let mut bar = Adapted::new(MenuBar {
visible: true,
@@ -72,7 +79,7 @@ impl MenuBar {
curved_circle: None,
blur: false,
color: None,
- recessed: crate::layout::control_relief(),
+ recessed: None,
title: String::new(),
menus: Adapted::new(ButtonStrip::new(x, y, w, h).with_inherit_menubar_font(true)),
menu_items: Vec::new(),
@@ -359,7 +366,7 @@ impl Adapted<MenuBar> {
/// than a slab sitting on it. Shading follows the DE-wide `light_source_position` /
/// `bevel_depth` config, inverted so the light-facing edges are the shadowed ones.
pub fn with_recess(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
@@ -464,7 +471,7 @@ impl Paint for MenuBar {
}
fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
- if self.recessed {
+ if self.recessed() {
// No background of our own: carve the root plate instead. The recess shading is
// a light/shadow overlay, so whatever the plate painted here (fill, rim
// gradient, blur) shows through modulated.
diff --git a/src/widget/display/progress_bar.rs b/src/widget/display/progress_bar.rs
index 9bee403..dcac390 100644
--- a/src/widget/display/progress_bar.rs
+++ b/src/widget/display/progress_bar.rs
@@ -14,19 +14,26 @@ pub struct ProgressBar {
/// plate below — no track fill, the plate is the floor — with the progress
/// fill inset onto that floor. Defaults to `control_relief()`; the flat
/// style keeps the filled, rounded track.
- recessed: bool,
+ recessed: Option<bool>,
}
impl ProgressBar {
+ /// The style in force: the per-widget override (`with_recessed`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(value: f32) -> Adapted<ProgressBar> {
- Adapted::new(ProgressBar { value, recessed: crate::layout::control_relief() })
+ Adapted::new(ProgressBar { value, recessed: None })
}
}
impl Adapted<ProgressBar> {
/// Recessed style: see the `recessed` field.
pub fn with_recessed(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
}
@@ -49,7 +56,7 @@ impl Paint for ProgressBar {
fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
let radius = crate::layout::slider_corner_radius();
- if self.recessed {
+ if self.recessed() {
// The Slider's recessed composition: the fill sits on the well's flat
// floor (past the wall's inner half-span), the carve comes after it so
// the walls' shading modulates what they cross.
diff --git a/src/widget/display/status_bar.rs b/src/widget/display/status_bar.rs
index a3f8b10..36beb0b 100644
--- a/src/widget/display/status_bar.rs
+++ b/src/widget/display/status_bar.rs
@@ -24,10 +24,17 @@ pub struct StatusBar {
/// background fill of its own, just the shaded wall facing the content, so the plate
/// shows through. `bg_color` is ignored while this is set — see
/// [`Adapted::<StatusBar>::with_recess`].
- pub recessed: bool,
+ pub recessed: Option<bool>,
}
impl StatusBar {
+ /// The style in force: the per-widget override (`with_recess`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new() -> Adapted<StatusBar> {
Adapted::new(StatusBar {
rect: Rect { x: 0.0, y: 0.0, width: 0.0, height: 0.0 },
@@ -36,7 +43,7 @@ impl StatusBar {
text_offset_x: None,
text_color: None,
bg_color: None,
- recessed: crate::layout::control_relief(),
+ recessed: None,
})
}
@@ -92,7 +99,7 @@ impl Adapted<StatusBar> {
/// (facing the content) — the other three sides are the plate's outer edge, which
/// carries its own roll.
pub fn with_recess(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
}
@@ -137,7 +144,7 @@ impl Paint for StatusBar {
/// default `all_rounded_quads` path) — plus the text label (the legacy `text_labels`
/// body; deliberately no `widget_font`, see module docs).
fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
- if self.recessed {
+ if self.recessed() {
// The recess shading is a light/shadow overlay — whatever the plate painted
// here shows through modulated, so no surface color is needed.
// Capped against the bar's own height so a deep DE-wide roll can't swallow it
diff --git a/src/widget/display/usage_bar.rs b/src/widget/display/usage_bar.rs
index c554c9d..46ab580 100644
--- a/src/widget/display/usage_bar.rs
+++ b/src/widget/display/usage_bar.rs
@@ -14,16 +14,23 @@ pub struct UsageBar {
/// Recessed-track style, the ProgressBar's: a well carved into the plate,
/// `bg_color` unused (the plate is the floor), the fill inset onto it.
/// Defaults to `control_relief()`.
- recessed: bool,
+ recessed: Option<bool>,
}
impl UsageBar {
+ /// The style in force: the per-widget override (`with_recessed`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(value: f32) -> Adapted<UsageBar> {
Adapted::new(UsageBar {
value: value.clamp(0.0, 1.0),
fill_color: [0.30, 0.50, 0.32, 1.0], // green-ish
bg_color: [0.15, 0.15, 0.24, 1.0], // dark-ish
- recessed: crate::layout::control_relief(),
+ recessed: None,
})
}
@@ -43,7 +50,7 @@ impl Adapted<UsageBar> {
/// Recessed style: see the `recessed` field.
pub fn with_recessed(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
}
@@ -61,7 +68,7 @@ impl Paint for UsageBar {
}
fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
- if self.recessed {
+ if self.recessed() {
// The ProgressBar's recessed composition: fill on the well floor, then
// the carve, rounded like the sliders' tracks.
let radius = crate::layout::slider_corner_radius();
diff --git a/src/widget/input/button.rs b/src/widget/input/button.rs
index c765ee3..04c3a4d 100644
--- a/src/widget/input/button.rs
+++ b/src/widget/input/button.rs
@@ -52,7 +52,7 @@ pub struct Button {
focused: bool,
/// Raised style: the background is an SDF-lit `Bevel` plate — fill plus a
/// rolled, lit edge — instead of a flat fill + border stroke.
- raised: bool,
+ raised: Option<bool>,
}
impl std::fmt::Debug for Button {
@@ -70,6 +70,13 @@ impl std::fmt::Debug for Button {
}
impl Button {
+ /// The style in force: the per-widget override (`with_raised`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn raised(&self) -> bool {
+ self.raised.unwrap_or_else(crate::layout::control_relief)
+ }
+
fn model(kind: ButtonKind) -> Button {
Button {
pressed: false,
@@ -86,7 +93,7 @@ impl Button {
icon_alpha: 1.0,
hovered: false,
focused: false,
- raised: crate::layout::control_relief(),
+ raised: None,
}
}
@@ -190,7 +197,7 @@ impl Button {
/// (flat styling, or a ListRow / MenuItem, transparent-until-hover
/// surfaces that would wear a permanent carved ring on every idle row).
pub fn plate(&self, rect: Rect) -> Option<crate::widget::ControlPlate> {
- if !self.raised
+ if !self.raised()
|| self.kind == ButtonKind::ListRow
|| self.kind == ButtonKind::MenuItem
{
@@ -232,7 +239,7 @@ impl Adapted<Button> {
/// Raised style: see the `raised` field.
pub fn with_raised(mut self, raised: bool) -> Self {
- self.raised = raised;
+ self.raised = Some(raised);
self
}
diff --git a/src/widget/input/button_strip.rs b/src/widget/input/button_strip.rs
index 1e9e45a..80459ad 100644
--- a/src/widget/input/button_strip.rs
+++ b/src/widget/input/button_strip.rs
@@ -28,13 +28,20 @@ pub struct ButtonStrip {
/// floor; the selected segment is a plateau raised back out of it, hover
/// and press a wash. Defaults to `control_relief()`; the flat style keeps
/// the plain state quads.
- pub recessed: bool,
+ pub recessed: Option<bool>,
/// Keyboard focus (FocusIn / FocusOut): the selected segment's plate wears
/// the ring; arrows move the selection, Enter / Space press it.
focused: bool,
}
impl ButtonStrip {
+ /// The style in force: the per-widget override (`with_recessed`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
Self {
x,
@@ -54,14 +61,14 @@ impl ButtonStrip {
last_scale: None,
inherit_menubar_font: false,
label: None,
- recessed: crate::layout::control_relief(),
+ recessed: None,
focused: false,
}
}
/// Recessed style: see the `recessed` field.
pub fn with_recessed(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
@@ -352,7 +359,7 @@ impl crate::widget::Paint for ButtonStrip {
// through `all_rounded_quads`, which the Paginator aggregates).
let (sx, sy, sw, sh) = self.rect();
let radius = crate::layout::button_corner_radius();
- let depth = if self.recessed {
+ let depth = if self.recessed() {
let short = if self.vertical { sw } else { sh };
let depth = crate::layout::bevel_width().min(short * 0.2);
let (well, radii) = crate::layout::carve_inside(Rect { x: sx, y: sy, width: sw, height: sh }, (radius, radius, radius, radius), depth);
@@ -376,12 +383,12 @@ impl crate::widget::Paint for ButtonStrip {
// The segment's footprint: in the well, inset by the wall's inner
// half-span so it stands on the floor (the selected plateau's rect);
// flat, the item rect itself. The state fill and the plateau share it.
- let inset = if self.recessed { depth * 0.5 } else { 0.0 };
+ let inset = if self.recessed() { depth * 0.5 } else { 0.0 };
let seg = Rect { x: r.0 + inset, y: r.1 + inset, width: (r.2 - 2.0 * inset).max(0.0), height: (r.3 - 2.0 * inset).max(0.0) };
let seg_r = (radius - inset).max(0.0);
let focus_ring = self.focused && Some(i) == self.selected;
if bg_color != [0.0, 0.0, 0.0, 0.0] {
- if focus_ring && !self.recessed {
+ if focus_ring && !self.recessed() {
// Flat: no rim to light, so the selected fill wears a hairline
// ring in the highlight.
let t = crate::widget::ControlPlate::focus_tint();
@@ -390,7 +397,7 @@ impl crate::widget::Paint for ButtonStrip {
pc.rounded_rect(seg, seg_r, (true, true, true, true), bg_color);
}
}
- if self.recessed && Some(i) == self.selected {
+ if self.recessed() && Some(i) == self.selected {
// The selected segment: a raised control plate standing on the
// well floor, faceless (the floor shows through), at the well's
// depth — its rim lit while the strip holds keyboard focus.
diff --git a/src/widget/input/checkbox.rs b/src/widget/input/checkbox.rs
index 0d2bb99..9ce7f85 100644
--- a/src/widget/input/checkbox.rs
+++ b/src/widget/input/checkbox.rs
@@ -233,7 +233,7 @@ pub struct Toggle {
/// beveled edges, the state half a raised plateau, the other recessed
/// (see `rocker_reliefs` and the paint impl) — and the flat style's
/// state gradient is dropped.
- raised: bool,
+ raised: Option<bool>,
/// The slide style's animated button position, 0 (left/off) → 1 (right/on).
/// Chases `toggled` in `tick` after a click; programmatic state syncs
/// (`set_toggled`, `set_value_string`) snap it, so only user interaction
@@ -245,6 +245,13 @@ pub struct Toggle {
}
impl Toggle {
+ /// The style in force: the per-widget override (`with_raised`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn raised(&self) -> bool {
+ self.raised.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new() -> Adapted<Toggle> {
Adapted::new(Toggle {
toggled: false,
@@ -253,7 +260,7 @@ impl Toggle {
hovered: false,
focused: false,
justify: Justification::Center,
- raised: crate::layout::control_relief(),
+ raised: None,
slide_t: 0.0,
slide_override: None,
})
@@ -369,7 +376,7 @@ impl Toggle {
edges: (true, true, true, true),
}];
}
- if !self.raised {
+ if !self.raised() {
return Vec::new();
}
// The carves stay inside the pill (`layout::carve_inside`): the halves are
@@ -442,7 +449,7 @@ impl Adapted<Toggle> {
/// Raised style: see the `raised` field.
pub fn with_raised(mut self, raised: bool) -> Self {
- self.raised = raised;
+ self.raised = Some(raised);
self
}
diff --git a/src/widget/input/color_selector.rs b/src/widget/input/color_selector.rs
index 5f97634..8fc9bcb 100644
--- a/src/widget/input/color_selector.rs
+++ b/src/widget/input/color_selector.rs
@@ -35,7 +35,7 @@ pub struct ColorSelector {
/// (the TextBox's, rim lit while editing) and the swatch a raised bevel
/// plate of its colour, instead of the hairline frame and the flat swatch
/// with its glow. Defaults to `control_relief()`.
- recessed: bool,
+ recessed: Option<bool>,
}
impl Clone for ColorSelector {
@@ -63,6 +63,13 @@ impl Clone for ColorSelector {
}
impl ColorSelector {
+ /// The style in force: the per-widget override (`with_recessed`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(color: [u8; 3]) -> Adapted<ColorSelector> {
Adapted::new(ColorSelector {
color,
@@ -81,7 +88,7 @@ impl ColorSelector {
live_rx: None,
revert_hex: None,
glyph_offsets: Vec::new(),
- recessed: crate::layout::control_relief(),
+ recessed: None,
})
}
@@ -103,7 +110,7 @@ impl ColorSelector {
live_rx: None,
revert_hex: None,
glyph_offsets: Vec::new(),
- recessed: crate::layout::control_relief(),
+ recessed: None,
})
}
@@ -112,7 +119,7 @@ impl ColorSelector {
/// widget's assigned content `rect`, or None when the style is off. The same
/// geometry `paint` carves (untinted).
pub fn field_relief(&self, rect: Rect) -> Option<(f32, f32, f32, f32, f32, f32)> {
- if !self.recessed {
+ if !self.recessed() {
return None;
}
let well_h = crate::layout::color_selector_height().min(rect.height);
@@ -133,7 +140,7 @@ impl ColorSelector {
impl Adapted<ColorSelector> {
/// Recessed style: see the `recessed` field.
pub fn with_recessed(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
@@ -251,7 +258,7 @@ impl Paint for ColorSelector {
// A real frame, not a border-quad-under-fill-quad: with no fill, the
// old full-rect border quad would read as a solid slab. Rounded at the
// selector's radius like the well it stands in for.
- if !self.recessed {
+ if !self.recessed() {
let fr = crate::layout::color_selector_corner_radius();
ctx.border(rect, (fr, fr, fr, fr), [0.0; 4], border_color, 1.0);
}
@@ -321,7 +328,7 @@ impl Paint for ColorSelector {
}
};
- if self.recessed {
+ if self.recessed() {
// The Breadcrumb composition: ONE well across the whole control,
// the hex text on its floor at the left and the swatch as the
// colour laid flush on the floor's right segment (the well's
diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index 601342a..01d1465 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -106,7 +106,7 @@ pub struct Dropdown {
corner_frame: Option<((f32, f32, f32, f32), f32, (bool, bool, bool, bool))>,
/// Raised style: the closed control's background is an SDF-lit `Bevel`
/// plate (fill + rolled lit edge) instead of a flat fill + border stroke.
- raised: bool,
+ raised: Option<bool>,
/// Keyboard focus (FocusIn / FocusOut): lights the trigger plate's rim.
focused: bool,
/// The open menu REPLACES the trigger instead of growing out of it: no
@@ -138,6 +138,13 @@ pub struct Dropdown {
}
impl Dropdown {
+ /// The style in force: the per-widget override (`with_raised`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn raised(&self) -> bool {
+ self.raised.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(options: Vec<String>, selected: usize) -> Adapted<Dropdown> {
Adapted::new(Dropdown {
options,
@@ -154,7 +161,7 @@ impl Dropdown {
label: None,
hovered: false,
corner_frame: None,
- raised: crate::layout::control_relief(),
+ raised: None,
focused: false,
menu_replaces_trigger: false,
anim_from: 0.0,
@@ -425,7 +432,7 @@ impl Dropdown {
// flat outlines, which a rolled edge replaces). A transparent
// configured fill degrades to a Boss: edges only, plate as the face —
// judged on the RAW alpha, before the opacity force above.
- if self.raised {
+ if self.raised() {
let depth = crate::layout::bevel_width().min(visual_h * 0.2);
// Concentric corner_frame adjustment applies to the relief too: a
// corner nested at equal gaps into the frame follows its curve.
@@ -737,7 +744,7 @@ impl Dropdown {
impl Adapted<Dropdown> {
/// Raised style: see the `raised` field.
pub fn with_raised(mut self, raised: bool) -> Self {
- self.raised = raised;
+ self.raised = Some(raised);
self
}
@@ -906,7 +913,7 @@ impl Paint for Dropdown {
c[3] = -crate::color::menu_opacity();
c
};
- if self.raised {
+ if self.raised() {
let depth = crate::layout::bevel_width().min(rect.height * 0.2);
let (t, tr) = crate::layout::carve_inside(
crate::scene::layout::Rect { x: ux, y: uy, width: uw, height: uh },
diff --git a/src/widget/input/font_selector.rs b/src/widget/input/font_selector.rs
index 082cc7d..27f432d 100644
--- a/src/widget/input/font_selector.rs
+++ b/src/widget/input/font_selector.rs
@@ -20,13 +20,20 @@ pub struct FontSelector {
/// with a transparent face (the plate shows through), the hover and press
/// states a wash inside it. Defaults to `control_relief()`; the flat style
/// keeps the framed dark field.
- raised: bool,
+ raised: Option<bool>,
/// Keyboard focus (FocusIn / FocusOut): lights the plate's rim and arms
/// Enter / Space to open the picker.
focused: bool,
}
impl FontSelector {
+ /// The style in force: the per-widget override (`with_raised`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn raised(&self) -> bool {
+ self.raised.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(font_family: String) -> Adapted<FontSelector> {
Adapted::new(FontSelector {
font_family,
@@ -34,7 +41,7 @@ impl FontSelector {
pressed: false,
hovered: false,
child: Arc::new(Mutex::new(None)),
- raised: crate::layout::control_relief(),
+ raised: None,
focused: false,
})
}
@@ -127,7 +134,7 @@ impl FontSelector {
impl Adapted<FontSelector> {
/// Raised style: see the `raised` field.
pub fn with_raised(mut self, raised: bool) -> Self {
- self.raised = raised;
+ self.raised = Some(raised);
self
}
}
@@ -160,7 +167,7 @@ impl Paint for FontSelector {
fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
let r = crate::layout::font_selector_corner_radius();
- if self.raised {
+ if self.raised() {
// The closed-dropdown chrome: a flush control plate with a
// transparent face, the state fill rounded to sit inside it.
ctx.control_plate(
diff --git a/src/widget/input/keybind_recorder.rs b/src/widget/input/keybind_recorder.rs
index 0b65053..e30eebd 100644
--- a/src/widget/input/keybind_recorder.rs
+++ b/src/widget/input/keybind_recorder.rs
@@ -18,12 +18,19 @@ pub struct KeybindRecorder {
/// plate below with no fill of its own, its rim lit in the highlight
/// accent while recording (the TextBox's editing treatment). Defaults to
/// `control_relief()`; the flat style is the shared well frame.
- recessed: bool,
+ recessed: Option<bool>,
/// Keyboard focus (FocusIn / FocusOut): Enter / Space arm recording.
focused: bool,
}
impl KeybindRecorder {
+ /// The style in force: the per-widget override (`with_recessed`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(value: String) -> Adapted<KeybindRecorder> {
Adapted::new(KeybindRecorder {
value,
@@ -31,7 +38,7 @@ impl KeybindRecorder {
just_changed: false,
pressed: false,
hovered: false,
- recessed: crate::layout::control_relief(),
+ recessed: None,
focused: false,
})
}
@@ -52,7 +59,7 @@ impl KeybindRecorder {
impl Adapted<KeybindRecorder> {
/// Recessed style: see the `recessed` field.
pub fn with_recessed(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
}
@@ -75,7 +82,7 @@ impl Paint for KeybindRecorder {
}
fn paint(&self, rect: Rect, ctx: &mut PaintCtx) {
- if self.recessed {
+ if self.recessed() {
let radius = crate::layout::textbox_corner_radius();
let depth = crate::layout::bevel_width().min(rect.height * 0.2);
let (well, radii) = crate::layout::carve_inside(rect, (radius, radius, radius, radius), depth);
diff --git a/src/widget/input/text_box.rs b/src/widget/input/text_box.rs
index 5b98a87..a49d265 100644
--- a/src/widget/input/text_box.rs
+++ b/src/widget/input/text_box.rs
@@ -105,10 +105,17 @@ pub struct TextBox {
rect: Rect,
/// Recessed style: a `Recess` overlay is carved over the box's own fill —
/// an inset well, the input-direction counterpart of the raised controls.
- recessed: bool,
+ recessed: Option<bool>,
}
impl TextBox {
+ /// The style in force: the per-widget override (`with_recessed`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new(text: String) -> Adapted<TextBox> {
let (style_family, style_size) = crate::layout::control_label_font_detached_parsed();
let editor_state = TextEditorState::new(text.clone());
@@ -151,7 +158,7 @@ impl TextBox {
label: None,
hovered: false,
rect: Rect { x: 0.0, y: 0.0, width: 0.0, height: 0.0 },
- recessed: crate::layout::control_relief(),
+ recessed: None,
})
}
@@ -1186,7 +1193,7 @@ impl TextBox {
/// the bridge is exactly how the two would drift apart.
pub fn well(&self) -> Option<(Rect, f32, f32, Option<[f32; 3]>)> {
let radius = crate::layout::textbox_corner_radius();
- if radius <= 0.0 || !self.recessed || !self.draw_bg_border {
+ if radius <= 0.0 || !self.recessed() || !self.draw_bg_border {
return None;
}
let top = self.label_top();
@@ -1209,7 +1216,7 @@ impl TextBox {
impl Adapted<TextBox> {
/// Recessed style: see the `recessed` field.
pub fn with_recessed(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
@@ -1526,7 +1533,7 @@ impl Paint for TextBox {
// well — the plate below is its floor, so the flat border and
// bg rects are skipped entirely. An opaque fill (e.g. the edit
// color while editing) draws as usual and gets carved.
- let bare = self.recessed && bg_color[3] <= 0.001;
+ let bare = self.recessed() && bg_color[3] <= 0.001;
if !bare {
ctx.rounded_rect(Rect { x, y: self.rect.y + top, width: w, height: visual_h }, radius, corners, border_color);
ctx.rounded_rect(
diff --git a/src/widget/input/trackpad.rs b/src/widget/input/trackpad.rs
index be16a53..08ff2a7 100644
--- a/src/widget/input/trackpad.rs
+++ b/src/widget/input/trackpad.rs
@@ -23,17 +23,24 @@ pub struct Trackpad {
/// Recessed style: the touch area is a well carved into the plate below,
/// a faint dark wash for its floor, instead of the framed dark pane.
/// Defaults to `control_relief()`.
- recessed: bool,
+ recessed: Option<bool>,
}
impl Trackpad {
+ /// The style in force: the per-widget override (`with_recessed`) when set, else
+ /// the DE's `control_relief`, read live so a runtime switch
+ /// (`layout::set_control_relief`) restyles every control at once.
+ fn recessed(&self) -> bool {
+ self.recessed.unwrap_or_else(crate::layout::control_relief)
+ }
+
pub fn new() -> Adapted<Trackpad> {
Adapted::new(Trackpad {
rect: Rect { x: 0.0, y: 0.0, width: 0.0, height: 0.0 },
label: None,
hovered: false,
fingers: Vec::new(),
- recessed: crate::layout::control_relief(),
+ recessed: None,
})
}
@@ -45,7 +52,7 @@ impl Trackpad {
impl Adapted<Trackpad> {
/// Recessed style: see the `recessed` field.
pub fn with_recessed(mut self, recessed: bool) -> Self {
- self.recessed = recessed;
+ self.recessed = Some(recessed);
self
}
}
@@ -96,7 +103,7 @@ impl Paint for Trackpad {
// opening shares (`PaintCtx::canvas_well`), rounded like the text wells;
// the fingers draw over the rim.
let radius = crate::layout::textbox_corner_radius();
- ctx.canvas_well(area, radius, self.recessed, false);
+ ctx.canvas_well(area, radius, self.recessed(), false);
// 3. Fingers
for finger in &self.fingers {