From 1732b12fbebb2e1cba82649eb0558751bf2bc681 Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Sun, 30 Nov 2025 15:38:52 +0100 Subject: [PATCH] use-string-trees --- src/musicplayer/ui/internal.gleam | 8 ++- src/musicplayer/ui/layout.gleam | 84 ++++++++++++++++++++----------- src/musicplayer/ui/ui.gleam | 26 ++++++++++ 3 files changed, 86 insertions(+), 32 deletions(-) diff --git a/src/musicplayer/ui/internal.gleam b/src/musicplayer/ui/internal.gleam index 9336fd1..2e8a8af 100644 --- a/src/musicplayer/ui/internal.gleam +++ b/src/musicplayer/ui/internal.gleam @@ -7,9 +7,13 @@ pub fn clear_screen() -> Nil { io.print("\u{001B}[2J\u{001B}[H") } -pub fn print_at(text: String, x: Int, y: Int) -> Nil { +pub fn chars_at(chars: String, x: Int, y: Int) -> String { let seq = "\u{001B}[" <> int.to_string(y) <> ";" <> int.to_string(x) <> "H" - io.print(seq <> text) + seq <> chars +} + +pub fn print(chars: String) -> Nil { + io.print(chars) } pub fn hide_cursor() -> Nil { diff --git a/src/musicplayer/ui/layout.gleam b/src/musicplayer/ui/layout.gleam index 35d0cf6..f5c8cf1 100644 --- a/src/musicplayer/ui/layout.gleam +++ b/src/musicplayer/ui/layout.gleam @@ -3,6 +3,7 @@ import gleam/float import gleam/int import gleam/list import gleam/string +import gleam/string_tree.{type StringTree} import musicplayer/logging/logging import musicplayer/ui/internal @@ -153,7 +154,8 @@ pub fn render(layout: Layout) -> Nil { let container_top_left_x = 1 let container_top_left_y = 1 - render_loop( + string_tree.new() + |> render_loop( layout, container_width, container_height, @@ -161,7 +163,10 @@ pub fn render(layout: Layout) -> Nil { container_top_left_y, 0, Section("Root"), + _, ) + |> string_tree.to_string + |> internal.print } pub fn render_loop( @@ -172,32 +177,34 @@ pub fn render_loop( container_top_left_y: Int, index: Int, from: Section, -) -> Nil { + tree: StringTree, +) -> StringTree { let margin = 2.0 case dict.get(layout.nodes, from) { - Error(_) -> Nil + Error(_) -> tree Ok(node) -> { - list.index_map(node.children, fn(child, i) { #(i, child) }) - |> list.each(fn(ic: #(Int, Section)) { - let #(i, child) = ic + let final_tree = + list.index_map(node.children, fn(child, i) { #(i, child) }) + |> list.fold(tree, fn(updated_tree: StringTree, ic: #(Int, Section)) { + let #(i, child) = ic - let cw = - container_width - *. { int.to_float(node.width_percent) /. 100.0 } - -. margin - |> float.floor + let cw = + container_width + *. { int.to_float(node.width_percent) /. 100.0 } + -. margin + |> float.floor - let ch = - container_height - *. { int.to_float(node.height_percent) /. 100.0 } - -. margin - |> float.floor + let ch = + container_height + *. { int.to_float(node.height_percent) /. 100.0 } + -. margin + |> float.floor - let cx = container_top_left_x + 1 - let cy = container_top_left_y + 1 - render_loop(layout, cw, ch, cx, cy, i, child) - }) + let cx = container_top_left_x + 1 + let cy = container_top_left_y + 1 + render_loop(layout, cw, ch, cx, cy, i, child, updated_tree) + }) logging.log("section: " <> string.inspect(from)) logging.log("section type: " <> string.inspect(node.t)) @@ -233,23 +240,40 @@ pub fn render_loop( logging.log("cx: " <> int.to_string(cx)) logging.log("cy: " <> int.to_string(cy)) - draw_box(cx, cy, width, height) + final_tree + |> string_tree.append(draw_box(cx, cy, width, height)) // Box heading - internal.print_at(node.content, cx, cy) + |> string_tree.append(internal.chars_at(node.content, cx, cy)) } } } -fn draw_box(x: Int, y: Int, width: Int, height: Int) -> Nil { +fn draw_box(x: Int, y: Int, width: Int, height: Int) -> String { + let box_tree = string_tree.new() let box_chars = #("┌", "┐", "└", "┘", "─", "│") let #(tl, tr, bl, br, h, v) = box_chars - internal.print_at(tl <> string.repeat(h, width - 2) <> tr, x, y) - list.range(1, height - 2) - |> list.each(fn(row) { - internal.print_at(v, x, y + row) - internal.print_at(v, x + width - 1, y + row) - }) + let box_tree = + string_tree.append( + box_tree, + internal.chars_at(tl <> string.repeat(h, width - 2) <> tr, x, y), + ) - internal.print_at(bl <> string.repeat(h, width - 2) <> br, x, y + height - 1) + let box_trees = + list.range(1, height - 2) + |> list.map(fn(row) { + box_tree + |> string_tree.append(internal.chars_at(v, x, y + row)) + |> string_tree.append(internal.chars_at(v, x + width - 1, y + row)) + }) + + string_tree.append( + string_tree.concat(box_trees), + internal.chars_at( + bl <> string.repeat(h, width - 2) <> br, + x, + y + height - 1, + ), + ) + |> string_tree.to_string } diff --git a/src/musicplayer/ui/ui.gleam b/src/musicplayer/ui/ui.gleam index 1dd2c49..6210c70 100644 --- a/src/musicplayer/ui/ui.gleam +++ b/src/musicplayer/ui/ui.gleam @@ -3,6 +3,7 @@ import gleam/int import gleam/list import gleam/otp/actor import gleam/string +import gleam/string_tree.{type StringTree} import musicplayer/logging/logging import musicplayer/ui/control.{type Control} @@ -103,3 +104,28 @@ fn update_dimensions_on_interval(ui: Subject(Control), interval_ms: Int) { process.sleep(interval_ms) update_dimensions_on_interval(ui, interval_ms) } +// fn render_layout(layout: Layout, from: Section) -> Nil { +// string_tree.new() +// |> render_layout_loop(layout, from, _) +// |> string_tree.to_string +// |> ui_internal.print +// } + +// fn render_layout_loop( +// layout: Layout, +// from: Section, +// tree: StringTree, +// ) -> StringTree { +// case dict.get(layout.nodes, from) { +// Error(_) -> tree +// Ok(node) -> { +// let acc_after_children = +// list.fold(node.children, tree, fn(current_acc, child_id) { +// render_layout_loop(layout, child_id, current_acc) +// }) + +// acc_after_children +// |> string_tree.append(ui_internal.chars_at(node.content, node.x, node.y)) +// } +// } +// }