react_loop.ml 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. open Base
  2. open Math
  3. type 'id t =
  4. { mutable tree : Draw_tree.t
  5. ; mutable state : Source.State.t
  6. ; callbacks : Component.callbacks
  7. ; mutable event_cb_ids : 'id list }
  8. type event = Tick | Click of Pos.t | Repaint | Exit
  9. module type EVENTS_LAYER = sig
  10. type callback_id
  11. val bind_callback : (event -> unit) -> callback_id
  12. val unregister : callback_id -> unit
  13. val poll_time_ms : unit -> int
  14. end
  15. module type GRAPHICS_LAYER = sig
  16. val clear : unit -> unit
  17. val rect : AABB.t -> Color.t -> unit
  18. end
  19. module Make(E : EVENTS_LAYER)(G : GRAPHICS_LAYER) :
  20. sig
  21. val run : Component.t -> unit
  22. end
  23. =
  24. struct
  25. let poll_time _ =
  26. E.poll_time_ms () / 1000
  27. let updates_of_sinks state sinks srcs =
  28. Sequence.concat_map (Sequence.of_list srcs)
  29. ~f:(fun src ->
  30. Map.find sinks src
  31. |> Option.value ~default:[]
  32. |> Sequence.of_list)
  33. |> Sequence.map
  34. ~f:(fun (path, fig_b) ->
  35. (path, Behavior.sample fig_b state))
  36. let handle_updated_sources t srcs =
  37. let updates = updates_of_sinks t.state t.callbacks.sinks srcs in
  38. begin
  39. t.tree <- Draw_tree.apply_updates_exn updates t.tree ;
  40. not (Sequence.is_empty updates)
  41. end
  42. let update_sources t (chg_src_map : (Source.value -> Source.value) Source.map) =
  43. let f ~key:src ~data:func state =
  44. let value = Source.State.get_exn src state in
  45. let value = func value in
  46. Source.State.set src value state
  47. in
  48. begin
  49. t.state <- Map.fold chg_src_map ~init:t.state ~f ;
  50. handle_updated_sources t (Map.keys chg_src_map)
  51. end
  52. let update_source ~src ~f t =
  53. update_sources t (Map.singleton (module Source) src f)
  54. let handle_evt t = function
  55. | Tick ->
  56. update_source t
  57. ~src:Source.time
  58. ~f:poll_time
  59. | Click(pos) ->
  60. let ev_arg = Event.Click(pos) in
  61. update_sources t @@
  62. List.fold (Draw_tree.capture_point ~pos t.tree)
  63. ~init:Source.empty_map
  64. ~f:(fun chg ev_id ->
  65. match Map.find t.callbacks.handlers ev_id with
  66. | Some(handler) ->
  67. Map.merge_skewed chg (handler ev_arg)
  68. ~combine:(fun ~key:_ f g x -> f (g x))
  69. | None -> chg)
  70. | Repaint ->
  71. true
  72. | Exit ->
  73. let () = List.iter ~f:E.unregister t.event_cb_ids in
  74. let () = t.event_cb_ids <- [] in
  75. false
  76. let repaint t =
  77. let () = G.clear () in
  78. Sequence.iter (Draw_tree.render t.tree)
  79. ~f:(function
  80. | Draw_tree.Draw.Rect(b, c) -> G.rect b c)
  81. let run app =
  82. let state = Source.State.of_time (poll_time ()) in
  83. let state, callbacks, tree = Component.mount state app in
  84. let t = { tree ; state ; callbacks ; event_cb_ids = [] } in
  85. let ec_id =
  86. E.bind_callback
  87. (fun ev -> if handle_evt t ev then repaint t)
  88. in
  89. let () = t.event_cb_ids <- [ec_id] in
  90. repaint t
  91. end