From 18c4793872f4ef634ad09a9168f756fce6d4799a Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Sat, 29 Nov 2025 20:46:35 +0100 Subject: [PATCH] wip-working-ish --- src/musicplayer/musicplayer.gleam | 1 + src/musicplayer/ui/layout.gleam | 95 +++++++++++++++++++++++++++---- src/musicplayer/ui/ui.gleam | 28 +++++---- 3 files changed, 98 insertions(+), 26 deletions(-) diff --git a/src/musicplayer/musicplayer.gleam b/src/musicplayer/musicplayer.gleam index 266b45b..efa4774 100644 --- a/src/musicplayer/musicplayer.gleam +++ b/src/musicplayer/musicplayer.gleam @@ -146,6 +146,7 @@ fn update_playback_time_loop( interval_ms: Int, ) { process.sleep(interval_ms) + // TODO only update if state is playing update_playback_time(mpv, ui) update_playback_time_loop(mpv, ui, interval_ms) diff --git a/src/musicplayer/ui/layout.gleam b/src/musicplayer/ui/layout.gleam index b1542a6..4dc5ee5 100644 --- a/src/musicplayer/ui/layout.gleam +++ b/src/musicplayer/ui/layout.gleam @@ -1,6 +1,11 @@ import gleam/dict +import gleam/erlang/process.{type Subject} +import gleam/int import gleam/list +import gleam/string +import musicplayer/logging/control as logging_control +import musicplayer/logging/logging import musicplayer/ui/internal pub type Layout { @@ -14,8 +19,16 @@ pub type Section { PlaybackTime } +/// A Nodes width and height is in percentage (of the available width/height of its parent Node) pub type Node { - Node(content: String, x: Int, y: Int, children: List(Section)) + Node( + content: String, + x: Int, + y: Int, + width_percent: Int, + height_percent: Int, + children: List(Section), + ) } pub fn new() -> Layout { @@ -23,15 +36,35 @@ pub fn new() -> Layout { dict.from_list([ #( Root, - Node(content: "", x: 0, y: 0, children: [ - Header, - Search, - PlaybackTime, - ]), + Node( + content: "", + x: 1, + y: 1, + width_percent: 100, + height_percent: 100, + children: [ + // Header, + // Search, + PlaybackTime, + ], + ), + ), + // #( + // Header, + // Node(content: "Music Player", width: 50, height: 10, children: []), + // ), + // #(Search, Node(content: "", width: 50, height: 10, children: [])), + #( + PlaybackTime, + Node( + content: "00:00", + x: 1, + y: 2, + width_percent: 100, + height_percent: 100, + children: [], + ), ), - #(Header, Node(content: "Music Player", x: 1, y: 1, children: [])), - #(Search, Node(content: "", x: 30, y: 1, children: [])), - #(PlaybackTime, Node(content: "00:00", x: 1, y: 2, children: [])), ]) Layout(0, 0, nodes: nodes) @@ -60,13 +93,53 @@ pub fn update_dimensions(layout: Layout, width: Int, height: Int) -> Layout { Layout(..layout, width:, height:) } -pub fn render(layout: Layout, from: Section) -> Nil { +pub fn render(logger: Subject(logging_control.Control), layout: Layout) -> Nil { + internal.clear_screen() + [layout.width, layout.height] + |> list.map(int.to_string) + |> string.join(" ") + |> string.append("layout - render: ", _) + |> logging.log(logger, _) + + render_loop(layout, layout.width, layout.height, Root) +} + +pub fn render_loop( + layout: Layout, + container_width: Int, + container_height: Int, + from: Section, +) -> Nil { case dict.get(layout.nodes, from) { Error(_) -> Nil Ok(node) -> { - list.each(node.children, fn(child) { render(layout, child) }) + list.each(node.children, fn(child) { + let cw = container_width * { node.width_percent / 100 } + let ch = container_height * { node.height_percent / 100 } + + render_loop(layout, cw, ch, child) + }) + + let width = container_width * { node.width_percent / 100 } + let height = container_height * { node.height_percent / 100 } + + draw_box(node.x, node.y, width, height) internal.print_at(node.content, node.x, node.y) } } } + +fn draw_box(x: Int, y: Int, width: Int, height: Int) -> Nil { + 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) + }) + + internal.print_at(bl <> string.repeat(h, width - 2) <> br, x, y + height - 1) +} diff --git a/src/musicplayer/ui/ui.gleam b/src/musicplayer/ui/ui.gleam index 094f946..5a8f73d 100644 --- a/src/musicplayer/ui/ui.gleam +++ b/src/musicplayer/ui/ui.gleam @@ -38,7 +38,7 @@ pub fn new() -> Result(Subject(Control), String) { internal.clear_screen() internal.hide_cursor() - redraw_on_update_loop(redraw) + redraw_loop(logger, redraw) }) Ok(ui) @@ -63,21 +63,18 @@ fn handle_message( |> string.append("ui - updating dimensions: ", _) |> logging.log - actor.continue( - State( - ..state, - layout: layout.update_dimensions(state.layout, width, height), - ), - ) + let layout = layout.update_dimensions(state.layout, width, height) + + process.send(state.redraw, layout) + actor.continue(State(..state, layout:)) } } } control.UpdateState(section, content) -> { let layout = layout.update_section(state.layout, section, content) - let state = State(..state, layout:) actor.send(state.redraw, layout) - actor.continue(state) + actor.continue(State(..state, layout:)) } control.Exit(reply_to) -> { @@ -88,13 +85,14 @@ fn handle_message( } } -fn redraw_on_update_loop(redraw: Subject(Layout)) -> Nil { - let layout = process.receive_forever(redraw) +fn redraw_loop( + logger: Subject(logging_control.Control), + redraw: Subject(Layout), +) -> Nil { + process.receive_forever(redraw) + |> layout.render(logger, _) - internal.clear_screen() - layout.render(layout, layout.Root) - - redraw_on_update_loop(redraw) + redraw_loop(logger, redraw) } fn update_dimensions_on_interval(ui: Subject(Control), interval_ms: Int) {