use crate::{
makepad_draw::*,
view::*,
widget::*,
};
live_design!{
KeyboardViewBase = {{KeyboardView}} {}
}
#[derive(Live)]
pub struct KeyboardView {
#[deref] view: View,
#[rust] area: Area,
#[live] outer_layout: Layout,
#[live] outer_walk: Walk,
#[live] keyboard_walk: Walk,
#[live] keyboard_min_shift: f64,
#[rust] next_frame: NextFrame,
#[rust] keyboard_shift: f64,
#[rust(AnimState::Closed)] anim_state: AnimState,
#[rust] draw_state: DrawStateWrap<Walk>,
}
enum AnimState{
Closed,
Opening{duration:f64, start_time:f64, ease:Ease, height:f64},
Open,
Closing{duration:f64, start_time:f64, ease:Ease, height:f64}
}
impl LiveHook for KeyboardView {
fn before_live_design(cx:&mut Cx){
register_widget!(cx, KeyboardView)
}
}
impl KeyboardView {
fn compute_max_height(&self, height:f64, cx:&Cx)->f64{
let self_rect = self.area.get_rect(cx);
let ime_rect = cx.get_ime_area_rect();
let av_height = self_rect.size.y - height;
let ime_height = ime_rect.size.y + ime_rect.pos.y + self.keyboard_min_shift;
if ime_height > av_height {
return ime_height - av_height
}
0.0
}
fn begin(&mut self, cx: &mut Cx2d, walk: Walk) {
cx.begin_turtle(walk, self.outer_layout.with_scroll(dvec2(0.,self.keyboard_shift)));
}
fn end(&mut self, cx: &mut Cx2d) {
cx.end_turtle_with_area(&mut self.area);
}
}
impl Widget for KeyboardView {
fn redraw(&mut self, cx: &mut Cx) {
self.area.redraw(cx);
}
fn handle_widget_event_with(&mut self, cx: &mut Cx, event: &Event, dispatch_action: &mut dyn FnMut(&mut Cx, WidgetActionItem)) {
if let Some(e) = self.next_frame.is_event(event){
match &self.anim_state{
AnimState::Opening{duration, start_time, ease, height}=>{
if e.time - start_time < *duration{
self.keyboard_shift = ease.map((e.time - start_time)/duration) * height;
self.next_frame = cx.new_next_frame();
}
else{
self.keyboard_shift = *height;
self.anim_state = AnimState::Open;
}
self.redraw(cx);
}
AnimState::Closing{duration, start_time, ease, height}=>{
if e.time - start_time < *duration{
self.keyboard_shift = (1.0-ease.map((e.time - start_time)/duration)) * height;
self.next_frame = cx.new_next_frame();
}
else{
self.keyboard_shift = 0.0;
self.anim_state = AnimState::Closed;
}
self.redraw(cx);
}
_=>()
}
}
match event{
Event::VirtualKeyboard(vk)=>{
match vk{
VirtualKeyboardEvent::WillShow{time, height, ease, duration}=>{
let height = self.compute_max_height(*height, cx);
self.anim_state = AnimState::Opening{
duration: *duration,
start_time: *time,
ease: *ease,
height: height
};
self.next_frame = cx.new_next_frame();
}
VirtualKeyboardEvent::WillHide{time, height:_, ease, duration}=>{
self.anim_state = AnimState::Closing{
height: self.keyboard_shift,
duration: *duration,
start_time: *time,
ease: *ease,
};
self.next_frame = cx.new_next_frame();
}
VirtualKeyboardEvent::DidShow{time:_, height}=>{
if let AnimState::Closed = self.anim_state{
self.keyboard_shift = self.compute_max_height(*height, cx);
}
self.anim_state = AnimState::Open;
self.redraw(cx);
}
VirtualKeyboardEvent::DidHide{time:_}=>{
self.anim_state = AnimState::Closed;
self.keyboard_shift = 0.0;
self.redraw(cx);
}
}
}
_=>()
}
self.view.handle_widget_event_with(cx, event, dispatch_action);
}
fn walk(&mut self, _cx:&mut Cx) -> Walk {
self.outer_walk
}
fn draw_walk_widget(&mut self, cx: &mut Cx2d, walk: Walk) -> WidgetDraw {
if self.draw_state.begin_with(cx, &(), |cx,_|{
self.view.walk(cx)
}){
self.begin(cx, walk);
}
if let Some(walk) = self.draw_state.get() {
self.view.draw_walk_widget(cx, walk)?;
}
self.end(cx);
WidgetDraw::done()
}
fn find_widgets(&mut self, path: &[LiveId], cached: WidgetCache, results: &mut WidgetSet) {
self.view.find_widgets(path, cached, results);
}
}