1use alloc::format;
20use alloc::string::String;
21use alloc::vec::Vec;
22
23use base::settings::{Kind, Settings, Val, KF_HIDDEN, KF_RESTART};
24
25use super::consts::*;
26use super::i18n::{t, tr};
27use super::keys::IC_UNDO;
28use super::value::RangeF;
29use super::Ui;
30
31const CONTROL_W: i32 = 200; impl Ui {
34 #[cfg_attr(jfgui_dev, track_caller)]
36 pub fn settings_page(&mut self, id: u32, s: &mut Settings) -> bool {
37 let _src = self.src_scope();
38 let schema = s.schema();
39 let shown = |i: usize| schema.keys[i].flags & KF_HIDDEN == 0;
40 let mut secs: Vec<&'static str> = schema.sections.iter().map(|x| x.0).collect();
41 for (i, d) in schema.keys.iter().enumerate() {
42 let sec = d.split().0;
43 if shown(i) && !secs.contains(&sec) {
44 secs.push(sec);
45 }
46 }
47 let mut changed = false;
48 self.id_push(id);
49 self.box_begin(0, BOX_V, 12);
50 for sec in secs {
51 let keys: Vec<usize> = (0..schema.keys.len()).filter(|&i| shown(i) && schema.keys[i].split().0 == sec).collect();
52 if keys.is_empty() {
53 continue;
54 }
55 let title = match schema.sections.iter().find(|x| x.0 == sec) {
56 Some(x) => t(x.1),
57 None if sec.is_empty() => tr("Allgemein"),
58 None => sec,
59 };
60 self.text(TS_BODY_STRONG, title);
61 self.box_begin(0, BOX_V | BOX_CARD | pad(16), 12);
62 for i in keys {
63 changed |= self.settings_row(s, i);
64 }
65 self.box_end();
66 }
67 self.box_end();
68 self.id_pop();
69 changed
70 }
71
72 fn settings_row(&mut self, s: &mut Settings, i: usize) -> bool {
74 let d = s.schema().keys[i];
75 let label = t(d.label);
76 self.id_push_str(d.name);
77 let cid = self.id("value");
78 self.box_begin(0, BOX_V, 2);
79 self.box_begin(0, BOX_H | BOX_XCENTER, 12);
80 self.next_size(-1, 0);
81 self.text(TS_BODY, label);
82 let cur = s.at(i).clone();
83 let mut new: Option<Val> = None;
84 match (d.kind, &cur) {
85 (Kind::Bool(_), Val::Bool(b)) => {
86 let mut v = *b as i32;
87 self.switch(cid, "", &mut v);
88 self.sem_name(cid, label);
89 if (v != 0) != *b {
90 new = Some(Val::Bool(v != 0));
91 }
92 }
93 (Kind::Int { min, max, step, .. }, Val::Int(x)) => {
94 let fit = |v: i64| v.clamp(i32::MIN as i64, i32::MAX as i64) as i32;
95 let rg = Range::new(fit(min), fit(max), fit(step).max(1), 0);
96 let mut v = fit(*x);
97 if self.number_box(cid, &mut v, &rg) & EV_ACT != 0 && v != fit(*x) {
98 new = Some(Val::Int(v as i64));
99 }
100 }
101 (Kind::Num { min, max, dec, .. }, Val::Num(x)) => {
102 let dec = dec.min(9);
103 let step = 1.0 / (0..dec).fold(1.0, |a, _| a * 10.0);
104 let mut v = *x;
105 if self.number_box_f(cid, &mut v, &RangeF::new(min, max, step, dec, 0)) & EV_ACT != 0 && v != *x {
106 new = Some(Val::Num(v));
107 }
108 }
109 (Kind::Text { max, .. }, Val::Text(txt)) => {
110 let mut b = txt.clone();
111 self.next_size(CONTROL_W, 0);
112 self.textbox(cid, None, &mut b, (max as u32).saturating_add(1).min(0xFF_FFFF));
113 if b != *txt {
114 new = Some(Val::Text(b));
115 }
116 }
117 (Kind::Choice { items, .. }, Val::Choice(k)) => {
118 let list: Vec<&str> = items.iter().map(|it| t(it.1)).collect();
119 let mut sel = *k as i32;
120 self.combobox(cid, &mut sel, &list);
121 if sel >= 0 && sel as usize != *k {
122 new = Some(Val::Choice(sel as usize));
123 }
124 }
125 (Kind::Color(_), Val::Color(c)) => {
126 let mut argb = 0xFF00_0000 | c;
127 let sw = self.swatch(self.id("swatch"), argb, false);
128 self.dropdown_button(cid, &format!("#{:06X}", c));
129 if sw & EV_ACT != 0 {
130 self.popup_open(cid);
131 }
132 self.sem_name(cid, label);
133 if self.flyout_begin(cid, FL_BELOW) {
134 self.color_picker_ex(self.id("pick"), &mut argb, CP_FIELDS);
135 }
136 self.flyout_end();
137 if argb & 0xFF_FFFF != *c {
138 new = Some(Val::Color(argb & 0xFF_FFFF));
139 }
140 }
141 _ => {}
142 }
143 if cur == s.default_at(i) {
144 self.next_flags(ST_DISABLED);
145 }
146 let reset: String = format!("{}: {}", tr("Zurücksetzen"), label);
147 if self.icon_button(self.id("reset"), IC_UNDO, &reset) & EV_ACT != 0 {
148 new = Some(s.default_at(i));
149 }
150 self.box_end();
151 if !d.help.is_empty() {
152 self.text(TS_CAPTION, t(d.help));
153 }
154 if d.flags & KF_RESTART != 0 {
155 self.text(TS_CAPTION, tr("Wird nach einem Neustart wirksam."));
156 }
157 self.box_end();
158 self.id_pop();
159 match new {
160 Some(v) => s.set_at(i, v),
161 None => false,
162 }
163 }
164
165 fn sem_name(&mut self, id: u32, label: &str) {
168 if let Some(r) = self.sems.iter_mut().rev().find(|r| r.id == id) {
169 r.label = Some(String::from(label));
170 }
171 }
172}