freya_components/
popup.rs

1use freya_animation::prelude::*;
2use freya_core::prelude::*;
3use torin::{
4    prelude::{
5        Alignment,
6        Position,
7    },
8    size::Size,
9};
10
11use crate::{
12    get_theme,
13    theming::component_themes::{
14        PopupTheme,
15        PopupThemePartial,
16    },
17};
18
19/// Popup background wrapper.
20#[derive(Clone, PartialEq)]
21pub struct PopupBackground {
22    pub children: Element,
23    pub on_press: EventHandler<Event<PressEventData>>,
24}
25
26impl PopupBackground {
27    pub fn new(
28        children: Element,
29        on_press: impl Into<EventHandler<Event<PressEventData>>>,
30    ) -> Self {
31        Self {
32            children,
33            on_press: on_press.into(),
34        }
35    }
36}
37
38impl Render for PopupBackground {
39    fn render(&self) -> impl IntoElement {
40        let animation = use_animation(|conf| {
41            conf.on_creation(OnCreation::Run);
42            AnimColor::new((0, 0, 0, 0), (0, 0, 0, 150)).time(150)
43        });
44        let background = animation.get().value();
45        let on_press = self.on_press.clone();
46
47        rect()
48            .layer(2000)
49            .position(Position::new_global())
50            .child(
51                rect()
52                    .on_press(on_press)
53                    .position(Position::new_global().top(0.).left(0.))
54                    .height(Size::window_percent(100.))
55                    .width(Size::window_percent(100.))
56                    .background(background),
57            )
58            .child(
59                rect()
60                    .position(Position::new_global().top(0.).left(0.))
61                    .height(Size::window_percent(100.))
62                    .width(Size::window_percent(100.))
63                    .center()
64                    .child(self.children.clone()),
65            )
66    }
67}
68
69/// Floating popup / dialog.
70#[derive(Clone, PartialEq)]
71pub struct Popup {
72    pub(crate) theme: Option<PopupThemePartial>,
73    children: Vec<Element>,
74    on_close_request: Option<EventHandler<()>>,
75    close_on_escape_key: bool,
76    key: DiffKey,
77}
78
79impl KeyExt for Popup {
80    fn write_key(&mut self) -> &mut DiffKey {
81        &mut self.key
82    }
83}
84
85impl Default for Popup {
86    fn default() -> Self {
87        Self::new()
88    }
89}
90
91impl Popup {
92    pub fn new() -> Self {
93        Self {
94            theme: None,
95            children: vec![],
96            on_close_request: None,
97            close_on_escape_key: true,
98            key: DiffKey::None,
99        }
100    }
101
102    pub fn on_close_request(mut self, on_close_request: impl Into<EventHandler<()>>) -> Self {
103        self.on_close_request = Some(on_close_request.into());
104        self
105    }
106}
107
108impl ChildrenExt for Popup {
109    fn get_children(&mut self) -> &mut Vec<Element> {
110        &mut self.children
111    }
112}
113
114impl Render for Popup {
115    fn render(&self) -> impl IntoElement {
116        let animations = use_animation(|conf| {
117            conf.on_creation(OnCreation::Run);
118            (
119                AnimNum::new(0.85, 1.)
120                    .time(250)
121                    .ease(Ease::Out)
122                    .function(Function::Expo),
123                AnimNum::new(0.2, 1.)
124                    .time(250)
125                    .ease(Ease::Out)
126                    .function(Function::Expo),
127            )
128        });
129
130        let PopupTheme { background, color } = get_theme!(&self.theme, popup);
131
132        let (scale, opacity) = &*animations.read();
133
134        let request_to_close = {
135            let handler = self.on_close_request.clone();
136            move || {
137                if let Some(h) = &handler {
138                    h.call(());
139                }
140            }
141        };
142
143        let on_global_key_down = {
144            let close = self.close_on_escape_key;
145            let req = request_to_close.clone();
146            move |e: Event<KeyboardEventData>| {
147                if close && e.key == Key::Escape {
148                    req();
149                }
150            }
151        };
152
153        PopupBackground::new(
154            rect()
155                .scale((scale.value(), scale.value()))
156                .opacity(opacity.value())
157                .corner_radius(12.)
158                .background(background)
159                .color(color)
160                .shadow(Shadow::new().y(4.).blur(5.).color((0, 0, 0, 30)))
161                .width(Size::px(500.))
162                .height(Size::auto())
163                .spacing(4.)
164                .padding(8.)
165                .on_global_key_down(on_global_key_down)
166                .children(self.children.clone())
167                .into(),
168            move |_| {
169                request_to_close();
170            },
171        )
172    }
173
174    fn render_key(&self) -> DiffKey {
175        self.key.clone().or(self.default_key())
176    }
177}
178
179/// Popup title.
180#[derive(PartialEq)]
181pub struct PopupTitle {
182    text: ReadState<String>,
183}
184
185impl PopupTitle {
186    pub fn new(text: impl Into<ReadState<String>>) -> Self {
187        Self { text: text.into() }
188    }
189}
190
191impl Render for PopupTitle {
192    fn render(&self) -> impl IntoElement {
193        rect().font_size(18.).padding(8.).child(
194            label()
195                .width(Size::fill())
196                .text(self.text.read().to_string()),
197        )
198    }
199}
200
201/// Popup content wrapper.
202#[derive(Clone, PartialEq)]
203pub struct PopupContent {
204    children: Vec<Element>,
205}
206impl Default for PopupContent {
207    fn default() -> Self {
208        Self::new()
209    }
210}
211
212impl PopupContent {
213    pub fn new() -> Self {
214        Self { children: vec![] }
215    }
216}
217
218impl ChildrenExt for PopupContent {
219    fn get_children(&mut self) -> &mut Vec<Element> {
220        &mut self.children
221    }
222}
223
224impl Render for PopupContent {
225    fn render(&self) -> impl IntoElement {
226        rect()
227            .font_size(15.)
228            .padding(8.)
229            .children(self.children.clone())
230    }
231}
232
233/// Popup buttons container.
234#[derive(Clone, PartialEq)]
235pub struct PopupButtons {
236    pub children: Vec<Element>,
237}
238
239impl Default for PopupButtons {
240    fn default() -> Self {
241        Self::new()
242    }
243}
244
245impl PopupButtons {
246    pub fn new() -> Self {
247        Self { children: vec![] }
248    }
249}
250
251impl ChildrenExt for PopupButtons {
252    fn get_children(&mut self) -> &mut Vec<Element> {
253        &mut self.children
254    }
255}
256
257impl Render for PopupButtons {
258    fn render(&self) -> impl IntoElement {
259        rect()
260            .width(Size::fill())
261            .main_align(Alignment::End)
262            .padding(8.)
263            .spacing(4.)
264            .horizontal()
265            .children(self.children.clone())
266    }
267}