;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; generat event handling
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define event-queue make-vector())


define post-event(evt)
  assert {{null? evt} or evt[event?:]} "invalid event object"
  if {not-null? evt}
    then
      assert {vector-length(event-queue) < 512} "too many events in the internal queue"
      vector-push! event-queue evt
  evt


define post-broadcast-event
  case-lambda
    (type)
      define evt new-gui-event('BROADCAST)
      {evt[broadcast-type:] := type}
      post-event evt
    (type src)
      define evt new-gui-event('BROADCAST)
      {evt[broadcast-type:] := type}
      {evt[source:] := src}
      post-event evt
    (type src udata)
      define evt new-gui-event('BROADCAST)
      {evt[broadcast-type:] := type}
      {evt[source:] := src}
      {evt[user-data:] := src}
      post-event evt


define process-event-queue()
  define evt
  ;; let's process newly posted messages too, why not.
  ;; this will allow us to implement everything via message posting (i hope).
  ;; 1024 is arbitrary number. should be enough for everyone.
  define count 1024 ;;vector-length(event-queue)
  if {null? desktop}
    vector-resize! event-queue 0
    while {{positive? count} and {positive? vector-length(event-queue)}}
      {evt := vector-pop-first!(event-queue)}
      if {{not-null? evt} and evt[alive?:]}
        desktop[handle-event: evt]
      dec! count


define reset-modifiers()
  gset! mouse-button-state 0
  gset! mouse-button-state-last 0
  gset! keyboard-mods-state 0
  gset! keyboard-mods-state-last 0

;; route SDL event to widget.
;; return gui event object or #nil if wasn't routed.
define route-sdl-event(sdl-evt)
  define evt #nil
  ;;
  define evt-set-mouse-xy(evt)
    define gx trunc{sdl:event-x(sdl-evt) / lgfx:window-scale-x}
    define gy trunc{sdl:event-y(sdl-evt) / lgfx:window-scale-y}
    {evt[gx:] := gx}
    {evt[gy:] := gy}
    {evt[x:] := gx}
    {evt[y:] := gy}
  ;;
  process-event-queue()
  ;; modify masts before "UP" events
  case (sdl:event-type sdl-evt)
    (MOUSE-UP)
      gset! mouse-button-state bit-reset(mouse-button-state sdl:event-button(sdl-evt))
    (KEY-UP)
      gset! keyboard-mods-state bit-notand(keyboard-mods-state sdl:event-scan-mod-mask(sdl-evt))
    (WINDOW)
      if {(sdl:event-window-action sdl-evt) eq? 'BLUR}
        reset-modifiers()
    else #void
  ;;
  if {not-null? desktop}
    case (sdl:event-type sdl-evt)
      (KEY-DOWN KEY-UP)
        {evt := new-gui-event(sdl:event-type(sdl-evt))}
        if sdl:event-any-mods?(sdl-evt)
          evt[any-mods!:]
        {evt[keysym:] := sdl:event-full-ksym-name(sdl-evt)}
        if sdl:names-equal?("kp-enter" sdl:event-full-ksym-name(sdl-evt))
          {evt[keysym:] := "RETURN"}
        ;printf "%s\n" sdl:event-full-ksym-name(sdl-evt)
      (MOUSE-DOWN MOUSE-UP)
        {evt := new-gui-event(sdl:event-type(sdl-evt))}
        evt-set-mouse-xy evt
        {evt[button:] := sdl:event-button(sdl-evt)}
        {evt[clicks:] := sdl:event-clicks(sdl-evt)}
      (MOUSE-MOTION)
        {evt := new-gui-event(sdl:event-type(sdl-evt))}
        evt-set-mouse-xy evt
        {evt[rel-x:] := {sdl:event-rel-x(sdl-evt) / lgfx:window-scale-x}}
        {evt[rel-y:] := {sdl:event-rel-y(sdl-evt) / lgfx:window-scale-y}}
        {evt[button:] := sdl:event-button(sdl-evt)}
      (MOUSE-WHEEL)
        {evt := new-gui-event(sdl:event-type(sdl-evt))}
        evt-set-mouse-xy evt
        {evt[wheel-x:] := sdl:event-wheel-x(sdl-evt)}
        {evt[wheel-y:] := {- sdl:event-wheel-y(sdl-evt)}}
        {evt[wheel-precise-x:] := sdl:event-wheel-precise-x(sdl-evt)}
        {evt[wheel-precise-y:] := sdl:event-wheel-precise-y(sdl-evt)}
      (TEXT-INPUT)
        {evt := new-gui-event(sdl:event-type(sdl-evt))}
        {evt[text:] := sdl:event-text(sdl-evt)}
      (WINDOW)
        if {(sdl:event-window-action sdl-evt) eq? 'BLUR}
          then
            {evt := new-gui-event('BROADCAST)}
            {evt[broadcast-type:] := 'GLOBAL-BLUR}
      else
        #void
  if {not-null? evt}
    desktop[handle-event: evt]
  ;; modify masts after "DOWN" events
  case (sdl:event-type sdl-evt)
    (MOUSE-DOWN)
      gset! mouse-button-state bit-set(mouse-button-state sdl:event-button(sdl-evt))
    (KEY-DOWN)
      gset! keyboard-mods-state bit-or(keyboard-mods-state sdl:event-scan-mod-mask(sdl-evt))
    else #void
  gset! mouse-button-state-last mouse-button-state
  gset! keyboard-mods-state-last keyboard-mods-state
  ;;
  process-event-queue()
  evt
