tuix_widgets/
panel.rs

1use crate::common::*;
2use crate::{Button, Label};
3
4const ICON_DOWN_OPEN_BIG: &str = "\u{e75c}";
5//const ICON_RIGHT_OPEN_BIG: &str = "\u{e75e}";
6
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub enum PanelEvent {
9    Open,
10    Close,
11}
12
13pub struct Panel {
14    header: Entity,
15    container1: Entity,
16    container2: Entity,
17    arrow: Entity,
18    collapsed: bool,
19    title: String,
20
21    container_height: f32,
22    container_width: f32,
23
24    expand_height_animation: Animation,
25    collapse_height_animation: Animation,
26    expand_width_animation: Animation,
27    collapse_width_animation: Animation,
28
29    fade_in_animation: Animation,
30    fade_out_animation: Animation,
31
32    move_up_animation: Animation,
33    move_down_animation: Animation,
34    move_left_animation: Animation,
35    move_right_animation: Animation,
36
37    arrow_cw_animation: Animation,
38    arrow_ccw_animation: Animation,
39}
40
41impl Panel {
42    pub fn new(title: &str) -> Self {
43        Panel {
44            header: Entity::default(),
45            container1: Entity::default(),
46            container2: Entity::default(),
47            arrow: Entity::default(),
48            title: title.to_string(),
49            collapsed: false,
50
51            container_height: 0.0,
52            container_width: 0.0,
53
54            expand_height_animation: Animation::default(),
55            collapse_height_animation: Animation::default(),
56            expand_width_animation: Animation::default(),
57            collapse_width_animation: Animation::default(),
58
59            fade_in_animation: Animation::default(),
60            fade_out_animation: Animation::default(),
61
62            move_up_animation: Animation::default(),
63            move_down_animation: Animation::default(),
64            move_left_animation: Animation::default(),
65            move_right_animation: Animation::default(),
66
67            arrow_cw_animation: Animation::default(),
68            arrow_ccw_animation: Animation::default(),
69        }
70    }
71
72    pub fn collapsed(mut self, flag: bool) -> Self {
73        self.collapsed = flag;
74
75        self
76    }
77}
78
79impl Widget for Panel {
80    type Ret = (Entity, Entity);
81    type Data = ();
82    fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
83        entity
84            .set_focusable(state, false)
85            //.set_width(state, Auto);
86            .set_height(state, Auto);
87
88        self.header = Button::new()
89            .on_release(move |_,state,_|
90                state.insert_event(
91                    Event::new(PanelEvent::Open).target(entity)
92                )
93            )
94            .build(state, entity, |builder| {
95                builder
96                    .set_layout_type(LayoutType::Row)
97                    //.set_child_left(Pixels(5.0))
98                    //.set_flex_direction(FlexDirection::Row)
99                    .class("header")
100            });
101
102        self.arrow = Element::new().build(state, self.header, |builder| {
103            builder
104                .set_text(ICON_DOWN_OPEN_BIG)
105                .set_font("icons")
106                .set_child_space(Stretch(1.0))
107                .set_top(Stretch(1.0))
108                .set_bottom(Stretch(1.0))
109                .set_width(Pixels(20.0))
110                .set_height(Pixels(20.0))
111                .set_hoverable(false)
112                .set_focusable(false)
113                //.set_background_color(Color::rgb(100, 100, 100))
114                .class("icon")
115        });
116
117        // Label
118        Label::new(&self.title).build(state, self.header, |builder| {
119            builder
120                //.set_width(Stretch(1.0))
121                .set_height(Stretch(1.0))
122                .set_left(Pixels(5.0))
123                .set_child_top(Stretch(1.0))
124                .set_child_bottom(Stretch(1.0))
125                .set_hoverable(false)
126                .set_focusable(false)
127                .class("label")
128        });
129
130        self.container1 = Element::new().build(state, entity, |builder| {
131            builder
132                .class("container1")
133                .set_focusable(false)
134                .set_width(Stretch(1.0))
135                .set_height(Auto)
136                .set_min_height(Pixels(0.0))
137        });
138
139        self.container2 = Element::new().build(state, self.container1, |builder| {
140            builder
141                .class("container2")
142                .set_focusable(false)
143                .set_clip_widget(self.container1)
144                //.set_child_left(Stretch(1.0))
145                //.set_child_right(Stretch(1.0))
146                .set_width(Stretch(1.0))
147                .set_height(Auto)
148        });
149
150        entity.set_element(state, "panel");
151
152        // Animations
153        let container_expand_animation = AnimationState::new()
154            .with_duration(std::time::Duration::from_millis(100))
155            .with_keyframe((0.0, Units::Pixels(0.0)))
156            .with_keyframe((1.0, Units::Pixels(0.0)));
157
158        self.expand_height_animation = state
159            .style
160            .height
161            .insert_animation(container_expand_animation.clone());
162
163        self.expand_width_animation = state
164            .style
165            .width
166            .insert_animation(container_expand_animation.clone());
167
168        let container_collapse_animation = AnimationState::new()
169            .with_duration(std::time::Duration::from_millis(100))
170            .with_keyframe((0.0, Units::Pixels(0.0)))
171            .with_keyframe((1.0, Units::Pixels(0.0)));
172
173        self.collapse_height_animation = state
174            .style
175            .height
176            .insert_animation(container_collapse_animation.clone());
177
178        self.collapse_width_animation = state
179            .style
180            .width
181            .insert_animation(container_collapse_animation.clone());
182
183        let container_fade_in_animation = AnimationState::new()
184            .with_duration(std::time::Duration::from_millis(1))
185            .with_keyframe((0.0, Opacity(0.0)))
186            .with_keyframe((1.0, Opacity(1.0)));
187
188        let container_hide_animation = AnimationState::new()
189            .with_duration(std::time::Duration::from_millis(100))
190            .with_keyframe((0.0, Units::Pixels(0.0)))
191            .with_keyframe((1.0, Units::Pixels(0.0)));
192
193        self.move_up_animation = state
194            .style
195            .top
196            .insert_animation(container_hide_animation.clone());
197
198        self.move_left_animation = state
199            .style
200            .left
201            .insert_animation(container_hide_animation.clone());
202
203        let container_reveal_animation = AnimationState::new()
204            .with_duration(std::time::Duration::from_millis(100))
205            .with_keyframe((0.0, Units::Pixels(0.0)))
206            .with_keyframe((1.0, Units::Pixels(0.0)));
207
208        self.move_down_animation = state
209            .style
210            .top
211            .insert_animation(container_reveal_animation.clone());
212
213        self.move_right_animation = state
214            .style
215            .left
216            .insert_animation(container_reveal_animation.clone());
217
218        self.fade_in_animation = state
219            .style
220            .opacity
221            .insert_animation(container_fade_in_animation);
222
223        let container_fade_out_animation = AnimationState::new()
224            .with_duration(std::time::Duration::from_millis(100))
225            .with_delay(std::time::Duration::from_millis(100))
226            .with_keyframe((0.0, Opacity(1.0)))
227            .with_keyframe((1.0, Opacity(0.0)));
228
229        self.fade_out_animation = state
230            .style
231            .opacity
232            .insert_animation(container_fade_out_animation);
233
234        let arrow_cw_animation = AnimationState::new()
235            .with_duration(std::time::Duration::from_millis(100))
236            .with_keyframe((0.0, -90.0))
237            .with_keyframe((1.0, 0.0));
238
239        self.arrow_cw_animation = state.style.rotate.insert_animation(arrow_cw_animation);
240
241        let arrow_ccw_animation = AnimationState::new()
242            .with_duration(std::time::Duration::from_millis(100))
243            .with_keyframe((0.0, 0.0))
244            .with_keyframe((1.0, -90.0));
245
246        self.arrow_ccw_animation = state.style.rotate.insert_animation(arrow_ccw_animation);
247
248        (self.container2, self.header)
249    }
250
251    fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
252        if let Some(panel_event) = event.message.downcast::<PanelEvent>() {
253            match panel_event {
254                PanelEvent::Open | PanelEvent::Close => {
255                    if event.target == entity {
256                        if self.collapsed {
257                            self.collapsed = false;
258
259                            entity.set_checked(state, true);
260
261                            match entity.get_layout_type(state) {
262                                LayoutType::Column => {
263                                    state.style.height.play_animation(
264                                        self.container1,
265                                        self.expand_height_animation,
266                                    );
267
268                                    self.container1.set_height(state, Units::Auto);
269
270                                    state
271                                        .style
272                                        .rotate
273                                        .play_animation(self.arrow, self.arrow_cw_animation);
274                                    
275                                    self.arrow.set_rotate(state, 0.0);
276                                }
277
278                                LayoutType::Row => {
279                                    state.style.width.play_animation(
280                                        self.container1,
281                                        self.expand_width_animation,
282                                    );
283
284                                    self.container1.set_width(state, Units::Auto);
285
286                                    state
287                                        .style
288                                        .rotate
289                                        .play_animation(self.arrow, self.arrow_ccw_animation);
290
291                                    self.arrow.set_rotate(state, -90.0);
292                                }
293
294                                _ => {}
295                            }
296
297                            state
298                                .style
299                                .top
300                                .play_animation(self.container2, self.move_down_animation);
301
302                            self.container2.set_opacity(state, 1.0);
303                        } else {
304                            self.collapsed = true;
305
306                            entity.set_checked(state, false);
307
308                            match entity.get_layout_type(state) {
309                                LayoutType::Column => {
310                                    if !state.style.height.is_animating(self.container1) {
311                                        let container_height =
312                                            state.data.get_height(self.container1);
313                                        //println!("Container Height: {} {}", self.container1, container_height);
314
315                                        if container_height != self.container_height {
316                                            //self.container_height = container_height;
317
318                                            if let Some(animation) = state
319                                                .style
320                                                .height
321                                                .get_animation_mut(self.expand_height_animation)
322                                            {
323                                                animation.keyframes.last_mut().unwrap().1 =
324                                                    Units::Pixels(container_height);
325                                            }
326
327                                            if let Some(animation) = state
328                                                .style
329                                                .height
330                                                .get_animation_mut(self.collapse_height_animation)
331                                            {
332                                                animation.keyframes.first_mut().unwrap().1 =
333                                                    Units::Pixels(container_height);
334                                            }
335
336                                            if let Some(animation) = state
337                                                .style
338                                                .top
339                                                .get_animation_mut(self.move_down_animation)
340                                            {
341                                                animation.keyframes.first_mut().unwrap().1 =
342                                                    Units::Pixels(-container_height);
343                                            }
344
345                                            if let Some(animation) = state
346                                                .style
347                                                .top
348                                                .get_animation_mut(self.move_up_animation)
349                                            {
350                                                animation.keyframes.last_mut().unwrap().1 =
351                                                    Units::Pixels(-container_height);
352                                            }
353
354                                            self.container_height = container_height;
355                                        }
356                                    }
357
358                                    state.style.height.play_animation(
359                                        self.container1,
360                                        self.collapse_height_animation,
361                                    );
362
363                                    self.container1.set_height(state, Units::Pixels(0.0));
364
365                                    state
366                                        .style
367                                        .rotate
368                                        .play_animation(self.arrow, self.arrow_ccw_animation);
369
370                                    self.arrow.set_rotate(state, -90.0);
371                                }
372
373                                LayoutType::Row => {
374                                    if !state.style.height.is_animating(self.container1) {
375                                        let container_width = state.data.get_width(self.container1);
376
377                                        if container_width != self.container_width {
378                                            //self.container_height = container_height;
379
380                                            if let Some(animation) = state
381                                                .style
382                                                .width
383                                                .get_animation_mut(self.expand_width_animation)
384                                            {
385                                                animation.keyframes.last_mut().unwrap().1 =
386                                                    Units::Pixels(container_width);
387                                            }
388
389                                            if let Some(animation) = state
390                                                .style
391                                                .width
392                                                .get_animation_mut(self.collapse_width_animation)
393                                            {
394                                                animation.keyframes.first_mut().unwrap().1 =
395                                                    Units::Pixels(container_width);
396                                            }
397
398                                            if let Some(animation) = state
399                                                .style
400                                                .left
401                                                .get_animation_mut(self.move_left_animation)
402                                            {
403                                                animation.keyframes.first_mut().unwrap().1 =
404                                                    Units::Pixels(-container_width);
405                                            }
406
407                                            if let Some(animation) = state
408                                                .style
409                                                .left
410                                                .get_animation_mut(self.move_right_animation)
411                                            {
412                                                animation.keyframes.last_mut().unwrap().1 =
413                                                    Units::Pixels(-container_width);
414                                            }
415
416                                            self.container_height = container_width;
417                                        }
418                                    }
419
420                                    state.style.width.play_animation(
421                                        self.container1,
422                                        self.collapse_width_animation,
423                                    );
424
425                                    self.container1.set_width(state, Units::Pixels(0.0));
426
427                                    state
428                                        .style
429                                        .rotate
430                                        .play_animation(self.arrow, self.arrow_cw_animation);
431
432                                    self.arrow.set_rotate(state, 0.0);
433                                }
434
435                                _ => {}
436                            }
437
438                            state
439                                .style
440                                .opacity
441                                .play_animation(self.container2, self.fade_out_animation);
442
443                            state
444                                .style
445                                .top
446                                .play_animation(self.container2, self.move_up_animation);
447
448                            self.container2.set_opacity(state, 0.0);
449                        }
450                    }
451                }
452            }
453        }
454
455        if let Some(window_event) = event.message.downcast::<WindowEvent>() {
456            match window_event {
457                WindowEvent::GeometryChanged(_) => {
458                    if event.target == self.container1 {
459                        match entity.get_layout_type(state) {
460                            LayoutType::Row => {
461                                self.arrow.set_rotate(state, -90.0);
462                            }
463
464                            _ => {}
465                        }
466
467                        event.consume();
468                    }
469                }
470                _ => {}
471            }
472        }
473    }
474}