makepad_widgets/
keyboard_view.rs

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