makepad_widgets/
keyboard_view.rs

1use crate::{
2    makepad_derive_widget::*,
3    makepad_draw::*,
4    view::*,
5    widget::*,
6};
7
8live_design!{
9    link widgets;
10    pub KeyboardViewBase = {{KeyboardView}} {}
11    pub KeyboardView = <KeyboardViewBase>{}
12}
13
14
15#[derive(Live, LiveHook, Widget)]
16pub struct KeyboardView {
17    #[deref] view: View,
18    #[redraw] #[rust] area: Area,
19    #[live] outer_layout: Layout,
20    #[live] outer_walk: Walk,
21    #[live] keyboard_walk: Walk,
22    #[live] keyboard_min_shift: f64,
23    #[rust] next_frame: NextFrame,
24    
25    #[rust] keyboard_shift: f64,
26    #[rust(AnimState::Closed)] anim_state: AnimState,
27    #[rust] draw_state: DrawStateWrap<Walk>,
28}
29
30enum AnimState{
31    Closed,
32    Opening{duration:f64, start_time:f64, ease:Ease, height:f64},
33    Open,
34    Closing{duration:f64, start_time:f64,  ease:Ease, height:f64}
35}
36
37impl KeyboardView {
38
39    fn compute_max_height(&self, height:f64, cx:&Cx)->f64{
40        let self_rect = self.area.rect(cx);
41        let ime_rect = cx.get_ime_area_rect();
42        let av_height = self_rect.size.y - height;
43        let ime_height = ime_rect.size.y + ime_rect.pos.y + self.keyboard_min_shift;
44        if  ime_height > av_height {
45            return ime_height - av_height 
46        }
47        0.0
48    }
49    
50    fn begin(&mut self, cx: &mut Cx2d, walk: Walk) { 
51        cx.begin_turtle(walk, self.outer_layout.with_scroll(dvec2(0.,self.keyboard_shift)));
52    }
53    
54    fn end(&mut self, cx: &mut Cx2d) {
55        cx.end_turtle_with_area(&mut self.area);
56    }
57}
58
59impl Widget for KeyboardView {
60    
61    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
62        if let Some(e) = self.next_frame.is_event(event){
63            match &self.anim_state{
64                AnimState::Opening{duration, start_time, ease, height}=>{
65                    if e.time - start_time < *duration{
66                        self.keyboard_shift = ease.map((e.time - start_time)/duration) * height;
67                        self.next_frame = cx.new_next_frame();
68                    }
69                    else{
70                        self.keyboard_shift = *height;
71                        self.anim_state = AnimState::Open;
72                    }
73                    self.redraw(cx);
74                }
75                AnimState::Closing{duration, start_time, ease, height}=>{
76                    if e.time - start_time < *duration{
77                        self.keyboard_shift = (1.0-ease.map((e.time - start_time)/duration)) * height;
78                        self.next_frame = cx.new_next_frame();
79                    }
80                    else{ 
81                        self.keyboard_shift = 0.0;
82                        self.anim_state = AnimState::Closed;
83                    }
84                    self.redraw(cx);
85                }
86                _=>()
87            }
88        }
89        match event{
90            Event::VirtualKeyboard(vk)=>{
91                match vk{
92                    VirtualKeyboardEvent::WillShow{time, height, ease, duration}=>{
93                        // ok so lets run an animation with next
94                        let height = self.compute_max_height(*height, cx);
95                        self.anim_state = AnimState::Opening{
96                            duration: *duration,
97                            start_time: *time,
98                            ease: *ease,
99                            height: height
100                        };
101                        self.next_frame = cx.new_next_frame();
102                    }
103                    VirtualKeyboardEvent::WillHide{time, height:_, ease, duration}=>{
104                        self.anim_state = AnimState::Closing{
105                            height: self.keyboard_shift,
106                            duration: *duration,
107                            start_time: *time,
108                            ease: *ease,
109                        };
110                        self.next_frame = cx.new_next_frame();
111                    }
112                    VirtualKeyboardEvent::DidShow{time:_, height}=>{
113                        if let AnimState::Closed = self.anim_state{
114                            self.keyboard_shift = self.compute_max_height(*height, cx);
115                        }
116                        self.anim_state = AnimState::Open;
117                        self.redraw(cx);
118                    }
119                    VirtualKeyboardEvent::DidHide{time:_}=>{
120                        self.anim_state = AnimState::Closed;
121                        self.keyboard_shift = 0.0;
122                        self.redraw(cx);
123                    }
124                }
125            }
126            _=>()
127        }
128        self.view.handle_event(cx, event, scope);
129    }
130    
131    
132    fn draw_walk(&mut self, cx: &mut Cx2d, scope:&mut Scope, walk: Walk) -> DrawStep {
133        if self.draw_state.begin_with(cx, &(), |cx,_|{
134            self.view.walk(cx)
135        }){
136            self.begin(cx, walk);
137        }
138        if let Some(walk) = self.draw_state.get() {
139            self.view.draw_walk(cx, scope, walk)?;
140        }
141        self.end(cx);
142        DrawStep::done()
143    }
144}
145