123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- open Base
- open Math
- type 'id t =
- { mutable tree : Draw_tree.t
- ; mutable state : Source.State.t
- ; callbacks : Component.callbacks
- ; mutable event_cb_ids : 'id list }
- type event = Tick | Click of Pos.t | Repaint | Exit
- module type EVENTS_LAYER = sig
- type callback_id
- val bind_callback : (event -> unit) -> callback_id
- val unregister : callback_id -> unit
- val poll_time_ms : unit -> int
- end
- module type GRAPHICS_LAYER = sig
- val clear : unit -> unit
- val rect : AABB.t -> Color.t -> unit
- end
- module Make(E : EVENTS_LAYER)(G : GRAPHICS_LAYER) :
- sig
- val run : Component.t -> unit
- end
- =
- struct
- let poll_time _ =
- E.poll_time_ms () / 1000
- let updates_of_sinks state sinks srcs =
- Sequence.concat_map (Sequence.of_list srcs)
- ~f:(fun src ->
- Map.find sinks src
- |> Option.value ~default:[]
- |> Sequence.of_list)
- |> Sequence.map
- ~f:(fun (path, fig_b) ->
- (path, Behavior.sample fig_b state))
- let handle_updated_sources t srcs =
- let updates = updates_of_sinks t.state t.callbacks.sinks srcs in
- begin
- t.tree <- Draw_tree.apply_updates_exn updates t.tree ;
- not (Sequence.is_empty updates)
- end
- let update_sources t (chg_src_map : (Source.value -> Source.value) Source.map) =
- let f ~key:src ~data:func state =
- let value = Source.State.get_exn src state in
- let value = func value in
- Source.State.set src value state
- in
- begin
- t.state <- Map.fold chg_src_map ~init:t.state ~f ;
- handle_updated_sources t (Map.keys chg_src_map)
- end
- let update_source ~src ~f t =
- update_sources t (Map.singleton (module Source) src f)
- let handle_evt t = function
- | Tick ->
- update_source t
- ~src:Source.time
- ~f:poll_time
- | Click(pos) ->
- let ev_arg = Event.Click(pos) in
- update_sources t @@
- List.fold (Draw_tree.capture_point ~pos t.tree)
- ~init:Source.empty_map
- ~f:(fun chg ev_id ->
- match Map.find t.callbacks.handlers ev_id with
- | Some(handler) ->
- Map.merge_skewed chg (handler ev_arg)
- ~combine:(fun ~key:_ f g x -> f (g x))
- | None -> chg)
- | Repaint ->
- true
- | Exit ->
- let () = List.iter ~f:E.unregister t.event_cb_ids in
- let () = t.event_cb_ids <- [] in
- false
- let repaint t =
- let () = G.clear () in
- Sequence.iter (Draw_tree.render t.tree)
- ~f:(function
- | Draw_tree.Draw.Rect(b, c) -> G.rect b c)
- let run app =
- let state = Source.State.of_time (poll_time ()) in
- let state, callbacks, tree = Component.mount state app in
- let t = { tree ; state ; callbacks ; event_cb_ids = [] } in
- let ec_id =
- E.bind_callback
- (fun ev -> if handle_evt t ev then repaint t)
- in
- let () = t.event_cb_ids <- [ec_id] in
- repaint t
- end
|