ribir_core 0.0.1-alpha.4

Ribir is a framework for building modern native/wasm cross-platform user interface applications.
Documentation
use std::convert::Infallible;

use crate::{
  data_widget::compose_child_as_data_widget, impl_compose_child_with_focus_for_listener,
  impl_listener, impl_listener_and_compose_child_with_focus, impl_query_self_only, prelude::*,
};

#[derive(Debug)]
pub struct KeyboardEvent {
  pub scan_code: ScanCode,
  pub key: VirtualKeyCode,
  pub common: EventCommon,
}

#[derive(Declare)]
pub struct KeyDownListener {
  #[declare(builtin, default, convert=custom)]
  on_key_down: MutRefItemSubject<'static, KeyboardEvent, Infallible>,
}

#[derive(Declare)]
pub struct KeyUpListener {
  #[declare(
    builtin,
    convert=custom
  )]
  on_key_up: MutRefItemSubject<'static, KeyboardEvent, Infallible>,
}

#[derive(Declare)]
pub struct KeyDownCaptureListener {
  #[declare(builtin, convert=custom)]
  on_key_down_capture: MutRefItemSubject<'static, KeyboardEvent, Infallible>,
}

#[derive(Declare)]
pub struct KeyUpCaptureListener {
  #[declare(builtin, convert=custom)]
  on_key_up_capture: MutRefItemSubject<'static, KeyboardEvent, Infallible>,
}

impl_listener_and_compose_child_with_focus!(
  KeyDownListener,
  KeyDownListenerDeclarer,
  on_key_down,
  KeyboardEvent,
  key_down_stream
);

impl_listener_and_compose_child_with_focus!(
  KeyUpListener,
  KeyUpListenerDeclarer,
  on_key_up,
  KeyboardEvent,
  key_up_stream
);

impl_listener_and_compose_child_with_focus!(
  KeyDownCaptureListener,
  KeyDownCaptureListenerDeclarer,
  on_key_down_capture,
  KeyboardEvent,
  key_down_capture_stream
);

impl_listener_and_compose_child_with_focus!(
  KeyUpCaptureListener,
  KeyUpCaptureListenerDeclarer,
  on_key_up_capture,
  KeyboardEvent,
  key_up_capture_stream
);

impl std::borrow::Borrow<EventCommon> for KeyboardEvent {
  #[inline]
  fn borrow(&self) -> &EventCommon { &self.common }
}

impl std::borrow::BorrowMut<EventCommon> for KeyboardEvent {
  #[inline]
  fn borrow_mut(&mut self) -> &mut EventCommon { &mut self.common }
}

impl std::ops::Deref for KeyboardEvent {
  type Target = EventCommon;

  #[inline]
  fn deref(&self) -> &Self::Target { &self.common }
}

impl std::ops::DerefMut for KeyboardEvent {
  #[inline]
  fn deref_mut(&mut self) -> &mut Self::Target { &mut self.common }
}

#[cfg(test)]
mod tests {
  use super::*;
  use crate::test_helper::*;
  use std::{cell::RefCell, rc::Rc};
  use winit::event::{DeviceId, ElementState, KeyboardInput, WindowEvent};

  fn new_key_event(key: VirtualKeyCode, state: ElementState) -> WindowEvent<'static> {
    #[allow(deprecated)]
    WindowEvent::KeyboardInput {
      device_id: unsafe { DeviceId::dummy() },
      input: KeyboardInput {
        scancode: 0,
        virtual_keycode: Some(key),
        state,
        modifiers: ModifiersState::default(),
      },
      is_synthetic: false,
    }
  }

  #[test]
  fn smoke() {
    #[derive(Default)]
    struct Keys(Rc<RefCell<Vec<String>>>);

    impl Compose for Keys {
      fn compose(this: State<Self>) -> Widget {
        widget! {
          states { this: this.into_writable() }
          MockBox {
            size: Size::zero(),
            on_key_down_capture: move |key| {
              this.0.borrow_mut().push(format!("key down capture {:?}", key.key));
            },
            on_key_up_capture: move |key| {
              this.0.borrow_mut().push(format!("key up capture {:?}", key.key));
            },
            MockBox {
              size: Size::zero(),
              auto_focus: true,
              on_key_down: move |key| {
                this.0
                  .borrow_mut()
                  .push(format!("key down {:?}", key.key));
              },
              on_key_up: move |key| {
                this.0.borrow_mut().push(format!("key up {:?}", key.key));
              }
            }
          }
        }
      }
    }

    let w = Keys::default();
    let keys = w.0.clone();

    let mut wnd = TestWindow::new(w);
    wnd.draw_frame();

    #[allow(deprecated)]
    wnd.processes_native_event(new_key_event(VirtualKeyCode::Key0, ElementState::Pressed));
    #[allow(deprecated)]
    wnd.processes_native_event(new_key_event(VirtualKeyCode::Key0, ElementState::Released));
    #[allow(deprecated)]
    wnd.processes_native_event(new_key_event(VirtualKeyCode::Key1, ElementState::Pressed));
    #[allow(deprecated)]
    wnd.processes_native_event(new_key_event(VirtualKeyCode::Key1, ElementState::Released));

    assert_eq!(
      &*keys.borrow(),
      &[
        "key down capture Key0",
        "key down Key0",
        "key up capture Key0",
        "key up Key0",
        "key down capture Key1",
        "key down Key1",
        "key up capture Key1",
        "key up Key1"
      ]
    );
  }
}