grafix_toolbox/gui/elements/
slidernum.rs1use super::*;
2
3#[derive(Debug)]
4pub struct SliderNum {
5 slider: Slider,
6 num: LineEdit,
7 inc: Button,
8 dec: Button,
9 pub value: f32,
10 last_value: f32,
11 step: Mod,
12}
13impl Default for SliderNum {
14 fn default() -> Self {
15 let (last_value, step) = (f32::NAN, Mod::empty());
16 let (slider, num, inc, dec, value) = Def();
17 Self { slider, num, inc, dec, value, last_value, step }
18 }
19}
20impl SliderNum {
21 pub fn draw<'s: 'l, 'l>(&'s mut self, r: &mut RenderLock<'l>, t: &'l Theme, layout @ Surf { size, .. }: Surf, (min, max): Vec2) -> f32 {
22 ASSERT!(min < max, "SliderNum range expects min < max");
23 let side = size.min_comp();
24 let (format, range, half_side) = (|v: &f32| format(*v, min < 0.), max - min, side * 0.5);
25
26 let Self { slider, num, inc, dec, value, last_value, step } = self;
27
28 let ss = layout.w_sub(half_side);
29 if size.x() < size.y() {
30 let v = slider.draw(r, t, ss, side) * range + min;
31 *value = v;
32 return v;
33 }
34
35 let adv_step = move |step: &Mod| {
36 1.0.or_val(range > 2., || {
37 let s = half_side / range;
38 let mag = 10f32.powf(s.abs().log10().floor());
39 (s / mag).round() * mag
40 })
41 .or_map(|_| !step.ctrl(), |s| s * 0.1.or_val(range < 1., || 20.))
42 .or_map(|_| !step.shift(), |s| s * 0.01.or_val(range < 100., || 200.))
43 };
44
45 let sl = ss.size((3., 0.9).mul(side));
46 let sb = ss.x_self(1).size((half_side, half_side));
47
48 if dec.draw(r, t, sb, "-") {
49 *value -= adv_step(step);
50 }
51 if inc.draw(r, t, sb.y(half_side), "+") {
52 *value += adv_step(step);
53 }
54
55 *value = value.clamp(min, max);
56
57 let (editing, edited) = num.edited(r);
58
59 if value != last_value {
60 num.text = format(value).into();
61 } else if editing {
62 num.text = "".into();
63 } else if edited {
64 *value = num.text.trim_start().parse::<f32>().map(|n| n.clamp(min, max)).unwrap_or(*value);
65 num.text = format(value).into();
66 }
67 slider.pip_pos = slider.pip_pos.or_val(value == last_value, || (*value - min) / range);
68
69 *last_value = *value;
70
71 let v = slider.draw(r, t, ss, side) * range + min;
72
73 *value = value.or_val(value.eps_eq(v), || v);
74
75 num.draw(r, t, sl, NumericOnly().pipe(Some));
76
77 r.logic(
78 layout,
79 move |e, _, _| {
80 if let &MouseButton { m, .. } = e
81 && m.pressed()
82 {
83 *step = m
84 }
85
86 Pass
87 },
88 0,
89 );
90 *value
91 }
92}
93
94impl<'s: 'l, 'l> Lock::SliderNum<'s, 'l, '_> {
95 pub fn draw<O>(self, g: impl Into<Surf>, l: O) -> f32
96 where
97 Vec2: Cast<O>,
98 {
99 let Self { s, r, t } = self;
100 s.draw(r, t, g.into(), Vec2(l))
101 }
102}
103
104fn format(n: f32, signed: bool) -> String {
105 let max_len = 6;
106
107 let slots = max_len - u32(signed);
108 let max_len = usize(max_len);
109
110 let n = (|| {
111 if n == 0. {
112 return "0".into();
113 }
114
115 let min_frac = 10_f32.powi(-i32(slots - 2));
116 if n >= f32(10_u32.pow(slots)) || n.abs() <= min_frac {
117 let n = format!("{n:+.*e}", usize(slots - 4));
118 return n.or_map(|_| signed, |n| n[1..].into());
119 }
120
121 if n.fract().abs() < min_frac {
122 return format!("{n:.0}");
123 }
124
125 let (mag, slots) = iVec2((n.abs().log10(), slots - 2));
126 let slots = (slots - mag).clamp(0, slots);
127 let n = format!("{n:.*}", usize(slots));
128 n.or_map(|_| slots < 1, |n| n.trim_end_matches('0').into())
129 })();
130
131 let l = n.len();
132 n.or_map(|_| l >= max_len, |n| [n, " ".repeat(max_len - l)].concat())
133}