1use everything_plugin::ui::winio::prelude::*;
6
7use crate::{App, HANDLER};
8
9#[allow(dead_code)]
10fn main() {
11 winio::ui::App::new("rs.compio.winio.widgets").run::<MainModel>(());
17}
18
19pub struct MainModel {
20 window: Child<Window>,
21 ulabel: Child<Label>,
22 plabel: Child<Label>,
23 uentry: Child<Edit>,
24 pentry: Child<Edit>,
25 pcheck: Child<CheckBox>,
26 canvas: Child<Canvas>,
27 combo: Child<ComboBox>,
28 list: Child<ObservableVec<String>>,
29 index: Option<usize>,
30 r1: Child<RadioButton>,
31 r2: Child<RadioButton>,
32 r3: Child<RadioButton>,
33 rindex: usize,
34 push_button: Child<Button>,
35 pop_button: Child<Button>,
36 show_button: Child<Button>,
37 progress: Child<Progress>,
38 mltext: Child<TextBox>,
39}
40
41#[derive(Debug)]
42pub enum MainMessage {
43 Noop,
44 Close,
45 Redraw,
46 List(ObservableVecEvent<String>),
47 Select,
48 Push,
49 Pop,
50 Show,
51 RSelect(usize),
52 PasswordCheck,
53 OptionsPage(OptionsPageMessage<App>),
54}
55
56impl From<OptionsPageMessage<App>> for MainMessage {
57 fn from(value: OptionsPageMessage<App>) -> Self {
58 Self::OptionsPage(value)
59 }
60}
61
62impl Component for MainModel {
63 type Event = ();
64 type Init<'a> = OptionsPageInit<'a, App>;
65 type Message = MainMessage;
66
67 fn init(mut init: Self::Init<'_>, sender: &ComponentSender<Self>) -> Self {
68 let mut window = init.window(sender);
70 window.set_text("Widgets example");
71 window.set_size(Size::new(800.0, 600.0));
72 init! {
73 canvas: Canvas = (&window),
74 ulabel: Label = (&window) => {
75 text: "Username:",
76 halign: HAlign::Right,
77 },
78 plabel: Label = (&window) => {
79 text: "Password:",
80 halign: HAlign::Right,
81 },
82 uentry: Edit = (&window) => {
83 text: "AAA",
84 },
85 pentry: Edit = (&window) => {
86 text: "123456",
87 password: true,
88 },
89 pcheck: CheckBox = (&window) => {
90 text: "Show",
91 checked: false,
92 },
93 combo: ComboBox = (&window),
94 list: ObservableVec<String> = (()) => {
95 items: [
97 "烫烫烫",
98 "昍昍昍",
99 "フフフフフフ",
100 "쳌쳌쳌"
101 ],
102 },
103 r1: RadioButton = (&window) => {
104 text: "屯屯屯",
105 checked: true,
106 },
107 r2: RadioButton = (&window) => {
108 text: "锟斤拷",
109 },
110 r3: RadioButton = (&window) => {
111 text: "╠╠╠"
112 },
113 push_button: Button = (&window) => {
114 text: "Push",
115 },
116 pop_button: Button = (&window) => {
117 text: "Pop",
118 },
119 show_button: Button = (&window) => {
120 text: "Show",
121 },
122 progress: Progress = (&window) => {
123 indeterminate: true,
124 },
125 mltext: TextBox = (&window) => {
126 },
127 }
128 HANDLER.with_app(|a| mltext.set_text(&a.config().s));
129
130 window.show();
131
132 Self {
133 window,
134 ulabel,
135 plabel,
136 uentry,
137 pentry,
138 pcheck,
139 canvas,
140 combo,
141 list,
142 index: None,
143 r1,
144 r2,
145 r3,
146 rindex: 0,
147 push_button,
148 pop_button,
149 show_button,
150 progress,
151 mltext,
152 }
153 }
154
155 async fn start(&mut self, sender: &ComponentSender<Self>) -> ! {
156 let mut radio_group = RadioButtonGroup::new([&mut *self.r1, &mut self.r2, &mut self.r3]);
157 start! {
158 sender, default: MainMessage::Noop,
159 self.window => {
160 WindowEvent::Close => MainMessage::Close,
161 WindowEvent::Resize => MainMessage::Redraw,
162 },
163 self.pcheck => {
164 CheckBoxEvent::Click => MainMessage::PasswordCheck,
165 },
166 self.combo => {
167 ComboBoxEvent::Select => MainMessage::Select,
168 },
169 self.push_button => {
170 ButtonEvent::Click => MainMessage::Push,
171 },
172 self.pop_button => {
173 ButtonEvent::Click => MainMessage::Pop,
174 },
175 self.show_button => {
176 ButtonEvent::Click => MainMessage::Show,
177 },
178 self.list => {
179 e => MainMessage::List(e),
180 },
181 radio_group => {
182 |i| Some(MainMessage::RSelect(i))
183 }
184 }
185 }
186
187 async fn update(&mut self, message: Self::Message, sender: &ComponentSender<Self>) -> bool {
188 futures_util::future::join(self.window.update(), self.canvas.update()).await;
189 match message {
190 MainMessage::Noop => false,
191 MainMessage::Close => {
192 sender.output(());
193 false
194 }
195 MainMessage::Redraw => true,
196 MainMessage::PasswordCheck => {
197 self.pentry.set_password(!self.pcheck.is_checked());
198 true
199 }
200 MainMessage::List(e) => {
201 self.pop_button.set_enabled(!self.list.is_empty());
202 self.combo
203 .emit(ComboBoxMessage::from_observable_vec_event(e))
204 .await
205 }
206 MainMessage::Select => {
207 self.index = self.combo.selection();
208 false
209 }
210 MainMessage::Push => {
211 self.list.push(
212 match self.rindex {
213 0 => &self.r1,
214 1 => &self.r2,
215 2 => &self.r3,
216 _ => unreachable!(),
217 }
218 .text(),
219 );
220 false
221 }
222 MainMessage::Pop => {
223 self.list.pop();
224 false
225 }
226 MainMessage::RSelect(i) => {
227 self.rindex = i;
228 false
229 }
230 MainMessage::Show => {
231 MessageBox::new()
232 .title("Show selected item")
233 .message(
234 self.index
235 .and_then(|index| self.list.get(index))
236 .map(|s| s.as_str())
237 .unwrap_or("No selection."),
238 )
239 .buttons(MessageBoxButton::Ok)
240 .show(&self.window)
241 .await;
242 false
243 }
244 MainMessage::OptionsPage(m) => {
245 tracing::debug!(?m, "Options page message");
246 match m {
247 OptionsPageMessage::Save(config, tx) => {
248 config.s = self.mltext.text();
249 tx.send(config).unwrap()
250 }
251 }
252 false
253 }
254 }
255 }
256
257 fn render(&mut self, _sender: &ComponentSender<Self>) {
258 let csize = self.window.client_size();
259 {
260 let mut cred_panel = layout! {
261 Grid::from_str("auto,1*,auto", "1*,auto,auto,1*").unwrap(),
262 self.ulabel => { column: 0, row: 1, valign: VAlign::Center },
263 self.uentry => { column: 1, row: 1, margin: Margin::new_all_same(4.0) },
264 self.plabel => { column: 0, row: 2, valign: VAlign::Center },
265 self.pentry => { column: 1, row: 2, margin: Margin::new_all_same(4.0) },
266 self.pcheck => { column: 2, row: 2 },
267 };
268
269 let mut rgroup_panel = layout! {
270 Grid::from_str("auto", "1*,auto,auto,auto,1*").unwrap(),
271 self.r1 => { row: 1 },
272 self.r2 => { row: 2 },
273 self.r3 => { row: 3 },
274 };
275
276 let mut buttons_panel = layout! {
277 StackPanel::new(Orient::Vertical),
278 self.push_button => { margin: Margin::new_all_same(4.0) },
279 self.pop_button => { margin: Margin::new_all_same(4.0) },
280 self.show_button => { margin: Margin::new_all_same(4.0) },
281 };
282
283 let mut root_panel = layout! {
284 Grid::from_str("1*,1*,1*", "1*,auto,1*").unwrap(),
285 cred_panel => { column: 1, row: 0 },
286 rgroup_panel => { column: 2, row: 0, halign: HAlign::Center },
287 self.canvas => { column: 0, row: 1, row_span: 2 },
288 self.combo => { column: 1, row: 1, halign: HAlign::Center },
289 self.progress => { column: 2, row: 1 },
290 self.mltext => { column: 1, row: 2, margin: Margin::new_all_same(8.0) },
291 buttons_panel => { column: 2, row: 2 },
292 };
293
294 root_panel.set_size(csize);
295 }
296
297 let size = self.canvas.size();
298 let is_dark = ColorTheme::current() == ColorTheme::Dark;
299 let back_color = if is_dark {
300 Color::new(255, 255, 255, 255)
301 } else {
302 Color::new(0, 0, 0, 255)
303 };
304 let brush = SolidColorBrush::new(back_color);
305 let pen = BrushPen::new(&brush, 1.0);
306 let mut ctx = self.canvas.context();
307 let cx = size.width / 2.0;
308 let cy = size.height / 2.0;
309 let r = cx.min(cy) - 2.0;
310 ctx.draw_pie(
311 &pen,
312 Rect::new(Point::new(cx - r, cy - r), Size::new(r * 2.0, r * 2.0)),
313 std::f64::consts::PI,
314 std::f64::consts::PI * 2.0,
315 );
316
317 let brush2 = LinearGradientBrush::new(
318 [
319 GradientStop::new(Color::new(0x87, 0xCE, 0xEB, 0xFF), 0.0),
320 GradientStop::new(back_color, 1.0),
321 ],
322 RelativePoint::zero(),
323 RelativePoint::new(0.0, 1.0),
324 );
325 let pen2 = BrushPen::new(&brush2, 1.0);
326 ctx.draw_round_rect(
327 &pen2,
328 Rect::new(
329 Point::new(cx - r - 1.0, cy - r - 1.0),
330 Size::new(r * 2.0 + 2.0, r * 1.618 + 2.0),
331 ),
332 Size::new(r / 10.0, r / 10.0),
333 );
334 let mut path = ctx.create_path_builder(Point::new(cx + r + 1.0 - r / 10.0, cy));
335 path.add_arc(
336 Point::new(cx, cy + r * 0.618 + 1.0),
337 Size::new(r + 1.0 - r / 10.0, r * 0.382 / 2.0),
338 0.0,
339 std::f64::consts::PI,
340 true,
341 );
342 path.add_line(Point::new(cx - r - 1.0 + r / 10.0, cy));
343 let path = path.build(false);
344 ctx.draw_path(&pen, &path);
345 let brush3 = RadialGradientBrush::new(
346 [
347 GradientStop::new(Color::new(0xF5, 0xF5, 0xF5, 0xFF), 0.0),
348 GradientStop::new(
349 Color::accent().unwrap_or(Color::new(0xFF, 0xC0, 0xCB, 0xFF)),
350 1.0,
351 ),
352 ],
353 RelativePoint::new(0.5, 0.5),
354 RelativePoint::new(0.2, 0.5),
355 RelativeSize::new(0.5, 0.5),
356 );
357 let font = DrawingFontBuilder::new()
358 .family("Arial")
359 .size(r / 5.0)
360 .halign(HAlign::Center)
361 .valign(VAlign::Bottom)
362 .build();
363 ctx.draw_str(&brush3, font, Point::new(cx, cy), "Hello world!");
364 }
365}