Skip to main content

cosmic/widget/
dialog.rs

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}