From b112da5b9825262b3b779bd699a4cf4bca8b6d01 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Wed, 26 Aug 2026 17:58:15 -0400 Subject: Rough cmc UI tweaking Signed-off-by: Andrew Opalach --- src/fruits/cmc/ui/panes/list.c | 57 +++++++++++++++++++++++++++++++-- src/fruits/cmc/ui/ui.c | 8 ++--- src/fruits/cmc/ui/util/waveform.c | 34 +++++++++++++++----- src/fruits/cmc/ui/widgets/now_playing.c | 42 ++++++++++++++++-------- 4 files changed, 113 insertions(+), 28 deletions(-) (limited to 'src/fruits/cmc/ui') diff --git a/src/fruits/cmc/ui/panes/list.c b/src/fruits/cmc/ui/panes/list.c index b599cc5..388e22f 100644 --- a/src/fruits/cmc/ui/panes/list.c +++ b/src/fruits/cmc/ui/panes/list.c @@ -226,11 +226,36 @@ void cmc_list_pane_clear(struct cmc_list_pane *lp) cmc_now_playing_clear(&lp->np); } +static u32 count_headers(struct cmc_list *list) +{ + struct cmc_list_entry *entry; + str header = AL_STR_EMPTY; + u32 count = 0; + al_array_foreach(list->entries, i, entry) { + u32 rslash = al_str_rfind(&entry->brief, '/'); + str remain = al_str_substr(&entry->brief, 0, rslash); + rslash = al_str_rfind(&remain, '/'); + str new_header; + if (rslash != AL_STR_NO_POS) { + new_header = al_str_substr(&remain, rslash + 1, remain.length); + } else { + new_header = remain; + } + if (al_str_is_empty(&header) || !al_str_eq(&header, &new_header)) { + header = new_header; + count++; + } + } + return count; +} + static void render_list_entries(struct cmc_list_pane *lp, struct cmc_list_tab *tab, s32 max_height) { struct cmc_list *list = tab->list; struct ncplane *n = lp->n; s32 tracked = tab->move.active ? tab->move.selected + tab->move.offset : tab->selected; + u32 headers = count_headers(list); + max_height -= headers; s32 count = (s32)list->entries.count; s32 midpoint = max_height / 2; s32 rounded = (max_height + 1) / 2; @@ -245,6 +270,9 @@ static void render_list_entries(struct cmc_list_pane *lp, struct cmc_list_tab *t top = tracked - midpoint; end = tracked + rounded; } + str header = AL_STR_EMPTY; + s32 last_y = 0; + s32 y_offset = 0; s32 index; struct cmc_list_entry *entry; for (s32 i = top; i < end; i++) { @@ -258,14 +286,39 @@ static void render_list_entries(struct cmc_list_pane *lp, struct cmc_list_tab *t } } entry = al_array_at(list->entries, index); + u32 rslash = al_str_rfind(&entry->brief, '/'); + str part; + if (rslash != AL_STR_NO_POS) { + part = al_str_substr(&entry->brief, rslash + 1, entry->brief.length); + } else { + part = entry->brief; + } + str remain = al_str_substr(&entry->brief, 0, rslash); + rslash = al_str_rfind(&remain, '/'); + str new_header; + if (rslash != AL_STR_NO_POS) { + new_header = al_str_substr(&remain, rslash + 1, remain.length); + } else { + new_header = remain; + } + if (al_str_is_empty(&header) || !al_str_eq(&header, &new_header)) { + header = new_header; + char *c_str = al_str_to_c_str(&header); + ncplane_set_styles(n, NCSTYLE_BOLD); + ncplane_putstr_yx(n, last_y, 0, c_str); + ncplane_set_styles(n, NCSTYLE_NONE); + al_free(c_str); + y_offset++; + } bool on_current = list->current >= 0 && index == list->current; bool styled = i == tracked; if (styled) { ncplane_set_styles(n, NCSTYLE_BOLD); ncplane_set_fg_palindex(n, 4); } - s32 y = i - top; - char *c_str = al_str_to_c_str(&entry->brief); + s32 y = i - top + y_offset; + last_y = y + 1; + char *c_str = al_str_to_c_str(&part); if (tab->move.active && i == tracked) { ncplane_putstr_yx(n, y, 0, c_str); } else if (on_current) { diff --git a/src/fruits/cmc/ui/ui.c b/src/fruits/cmc/ui/ui.c index b51ec53..55441e9 100644 --- a/src/fruits/cmc/ui/ui.c +++ b/src/fruits/cmc/ui/ui.c @@ -176,9 +176,9 @@ static bool relayout(struct cmc_ui *ui, struct ncplane *stdplane) if (ui->n) ncplane_destroy(ui->n); struct ncplane_options nopts = { 0 }; nopts.x = 1; - nopts.y = 1; + nopts.y = 0; nopts.margin_r = 2; - nopts.margin_b = 1; + nopts.margin_b = 0; nopts.flags = NCPLANE_OPTION_MARGINALIZED; ui->n = ncplane_create(stdplane, &nopts); @@ -223,7 +223,7 @@ static s32 log_callback(void *userdata, u8 level, char *message) { struct cmc_ui *ui = (struct cmc_ui *)userdata; (void)level; - cmc_log_pane_push_message(&ui->log, message); + cmc_log_pane_push_message(&ui->log, strdup(message)); return al_strnlen(message, AL_LOG_MESSAGE_SIZE); } @@ -263,7 +263,7 @@ bool cmc_ui_init(struct cmc_ui *ui, struct nn_event_loop *loop, struct cmc *c) nn_poll_start(&ui->input_poll, ui->loop); nn_timer_init(&ui->render_timer, ui->loop, render_timer_callback, ui); - nn_timer_set_repeat(&ui->render_timer, NNWT_TS_FROM_USEC(200000)); + nn_timer_set_repeat(&ui->render_timer, NNWT_TS_FROM_USEC(40000)); nn_timer_again(&ui->render_timer); return true; diff --git a/src/fruits/cmc/ui/util/waveform.c b/src/fruits/cmc/ui/util/waveform.c index 624069e..f43890d 100644 --- a/src/fruits/cmc/ui/util/waveform.c +++ b/src/fruits/cmc/ui/util/waveform.c @@ -1,18 +1,21 @@ #include #include +#include "../../util/color_palette.h" + #include "waveform.h" #define WITHIN_RMS(low, high, rms) \ ((low >= 0 && low <= rms) || (high < 0 && high >= -rms) || (low < 0 && high > 0 && rms > 0)) -//#define OUTPUT_WAVEFORM_PNG +#define OUTPUT_WAVEFORM_PNG //#define WAVEFORM_REFERENCE_MODE #ifdef OUTPUT_WAVEFORM_PNG #include #include +#include #define STB_IMAGE_WRITE_IMPLEMENTATION -#include +//#include // min/max: #BC615E, #F4EAE0 // rms: #FF928F, #E4CAAF @@ -21,9 +24,10 @@ // rms: #f44f7a, #c84064 // extra: #f6ac7f, #F5F4FA, #5b524b // left channel: n == 0, right channel: n == 1. -#define COLOR_FOR_PIXEL(n, rms) rms ? \ - n == 0 ? nn_htonl(0xe4caaf99) : nn_htonl(0xff928fff) : \ - n == 0 ? nn_htonl(0xf4eae099) : nn_htonl(0xbc615eff) +static u32 color1, color2, color3, color4; +#define COLOR_FOR_PIXEL(n, rms) ((rms) ? \ + ((n == 0) ? color1 : color3) : \ + ((n == 0) ? color2 : color4)) // ss: current sample, ns: next sample. #define HIT_WAVE(low, high, ss, ns) \ @@ -33,6 +37,11 @@ static void test_write_bitmap(struct cmc_list_entry *entry, u32 width, u32 heigh { f64 start = nn_get_tick(); + color1 = nn_htonl((global_color_palette.colors[CAMU_COLOR5] << 8) | 0xFF); + color2 = nn_htonl((global_color_palette.colors[CAMU_COLOR2] << 8) | 0xFF); + color3 = nn_htonl((global_color_palette.colors[CAMU_COLOR3] << 8) | 0xFF); + color4 = nn_htonl((global_color_palette.colors[CAMU_COLOR1] << 8) | 0xFF); + *rgba = al_calloc(width * height, 4); u32 channels = entry->raw.fmt.channel_count; @@ -72,7 +81,12 @@ static void test_write_bitmap(struct cmc_list_entry *entry, u32 width, u32 heigh for (u32 j = 0; j < height; j++) { low = steps[j + 1], high = steps[j]; if (low < max && high >= min) { - (*rgba)[j * width + i] = COLOR_FOR_PIXEL(n, WITHIN_RMS(low, high, rms)); + bool in_rms = WITHIN_RMS(low, high, rms); + u32 *out = *rgba + (j * width + i); + if (n == 1 && *out == COLOR_FOR_PIXEL(0, true) && !in_rms) { + continue; + } + *out = COLOR_FOR_PIXEL(n, in_rms); } } #else @@ -82,7 +96,12 @@ static void test_write_bitmap(struct cmc_list_entry *entry, u32 width, u32 heigh for (u32 j = 0; j < height; j++) { low = steps[j + 1], high = steps[j]; if (HIT_WAVE(low, high, ss, ns)) { - (*rgba)[j * width + i] = COLOR_FOR_PIXEL(n, WITHIN_RMS(low, high, rms)); + bool in_rms = WITHIN_RMS(low, high, rms); + u32 *out = *rgba + (j * width + i); + if (n == 1 && *out == COLOR_FOR_PIXEL(0, true) && !in_rms) { + continue; + } + *out = COLOR_FOR_PIXEL(n, in_rms); } } } @@ -93,7 +112,6 @@ static void test_write_bitmap(struct cmc_list_entry *entry, u32 width, u32 heigh log_info("generating waveform took: %.2fs.", nn_get_tick() - start); //stbi_write_png("./waveform.png", width, height, 4, *rgba, width * 4); - /* struct nn_file file; nn_file_open(&file, &al_str_c("./raw_samples.raw"), NNWT_FILE_CREATE); diff --git a/src/fruits/cmc/ui/widgets/now_playing.c b/src/fruits/cmc/ui/widgets/now_playing.c index 9edf6ca..56405b3 100644 --- a/src/fruits/cmc/ui/widgets/now_playing.c +++ b/src/fruits/cmc/ui/widgets/now_playing.c @@ -140,32 +140,46 @@ void cmc_now_playing_render(struct cmc_now_playing *np, struct cmc_list_entry *e 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); + s32 width1 = camu_print_time(timestr, sizeof(timestr), pos, true, 3); ncplane_putstr_yx(np->n, 1, 4, timestr); - ncplane_putstr_yx(np->n, 1, 4 + offset, "⎹"); - - if (entry) { - char *c_str = al_str_to_c_str(&entry->brief); - ncplane_putnstr_yx(np->n, 1, 6 + offset, MIN(al_strlen(c_str), (size_t)60), c_str); - al_free(c_str); - } + ncplane_putstr_yx(np->n, 1, 4 + width1, "⎹"); + s32 width2; bool show_remaining = false; if (show_remaining) { - offset = camu_print_time(timestr, sizeof(timestr), remaining, true, 4); + width2 = camu_print_time(timestr, sizeof(timestr), remaining, true, 3); } else { - offset = camu_print_time(timestr, sizeof(timestr), duration, true, 4); + width2 = camu_print_time(timestr, sizeof(timestr), duration, true, 3); } - ncplane_putstr_yx(np->n, 1, width - 4 - offset, "⎸"); + s32 x1 = width - 4 - width2; + ncplane_putstr_yx(np->n, 1, x1, "⎸"); // "=" Duration, "+" Segment, "-" Remaining. if (show_remaining) { - ncplane_putstr_yx(np->n, 1, width - 3 - offset, "-"); + ncplane_putstr_yx(np->n, 1, x1 + 1, "-"); } else { - ncplane_putstr_yx(np->n, 1, width - 3 - offset, "="); + ncplane_putstr_yx(np->n, 1, x1 + 1, "="); } - ncplane_putstr_yx(np->n, 1, width - 2 - offset, timestr); + ncplane_putstr_yx(np->n, 1, x1 + 2, timestr); if (entry) { + u32 rslash = al_str_rfind(&entry->brief, '/'); + str part; + if (rslash != AL_STR_NO_POS) { + part = al_str_substr(&entry->brief, rslash + 1, entry->brief.length); + } else { + part = entry->brief; + } + char *c_str = al_str_to_c_str(&part); + s32 x2 = 6 + width1; + // @TODO: Can mid be negative. + s32 mid = x1 - x2; + ncplane_putnstr_yx(np->n, 1, x2, MIN(al_strlen(c_str), (size_t)mid), c_str); + if (part.length >= mid) { + ncplane_putnstr_yx(np->n, 1, x2 + mid - 1, 1, "."); + ncplane_putnstr_yx(np->n, 1, x2 + mid - 2, 1, "."); + } + al_free(c_str); + bool visual_cached = false; struct cmc_now_playing_visual *visual; al_array_foreach_ptr(np->visuals, i, visual) { -- cgit v1.2.3-101-g0448