defmodule Scenic.Driver.Renderling.Window do @moduledoc """ The Scenic for windowed applications. """ alias Scenic.ViewPort alias Scenic.Driver.Renderling.Window.{Config, Nif} use Scenic.Driver require Logger @default_limit 29 @default_layer 0 @default_opacity 255 @position_schema [ scaled: [type: :boolean, default: false], centered: [type: :boolean, default: false], orientation: [type: {:in, [:normal, :left, :right, :upside_down]}, default: :normal] ] @window_schema [ title: [type: :string, default: "Scenic Window"], resizeable: [type: :boolean, default: false] ] @opts_schema [ name: [type: {:or, [:atom, :string]}], limit_ms: [type: :non_neg_integer, default: @default_limit], layer: [type: :integer, default: @default_layer], opacity: [type: :integer, default: @default_opacity], debug: [type: :boolean, default: false], debugger: [type: :string, default: ""], debug_fps: [type: :integer, default: 0], antialias: [type: :boolean, default: true], position: [type: :keyword_list, keys: @position_schema, default: []], window: [type: :keyword_list, keys: @window_schema, default: []], cursor: [type: :boolean, default: false], key_map: [type: :atom, default: Scenic.KeyMap.USEnglish], on_close: [ type: {:or, [:mfa, {:in, [:restart, :stop_driver, :stop_viewport, :stop_system, :halt_system]}]}, default: :restart ], input_blacklist: [type: {:list, :string}, default: []] ] @doc false @impl Scenic.Driver def validate_opts(opts), do: NimbleOptions.validate(opts, @opts_schema) @doc false @impl true def init(driver, opts) do {width, height} = driver.viewport.size config = opts |> Keyword.update( :window, [width: width, height: height], &Keyword.merge(&1, width: width, height: height) ) |> Config.init() driver = assign(driver, config: config, server: Nif.init(config)) Process.flag(:trap_exit, true) Logger.info("#{inspect(__MODULE__)}: start #{inspect(opts)}, pid: #{inspect(self())}") {:ok, driver} end @doc false @impl true def update_scene(ids, driver) do Enum.reduce_while(ids, {:ok, driver}, fn id, {:ok, driver} -> case ViewPort.get_script(driver.viewport, id) do {:ok, script} -> Nif.update_scene(script, id, driver.assigns.server) {:cont, {:ok, driver}} {:error, reason} -> {:halt, {:error, reason}} end end) end @doc false @impl true def reset_scene(driver) do Nif.reset_scene(driver.assigns.server) {:ok, driver} end @doc false @impl true def del_scripts(ids, driver) do Nif.del_scripts(ids, driver.assigns.server) {:ok, driver} end @doc false @impl true def clear_color(color, driver) do Nif.clear_color(color, driver.assigns.server) {:ok, driver} end @doc false @impl GenServer def terminate(_, driver) do Nif.terminate(driver.assigns.server) end end