defmodule ElementTui.Component.Flex do defstruct weight: 1.0, element: nil, direction: :all def new(element, direction, weight) do %ElementTui.Component.Flex{element: element, weight: weight, direction: direction} end @doc """ Takes a list of sizes and their flex weights and redistributes the available space to the flex components """ def distribute(xs, available) do # We need the cumulative sum of weights, so we can disperse properly {cw, _} = xs |> Enum.reverse() |> Enum.map_reduce(0, fn {_, kw}, acc -> acc = acc + (Keyword.get(kw, :flex, nil) || 0) {acc, acc} end) cw = cw |> Enum.reverse() # Here we distribute the weights {xs, _} = xs |> Enum.zip(cw) |> Enum.map_reduce(available, fn {{x, kw}, total_weight}, acc -> case Keyword.get(kw, :flex, nil) do nil -> {x, acc} size -> w = Kernel.round(size / total_weight * acc) {w, acc - w} end end) xs end end defimpl ElementTui.Component, for: ElementTui.Component.Flex do alias ElementTui.Component.Flex def calculate_dim(%Flex{element: el, weight: weight, direction: dir}, width, height) do {w, h, kw} = ElementTui.Parser.calculate_dim(el, width, height) case dir do :vertical -> {w, h, Keyword.merge(kw, vflex: weight)} :horizontal -> {w, h, Keyword.merge(kw, hflex: weight)} _ -> {w, h, Keyword.merge(kw, hflex: weight, vflex: weight)} end end def parse(%Flex{element: el, direction: dir}, x, y, width, height) do parsed = ElementTui.Parser.parse(el, x, y, width, height) case dir do :vertical -> %{parsed | height: height} :horizontal -> %{parsed | width: width} _ -> %{parsed | width: width, height: height} end end end