makepad_widgets/
keyboard_view.rs1use 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 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