ribir_core 0.4.0-alpha.2

A non-intrusive declarative GUI framework, to build modern native/wasm cross-platform applications.
Documentation
use super::CommonEvent;
use crate::impl_common_event_deref;
mod from_mouse;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PointerId(usize);

/// The pointer is a hardware-agnostic device that can target a specific set of
/// screen coordinates. Having a single event model for pointers can simplify
/// creating Web sites and applications and provide a good user experience
/// regardless of the user's hardware. However, for scenarios when
/// device-specific handling is desired, pointer events defines a pointerType
/// property to inspect the device type which produced the event.
/// Reference: <https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#term_pointer_event>
#[derive(Debug)]
pub struct PointerEvent {
  /// A unique identifier for the pointer causing the event.
  pub id: PointerId,
  /// The width (magnitude on the X axis), in pixels, of the contact geometry of
  /// the pointer.
  pub width: f32,
  /// the height (magnitude on the Y axis), in pixels, of the contact geometry
  /// of the pointer.
  pub height: f32,
  /// the normalized pressure of the pointer input in the range of 0 to 1, where
  /// 0 and 1 represent the minimum and maximum pressure the hardware is capable
  /// of detecting, respectively. tangentialPressure
  /// The normalized tangential pressure of the pointer input (also known as
  /// barrel pressure or cylinder stress) in the range -1 to 1, where 0 is the
  /// neutral position of the control.
  pub pressure: f32,
  /// The plane angle (in degrees, in the range of -90 to 90) between the Y–Z
  /// plane and the plane containing both the pointer (e.g. pen stylus) axis and
  /// the Y axis.
  pub tilt_x: f32,
  /// The plane angle (in degrees, in the range of -90 to 90) between the X–Z
  /// plane and the plane containing both the pointer (e.g. pen stylus) axis and
  /// the X axis.
  pub tilt_y: f32,
  /// The clockwise rotation of the pointer (e.g. pen stylus) around its major
  /// axis in degrees, with a value in the range 0 to 359.
  pub twist: f32,
  ///  Indicates the device type that caused the event (mouse, pen, touch, etc.)
  pub point_type: PointerType,
  /// Indicates if the pointer represents the primary pointer of this pointer
  /// type.
  pub is_primary: bool,

  pub common: CommonEvent,
}

bitflags! {
  #[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
  pub struct MouseButtons: u8 {
    /// Primary button (usually the left button)
    const PRIMARY = 0b0000_0001;
    /// Secondary button (usually the right button)
    const SECONDARY = 0b0000_0010;
    /// Auxiliary button (usually the mouse wheel button or middle button)
    const AUXILIARY = 0b0000_0100;
    /// 4th button (typically the "Browser Back" button)
    const FOURTH = 0b0000_1000;
    /// 5th button (typically the "Browser Forward" button)
    const FIFTH = 0b0001_0000;
  }
}

#[derive(Debug, Clone, PartialEq)]
pub enum PointerType {
  /// The event was generated by a mouse device.
  Mouse,
  /// The event was generated by a pen or stylus device.
  Pen,
  /// The event was generated by a touch, such as a finger.
  Touch,
}

impl_common_event_deref!(PointerEvent);
#[cfg(test)]
mod tests {
  use std::{cell::RefCell, rc::Rc};

  use winit::{
    dpi::LogicalPosition,
    event::{DeviceId, ElementState, MouseButton, WindowEvent},
  };

  use crate::{
    prelude::*,
    reset_test_env,
    test_helper::{MockBox, MockMulti, TestWindow},
  };

  fn tap_on(wnd: &Window, x: f32, y: f32) {
    let device_id = unsafe { DeviceId::dummy() };
    let logical = LogicalPosition::new(x, y);
    #[allow(deprecated)]
    wnd.processes_native_event(WindowEvent::CursorMoved {
      device_id,
      position: logical.to_physical(1.),
    });

    wnd.process_mouse_input(device_id, ElementState::Pressed, MouseButton::Left);

    wnd.process_mouse_input(device_id, ElementState::Released, MouseButton::Left);
  }

  #[test]
  fn tap_focus() {
    reset_test_env!();

    let tap_cnt = Rc::new(RefCell::new(0));
    let is_focused = Rc::new(RefCell::new(false));

    let tap_cnt1 = tap_cnt.clone();
    let tap_cnt2 = tap_cnt.clone();
    let is_focused2 = is_focused.clone();
    let w = fn_widget! {
      let mut host = @MockMulti {};
      watch!($host.has_focus())
        .subscribe(move |v| *is_focused2.borrow_mut() = v);

      @$host {
        @MockBox {
          size: Size::new(50., 50.,),
          on_tap: move |_| *tap_cnt1.borrow_mut() += 1,
        }
        @MockBox {
          size: Size::new(50., 50.,),
          on_tap: move |_| *tap_cnt2.borrow_mut() += 1,
          on_key_down: move |_| println!("dummy code"),
        }
      }
    };
    let mut wnd = TestWindow::new_with_size(w, Size::new(100., 100.));
    wnd.draw_frame();

    tap_on(&wnd, 25., 25.);
    wnd.draw_frame();
    assert_eq!(*tap_cnt.borrow(), 1);
    assert!(!*is_focused.borrow());

    tap_on(&wnd, 75., 25.);
    wnd.draw_frame();
    assert_eq!(*tap_cnt.borrow(), 2);
    assert!(*is_focused.borrow());
  }
}