# `Expresso.Element.Hierarchy.Layout`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/element/hierarchy/layout.ex#L1)

The layout of a tree: the place of each box and the path of each line

The layout is recursive. Each subtree is a box, and the layout of a node
places the boxes of the subtrees under it with one of three layouts:

| Layout | The nodes under a node |
| --- | --- |
| `:top_down` | Side by side in one row under the node. The node is at the center above the row. |
| `:left_right` | One under the other in a column at the right of the node. The node is at the middle at the left. |
| `:stacked` | One under the other below the node, with an indent. |

The layout does not move a subtree into the space next to a smaller
subtree, so the author can predict the place of each box. `docs/tree.md`
gives the reasons.

Each level has a size of its own, from the `box` option of the tree. In a
tree with one layout, the boxes of one level thus have their tops in one
row for `:top_down`, and their left edges in one column for `:left_right`.

A line goes from the edge of a box to the edge of the box of a child, with
horizontal and vertical parts only. The lines of the children of one node
share the part from the box of the node.

The layout is a function of the tree and the options only, so the same tree
gives the same picture each time.

# `box`

```elixir
@type box() :: %{
  node: Expresso.Element.Node.t(),
  depth: non_neg_integer(),
  x: number(),
  y: number(),
  width: pos_integer(),
  height: pos_integer()
}
```

One box: its node, its level from 0, its place and its size

# `layout`

```elixir
@type layout() :: :top_down | :left_right | :stacked
```

A layout of the nodes under a node

# `options`

```elixir
@type options() :: [
  layout: layout(),
  stack_from: pos_integer() | nil,
  offset: {number(), number()}
]
```

The options of the layout: the layout of the tree, the first stacked level,
and an offset that moves each box and each line

# `size`

```elixir
@type size() :: %{width: pos_integer(), height: pos_integer()}
```

The width and the height of a box

# `t`

```elixir
@type t() :: %{
  boxes: [box()],
  lines: [String.t()],
  targets: [String.t()],
  width: number(),
  height: number()
}
```

The boxes in the order of the tree, the paths of the lines, the name of the
node at the end of each line, and the size of the drawing

# `layout`

```elixir
@spec layout(Expresso.Element.Node.t(), [size()], options()) :: t()
```

Return the layout of a tree from its root and the size of each level

The last size applies to each deeper level. The layout of the nodes under a
node comes from the first of these:

1. The `layout` option of the node.
2. The option `stack_from`: the nodes of that level and below are stacked.
   The root is level 1.
3. The `layout` option of the nearest node above it with the option.
4. The `layout` option of the tree, which is `:top_down` by default.

```
iex> alias Expresso.Element.Node
iex> root = %Node{name: "A", elements: [%Node{name: "B"}, %Node{name: "C"}]}
iex> layout = Expresso.Element.Hierarchy.Layout.layout(root, [%{width: 100, height: 40}], [])
iex> Enum.map(layout.boxes, &{&1.node.name, &1.x, &1.y})
[{"A", 62, 0}, {"B", 0, 88}, {"C", 124, 88}]
iex> {layout.width, layout.height}
{224, 128}
iex> layout = Expresso.Element.Hierarchy.Layout.layout(root, [%{width: 100, height: 40}], layout: :left_right)
iex> Enum.map(layout.boxes, &{&1.node.name, &1.x, &1.y})
[{"A", 0, 32}, {"B", 148, 0}, {"C", 148, 64}]
```

# `layouts`

```elixir
@spec layouts() :: [layout()]
```

Return the three layouts

# `number`

```elixir
@spec number(number()) :: number()
```

Return a float with no fraction as an integer, so its text has no ".0"

    iex> Expresso.Element.Hierarchy.Layout.number(62.0)
    62
    iex> Expresso.Element.Hierarchy.Layout.number(61.5)
    61.5

# `size`

```elixir
@spec size([size()], non_neg_integer()) :: size()
```

Return the size of the boxes of a level, from 0 for the root

    iex> sizes = [%{width: 280, height: 120}, %{width: 220, height: 96}]
    iex> Expresso.Element.Hierarchy.Layout.size(sizes, 0)
    %{width: 280, height: 120}
    iex> Expresso.Element.Hierarchy.Layout.size(sizes, 5)
    %{width: 220, height: 96}

# `top_down`

```elixir
@spec top_down(Expresso.Element.Node.t(), [size()]) :: t()
```

Return the layout of a tree in which each node has the layout `:top_down`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
