Current section
Files
Jump to
Current section
Files
lib/runtime.ex
defmodule Orange.Runtime do
@moduledoc false
# The runtime module is responsible for rendering the UI components. The runtime consists of multiple
# components:
#
# 1. `Orange.Runtime.RenderLoop`: UI rendering loop, implemented as a GenServer. Re-render is triggered in these cases:
# a. Receive events from the event poller
# b. Receive state update requests from update callbacks
# 2. `Orange.Runtime.EventManager`: manages event subscriptions and dispatches events to the subscribed components
# 3. `Orange.Runtime.EventPoller`: polls for events from the terminal and sends to the render loop
def start(root) do
children = [
event_manager_impl(),
{event_poller_impl(), [[event_receiver: __MODULE__.RenderLoop]]},
{__MODULE__.RenderLoop, [root]}
]
Supervisor.start_link(children, strategy: :one_for_all, name: __MODULE__)
end
def stop do
spawn(fn ->
:ok = Supervisor.stop(__MODULE__)
end)
end
defp event_manager_impl(),
do: Application.get_env(:orange, :event_manager, __MODULE__.EventManager)
defp event_poller_impl(),
do: Application.get_env(:orange, :event_poller, __MODULE__.EventPoller)
def subscribe(component_id), do: find_component_and_apply!(component_id, :subscribe)
def unsubscribe(component_id), do: find_component_and_apply!(component_id, :unsubscribe)
def focus(component_id), do: find_component_and_apply!(component_id, :focus)
def unfocus(component_id), do: find_component_and_apply!(component_id, :unfocus)
defp find_component_and_apply!(component_id, function) do
case __MODULE__.RenderLoop.component_ref_by_id(component_id) do
nil ->
raise("""
#{__MODULE__}.#{function}: component not found
- component_id: #{inspect(component_id)}
""")
component_ref when is_reference(component_ref) ->
apply(event_manager_impl(), function, [component_ref])
end
end
end