lib/tabs/tabs.ex

defmodule FloUI.Tabs do
  alias Scenic.Graph
  alias Scenic.Primitive

  @moduledoc ~S"""
  ## Usage in SnapFramework

  The following example uses FloUI.Tabs and Grid to lay the tabs out. Iterates over the @tabs assign to render each tab.
  @module.get_tab_width runs FontMetrics on the label to get the width.

  ``` elixir
  <%= graph font_size: 20 %>

  <%= component FloUI.Tabs, {@active_tab, @tabs}, id: :tabs do %>
      <%= component FloUI.Grid, %{
          start_xy: {0, 0},
          max_xy: {@module.get_tabs_width(@tabs), 40}
      } do %>
          <%= for {{label, cmp}, i} <- Enum.with_index(@tabs) do %>
              <%= component FloUI.Tab,
                  {label, cmp},
                  selected?: if(i == 0, do: true, else: false),
                  id: :"#{label}",
                  width: @module.get_tab_width(label),
                  height: 40
              %>
          <% end %>
      <% end %>
  <% end %>
  ```
  """

  use SnapFramework.Component,
    name: :tabs,
    template: "lib/tabs/tabs.eex",
    controller: FloUI.TabsController,
    assigns: [
      active_tab: nil,
      active_pid: nil,
      tabs: nil
    ],
    opts: []

  defcomponent(:tabs, :any)

  use_effect([assigns: [active_tab: :any]],
    run: [:on_tab_change]
  )

  def setup(%{assigns: %{data: {active_tab, tabs}}} = scene) do
    scene |> assign(active_tab: active_tab, tabs: tabs)
  end

  def process_info({:tab_pid, pid}, scene) do
    {:noreply, assign(scene, active_pid: pid)}
  end

  def process_event(
        {:select_tab, cmp},
        pid,
        %{assigns: %{active_tab: active_tab, active_pid: active_pid}} = scene
      )
      when cmp != active_tab do
    GenServer.call(active_pid, {:put, false})

    scene =
      scene
      |> assign(active_tab: cmp, active_pid: pid)

    {:cont, {:select_tab, cmp}, scene}
  end

  def process_event({:select_tab, _cmp}, _pid, scene) do
    {:noreply, scene}
  end

  def process_event(event, _, scene) do
    {:cont, event, scene}
  end
end