1use alloc::rc::Rc;
37use alloc::string::String;
38use alloc::vec::Vec;
39
40use super::cmd::{Draw, DrawRef, Gfx};
41use super::consts::*;
42use super::keys::*;
43use super::{Sp, Ui};
44use gfx::Surface;
45use rt::fx::{cvtt, cvttd, cvttd64, maxsd, minsd};
46pub use rt::fx::cvtd;
48
49const TRK_POOL: usize = 64; const PROP_NB_W: i32 = 88; pub const NO_DEFAULT: i32 = i32::MIN;
53
54static POW10: [f64; 19] = [
55 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11, 1.0e12, 1.0e13,
56 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18,
57];
58const RAD2DEG: f64 = 57.29577951308232;
59const DEG2RAD: f64 = 0.017453292519943295;
60
61#[derive(Clone, Copy, Default, Debug)]
63pub struct RangeF {
64 pub min: f64,
65 pub max: f64,
66 pub step: f64,
67 pub dec: u32,
68 pub flags: u32,
69}
70
71impl RangeF {
72 pub const fn new(min: f64, max: f64, step: f64, dec: u32, flags: u32) -> RangeF {
73 RangeF { min, max, step, dec, flags }
74 }
75}
76
77#[derive(Clone, Default)]
81pub struct Track {
82 pub flags: u32,
83 pub n: u32,
84 pub stops: [u32; TK_MAXN],
85 pub custom: Option<(DrawRef, usize, u32)>,
86}
87
88impl Track {
89 pub fn new(flags: u32, stops: &[u32]) -> Track {
91 let mut t = Track { flags, n: stops.len().min(TK_MAXN) as u32, ..Track::default() };
92 t.stops[..t.n as usize].copy_from_slice(&stops[..t.n as usize]);
93 t
94 }
95}
96
97pub(crate) struct S {
99 pub(crate) decimal_sep: u32,
100 trk: Vec<(u64, Rc<TrackDraw>)>,
101 trk_next: usize,
102}
103
104impl Default for S {
105 fn default() -> S {
106 S { decimal_sep: 44, trk: Vec::new(), trk_next: 0 }
107 }
108}
109
110pub fn part_id(id: u32, k: u32) -> u32 {
114 ((id << 4) | (k & 15)) & 0x0FFF_FFFF | PART_BASE
115}
116
117pub(crate) fn vl_state(ev: u32, disabled: bool) -> u32 {
119 if disabled {
120 3
121 } else if ev & EV_HELD != 0 {
122 2
123 } else if ev & EV_HOVER != 0 {
124 1
125 } else {
126 0
127 }
128}
129
130pub(crate) fn f_round(x: f64) -> i64 {
132 if x >= 0.0 { cvttd64(x + 0.5) } else { cvttd64(x - 0.5) }
133}
134
135fn f_floor(x: f64) -> f64 {
137 let mut t = cvttd64(x);
138 if (t as f64) > x {
139 t = t.wrapping_sub(1);
140 }
141 t as f64
142}
143
144fn rf_dec(rf: &RangeF) -> usize {
146 rf.dec.min(6) as usize
147}
148
149pub(crate) fn rf_fix(rf: &RangeF, v: f64) -> f64 {
152 let mut x = if v.is_nan() { rf.min } else { v };
153 x = maxsd(x, rf.min);
154 x = minsd(x, rf.max);
155 if rf.step > 0.0 {
156 x = x - rf.min;
157 x = x / rf.step;
158 x = f_round(x) as f64;
159 x = x * rf.step;
160 x = x + rf.min;
161 x = minsd(x, rf.max);
162 }
163 let p = POW10[rf_dec(rf)];
164 x = x * p;
165 x = f_round(x) as f64;
166 x = x / p;
167 x = maxsd(x, rf.min);
168 x = minsd(x, rf.max);
169 x + 0.0
170}
171
172pub(crate) fn rf_scaled(rf: &RangeF, v: f64) -> i32 {
174 let r = f_round(v * POW10[rf_dec(rf)]);
175 r.clamp(i32::MIN as i64, i32::MAX as i64) as i32
176}
177
178pub(crate) fn rf_t16(rf: &RangeF, v: f64) -> i32 {
180 let x = v - rf.min;
181 let d = rf.max - rf.min;
182 if !(d > 0.0) {
183 return 0;
184 }
185 let r = f_round(x / d * 65536.0);
186 if r < 0 {
187 0
188 } else if r > 65536 {
189 65536
190 } else {
191 r as i32
192 }
193}
194
195fn rf_from_t16(rf: &RangeF, t: i32) -> f64 {
197 let mut x = t as f64 / 65536.0;
198 let d = rf.max - rf.min;
199 x = x * d;
200 x = x + rf.min;
201 rf_fix(rf, x)
202}
203
204pub fn deg_atan2(y: f64, x: f64) -> f64 {
206 rt::x87::atan2(y, x) * RAD2DEG
207}
208
209pub fn deg_sincos(d: f64) -> (f64, f64) {
211 rt::x87::sincos(d * DEG2RAD)
212}
213
214fn utf8_push(out: &mut Vec<u8>, c: u32) {
216 if c < 0x80 {
217 out.push(c as u8);
218 } else if c < 0x800 {
219 out.push(0xC0 | (c >> 6) as u8);
220 out.push(0x80 | (c & 63) as u8);
221 } else if c < 0x10000 {
222 out.push(0xE0 | (c >> 12) as u8);
223 out.push(0x80 | ((c >> 6) & 63) as u8);
224 out.push(0x80 | (c & 63) as u8);
225 } else {
226 out.push(0xF0 | ((c >> 18) & 7) as u8);
227 out.push(0x80 | ((c >> 12) & 63) as u8);
228 out.push(0x80 | ((c >> 6) & 63) as u8);
229 out.push(0x80 | (c & 63) as u8);
230 }
231}
232
233pub(crate) fn fmt_f64_sep(v: f64, decimals: u32, sep: u32) -> String {
235 let dec = decimals.min(6) as usize;
236 let x = if v.is_nan() { 0.0 } else { v };
237 let mut r = f_round(x * POW10[dec]) as u64;
238 let mut out = Vec::with_capacity(32);
239 if (r as i64) < 0 {
240 out.push(b'-');
241 r = (r as i64).wrapping_neg() as u64;
242 }
243 let mut dig = [0u8; 32];
245 let mut n = 0;
246 loop {
247 dig[n] = b'0' + (r % 10) as u8;
248 r /= 10;
249 n += 1;
250 if n >= 24 {
251 break;
252 }
253 if r != 0 || n <= dec {
254 continue;
255 }
256 break;
257 }
258 let mut i = n;
259 for _ in 0..n - dec {
260 i -= 1;
261 out.push(dig[i]);
262 }
263 if dec != 0 {
264 utf8_push(&mut out, sep);
265 while i > 0 {
266 i -= 1;
267 out.push(dig[i]);
268 }
269 }
270 String::from_utf8_lossy(&out).into_owned()
271}
272
273pub(crate) fn parse_f64_sep(s: &[u8], sep: u32) -> Option<f64> {
275 let at = |i: usize| if i < s.len() { s[i] } else { 0 };
276 let mut i = 0;
277 while at(i) == b' ' {
278 i += 1;
279 }
280 let mut neg = false;
281 if at(i) == b'-' {
282 neg = true;
283 i += 1;
284 } else if at(i) == b'+' {
285 i += 1;
286 }
287 let mut m: u64 = 0; let mut digits = 0; let mut frac = 0usize; let mut dropped = 0usize; let mut seen_sep = false;
292 loop {
293 let c = at(i);
294 if c.is_ascii_digit() {
295 digits += 1;
296 i += 1;
297 if m >= 100_000_000_000_000_000 {
298 if !seen_sep {
299 dropped += 1; }
301 } else {
302 m = m * 10 + (c - b'0') as u64;
303 if seen_sep {
304 frac += 1;
305 }
306 }
307 } else if c == b',' || c == b'.' || c as u32 == sep {
308 if seen_sep {
309 break;
310 }
311 seen_sep = true;
312 i += 1;
313 } else {
314 break;
315 }
316 }
317 if digits == 0 {
318 return None;
319 }
320 let mut x = m as i64 as f64;
321 x = x / POW10[frac.min(18)];
322 x = x * POW10[dropped.min(18)];
323 if neg {
324 x = 0.0 - x;
325 }
326 Some(x)
327}
328
329pub fn grad_at(tk: &Track, t: i32) -> u32 {
333 let n = tk.n.min(TK_MAXN as u32);
334 if n == 0 {
335 return 0;
336 }
337 if n == 1 {
338 return tk.stops[0];
339 }
340 let t = if t < 0 { 0 } else if t as u32 > 65536 { 65536 } else { t };
341 let segs = n - 1;
342 let pos = (t as u32).wrapping_mul(segs); let mut seg = pos >> 16;
344 let mut f = (pos & 0xFFFF) as i32;
345 if seg >= segs {
346 seg = segs - 1; f = 0x10000;
348 }
349 let c0 = tk.stops[seg as usize];
350 let c1 = tk.stops[seg as usize + 1];
351 let mut r = 0u32;
352 for sh in [0, 8, 16, 24] {
353 let a = ((c0 >> sh) & 255) as i32;
354 let b = ((c1 >> sh) & 255) as i32;
355 let v = a + ((b - a).wrapping_mul(f) >> 16);
356 r |= (v as u32) << sh;
357 }
358 r
359}
360
361pub fn px_mix(dst: u32, src: u32, k: u32) -> u32 {
364 let ik = 255u32.wrapping_sub(k);
365 let mut r = 0;
366 for sh in [0, 8, 16] {
367 let mut v = ((dst >> sh) & 255).wrapping_mul(ik).wrapping_add(((src >> sh) & 255).wrapping_mul(k)).wrapping_add(128);
368 v = (v.wrapping_add(v >> 8)) >> 8;
369 r |= v << sh;
370 }
371 r
372}
373
374fn track_hash(tk: &Track) -> u32 {
376 let n = tk.n.min(TK_MAXN as u32) as usize;
377 let mut h: u64 = 0xCBF2_9CE4_8422_2325;
378 let mut eat = |v: u32| {
379 for b in v.to_le_bytes() {
380 h ^= b as u64;
381 h = h.wrapping_mul(0x0000_0100_0000_01B3);
382 }
383 };
384 eat(tk.flags);
385 eat(tk.n);
386 for &s in &tk.stops[..n] {
387 eat(s);
388 }
389 (h as u32) ^ (h >> 32) as u32
390}
391
392pub(crate) struct TrackDraw {
397 tk: Track,
398 cell: i32,
399}
400
401impl Draw for TrackDraw {
402 fn draw(&self, g: &mut Gfx, r: [i32; 4]) {
403 let tk = &self.tk;
404 let k = g.dc.clip;
405 let cx0 = k[0].max(r[0]);
407 let cy0 = k[1].max(r[1]);
408 let cx1 = k[2].min(r[0].wrapping_add(r[2]));
409 let cy1 = k[3].min(r[1].wrapping_add(r[3]));
410 let flags = tk.flags;
411 let vert = r[3] > r[2];
413 let (thick, len) = if vert { (r[2], r[3]) } else { (r[3], r[2]) };
414 let rad = thick as f32 * 0.5;
415 let inset = if flags & TK_RECT != 0 { 0 } else { ((thick as u32) >> 1) as i32 };
416 let travel = len.wrapping_sub(inset + inset).max(1);
417 let cell = self.cell as u32;
418 let stride = g.sf.stride as usize;
419 let mut y = cy0;
420 while y < cy1 {
421 let row = y as usize * stride;
422 let mut x = cx0;
423 while x < cx1 {
424 let (mut u, mut v) = (x.wrapping_sub(r[0]), y.wrapping_sub(r[1]));
426 if vert {
427 let uu = r[3].wrapping_sub(1).wrapping_sub(v);
428 v = u;
429 u = uu;
430 }
431 let t = ((((u.wrapping_sub(inset)) as i64) << 16) / travel as i64) as i32;
433 let c = grad_at(tk, t);
434 let mut cov: u32 = 255;
436 let mut skip = false;
437 if flags & TK_RECT == 0 {
438 let fu = u as f32 + 0.5;
439 let mut centre = rad;
440 let mut cap = !(fu >= rad); if !cap {
442 let e = len as f32 - rad;
443 if !(fu <= e) {
444 cap = true;
445 centre = e;
446 }
447 }
448 if cap {
449 let du = fu - centre;
450 let dv = v as f32 + 0.5 - rad;
451 let d = rt::fx::sqrt(du * du + dv * dv);
452 let kk = cvtt((rad + 0.5 - d) * 255.0);
453 if kk <= 0 {
454 skip = true;
455 } else {
456 cov = kk.min(255) as u32;
457 }
458 }
459 }
460 if !skip {
461 let a = c >> 24;
462 let (src, kk) = if flags & TK_CHECKER != 0 {
463 let odd = ((u as u32) / cell).wrapping_add((v as u32) / cell) & 1;
465 let bg = if odd != 0 { 0xCC_CCCC } else { 0xFF_FFFF };
466 (px_mix(bg, c, a), cov)
467 } else {
468 (c, (a * cov + 127) / 255)
469 };
470 let o = row + x as usize * 4;
471 let px = u32::from_le_bytes([g.sf.px[o], g.sf.px[o + 1], g.sf.px[o + 2], g.sf.px[o + 3]]);
472 let out = px_mix(px, src, kk);
473 g.sf.px[o..o + 4].copy_from_slice(&out.to_le_bytes());
474 }
475 x += 1;
476 }
477 y += 1;
478 }
479 }
480}
481
482impl Ui {
483 pub fn cmd_track(&mut self, x: i32, y: i32, w: i32, h: i32, tk: &Track) {
486 if tk.flags & TK_CUSTOM != 0 {
487 let (f, user, ver) = match &tk.custom {
488 Some((f, u, v)) => (Some(f.clone()), *u, *v),
489 None => (None, 0, 0),
490 };
491 self.cmd_custom(x, y, w, h, f, user, ver);
492 return;
493 }
494 let ver = track_hash(tk);
495 let f = self.track_drawing(tk);
496 self.cmd_custom(x, y, w, h, Some(f), 0, ver);
497 }
498
499 fn track_drawing(&mut self, tk: &Track) -> DrawRef {
502 let cell = self.dp(4).max(1);
503 let mut t = tk.clone();
504 t.custom = None;
505 let key = ((track_hash(&t) as u64) << 32) | cell as u32 as u64;
506 let s = &mut self.m.value;
507 let same = |d: &TrackDraw| d.cell == cell && d.tk.flags == t.flags && d.tk.n == t.n && d.tk.stops == t.stops;
508 if let Some((_, d)) = s.trk.iter().find(|(k, d)| *k == key && same(d)) {
509 return d.clone();
510 }
511 let d = Rc::new(TrackDraw { tk: t, cell });
512 if s.trk.len() < TRK_POOL {
513 s.trk.push((key, d.clone()));
514 } else {
515 let i = s.trk_next % TRK_POOL;
516 s.trk[i] = (key, d.clone());
517 s.trk_next = i + 1;
518 }
519 d
520 }
521
522 pub fn decimal_sep(&self) -> u32 {
526 self.m.value.decimal_sep
527 }
528
529 pub fn set_decimal_sep(&mut self, c: u32) {
531 self.m.value.decimal_sep = c;
532 }
533
534 pub fn fmt_f64(&self, v: f64, decimals: u32) -> String {
536 fmt_f64_sep(v, decimals, self.m.value.decimal_sep)
537 }
538
539 pub fn parse_f64(&self, s: &str) -> Option<f64> {
542 parse_f64_sep(s.as_bytes(), self.m.value.decimal_sep)
543 }
544
545 fn vl_disabled(&self) -> bool {
549 self.wp.ctx.last_state == SS_DISABLED as u32
550 }
551
552 pub(crate) fn sld_place(&mut self, rgflags: u32) {
554 let st = self.style;
555 let mut sp = Sp { flags: rgflags, ..Sp::default() };
556 let (w, h) = st.value_slider_size(self, &mut sp);
557 self.place(w, h);
558 }
559
560 pub(crate) fn sld_behave(&mut self, id: u32, stflags: u32) -> u32 {
563 let mut hb = HB_FOCUS | CUR_HAND << HB_CURSOR_SHIFT;
564 if stflags & ST_NOFOCUS != 0 {
565 hb &= !HB_FOCUS;
566 }
567 if stflags & ST_DISABLED != 0 {
568 hb |= HB_DISABLED;
569 }
570 self.behave(id, hb)
571 }
572
573 pub(crate) fn sld_ptr_t(&mut self, rgflags: u32) -> i32 {
575 let st = self.style;
576 let thumb = st.value_slider_thumb(self);
577 let half = ((thumb as u32) >> 1) as i32;
578 let r = self.wp.ctx.last_rect;
579 let (mx, my) = (self.wp.ctx.mx, self.wp.ctx.my);
580 let (mut p, len) = if rgflags & RG_VERT == 0 {
581 (mx.wrapping_sub(r[0]).wrapping_sub(half), r[2])
582 } else {
583 (r[1].wrapping_add(r[3]).wrapping_sub(half).wrapping_sub(my), r[3])
584 };
585 let len = len.wrapping_sub(thumb).max(1);
586 if p < 0 {
587 p = 0;
588 }
589 if p > len {
590 p = len;
591 }
592 (((p as i64) << 16) / len as i64) as i32
593 }
594
595 pub(crate) fn sld_keys(&mut self) -> (i32, u32) {
597 let mut steps = 0i32;
598 steps += self.key(VK_RIGHT) as i32;
599 steps += self.key(VK_UP) as i32;
600 steps -= self.key(VK_LEFT) as i32;
601 steps -= self.key(VK_DOWN) as i32;
602 steps += self.key(VK_PRIOR) as i32 * 10;
603 steps -= self.key(VK_NEXT) as i32 * 10;
604 let mut he = 0;
605 if self.key(VK_HOME) {
606 he = 1;
607 }
608 if self.key(VK_END) {
609 he = 2;
610 }
611 if steps != 0 || he != 0 {
612 self.wp.ctx.focus_visible = true;
613 }
614 (steps, he)
615 }
616
617 pub(crate) fn sld_draw(&mut self, t: i32, state: u32, rgflags: u32, track: Option<&Track>) {
620 let st = self.style;
621 let mut sp = Sp { value: t, state, flags: rgflags, track, ..Sp::default() };
622 sp.place(self.wp.ctx.last_rect);
623 st.value_slider(self, &sp);
624 }
625
626 #[cfg_attr(jfgui_dev, track_caller)]
630 pub fn slider_f(&mut self, id: u32, v: &mut f64, rf: &RangeF) -> u32 {
631 let _src = self.src_scope();
632 let old = v.to_bits();
633 let stflags = self.take_flags();
634 let rgf = rf.flags;
635 let mut keych = false;
636 self.sld_place(rgf);
637 let mut ev = self.sld_behave(id, stflags);
638 self.touch_grab(if rgf & RG_VERT != 0 { super::touch::AX_V } else { super::touch::AX_H });
639 if ev & EV_HELD != 0 {
640 let t = self.sld_ptr_t(rgf);
641 *v = rf_from_t16(rf, t);
642 } else if ev & EV_FOCUS != 0 {
643 let (steps, he) = self.sld_keys();
644 if he == 1 {
645 *v = rf.min;
646 keych = true;
647 } else if he == 2 {
648 *v = rf.max;
649 keych = true;
650 } else if steps != 0 {
651 keych = true;
652 let st = if rf.step > 0.0 { rf.step } else { (rf.max - rf.min) * 0.01 };
654 *v = steps as f64 * st + *v;
655 }
656 }
657 if let Some(x) = self.a11y_value(id) {
659 *v = x as f64 / POW10[rf_dec(rf)];
660 keych = true;
661 }
662 *v = rf_fix(rf, *v);
663 if v.to_bits() != old {
664 ev |= EV_ACT;
665 if keych {
666 ev |= EV_COMMIT;
667 }
668 self.repass();
669 }
670 let t = rf_t16(rf, *v);
671 let state = vl_state(ev, self.vl_disabled());
672 self.sld_draw(t, state, rgf, None);
673 self.focus_ring_draw(ev);
674 let val = rf_scaled(rf, *v);
675 let r = self.sem(K_SLIDER, id, None, val);
676 r.max = rf_scaled(rf, rf.max);
677 r.min = rf_scaled(rf, rf.min);
678 ev
679 }
680
681 #[cfg_attr(jfgui_dev, track_caller)]
686 pub fn track_slider(&mut self, id: u32, v: &mut i32, rg: &Range, track: Option<&Track>) -> u32 {
687 let _src = self.src_scope();
688 let old = *v;
689 let stflags = self.take_flags();
690 let rgf = rg.flags;
691 let mut keych = false;
692 self.sld_place(rgf);
693 let mut ev = self.sld_behave(id, stflags);
694 self.touch_grab(if rgf & RG_VERT != 0 { super::touch::AX_V } else { super::touch::AX_H });
695 if ev & EV_HELD != 0 {
696 let t = self.sld_ptr_t(rgf);
697 let span = rg.max.wrapping_sub(rg.min) as i64;
699 let mut x = ((t as i64).wrapping_mul(span).wrapping_add(32768) >> 16) as i32;
700 x = x.wrapping_add(rg.min);
701 if rg.step > 1 {
702 let half = ((rg.step as u32) >> 1) as i32;
703 x = (x.wrapping_sub(rg.min).wrapping_add(half) / rg.step).wrapping_mul(rg.step).wrapping_add(rg.min);
704 }
705 *v = x;
706 } else if ev & EV_FOCUS != 0 {
707 let (steps, he) = self.sld_keys();
708 if he == 1 {
709 *v = rg.min;
710 keych = true;
711 } else if he == 2 {
712 *v = rg.max;
713 keych = true;
714 } else if steps != 0 {
715 keych = true;
716 let st = rg.step.max(1);
717 *v = v.wrapping_add(steps.wrapping_mul(st));
718 }
719 }
720 if let Some(x) = self.a11y_value(id) {
722 *v = x;
723 keych = true;
724 }
725 let mut x = *v;
726 if x < rg.min {
727 x = rg.min;
728 }
729 if x > rg.max {
730 x = rg.max;
731 }
732 *v = x;
733 if x != old {
734 ev |= EV_ACT;
735 if keych {
736 ev |= EV_COMMIT;
737 }
738 self.repass();
739 }
740 let span = rg.max.wrapping_sub(rg.min);
742 let t: i32 = if span > 0 { ((((v.wrapping_sub(rg.min)) as i64) << 16) / span as i64) as i32 } else { 0 };
743 let state = vl_state(ev, self.vl_disabled());
744 self.sld_draw(t, state, rgf, track);
745 self.focus_ring_draw(ev);
746 let r = self.sem(K_SLIDER, id, None, *v);
747 r.max = rg.max;
748 r.min = rg.min;
749 ev
750 }
751
752 fn prop_begin(&mut self, label: &str) -> Option<String> {
757 self.box_begin(0, BOX_V, 4);
758 self.text(TS_BODY, label);
759 let l = self.sems.last().and_then(|s| s.label.clone());
760 self.box_begin(0, BOX_H | BOX_XCENTER, 8);
761 self.next_size(-1, 0);
762 l
763 }
764
765 fn set_last_label(&mut self, l: Option<String>) {
767 if let Some(s) = self.sems.last_mut() {
768 s.label = l;
769 }
770 }
771
772 fn prop_reset(&mut self, id: u32, same: bool) -> u32 {
774 if same {
775 self.next_flags(ST_DISABLED);
776 }
777 self.icon_button(part_id(id, 2), IC_UNDO, crate::i18n::tr("Zurücksetzen"))
778 }
779
780 #[cfg_attr(jfgui_dev, track_caller)]
783 pub fn prop_slider(&mut self, id: u32, label: &str, v: &mut i32, rg: &Range, default: i32) -> u32 {
784 let _src = self.src_scope();
785 let l = self.prop_begin(label);
786 let mut ev = self.slider(id, v, rg);
787 self.set_last_label(l);
788 self.next_size(PROP_NB_W, 0);
789 let nb = part_id(id, 1);
790 ev |= self.number_box(nb, v, rg);
791 if self.nb_live(nb, v) {
792 ev |= EV_ACT;
794 self.repass();
795 }
796 if default != NO_DEFAULT {
797 let same = *v == default;
798 if self.prop_reset(id, same) & EV_ACT != 0 {
799 *v = default;
800 ev |= EV_ACT | EV_COMMIT;
801 self.repass();
802 }
803 }
804 self.box_end();
805 self.box_end();
806 ev
807 }
808
809 #[cfg_attr(jfgui_dev, track_caller)]
812 pub fn prop_slider_f(&mut self, id: u32, label: &str, v: &mut f64, rf: &RangeF, default: Option<f64>) -> u32 {
813 let _src = self.src_scope();
814 let l = self.prop_begin(label);
815 let mut ev = self.slider_f(id, v, rf);
816 self.set_last_label(l);
817 self.next_size(PROP_NB_W, 0);
818 let nb = part_id(id, 1);
819 ev |= self.number_box_f(nb, v, rf);
820 if self.nb_live_f(nb, v) {
821 ev |= EV_ACT;
823 self.repass();
824 }
825 if let Some(d) = default {
826 let d = rf_fix(rf, d); let same = v.to_bits() == d.to_bits();
828 if self.prop_reset(id, same) & EV_ACT != 0 {
829 *v = d;
830 ev |= EV_ACT | EV_COMMIT;
831 self.repass();
832 }
833 }
834 self.box_end();
835 self.box_end();
836 ev
837 }
838
839 #[cfg_attr(jfgui_dev, track_caller)]
843 pub fn angle(&mut self, id: u32, deg: &mut f64, flags: u32) -> u32 {
844 let _src = self.src_scope();
845 let old = deg.to_bits();
846 let mut keych = false;
847 let stflags = self.take_flags();
848 let st = self.style;
849 let mut sp = Sp::default();
850 let (w, h) = st.angle_size(self, &mut sp);
851 self.place(w, h);
852 let mut ev = self.sld_behave(id, stflags);
853 self.touch_grab(super::touch::AX_ALL);
854 let r = self.wp.ctx.last_rect;
856 self.ltr_begin(r[0], r[2]);
857 let cx = (r[0] << 8).wrapping_add(r[2] << 7);
858 let cy = (r[1] << 8).wrapping_add(r[3] << 7);
859 if ev & EV_HELD != 0 {
860 let dx = (self.ltr_x(self.wp.ctx.mx) << 8).wrapping_sub(cx);
862 let dy = cy.wrapping_sub(self.wp.ctx.my << 8);
863 if dx | dy != 0 {
864 let mut a = deg_atan2(dy as f64, dx as f64);
865 if self.mods & MOD_SHIFT != 0 {
866 a = f_round(a / 15.0) as f64 * 15.0;
867 }
868 *deg = a;
869 }
870 } else if ev & EV_FOCUS != 0 {
871 let (steps, he) = self.sld_keys();
872 if he == 1 {
873 *deg = 0.0; keych = true;
875 } else if steps != 0 {
876 keych = true;
877 let x = if steps >= 10 || steps <= -10 {
879 ((steps / 10).wrapping_mul(15)) as f64
880 } else if self.mods & MOD_SHIFT != 0 {
881 steps.wrapping_mul(15) as f64
882 } else {
883 steps as f64
884 };
885 *deg = x + *deg;
886 }
887 }
888 *deg = ang_norm(*deg, flags);
889 if deg.to_bits() != old {
890 ev |= EV_ACT;
891 if keych {
892 ev |= EV_COMMIT;
893 }
894 self.repass();
895 }
896 let state = vl_state(ev, self.vl_disabled());
897 sp.place(self.wp.ctx.last_rect);
899 sp.state = state;
900 sp.ev = ev;
901 sp.f = *deg;
902 sp.s[0] = self.focus_ring(ev) as i32;
903 st.angle(self, &sp);
904 self.ltr_end();
905 let v = f_round(*deg * 100.0) as i32;
906 self.sem(K_SLIDER, id, None, v).max = if flags & ANG_360 != 0 { 36000 } else { 18000 };
907 ev
908 }
909
910 #[allow(clippy::too_many_arguments)]
915 #[cfg_attr(jfgui_dev, track_caller)]
916 pub fn pan(&mut self, id: u32, x: &mut f64, y: &mut f64, thumb: Option<&Rc<Surface>>, ver: u32, flags: u32) -> u32 {
917 let _src = self.src_scope();
918 let (ox, oy) = (x.to_bits(), y.to_bits());
919 let mut keych = false;
920 let stflags = self.take_flags();
921 let (lo, span) = if flags & PAN_UNIT != 0 { (0.0, 1.0) } else { (-1.0, 2.0) };
923 let st = self.style;
924 let mut sp = Sp { img: thumb, img_ver: ver, ..Sp::default() };
925 let (w, h) = st.pan_size(self, &mut sp);
926 self.place(w, h);
927 let mut ev = self.sld_behave(id, stflags);
928 self.touch_grab(super::touch::AX_ALL);
929 let frac = |p: i32, len: i32| {
930 let len = len.max(1);
931 let mut f = p as f64 / len as f64;
932 f = maxsd(f, 0.0);
933 f = minsd(f, 1.0);
934 f = f * span;
935 f + lo
936 };
937 let r = self.wp.ctx.last_rect;
938 self.ltr_begin(r[0], r[2]); if ev & EV_HELD != 0 {
940 let r = self.wp.ctx.last_rect;
942 *x = frac(self.ltr_x(self.wp.ctx.mx).wrapping_sub(r[0]), r[2]);
943 *y = frac(self.wp.ctx.my.wrapping_sub(r[1]), r[3]);
944 } else if ev & EV_FOCUS != 0 {
945 let mut dx = 0i32;
947 let mut dy = 0i32;
948 let (right, left) = if self.rtl { (VK_LEFT, VK_RIGHT) } else { (VK_RIGHT, VK_LEFT) };
950 dx += self.key(right) as i32;
951 dx -= self.key(left) as i32;
952 dy += self.key(VK_DOWN) as i32;
953 dy -= self.key(VK_UP) as i32;
954 if self.key(VK_HOME) {
955 let c = span * 0.5 + lo;
956 *x = c;
957 *y = c;
958 keych = true;
959 self.wp.ctx.focus_visible = true;
960 } else if dx | dy != 0 {
961 keych = true;
962 self.wp.ctx.focus_visible = true;
963 let mut st = span * 0.01;
964 if self.mods & MOD_SHIFT != 0 {
965 st = st * 10.0;
966 }
967 *x = dx as f64 * st + *x;
968 *y = dy as f64 * st + *y;
969 }
970 }
971 let clamp = |v: f64| {
973 let mut v = if v.is_nan() { lo } else { v };
974 v = v * 10000.0;
975 v = f_round(v) as f64;
976 v = v / 10000.0;
977 v = maxsd(v, lo);
978 v = minsd(v, lo + span);
979 v + 0.0
980 };
981 *x = clamp(*x);
982 *y = clamp(*y);
983 if x.to_bits() != ox || y.to_bits() != oy {
984 ev |= EV_ACT;
985 if keych {
986 ev |= EV_COMMIT;
987 }
988 self.repass();
989 }
990 let state = vl_state(ev, self.vl_disabled());
991 let r = self.wp.ctx.last_rect;
993 let px = cvttd((*x - lo) / span * r[2] as f64).wrapping_add(r[0]);
994 let py = cvttd((*y - lo) / span * r[3] as f64).wrapping_add(r[1]);
995 sp.place(r);
997 sp.state = state;
998 sp.value = px;
999 sp.value2 = py;
1000 st.pan(self, &sp);
1001 self.focus_ring_draw(ev);
1002 self.ltr_end();
1003 let my = f_round(*y * 1000.0) as i32;
1005 let mx = f_round(*x * 1000.0) as i32;
1006 self.sem(K_SLIDER, id, None, mx).max = my;
1007 ev
1008 }
1009}
1010
1011fn ang_norm(v: f64, flags: u32) -> f64 {
1014 let x = if v.is_nan() { 0.0 } else { v };
1015 let a360 = flags & ANG_360 != 0;
1016 if !a360 && x >= -180.0 && x <= 180.0 {
1019 return x + 0.0;
1020 }
1021 let lo = if a360 { 0.0 } else { -180.0 };
1023 let mut k = x - lo;
1024 k = k / 360.0;
1025 k = f_floor(k);
1026 k = k * 360.0;
1027 let mut y = x - k; if !a360 && !(y > -180.0) {
1029 y = 180.0; }
1031 y + 0.0
1032}