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