Skip to content

Implement <Slider> tag (egui::Slider) #29

@ZhukMax

Description

@ZhukMax

Add a declarative <Slider> widget with a controlled numeric binding and range configuration. Support common UX options (label text, show value, vertical orientation, enable/disable, tooltip) and emit change events. Provide optional value quantization via step.

  • A core numeric control for settings/preferences and live tweaking.
  • Keeps templates concise while preserving a controlled-value model consistent with other EFx inputs.
  • Reduces imperative boilerplate around egui sliders.

Scope

  • Tag: <Slider>

  • Required: value={number_expr}, and either min/max or range="a..=b".

  • Optional attributes:

    • text="..." (label next to/inside the slider) or inline text children (mutually exclusive).
    • showValue=bool (display current value on the slider).
    • orientation="horizontal|vertical" (default: horizontal).
    • step=number (quantize the resulting value to multiples of step after drag).
    • enabled=bool, tooltip="...", id="...", width=f32, height=f32 (best-effort).
  • Events:

    • onChange={|v| ...} — called when value changes.
    • onRelease={|v| ...} — optional; fires when the user releases the drag (based on Response::drag_released()).

Non-goals (here): custom value formatter, units/suffix, logarithmic scaling (can be proposed later if needed).


Proposed API (sketch)

Template

// Basic float slider with label text via attribute
efx!(ui, r#"
<Slider value={model.opacity} min="0.0" max="1.0" step="0.05"
        text="Opacity" showValue="true" onChange={|v| model.opacity = v}/>
"#);

// Vertical integer slider with inline label and release event
efx!(ui, r#"
<Slider value={model.quality} range="0..=100" orientation="vertical"
        onRelease={|v| save_quality(v)}>
  Quality
</Slider>
"#);

Conceptual mapping to egui

let mut v = /* bound number */;
let range = min..=max; // or parsed from "a..=b"
let mut s = egui::Slider::new(&mut v, range);

if let Some(label) = text_or_children_label { s = s.text(label); }
if show_value { s = s.show_value(true); }
if is_vertical { /* use vertical ctor or style hint if available */ }

let resp = if enabled { ui.add(s) } else { ui.add_enabled(false, s) };
if let Some(tip) = tooltip { resp.on_hover_text(tip); }

let mut v_out = v;
// Quantize if step is present
if let Some(step) = step_opt { v_out = quantize_to_step(v_out, step, min, max); }

let changed = resp.changed() && v_out != original_value;
if changed   { /* write back */ /* emit onChange(v_out) */ }
if resp.drag_released() { /* emit onRelease(v_out) */ }

Tasks

  • AST & parsing

    • Add <Slider> node with attributes: value, min, max / range, text, showValue, orientation, step, enabled, tooltip, id, width, height.
    • Enforce single label source: children or text=... (error if both).
    • Validate range format (a..=b) and numeric types.
  • Codegen

    • Bind value={expr} by copying into a local, pass &mut to egui::Slider, then write back if changed.
    • Map optional properties: label, showValue, enabled, tooltip, id, size hints.
    • Support vertical orientation using the appropriate egui API (vertical constructor or parameter).
    • Implement post-drag quantization for step (round to nearest multiple within [min, max]).
    • Emit onChange(v) when value changes; emit onRelease(v) when drag ends.
  • Diagnostics

    • Missing value or min/max/range → clear error with expected usage.
    • Type mismatches (non-numeric value, mixed numeric types) → actionable message.
    • min > max or invalid range → compile error.
    • Dual label sources (children + text) → error; suggest picking one.
    • Unknown attributes → list allowed attributes for <Slider>.
  • Examples & docs

    • examples/slider_basic.rs (float with step, showValue).
    • examples/slider_vertical.rs (integer, vertical, onRelease).
    • Cookbook snippet in docs/cookbook.md; entry in docs/tags.md.
  • Tests

    • trybuild UI tests: missing/invalid attrs, wrong types, label conflict, bad ranges.
    • Unit test for quantization helper (step) and orientation mapping.
    • Ensure examples build for wasm32-unknown-unknown (no runtime).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions