diff options
| author | 2025-04-25 15:56:56 -0400 | |
|---|---|---|
| committer | 2025-04-25 15:56:56 -0400 | |
| commit | b1985414e54edf1eebe597551a48609ad08c6cfa (patch) | |
| tree | 4a4def499348e0c9ccb52472e7c862f814993931 /src/fruits/cmc/ui/widgets | |
| parent | 76fc9fe33dd58926e552b6bd3b79d798b452c6ed (diff) | |
| download | camu-b1985414e54edf1eebe597551a48609ad08c6cfa.tar.gz camu-b1985414e54edf1eebe597551a48609ad08c6cfa.tar.bz2 camu-b1985414e54edf1eebe597551a48609ad08c6cfa.zip | |
Partial cmc ui refactor
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/fruits/cmc/ui/widgets')
| -rw-r--r-- | src/fruits/cmc/ui/widgets/now_playing.c | 223 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/widgets/now_playing.h | 25 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/widgets/tile.h | 5 |
3 files changed, 253 insertions, 0 deletions
diff --git a/src/fruits/cmc/ui/widgets/now_playing.c b/src/fruits/cmc/ui/widgets/now_playing.c new file mode 100644 index 0000000..d30590c --- /dev/null +++ b/src/fruits/cmc/ui/widgets/now_playing.c @@ -0,0 +1,223 @@ +#include <math.h> + +#include "../../../../liana/list.h" +#include "../../../../sink/util.h" + +#include "../../cmc.h" + +#include "../util/waveform.h" +#include "../util/notcurses_ext.h" + +#include "now_playing.h" + +void cmc_now_playing_init(struct cmc_now_playing *np) +{ + al_array_init(np->visuals); +} + +bool cmc_now_playing_layout(struct cmc_now_playing *np, struct ncplane *parent, u32 y) +{ + if (np->n) ncplane_destroy(np->n); + u32 width = ncplane_dim_x(parent); + u32 height = ncplane_dim_y(parent); + struct ncplane_options nopts = { 0 }; + nopts.x = 0; + nopts.y = y; + nopts.cols = width; + nopts.rows = height - y; + np->n = ncplane_create(parent, &nopts); + if (np->wave) ncplane_destroy(np->wave); + nopts.x = 1; + nopts.y = 3; + nopts.rows = 5; + nopts.cols = width - 2; + np->wave = ncplane_create(np->n, &nopts); + np->blitted = NULL; + struct cmc_now_playing_visual *visual; + al_array_foreach_ptr(np->visuals, i, visual) { + if (visual->visual) ncvisual_destroy(visual->visual); + } + np->visuals.count = 0; + return true; +} + +static void get_entry_duration_and_pos(struct cmc_list_entry *entry, u64 *duration, u64 *pos) +{ + *pos = entry->offset; + *duration = entry->duration; + u64 now = nn_get_timestamp(); + bool paused = entry->start == LIANA_TIMESTAMP_INVALID; + if (!paused && now > entry->start) { + *pos += now - entry->start; + } + *pos = MIN(*pos, *duration); +} + +bool cmc_now_playing_tick(struct cmc_now_playing *np, struct cmc_list_entry *entry) +{ + return true; + u64 duration = 0, pos = 0; + if (entry) get_entry_duration_and_pos(entry, &duration, &pos); + u32 width = ncplane_dim_x(np->n); + f32 percent = 1.f; + if (duration > 0) percent = MIN(pos / (f32)duration, 1.f); + u32 segments = (width - 2) * percent; + if (segments != np->segment_count) { + np->segment_count = segments; + return true; + } else { + // @TODO: Avoiding judder: Implement and utilize tick timing change. + if (pos < np->last_pos || pos - np->last_pos > 1000000) { + np->last_pos = pos; + return true; + } + } + return false; +} + +void cmc_now_playing_erase(struct cmc_now_playing *np) +{ + ncplane_erase(np->n); +} + +void cmc_now_playing_render(struct cmc_now_playing *np, struct cmc_list_entry *entry) +{ + u64 duration = 0, pos = 0; + if (entry) get_entry_duration_and_pos(entry, &duration, &pos); + u64 remaining = duration - pos; + + ncplane_set_styles(np->n, NCSTYLE_BOLD); + if (remaining == 0) { + ncplane_putstr_yx(np->n, 1, 2, "∨"); + } else { + al_assert(entry); + if (remaining == 0) { + ncplane_putstr_yx(np->n, 1, 2, "∨"); + } else { + bool paused = entry->start == LIANA_TIMESTAMP_INVALID; + ncplane_putstr_yx(np->n, 1, 2, paused ? "^": ">"); + } + } + ncplane_set_styles(np->n, NCSTYLE_NONE); + + u32 width = ncplane_dim_x(np->n); + u32 height = ncplane_dim_y(np->n); + + // ━ ╸╺ ╼ ╾ ╴╶ + //ncplane_set_fg_palindex(np->n, 8); + f32 percent = 1.f; + if (duration > 0) percent = MIN(pos / (f32)duration, 1.f); + u32 bar_width = width - 1; + u32 segments = roundf((bar_width * 4) * percent); + u32 head = segments % 4; + segments /= 4; + for (u32 i = 0; i < segments; i++) { + ncplane_putstr_yx(np->n, 2, i + 1, "━"); + } + char *head_segment; + switch (head) { + case 0: + head_segment = " "; + break; + case 1: + head_segment = "╴"; + break; + case 2: + head_segment = "╸"; + break; + case 3: + head_segment = "╾"; + break; + } + ncplane_putstr_yx(np->n, 2, segments + 1, head_segment); + ncplane_set_fg_default(np->n); + + char timestr[16] = { 0 }; // max = 829128280:01:49\0 + s32 offset = camu_print_time(timestr, sizeof(timestr), pos, true, 4); + ncplane_putstr_yx(np->n, 1, 4, timestr); + ncplane_putstr_yx(np->n, 1, 4 + offset, "⎹"); + + if (entry) { + cmc_ui_putnwstr_yx(np->n, 1, 6 + offset, MIN(entry->name.length, (u32)60), &entry->name); + } + + bool show_remaining = false; + if (show_remaining) { + offset = camu_print_time(timestr, sizeof(timestr), remaining, true, 4); + } else { + offset = camu_print_time(timestr, sizeof(timestr), duration, true, 4); + } + ncplane_putstr_yx(np->n, 1, width - 4 - offset, "⎸"); + // "=" Duration, "+" Segment, "-" Remaining. + if (show_remaining) { + ncplane_putstr_yx(np->n, 1, width - 3 - offset, "-"); + } else { + ncplane_putstr_yx(np->n, 1, width - 3 - offset, "="); + } + ncplane_putstr_yx(np->n, 1, width - 2 - offset, timestr); + + if (entry) { + bool visual_cached = false; + struct cmc_now_playing_visual *visual; + al_array_foreach_ptr(np->visuals, i, visual) { + if (visual->entry == entry) { + visual_cached = true; + break; + } + } + + if (!visual_cached) { + if (entry->raw.data != NULL) { + al_array_push(np->visuals, (struct cmc_now_playing_visual){}); + visual = &al_array_last(np->visuals); + visual->entry = entry; + u32 *rgba; + u32 pixel_width, pixel_height; + ncplane_pixel_geom(np->wave, &pixel_height, &pixel_width, NULL, NULL, NULL, NULL); + cmc_draw_waveform(entry, pixel_width, pixel_height, false, entry->raw.drawing, &rgba); + visual->visual = ncvisual_from_rgba(rgba, pixel_height, pixel_width * 4, pixel_width); + } else { + visual = NULL; + } + } + + if (visual && entry != np->blitted) { + ncplane_erase(np->wave); + struct ncvisual_options vopts = { 0 }; + vopts.blitter = NCBLIT_PIXEL; + vopts.scaling = NCSCALE_STRETCH; + vopts.flags = NCVISUAL_OPTION_NOINTERPOLATE; + vopts.n = np->wave; + vopts.x = 0; + vopts.y = 0; + ncvisual_blit(ncplane_notcurses(np->wave), visual->visual, &vopts); + np->blitted = entry; + } + } + + u64 c = 0; + ncchannels_set_fg_default(&c); + //ncchannels_set_fg_palindex(&c, 8); + ncchannels_set_bg_default(&c); + ncchannels_set_bg_alpha(&c, 0); + ncchannels_set_fg_alpha(&c, 255); + ncplane_cursor_move_yx(np->n, 0, 0); + //ncplane_double_box(np->n, NCSTYLE_NONE, c, height - 1, width - 1, 0); + ncplane_light_box(np->n, NCSTYLE_NONE, c, height - 1, width - 1, 0); + //ncplane_set_fg_palindex(np->n, 8); + if (segments > 0 || head > 0) { + if (segments == 0 && head == 1) { + ncplane_putstr_yx(np->n, 2, 0, "├"); + } else { + ncplane_putstr_yx(np->n, 2, 0, "┝"); + } + if (segments == bar_width || (segments == bar_width - 1 && head > 0)) { + if (head == 1) { + ncplane_putstr_yx(np->n, 2, width - 1, "┤"); + } else { + ncplane_putstr_yx(np->n, 2, width - 1, "┥"); + } + } + } + ncplane_set_fg_default(np->n); +} diff --git a/src/fruits/cmc/ui/widgets/now_playing.h b/src/fruits/cmc/ui/widgets/now_playing.h new file mode 100644 index 0000000..5993c59 --- /dev/null +++ b/src/fruits/cmc/ui/widgets/now_playing.h @@ -0,0 +1,25 @@ +#pragma once + +#include <al/array.h> +#include <notcurses/notcurses.h> + +struct cmc_now_playing_visual { + struct ncvisual *visual; + struct cmc_list_entry *entry; +}; + +struct cmc_now_playing { + struct ncplane *n; + bool tick; + u64 last_pos; + u32 segment_count; + struct ncplane *wave; + array(struct cmc_now_playing_visual) visuals; + struct cmc_list_entry *blitted; +}; + +void cmc_now_playing_init(struct cmc_now_playing *np); +bool cmc_now_playing_layout(struct cmc_now_playing *np, struct ncplane *parent, u32 y); +bool cmc_now_playing_tick(struct cmc_now_playing *np, struct cmc_list_entry *entry); +void cmc_now_playing_erase(struct cmc_now_playing *np); +void cmc_now_playing_render(struct cmc_now_playing *np, struct cmc_list_entry *entry); diff --git a/src/fruits/cmc/ui/widgets/tile.h b/src/fruits/cmc/ui/widgets/tile.h new file mode 100644 index 0000000..6f15c7d --- /dev/null +++ b/src/fruits/cmc/ui/widgets/tile.h @@ -0,0 +1,5 @@ +#pragma once + +struct cmc_tile { + +}; |