Layout consist of multiple Views

This commit is contained in:
Alexander Heldt
2025-12-21 13:21:14 +01:00
parent ed69566f6f
commit 95eaeb60f4
4 changed files with 177 additions and 116 deletions

View File

@@ -33,13 +33,41 @@ pub type Node {
Cell(content: String, style: Style)
}
pub type ViewIdx =
Int
pub type View =
dict.Dict(Section, Node)
// Layout consists of a list Views, and only one View is rendered at a time
pub type Layout {
Layout(columns: Int, rows: Int, nodes: dict.Dict(Section, Node))
Layout(
columns: Int,
rows: Int,
current_view: ViewIdx,
views: dict.Dict(ViewIdx, View),
)
}
pub fn new(columns: Int, rows: Int, nodes: List(#(Section, Node))) -> Layout {
pub fn new(
columns: Int,
rows: Int,
views: List(List(#(Section, Node))),
) -> Layout {
let views =
list.index_map(views, fn(view_nodes, i) { #(i, view_nodes) })
|> list.fold(dict.new(), fn(view_acc, iv) {
let #(i, view_nodes) = iv
dict.insert(view_acc, i, view_loop(i, view_nodes))
})
Layout(columns:, rows:, current_view: 0, views:)
}
fn view_loop(i: ViewIdx, view_nodes: List(#(Section, Node))) -> View {
let children =
nodes
view_nodes
|> list.flat_map(fn(node) {
case pair.second(node) {
Row(children: c, ..) -> c
@@ -51,22 +79,19 @@ pub fn new(columns: Int, rows: Int, nodes: List(#(Section, Node))) -> Layout {
// All sections that are not children of other nodes will be added as
// children to the root
let orphans =
nodes
view_nodes
|> list.map(pair.first)
|> list.filter(fn(node) { !set.contains(children, node) })
let nodes =
dict.from_list(nodes)
|> dict.insert(
Section(root_section),
Row(
content: "",
style: Style(dimensions: Percent(width: 100, height: 100)),
children: orphans,
),
)
Layout(columns:, rows:, nodes:)
dict.from_list(view_nodes)
|> dict.insert(
Section(string.append("view_", string.inspect(i))),
Row(
content: "",
style: Style(dimensions: Percent(width: 100, height: 100)),
children: orphans,
),
)
}
pub fn update_section(
@@ -74,16 +99,25 @@ pub fn update_section(
section: Section,
content: String,
) -> Layout {
case dict.get(layout.nodes, section) {
case dict.get(layout.views, layout.current_view) {
Error(_) -> layout
Ok(node) -> {
let updated = case node {
Cell(..) -> Cell(..node, content: content)
Row(..) -> Row(..node, content: content)
}
Ok(view) ->
case dict.get(view, section) {
Error(_) -> layout
Ok(node) -> {
let updated_node = case node {
Cell(..) -> Cell(..node, content: content)
Row(..) -> Row(..node, content: content)
}
Layout(..layout, nodes: dict.insert(layout.nodes, section, updated))
}
let updated_view = dict.insert(view, section, updated_node)
Layout(
..layout,
views: dict.insert(layout.views, layout.current_view, updated_view),
)
}
}
}
}
@@ -107,11 +141,21 @@ pub fn render(layout: Layout) -> Nil {
position_index: 0,
)
let buffer: Buffer = dict.new()
case dict.get(layout.views, layout.current_view) {
Error(_) -> Nil
Ok(view) -> {
let buffer: Buffer = dict.new()
render_loop(layout, context, Section(root_section), buffer)
|> plot.flush_buffer(layout.columns, layout.rows)
|> internal.update
render_loop(
view,
context,
Section(string.append("view_", string.inspect(layout.current_view))),
buffer,
)
|> plot.flush_buffer(layout.columns, layout.rows)
|> internal.update
}
}
}
pub type RenderContext {
@@ -125,12 +169,12 @@ pub type RenderContext {
}
pub fn render_loop(
layout: Layout,
view: View,
context: RenderContext,
from: Section,
buffer: Buffer,
) -> Buffer {
case dict.get(layout.nodes, from) {
case dict.get(view, from) {
Error(_) -> buffer
Ok(node) -> {
// Margin between container and the node being rendered
@@ -193,7 +237,7 @@ pub fn render_loop(
position_index: i,
)
render_loop(layout, context, child, acc_buffer)
render_loop(view, context, child, acc_buffer)
})
}
}

View File

@@ -16,41 +16,43 @@ pub fn main() {
/// First row has two cells
/// Second row has no cells
fn two_rows_with_cells(columns: Int, rows: Int) -> layout.Layout {
let nodes = [
#(
Section("Row1"),
layout.Row(
content: "row 1",
style: Style(dimensions: Percent(width: 100, height: 50)),
children: [
Section("A"),
Section("B"),
],
let views = [
[
#(
Section("Row1"),
layout.Row(
content: "row 1",
style: Style(dimensions: Percent(width: 100, height: 50)),
children: [
Section("A"),
Section("B"),
],
),
),
),
#(
Section("A"),
layout.Cell(
content: "cell 1",
style: Style(dimensions: Percent(width: 50, height: 50)),
#(
Section("A"),
layout.Cell(
content: "cell 1",
style: Style(dimensions: Percent(width: 50, height: 50)),
),
),
),
#(
Section("B"),
layout.Cell(
content: "cell 2",
style: Style(dimensions: Percent(width: 50, height: 50)),
#(
Section("B"),
layout.Cell(
content: "cell 2",
style: Style(dimensions: Percent(width: 50, height: 50)),
),
),
),
#(
Section("Row2"),
layout.Row(
content: "row 2",
style: Style(dimensions: Percent(width: 50, height: 50)),
children: [],
#(
Section("Row2"),
layout.Row(
content: "row 2",
style: Style(dimensions: Percent(width: 50, height: 50)),
children: [],
),
),
),
],
]
layout.new(columns, rows, nodes)
layout.new(columns, rows, views)
}

View File

@@ -19,30 +19,41 @@ pub fn new() -> Result(Subject(Control), String) {
let layout =
[
#(
layout.Header,
layout.Row(
content: "Foo (1) | Bar (2) | Baz (3)",
style: layout.Style(dimensions: layout.Percent(width: 100, height: 33)),
children: [],
[
#(
layout.Header,
layout.Row(
content: "Foo (1) | Bar (2) | Baz (3)",
style: layout.Style(dimensions: layout.Percent(
width: 100,
height: 33,
)),
children: [],
),
),
),
#(
layout.Search,
layout.Row(
content: "",
style: layout.Style(dimensions: layout.Percent(width: 100, height: 33)),
children: [],
#(
layout.Search,
layout.Row(
content: "",
style: layout.Style(dimensions: layout.Percent(
width: 100,
height: 33,
)),
children: [],
),
),
),
#(
layout.PlaybackTime,
layout.Row(
content: "00:00",
style: layout.Style(dimensions: layout.Percent(width: 100, height: 33)),
children: [],
#(
layout.PlaybackTime,
layout.Row(
content: "00:00",
style: layout.Style(dimensions: layout.Percent(
width: 100,
height: 33,
)),
children: [],
),
),
),
],
]
|> layout.new(0, 0, _)