///|
pub(all) struct HostInputContract {
  capabilities : HostInputCapabilities
  coordinates : HostCoordinatePolicy
} derive(Eq, Debug, ToJson)

///|
pub extend HostInputContract with Debug::{to_repr}

///|
pub extend HostInputContract with Eq::{not_equal, equal}

///|
pub extend HostInputContract with ToJson::{to_json}

///|
pub(all) enum HostScrollPhase {
  Started
  Moved
  Ended
  Cancelled
} derive(Eq, Debug, ToJson)

///|
pub extend HostScrollPhase with Debug::{to_repr}

///|
pub extend HostScrollPhase with Eq::{not_equal, equal}

///|
pub extend HostScrollPhase with ToJson::{to_json}

///|
pub(all) enum HostScrollDelta {
  Lines(@core.Point)
  Pixels(@core.Point)
} derive(Eq, Debug, ToJson)

///|
pub extend HostScrollDelta with Debug::{to_repr}

///|
pub extend HostScrollDelta with Eq::{not_equal, equal}

///|
pub extend HostScrollDelta with ToJson::{to_json}

///|
pub(all) struct HostScrollEvent {
  position : @core.Point
  delta : HostScrollDelta
  phase : HostScrollPhase
} derive(Eq, Debug, ToJson)

///|
pub extend HostScrollEvent with Debug::{to_repr}

///|
pub extend HostScrollEvent with Eq::{not_equal, equal}

///|
pub extend HostScrollEvent with ToJson::{to_json}

///|
pub(all) struct HostFocusEvent {
  focused : Bool
  pointer_cancel_position : @core.Point?
} derive(Eq, Debug, ToJson)

///|
pub extend HostFocusEvent with Debug::{to_repr}

///|
pub extend HostFocusEvent with Eq::{not_equal, equal}

///|
pub extend HostFocusEvent with ToJson::{to_json}

///|
pub(all) enum Event {
  Resized(@core.SurfaceMetrics)
  Pointer(@core.PointerEvent)
  Scroll(HostScrollEvent)
  Focus(HostFocusEvent)
  Keyboard(@core.KeyboardEvent)
  TextInput(@core.TextInputEvent)
  DragDrop(@core.DragDropEvent)
  ThemeChanged(@core.ColorScheme)
  Command(@core.CommandIntent)
  RedrawRequested
  CloseRequested
} derive(Eq, Debug, ToJson)

///|
pub extend Event with Debug::{to_repr}

///|
pub extend Event with Eq::{not_equal, equal}

///|
pub extend Event with ToJson::{to_json}

///|
pub(all) struct EventResult {
  needs_rebuild : Bool
  needs_redraw : Bool
  redraw_requested : Bool
  close_requested : Bool
} derive(Eq, Debug, ToJson)

///|
pub extend EventResult with Debug::{to_repr}

///|
pub extend EventResult with Eq::{not_equal, equal}

///|
pub extend EventResult with ToJson::{to_json}

///|
pub fn HostInputContract::new(
  capabilities? : HostInputCapabilities = HostInputCapabilities::new(),
  coordinates? : HostCoordinatePolicy = HostCoordinatePolicy::logical(),
) -> HostInputContract {
  { capabilities, coordinates, }
}

///|
pub fn HostScrollEvent::new(
  position~ : @core.Point,
  delta~ : HostScrollDelta,
  phase? : HostScrollPhase = Moved,
) -> HostScrollEvent {
  { position, delta, phase, }
}

///|
pub fn HostScrollDelta::to_logical_pixels(
  self : HostScrollDelta,
  line_extent? : Double = 40.0,
) -> @core.Point {
  match self {
    Pixels(delta) => delta
    Lines(delta) =>
      @core.Point::new(x=delta.x * line_extent, y=delta.y * line_extent)
  }
}

///|
pub fn HostScrollEvent::to_pointer_event(
  self : HostScrollEvent,
) -> @core.PointerEvent {
  @core.PointerEvent::new(
    position=self.position,
    phase=Move,
    wheel_delta=self.delta.to_logical_pixels(),
  )
}

///|
pub fn HostFocusEvent::new(
  focused~ : Bool,
  pointer_cancel_position? : @core.Point? = None,
) -> HostFocusEvent {
  { focused, pointer_cancel_position, }
}

///|
pub fn HostFocusEvent::to_core(self : HostFocusEvent) -> @core.AppEvent? {
  match (self.focused, self.pointer_cancel_position) {
    (false, Some(position)) =>
      Some(Pointer(@core.PointerEvent::new(position~, phase=Cancel)))
    _ => None
  }
}

///|
pub fn Event::to_core(self : Event) -> @core.AppEvent? {
  match self {
    Resized(metrics) => Some(Resize(metrics.logical_size))
    Pointer(event) => Some(Pointer(event))
    Scroll(event) => Some(Pointer(event.to_pointer_event()))
    Focus(event) => event.to_core()
    Keyboard(event) => Some(Keyboard(event))
    TextInput(event) => Some(TextInput(event))
    DragDrop(event) => Some(DragDrop(event))
    ThemeChanged(_) => None
    Command(_) => None
    RedrawRequested => Some(Redraw(Explicit))
    CloseRequested => Some(CloseRequested)
  }
}