defmodule ElementTui.Tui do @moduledoc """ This genserver will be started by the application. It will also handle drawing, in order to make sure we write single threaded. In general a user should not need to use this directly, but instead use the main ElementTui module. """ use GenServer alias ElementTui.TermBox2Ex def start_link(opts \\ []) do GenServer.start_link(__MODULE__, %{}, opts) end def puts(x, y, attr, bg_attr, line) do GenServer.cast(ElementTui.Tui, {:puts, x, y, attr, bg_attr, line}) end def clear do GenServer.cast(ElementTui.Tui, :clear) end def clear_region(x, y, width, height) do GenServer.cast(ElementTui.Tui, {:clear_region, x, y, width, height}) end def present() do GenServer.cast(ElementTui.Tui, {:present}) end def poll(timeout_ms) do # TODO: we should pass current time, so we account for potential delay in message handling GenServer.call(ElementTui.Tui, {:poll, timeout_ms}) end @impl true def init(init) do TermBox2Ex.ex_start() Process.flag(:trap_exit, true) {:ok, init} end @impl true def terminate(_reason, _state) do TermBox2Ex.ex_stop() # IO.puts "Going Down: #{inspect(state)}" :normal end @impl true def handle_call({:poll, timeout_ms}, _from, state) do ev = TermBox2Ex.poll(timeout_ms) {:reply, ev, state} end @impl true def handle_cast({:puts, x, y, attr, bg_attr, line}, state) do TermBox2Ex.puts(x, y, attr, bg_attr, line) {:noreply, state} end def handle_cast(:clear, state) do TermBox2Ex.clear() {:noreply, state} end def handle_cast({:clear_region, x, y, width, height}, state) do TermBox2Ex.clear_region(x, y, width, height) {:noreply, state} end def handle_cast({:present}, state) do TermBox2Ex.present() # NOTE: This currently relies on good behaviour by the user, who will need to call present only once every "draw" # but I currently do not see a way around that without requiring the user to unset the cursor manually, could have an opt # passed to present? TermBox2Ex.hide_cursor() {:noreply, state} end end