defmodule FloUI.Scrollable.ScrollableContainerController do import Scenic.Primitives, only: [group: 3] import FloUI.Scrollable.ScrollBar, only: [scroll_bar: 3] alias Scenic.Graph alias Scenic.Primitive alias Scenic.Math.Vector2 def on_scroll_position_change( %{ assigns: %{ scroll_position: scroll_position, scroll_bars_state: %{ vertical: %{ scrolling: vert_scrolling }, horizontal: %{ scrolling: horiz_scrolling } } } } = scene ) when vert_scrolling == :dragging or horiz_scrolling == :dragging do graph = scene.assigns.graph |> Graph.modify( :content, &Primitive.put_transform(&1, :translate, scroll_position) ) Scenic.Scene.assign(scene, graph: graph) end def on_scroll_position_change(%{assigns: %{content: %{x: x, y: y}}} = scene) do IO.puts "update container position" graph = scene.assigns.graph |> Graph.modify( :content, &Primitive.put_transform(&1, :translate, Vector2.add(scene.assigns.scroll_position, {x, y})) ) |> Graph.modify( :vertical_scroll_bar, &scroll_bar( &1, %{ scroll_position: Vector2.sub(scene.assigns.scroll_position, {x, y}) }, [] ) ) |> Graph.modify( :horizontal_scroll_bar, &scroll_bar( &1, %{ scroll_position: Vector2.sub(scene.assigns.scroll_position, {x, y}) }, [] ) ) Scenic.Scene.assign(scene, graph: graph) end def on_children_change(scene) do graph = scene.assigns.graph |> Graph.delete(:content_container) scene |> Scenic.Scene.assign(graph: graph) |> render_content end def render_content( %{ assigns: %{ children: children, graph: graph, frame: %{x: x, y: y, width: width, height: height} } } = scene ) do graph = graph |> group( fn g -> group(g, &render_children(&1, children), id: :content) end, scissor: {width, height}, translate: {x, y}, id: :content_container ) Scenic.Scene.assign(scene, graph: graph) end def render_children(g, children) do Enum.reduce(children, g, fn child, g -> g |> child[:module].add_to_graph(child[:data], child[:opts]) end) end end