1use crate::iced::{Length, Pixels};
2use crate::{Element, style, theme, widget};
3use std::borrow::Cow;
4
5pub fn dialog<'a, Message>() -> Dialog<'a, Message> {
6 Dialog::new()
7}
8
9pub struct Dialog<'a, Message> {
10 title: Option<Cow<'a, str>>,
11 icon: Option<Element<'a, Message>>,
12 body: Option<Cow<'a, str>>,
13 controls: Vec<Element<'a, Message>>,
14 primary_action: Option<Element<'a, Message>>,
15 secondary_action: Option<Element<'a, Message>>,
16 tertiary_action: Option<Element<'a, Message>>,
17 width: Option<Length>,
18 height: Option<Length>,
19 max_width: Option<Pixels>,
20 max_height: Option<Pixels>,
21}
22
23impl<Message> Default for Dialog<'_, Message> {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl<'a, Message> Dialog<'a, Message> {
30 pub fn new() -> Self {
31 Self {
32 title: None,
33 icon: None,
34 body: None,
35 controls: Vec::new(),
36 primary_action: None,
37 secondary_action: None,
38 tertiary_action: None,
39 width: None,
40 height: None,
41 max_width: None,
42 max_height: None,
43 }
44 }
45
46 pub fn title(mut self, title: impl Into<Cow<'a, str>>) -> Self {
47 self.title = Some(title.into());
48 self
49 }
50
51 pub fn icon(mut self, icon: impl Into<Element<'a, Message>>) -> Self {
52 self.icon = Some(icon.into());
53 self
54 }
55
56 pub fn body(mut self, body: impl Into<Cow<'a, str>>) -> Self {
57 self.body = Some(body.into());
58 self
59 }
60
61 pub fn control(mut self, control: impl Into<Element<'a, Message>>) -> Self {
62 self.controls.push(control.into());
63 self
64 }
65
66 pub fn primary_action(mut self, button: impl Into<Element<'a, Message>>) -> Self {
67 self.primary_action = Some(button.into());
68 self
69 }
70
71 pub fn secondary_action(mut self, button: impl Into<Element<'a, Message>>) -> Self {
72 self.secondary_action = Some(button.into());
73 self
74 }
75
76 pub fn tertiary_action(mut self, button: impl Into<Element<'a, Message>>) -> Self {
77 self.tertiary_action = Some(button.into());
78 self
79 }
80
81 pub fn width(mut self, width: impl Into<Length>) -> Self {
82 self.width = Some(width.into());
83 self
84 }
85
86 pub fn height(mut self, height: impl Into<Length>) -> Self {
87 self.height = Some(height.into());
88 self
89 }
90
91 pub fn max_height(mut self, max_height: impl Into<Pixels>) -> Self {
92 self.max_height = Some(max_height.into());
93 self
94 }
95
96 pub fn max_width(mut self, max_width: impl Into<Pixels>) -> Self {
97 self.max_width = Some(max_width.into());
98 self
99 }
100}
101
102impl<'a, Message: Clone + 'static> From<Dialog<'a, Message>> for Element<'a, Message> {
103 fn from(dialog: Dialog<'a, Message>) -> Self {
104 let cosmic_theme::Spacing {
105 space_l,
106 space_m,
107 space_s,
108 space_xxs,
109 ..
110 } = theme::THEME.lock().unwrap().cosmic().spacing;
111
112 let mut content_col = widget::column::with_capacity(3 + dialog.controls.len() * 2);
113
114 let mut should_space = false;
115
116 if let Some(title) = dialog.title {
117 content_col = content_col.push(widget::text::title3(title));
118 should_space = true;
119 }
120 if let Some(body) = dialog.body {
121 if should_space {
122 content_col = content_col
123 .push(widget::space::vertical().height(Length::Fixed(space_xxs.into())));
124 }
125 content_col = content_col.push(
126 widget::container(widget::scrollable(widget::text::body(body))).max_height(300.),
127 );
128 should_space = true;
129 }
130 for control in dialog.controls {
131 if should_space {
132 content_col = content_col
133 .push(widget::space::vertical().height(Length::Fixed(space_s.into())));
134 }
135 content_col = content_col.push(control);
136 should_space = true;
137 }
138
139 let mut content_row = widget::row::with_capacity(2).spacing(space_s);
140 if let Some(icon) = dialog.icon {
141 content_row = content_row.push(icon);
142 }
143 content_row = content_row.push(content_col);
144
145 let mut button_row = widget::row::with_capacity(4).spacing(space_xxs);
146 if let Some(button) = dialog.tertiary_action {
147 button_row = button_row.push(button);
148 }
149 button_row = button_row.push(widget::space::horizontal());
150 if let Some(button) = dialog.secondary_action {
151 button_row = button_row.push(button);
152 }
153 if let Some(button) = dialog.primary_action {
154 button_row = button_row.push(button);
155 }
156
157 let mut container = widget::container(
158 widget::column::with_children([content_row.into(), button_row.into()]).spacing(space_l),
159 )
160 .class(style::Container::Dialog)
161 .padding(space_m)
162 .width(dialog.width.unwrap_or(Length::Fixed(570.0)));
163
164 if let Some(height) = dialog.height {
165 container = container.height(height);
166 }
167
168 if let Some(max_width) = dialog.max_width {
169 container = container.max_width(max_width);
170 }
171
172 if let Some(max_height) = dialog.max_height {
173 container = container.max_height(max_height);
174 }
175
176 Element::from(container)
177 }
178}