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) 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 { 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 = let children =
nodes view_nodes
|> list.flat_map(fn(node) { |> list.flat_map(fn(node) {
case pair.second(node) { case pair.second(node) {
Row(children: c, ..) -> c 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 // All sections that are not children of other nodes will be added as
// children to the root // children to the root
let orphans = let orphans =
nodes view_nodes
|> list.map(pair.first) |> list.map(pair.first)
|> list.filter(fn(node) { !set.contains(children, node) }) |> list.filter(fn(node) { !set.contains(children, node) })
let nodes = dict.from_list(view_nodes)
dict.from_list(nodes)
|> dict.insert( |> dict.insert(
Section(root_section), Section(string.append("view_", string.inspect(i))),
Row( Row(
content: "", content: "",
style: Style(dimensions: Percent(width: 100, height: 100)), style: Style(dimensions: Percent(width: 100, height: 100)),
children: orphans, children: orphans,
), ),
) )
Layout(columns:, rows:, nodes:)
} }
pub fn update_section( pub fn update_section(
@@ -74,15 +99,24 @@ pub fn update_section(
section: Section, section: Section,
content: String, content: String,
) -> Layout { ) -> Layout {
case dict.get(layout.nodes, section) { case dict.get(layout.views, layout.current_view) {
Error(_) -> layout
Ok(view) ->
case dict.get(view, section) {
Error(_) -> layout Error(_) -> layout
Ok(node) -> { Ok(node) -> {
let updated = case node { let updated_node = case node {
Cell(..) -> Cell(..node, content: content) Cell(..) -> Cell(..node, content: content)
Row(..) -> Row(..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, position_index: 0,
) )
case dict.get(layout.views, layout.current_view) {
Error(_) -> Nil
Ok(view) -> {
let buffer: Buffer = dict.new() let buffer: Buffer = dict.new()
render_loop(layout, context, Section(root_section), buffer) render_loop(
view,
context,
Section(string.append("view_", string.inspect(layout.current_view))),
buffer,
)
|> plot.flush_buffer(layout.columns, layout.rows) |> plot.flush_buffer(layout.columns, layout.rows)
|> internal.update |> internal.update
}
}
} }
pub type RenderContext { pub type RenderContext {
@@ -125,12 +169,12 @@ pub type RenderContext {
} }
pub fn render_loop( pub fn render_loop(
layout: Layout, view: View,
context: RenderContext, context: RenderContext,
from: Section, from: Section,
buffer: Buffer, buffer: Buffer,
) -> Buffer { ) -> Buffer {
case dict.get(layout.nodes, from) { case dict.get(view, from) {
Error(_) -> buffer Error(_) -> buffer
Ok(node) -> { Ok(node) -> {
// Margin between container and the node being rendered // Margin between container and the node being rendered
@@ -193,7 +237,7 @@ pub fn render_loop(
position_index: i, position_index: i,
) )
render_loop(layout, context, child, acc_buffer) render_loop(view, context, child, acc_buffer)
}) })
} }
} }

View File

@@ -16,7 +16,8 @@ pub fn main() {
/// First row has two cells /// First row has two cells
/// Second row has no cells /// Second row has no cells
fn two_rows_with_cells(columns: Int, rows: Int) -> layout.Layout { fn two_rows_with_cells(columns: Int, rows: Int) -> layout.Layout {
let nodes = [ let views = [
[
#( #(
Section("Row1"), Section("Row1"),
layout.Row( layout.Row(
@@ -50,7 +51,8 @@ fn two_rows_with_cells(columns: Int, rows: Int) -> layout.Layout {
children: [], children: [],
), ),
), ),
],
] ]
layout.new(columns, rows, nodes) layout.new(columns, rows, views)
} }

View File

@@ -18,12 +18,16 @@ pub fn new() -> Result(Subject(Control), String) {
let redraw: Subject(Layout) = process.named_subject(redraw_name) let redraw: Subject(Layout) = process.named_subject(redraw_name)
let layout = let layout =
[
[ [
#( #(
layout.Header, layout.Header,
layout.Row( layout.Row(
content: "Foo (1) | Bar (2) | Baz (3)", content: "Foo (1) | Bar (2) | Baz (3)",
style: layout.Style(dimensions: layout.Percent(width: 100, height: 33)), style: layout.Style(dimensions: layout.Percent(
width: 100,
height: 33,
)),
children: [], children: [],
), ),
), ),
@@ -31,7 +35,10 @@ pub fn new() -> Result(Subject(Control), String) {
layout.Search, layout.Search,
layout.Row( layout.Row(
content: "", content: "",
style: layout.Style(dimensions: layout.Percent(width: 100, height: 33)), style: layout.Style(dimensions: layout.Percent(
width: 100,
height: 33,
)),
children: [], children: [],
), ),
), ),
@@ -39,10 +46,14 @@ pub fn new() -> Result(Subject(Control), String) {
layout.PlaybackTime, layout.PlaybackTime,
layout.Row( layout.Row(
content: "00:00", content: "00:00",
style: layout.Style(dimensions: layout.Percent(width: 100, height: 33)), style: layout.Style(dimensions: layout.Percent(
width: 100,
height: 33,
)),
children: [], children: [],
), ),
), ),
],
] ]
|> layout.new(0, 0, _) |> layout.new(0, 0, _)

View File

@@ -12,7 +12,8 @@ pub fn main() -> Nil {
} }
pub fn percent_layout_test() { pub fn percent_layout_test() {
let nodes = [ let views = [
[
#( #(
Section("Row1"), Section("Row1"),
layout.Row( layout.Row(
@@ -46,11 +47,12 @@ pub fn percent_layout_test() {
children: [], children: [],
), ),
), ),
],
] ]
let columns = 80 let columns = 80
let rows = 20 let rows = 20
let layout = layout.new(columns, rows, nodes) let layout = layout.new(columns, rows, views)
let expected = let expected =
" "
@@ -87,11 +89,13 @@ pub fn percent_layout_test() {
position_index: 0, position_index: 0,
) )
let assert Ok(view) = dict.get(layout.views, layout.current_view)
let flushed = let flushed =
layout.render_loop( layout.render_loop(
layout, view,
context, context,
Section(layout.root_section), Section(string.append("view_", string.inspect(layout.current_view))),
dict.new(), dict.new(),
) )
|> plot.flush_buffer(layout.columns, layout.rows) |> plot.flush_buffer(layout.columns, layout.rows)