Packages

Scrollable component for the Scenic library

Current section

Files

Jump to
scenic_scrollable lib utility scene_inspector.ex
Raw

lib/utility/scene_inspector.ex

defmodule Scenic.Scrollable.SceneInspector do
alias Scenic.ViewPort.Tables
@moduledoc false
# This module is meant for testing and debugging purposes only
defmacro __using__(opts) do
quote do
enabled = Enum.member?(unquote(opts)[:env] || [], Mix.env())
if enabled do
@doc false
@spec inspect(pid) :: {:ok, {pid, term}} | {:error, :invalid_module}
def inspect(pid) do
module = __MODULE__
case GenServer.call(pid, :inspect_state) do
{pid, ^module, state} -> {:ok, {pid, state}}
_ -> {:error, :invalid_module}
end
end
@doc false
@spec inspect() :: {:ok, {pid, term}} | {:error, atom}
def inspect() do
module = __MODULE__
:ets.match(Tables.scenes_table(), {:_, {:"$1", :_, :_}})
|> Enum.map(fn
[pid] -> GenServer.call(pid, :inspect_state)
_ -> {:error, :invalid_pid}
end)
|> Enum.map(fn
{pid, ^module, state} -> {:ok, {pid, state}}
_ -> {:error, :invalid_module}
end)
|> Enum.find(fn
{:ok, _} -> true
_ -> false
end)
|> (fn
nil -> {:error, :scene_not_running}
ok -> ok
end).()
end
@doc false
@spec inspect_until_found() :: {:ok, {pid, term}} | {:error, atom}
def inspect_until_found() do
case inspect() do
{:ok, _} = ok ->
ok
{:error, :scene_not_running} ->
Process.send_after(self(), :inspect_until_found, 100)
receive do
:inspect_until_found -> inspect_until_found()
_ -> {:error, :unexpected_message}
end
error ->
error
end
end
@doc false
@spec wait_until_destroyed(pid) :: :ok | {:error, atom}
def wait_until_destroyed(pid) do
:ets.match(Tables.scenes_table(), {:_, {:"$1", :_, :_}})
|> Enum.find(fn
[^pid] -> true
_ -> false
end)
|> (fn
nil ->
:ok
_ ->
Process.send_after(self(), :wait_until_destroyed, 100)
receive do
:wait_until_destroyed -> wait_until_destroyed(pid)
_ -> {:error, :unexpected_message}
end
end).()
end
@doc false
@spec simulate_left_button_press(pid, Scenic.Math.vector_2(), atom) :: :ok
def simulate_left_button_press(pid, position, origin_id) do
simulate_input(pid, {:cursor_button, {:left, :press, 0, position}}, origin_id)
end
@doc false
@spec simulate_left_button_release(pid, Scenic.Math.vector_2(), atom) :: :ok
def simulate_left_button_release(pid, position, origin_id) do
simulate_input(pid, {:cursor_button, {:left, :release, 0, position}}, origin_id)
end
@doc false
@spec simulate_mouse_move(pid, Scenic.Math.vector_2(), atom) :: :ok
def simulate_mouse_move(pid, position, origin_id) do
simulate_input(pid, {:cursor_pos, position}, origin_id)
end
@doc false
@spec simulate_mouse_exit(pid, atom) :: :ok
def simulate_mouse_exit(pid, origin_id) do
simulate_input(pid, {:cursor_exit, origin_id}, origin_id)
end
@doc false
@spec simulate_key_press(pid, String.t(), atom) :: :ok
def simulate_key_press(pid, key, origin_id) do
simulate_input(pid, {:key, {key, :press, 0}}, origin_id)
end
@doc false
@spec simulate_key_release(pid, String.t(), atom) :: :ok
def simulate_key_release(pid, key, origin_id) do
simulate_input(pid, {:key, {key, :press, 0}}, origin_id)
end
@doc false
@spec simulate_input(pid, term, atom) :: :ok
def simulate_input(pid, event, origin_id) do
context = make_input_context(event, origin_id)
GenServer.cast(pid, {:input, event, context})
end
@doc false
@spec make_input_context(term, atom) :: Scenic.ViewPort.Context.t()
defp make_input_context(event, origin_id) do
viewport = get_viewport()
Scenic.ViewPort.Context.build(%{
viewport: viewport,
graph_key: get_root_graph_key(viewport),
uid: 0,
id: origin_id,
raw_input: event
})
end
@doc false
@spec get_viewport() :: pid | nil
defp get_viewport() do
GenServer.whereis(:main_viewport)
end
@doc false
@spec get_root_graph_key(pid) :: term
defp get_root_graph_key(viewport) do
{:ok, %{root_graph: root}} = Scenic.ViewPort.info(viewport)
root
end
@doc false
def handle_call(:inspect_state, _from, state),
do: {:reply, {self(), __MODULE__, state}, state}
end
end
end
end