Add a declarative <DragValue> numeric input with a controlled binding. Support drag-to-change with configurable speed, optional clamping to a range, formatting (prefix/suffix, decimals), enable/disable, and tooltips. Emit onChange during updates and optionally onRelease when the user stops dragging/commits.
- Covers a precise numeric input pattern common in tooling, inspectors, and property panels.
- Reduces imperative glue around
egui::DragValue while keeping a controlled-value model.
- Complements
<Slider> for “fine-grained” adjustments and typed entry.
Scope
Non-goals (here): custom formatter callbacks; exponential/logarithmic scaling.
Proposed API (sketch)
Float with range, prefix/suffix
efx!(ui, r#"
<DragValue value={props.price} range="0.0..=9999.0" speed="0.25"
prefix="$" fixedDecimals="2" onChange={|v| props.price = v}/>
"#);
Integer with min/max, quantization and release event
efx!(ui, r#"
<DragValue value={model.count} min="0" max="1000" speed="1.0" step="5"
suffix=" pcs" onRelease={|v| persist(v)}/>
"#);
Conceptual mapping to egui
let mut v = /* bound number */;
let mut dv = egui::DragValue::new(&mut v).speed(speed);
// Clamp range
if let Some(r) = clamp_range { dv = dv.clamp_range(r); }
if !clamp_to_range { dv = dv.clamp_to_range(false); }
// Formatting
if let Some(p) = prefix { dv = dv.prefix(p); }
if let Some(s) = suffix { dv = dv.suffix(s); }
if let Some(n) = fixed_decimals { dv = dv.fixed_decimals(n); }
else {
if let Some(n) = min_decimals { dv = dv.min_decimals(n); }
if let Some(n) = max_decimals { dv = dv.max_decimals(n); }
}
// Width hint
if let Some(w) = width { dv = dv.width(w); }
let resp = if enabled { ui.add(dv) } else { ui.add_enabled(false, dv) };
if let Some(tip) = tooltip { resp.on_hover_text(tip); }
// Optional quantization
let v_out = if let Some(step) = step { quantize(v, step, clamp_range) } else { v };
let changed = resp.changed() /* and v_out != old */;
if changed { /* write back bound value */ /* emit onChange(v_out) */ }
if resp.drag_released() { /* emit onRelease(v_out) */ }
Tasks
Add a declarative
<DragValue>numeric input with a controlled binding. Support drag-to-change with configurablespeed, optional clamping to a range, formatting (prefix/suffix, decimals), enable/disable, and tooltips. EmitonChangeduring updates and optionallyonReleasewhen the user stops dragging/commits.egui::DragValuewhile keeping a controlled-value model.<Slider>for “fine-grained” adjustments and typed entry.Scope
Tag:
<DragValue>Required:
value={number_expr}Optional attributes:
speed=number(default sensible),clampToRange=bool(defaulttrue)min=number,max=numberorrange="a..=b"(mutually exclusive withmin/max)prefix="...",suffix="...",minDecimals=u8,maxDecimals=u8,fixedDecimals=u8(mutually exclusive withminDecimals/maxDecimals)step=number(snap to multiples inside range after change)enabled=bool,tooltip="...",id="...",width=f32Events:
onChange={|v| ...}— fires when value changes;onRelease={|v| ...}— fires when drag ends (commit-like).Non-goals (here): custom formatter callbacks; exponential/logarithmic scaling.
Proposed API (sketch)
Float with range, prefix/suffix
Integer with min/max, quantization and release event
Conceptual mapping to egui
Tasks
AST & parsing
<DragValue>node; parsevalue,speed,min/maxorrange,clampToRange, formatting attrs,step, and common attrs.rangexor (min&max);fixedDecimalsxor (minDecimals/maxDecimals).min ≤ max.Codegen
value={expr}via local copy →egui::DragValue::new(&mut v)→ write back on change.clamp_range(..); respectclampToRange=false.prefix,suffix, decimals) andwidth.stepquantization (snap to nearest multiple within range) before emitting events.onChange(v)andonRelease(v)appropriately.Diagnostics
valueor bad type → clear error (expects numeric).min > maxor malformedrange→ compile error with example.<DragValue>.Examples & docs
examples/drag_value_price.rs(float with currency, fixed decimals).examples/drag_value_int.rs(int with step snapping and onRelease).docs/tags.md.Tests
wasm32-unknown-unknown(no runtime launch).