cosmic/widget/
dialog.rs

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