Current section

Files

Jump to
scenic lib scenic.ex
Raw

lib/scenic.ex

defmodule Scenic do
@moduledoc """
Scenic is an application framework written directly on the Elixir/Erlang/OTP stack.
With it you can build client-side applications that operate identically across all
supported operating systems, including MacOS, Ubuntu, Nerves/Linux, and more.
Scenic is primarily aimed at fixed screen connected devices (IoT), but can also be
used to build portable applications.
## Helpful Guides
[General Overview](overview_general.html) | [**Getting Started**](getting_started.html) | [Nerves](getting_started_nerves.html)
[Structure of a Scene](scene_structure.html) | [Lifecycle of a Scene](scene_lifecycle.html) | [Standard Components](Scenic.Components.html)
[Graph Overview](overview_graph.html) | [ViewPort Overview](overview_viewport.html) | [Driver Overview](overview_driver)
[Primitives](Scenic.Primitives.html) | [Styles](styles_overview.html) | [Transforms](transforms_overview.html)
[Contributing](contributing.html) | [Code of Conduct](code_of_conduct.html.html) |
If you are new to scenic, then you should read the [General Overview](overview_general.html),
[Getting Started](getting_started.html), and [Structure of a Scene](scene_structure.html) guides first.
## Configure Scenic
In order to start Scenic, you should first build a configuration for one or more
ViewPorts. These configuration maps will be passed in to the main Scenic
supervisor. These configurations should live in your app's config.exs file.
use Mix.Config
# Configure the main viewport for the Scenic application
config :my_application, :viewport, %{
name: :main_viewport,
size: {700, 600},
default_scene: {MyApplication.Scene.Example, nil},
drivers: [
%{
module: Scenic.Driver.Glfw,
name: :glfw,
opts: [resizeable: false, title: "Example Application"],
}
]
}
In the ViewPort configuration you can do things like set a name for the
ViewPort process, its size, the default scene and start one or more drivers.
See the documentation for [ViewPort Configuration](Scenic.ViewPort.Config.html)
to learn more about how to set the options on a viewport.
Note that all the drivers are in seperate Hex packages as you should choose the
correct one for your application. For example, the `Scenic.Driver.Glfw` driver draws
your scenes into a window under MacOS and Ubuntu. It should work on other
OS's as well, such as other flavors of Unix or Windows, but I haven't worked
on or tested those yet.
## Supervise Scenic
The Scenic module itself is a supervisor that manages all the machinery that
makes the [Scenes](overview_scene.html), [ViewPorts](overview_viewport.html),
and [Drivers](overview_driver.html) run.
In order to run any Scenic application, you will need to start the Scenic
supervisor in your supervision tree.
Load a configuration for one or more ViewPorts, then add Scenic to your root supervisor.
defmodule MyApplication do
def start(_type, _args) do
import Supervisor.Spec, warn: false
# load the viewport configuration from config
main_viewport_config = Application.get_env(:my_application :viewport)
# start the application with the viewport
children = [
supervisor(Scenic, [viewports: [main_viewport_config]]),
]
Supervisor.start_link(children, strategy: :one_for_one)
end
end
Note that you can start the Scenic supervisor without any ViewPort
Configurations. In that case, you are responsible for supervising
the ViewPorts yourself. This is not recommended for devices
as Scenic should know how to restart the main ViewPort in the event
of an error.
"""
use Supervisor
@viewports :scenic_dyn_viewports
# --------------------------------------------------------
@doc false
def child_spec(opts) do
%{
start: {__MODULE__, :start_link, [opts]},
type: :supervisor,
restart: :permanent,
shutdown: 500
}
end
# --------------------------------------------------------
@doc false
def start_link(opts \\ [])
def start_link({a, b}), do: start_link([{a, b}])
def start_link(opts) when is_list(opts) do
Supervisor.start_link(__MODULE__, opts, name: :scenic)
end
# --------------------------------------------------------
@doc false
def init(opts) do
opts
|> Keyword.get(:viewports, [])
|> do_init
end
# --------------------------------------------------------
# init with no default viewports
defp do_init([]) do
[
{Scenic.ViewPort.Tables, nil},
supervisor(Scenic.Cache.Supervisor, []),
{DynamicSupervisor, name: @viewports, strategy: :one_for_one}
]
|> Supervisor.init(strategy: :one_for_one)
end
# --------------------------------------------------------
# init with default viewports
defp do_init(viewports) do
[
{Scenic.ViewPort.Tables, nil},
supervisor(Scenic.Cache.Supervisor, []),
supervisor(Scenic.ViewPort.SupervisorTop, [viewports]),
{DynamicSupervisor, name: @viewports, strategy: :one_for_one}
]
|> Supervisor.init(strategy: :one_for_one)
end
end