1use crate::{BACK_CMD, CANCEL_CMD, FINISH_CMD, NEXT_CMD, PageArgs, Wizard};
2use zng_ext_font::FontWeight;
3use zng_ext_input::focus::TabIndex;
4use zng_wgt::{align, border, is_rtl, prelude::*};
5use zng_wgt_button::Button;
6use zng_wgt_container::{Container, padding};
7use zng_wgt_fill::{background, background_color};
8use zng_wgt_input::focus::tab_index;
9use zng_wgt_markdown::Markdown;
10use zng_wgt_scroll::{Scroll, ScrollMode};
11use zng_wgt_size_offset::width;
12use zng_wgt_stack::{Stack, StackDirection};
13use zng_wgt_style::style_fn;
14use zng_wgt_text::Text;
15
16context_var! {
17 pub static HEADER_FN_VAR: WidgetFn<HeaderFnArgs> = WidgetFn::new(default_header_fn);
19
20 pub static HEADER_BACKGROUND_FN_VAR: WidgetFn<()> = WidgetFn::nil();
22
23 pub static SIDE_FN_VAR: WidgetFn<SideFnArgs> = WidgetFn::new(default_side_fn);
25
26 pub static SIDE_BACKGROUND_FN_VAR: WidgetFn<()> = WidgetFn::nil();
28
29 pub static SIDE_EXTRA_FN_VAR: WidgetFn<PageArgs> = WidgetFn::nil();
32
33 pub static CONTENT_FN_VAR: WidgetFn<ContentFnArgs> = WidgetFn::new(default_content_fn);
35
36 pub static FOOTER_FN_VAR: WidgetFn<FooterFnArgs> = WidgetFn::new(default_footer_fn);
38
39 pub static FOOTER_EXTRA_FN_VAR: WidgetFn<PageArgs> = WidgetFn::nil();
41
42 pub static PANEL_FN_VAR: WidgetFn<PanelFnArgs> = WidgetFn::new(default_panel_fn);
44}
45
46#[non_exhaustive]
50pub struct HeaderFnArgs {
51 pub header: UiNode,
57
58 pub background: UiNode,
62
63 pub index: usize,
65 pub pages_len: usize,
67 pub titles: Vec<Var<Txt>>,
69 pub skips: Vec<Var<bool>>,
71}
72impl HeaderFnArgs {
73 pub fn is_first(&self) -> bool {
75 self.index == 0
76 }
77
78 pub fn is_last(&self) -> bool {
80 self.index == self.pages_len.saturating_sub(1)
81 }
82
83 pub fn wizard_id(&self) -> WidgetId {
85 WIDGET.id()
86 }
87}
88
89#[non_exhaustive]
93pub struct SideFnArgs {
94 pub side: UiNode,
106
107 pub side_extra: UiNode,
117
118 pub background: UiNode,
122
123 pub index: usize,
125 pub pages_len: usize,
127}
128impl SideFnArgs {
129 pub fn is_first(&self) -> bool {
131 self.index == 0
132 }
133
134 pub fn is_last(&self) -> bool {
136 self.index == self.pages_len.saturating_sub(1)
137 }
138
139 pub fn wizard_id(&self) -> WidgetId {
141 WIDGET.id()
142 }
143}
144
145#[non_exhaustive]
149pub struct ContentFnArgs {
150 pub content: UiNode,
156
157 pub index: usize,
159 pub pages_len: usize,
161}
162impl ContentFnArgs {
163 pub fn is_first(&self) -> bool {
165 self.index == 0
166 }
167
168 pub fn is_last(&self) -> bool {
170 self.index == self.pages_len.saturating_sub(1)
171 }
172
173 pub fn wizard_id(&self) -> WidgetId {
175 WIDGET.id()
176 }
177}
178
179#[non_exhaustive]
183pub struct FooterFnArgs {
184 pub footer: UiNode,
189
190 pub footer_extra: UiNode,
200
201 pub index: usize,
203 pub pages_len: usize,
205}
206impl FooterFnArgs {
207 pub fn is_first(&self) -> bool {
209 self.index == 0
210 }
211
212 pub fn is_last(&self) -> bool {
214 self.index == self.pages_len.saturating_sub(1)
215 }
216
217 pub fn wizard_id(&self) -> WidgetId {
219 WIDGET.id()
220 }
221}
222
223pub struct PanelFnArgs {
231 pub header: UiNode,
237 pub side: UiNode,
243 pub content: UiNode,
249 pub footer: UiNode,
255}
256
257pub fn default_header_fn(args: HeaderFnArgs) -> UiNode {
261 Container! {
262 child = args.header;
263 padding = (10, 10, 10, 20);
264 border = {
265 widths: (0, 0, 1, 0),
266 sides: colors::GRAY.with_alpha(40.pct()),
267 };
268 background = args.background;
269 }
270}
271
272pub fn default_page_header(args: PageArgs) -> UiNode {
278 Stack! {
279 children = ui_vec![default_page_header_title(args.title), default_page_header_info(args.info),];
280 direction = StackDirection::top_to_bottom();
281 spacing = 5;
282 align = Align::START;
283 }
284}
285pub fn default_page_header_title(title: Var<Txt>) -> UiNode {
289 Text! {
290 txt = title;
291 font_weight = FontWeight::BOLD;
292 }
293}
294pub fn default_page_header_info(info: Var<Txt>) -> UiNode {
298 Markdown! {
299 txt = info;
300 }
301}
302
303pub fn default_side_fn(args: SideFnArgs) -> UiNode {
307 Stack! {
308 direction = StackDirection::top_to_bottom();
309 children = args.side;
310 children_align = Align::BOTTOM_START;
311 spacing = 5;
312 padding = 5;
313 width = 200;
314 background = args.background;
315 border = {
316 widths: (0, 1, 0, 0),
317 sides: colors::GRAY.with_alpha(40.pct()),
318 };
319 when #is_rtl {
320 border = {
321 widths: (0, 0, 0, 1),
322 sides: colors::GRAY.with_alpha(40.pct()),
323 };
324 }
325
326 zng_wgt_button::style_fn = style_fn!(|_| zng_wgt_button::LinkStyle!());
327 }
328}
329
330pub fn default_page_side(_: PageArgs) -> UiNode {
336 ui_vec![].into_node()
337}
338
339pub fn default_content_fn(args: ContentFnArgs) -> UiNode {
343 Scroll! {
344 mode = ScrollMode::VERTICAL;
345 child = args.content;
346 child_align = Align::FILL;
347 padding = 20;
348 background_color = light_dark(rgb(0.85, 0.85, 0.85), rgb(0.15, 0.15, 0.15));
349 }
350}
351
352pub fn default_footer_fn(args: FooterFnArgs) -> UiNode {
356 Stack! {
357 children = args.footer.into_list();
358 direction = StackDirection::start_to_end();
359 spacing = 5;
360 padding = 5;
361 children_align = Align::END;
362 border = {
363 widths: (1, 0, 0, 0),
364 sides: colors::GRAY.with_alpha(40.pct()),
365 };
366 }
367}
368
369pub fn default_page_footer(args: PageArgs) -> UiNode {
375 let id = args.wizard_id();
376 if args.is_first() {
377 ui_vec![default_page_footer_next(id), default_page_footer_cancel(id)]
378 } else if args.is_last() {
379 ui_vec![default_page_footer_back(id), default_page_footer_finish(id)]
380 } else {
381 ui_vec![
382 default_page_footer_back(id),
383 default_page_footer_next(id),
384 default_page_footer_cancel(id)
385 ]
386 }
387 .into_node()
388}
389pub fn default_page_footer_back(wizard_id: WidgetId) -> UiNode {
391 Button! {
392 cmd = BACK_CMD.scoped(wizard_id);
393 tab_index = TabIndex::FIRST - 1;
394 }
395}
396pub fn default_page_footer_next(wizard_id: WidgetId) -> UiNode {
398 Button! {
399 cmd = NEXT_CMD.scoped(wizard_id);
400 tab_index = TabIndex::FIRST;
401 }
402}
403pub fn default_page_footer_finish(wizard_id: WidgetId) -> UiNode {
405 Button! {
406 cmd = FINISH_CMD.scoped(wizard_id);
407 tab_index = TabIndex::FIRST;
408 style_fn = style_fn!(|_| zng_wgt_button::PrimaryStyle!());
409 }
410}
411pub fn default_page_footer_cancel(wizard_id: WidgetId) -> UiNode {
413 Button! {
414 cmd = CANCEL_CMD.scoped(wizard_id);
415 tab_index = TabIndex::FIRST - 2;
416 }
417}
418
419pub fn default_panel_fn(args: PanelFnArgs) -> UiNode {
423 Container! {
424 child_bottom = args.footer;
425 child_start = args.side;
426 child_top = args.header;
427 child = args.content;
428 }
429}
430
431#[property(CONTEXT, default(HEADER_FN_VAR), widget_impl(Wizard))]
435pub fn header_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<HeaderFnArgs>>) -> UiNode {
436 with_context_var(child, HEADER_FN_VAR, wgt_fn)
437}
438
439#[property(CONTEXT, default(HEADER_BACKGROUND_FN_VAR), widget_impl(Wizard))]
443pub fn header_background_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<()>>) -> UiNode {
444 with_context_var(child, HEADER_BACKGROUND_FN_VAR, wgt_fn)
445}
446
447#[property(CONTEXT, default(SIDE_FN_VAR), widget_impl(Wizard))]
451pub fn side_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<SideFnArgs>>) -> UiNode {
452 with_context_var(child, SIDE_FN_VAR, wgt_fn)
453}
454
455#[property(CONTEXT, default(SIDE_BACKGROUND_FN_VAR), widget_impl(Wizard))]
459pub fn side_background_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<()>>) -> UiNode {
460 with_context_var(child, SIDE_BACKGROUND_FN_VAR, wgt_fn)
461}
462
463#[property(CONTEXT, default(SIDE_EXTRA_FN_VAR), widget_impl(Wizard))]
471pub fn side_extra_fn(child: impl IntoUiNode, side_extra_fn: impl IntoVar<WidgetFn<PageArgs>>) -> UiNode {
472 with_context_var(child, SIDE_EXTRA_FN_VAR, side_extra_fn)
473}
474
475#[property(CONTEXT, default(CONTENT_FN_VAR), widget_impl(Wizard))]
479pub fn content_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<ContentFnArgs>>) -> UiNode {
480 with_context_var(child, CONTENT_FN_VAR, wgt_fn)
481}
482
483#[property(CONTEXT, default(FOOTER_FN_VAR), widget_impl(Wizard))]
487pub fn footer_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<FooterFnArgs>>) -> UiNode {
488 with_context_var(child, FOOTER_FN_VAR, wgt_fn)
489}
490
491#[property(CONTEXT, default(FOOTER_EXTRA_FN_VAR), widget_impl(Wizard))]
495pub fn footer_extra_fn(child: impl IntoUiNode, footer_extra_fn: impl IntoVar<WidgetFn<PageArgs>>) -> UiNode {
496 with_context_var(child, FOOTER_EXTRA_FN_VAR, footer_extra_fn)
497}
498
499#[property(CONTEXT, default(PANEL_FN_VAR), widget_impl(Wizard))]
503pub fn panel_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<PanelFnArgs>>) -> UiNode {
504 with_context_var(child, PANEL_FN_VAR, wgt_fn)
505}