diff options
| author | 2025-04-07 12:37:15 -0400 | |
|---|---|---|
| committer | 2025-04-07 12:37:15 -0400 | |
| commit | a6d104090ef752126766ef237db1ff1dc6b966f0 (patch) | |
| tree | 1e3a9f545fb1305115f33cb9afc8ef53f0ee8491 /src/fruits | |
| parent | 0f583e348794b45e4307e70a29865faddcba407f (diff) | |
| download | camu-a6d104090ef752126766ef237db1ff1dc6b966f0.tar.gz camu-a6d104090ef752126766ef237db1ff1dc6b966f0.tar.bz2 camu-a6d104090ef752126766ef237db1ff1dc6b966f0.zip | |
cmc cleanup and testing
- Add waveform drawing notes.
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/fruits')
| -rw-r--r-- | src/fruits/cmc/cmc.c | 134 | ||||
| -rw-r--r-- | src/fruits/cmc/cmc.h | 8 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/pane_list.c | 224 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/pane_search.c | 30 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/ui.c | 47 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/ui.h | 19 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/waveform.h | 104 | ||||
| -rw-r--r-- | src/fruits/cmv/cmv.c | 2 | ||||
| -rw-r--r-- | src/fruits/ctv/ctv.c | 2 |
9 files changed, 421 insertions, 149 deletions
diff --git a/src/fruits/cmc/cmc.c b/src/fruits/cmc/cmc.c index 61ac25a..4278663 100644 --- a/src/fruits/cmc/cmc.c +++ b/src/fruits/cmc/cmc.c @@ -2,7 +2,6 @@ #include <nnwt/event_loop.h> #include <nnwt/packet.h> -#include "../../portal/src/packet_ext.h" #include "../../server/common.h" #include "../../liana/list.h" @@ -29,7 +28,7 @@ static struct cmc_search *get_search_by_id(struct cmc *c, s32 id) } */ -static void parse_list_entry(struct nn_packet *packet, struct cmc_list_entry *entry, u32 id) +static void read_list_entry(struct nn_packet *packet, struct cmc_list_entry *entry, u32 id) { entry->id = id; entry->duration = nn_packet_read_u64(packet); @@ -38,7 +37,10 @@ static void parse_list_entry(struct nn_packet *packet, struct cmc_list_entry *en entry->offset = nn_packet_read_u64(packet); wstr w; nn_packet_read_wstr(packet, &w); - al_wstr_clone(&entry->name, &w); + if (!al_wstr_eq(&entry->name, &w)) { + al_wstr_free(&entry->name); + al_wstr_clone(&entry->name, &w); + } } static void parse_initial_user_state(struct cmc *c, struct nn_packet *packet) @@ -66,25 +68,35 @@ static void parse_initial_user_state(struct cmc *c, struct nn_packet *packet) u32 inner_count = nn_packet_read_s32(packet); for (u32 j = 0; j < inner_count; j++) { u32 id = nn_packet_read_u32(packet); - struct cmc_list_entry entry; - parse_list_entry(packet, &entry, id); + struct cmc_list_entry *entry = al_alloc_object(struct cmc_list_entry); + read_list_entry(packet, entry, id); al_array_push(list->entries, entry); } al_array_push(c->lists, list); } } +static struct cmc_list *get_list_by_name(struct cmc *c, str *name) +{ + struct cmc_list *list; + al_array_foreach(c->lists, i, list) { + if (al_str_eq(&list->name, name)) return list; + } + return NULL; +} + static void client_callback(void *userdata, u8 op, void *opaque) { struct cmc *c = (struct cmc *)userdata; switch (op) { case CAMU_CLIENT_LOGGED_IN: { struct nn_packet *packet = (struct nn_packet *)opaque; - switch (c->command) { + switch (c->cli.command) { case CLI_OPEN_UI: parse_initial_user_state(c, packet); if (!cmc_ui_init(&c->ui, &c->loop, c)) { - nn_event_loop_break_one(&c->loop); + camu_client_disconnect(&c->client); + break; } struct cmc_list *list; al_array_foreach(c->lists, i, list) { @@ -96,11 +108,16 @@ static void client_callback(void *userdata, u8 op, void *opaque) } break; case CLI_ADD: { + str *arg; + al_array_foreach_ptr(c->cli.args, i, arg) { + al_str_free(arg); + } + camu_client_disconnect(&c->client); break; } case CLI_SEARCH: { str *arg; - al_array_foreach_ptr(c->args, i, arg) { + al_array_foreach_ptr(c->cli.args, i, arg) { camu_client_create_search(&c->client, &al_str_c("youtube"), arg); al_str_free(arg); } @@ -124,53 +141,50 @@ static void client_callback(void *userdata, u8 op, void *opaque) case CAMU_CLIENT_GOT_META: { struct nn_packet *packet = (struct nn_packet *)opaque; u8 op = nn_packet_read_u8(packet); + str name; + nn_packet_read_str(packet, &name); + struct cmc_list *list = get_list_by_name(c, &name); + if (!list) break; switch (op) { - case LIANA_META_CURRENT_CHANGED: { - str name; - nn_packet_read_str(packet, &name); - struct cmc_list *list; - al_array_foreach(c->lists, i, list) { - if (al_str_eq(&list->name, &name)) { - list->current = nn_packet_read_s32(packet); - u32 id = nn_packet_read_u32(packet); - struct cmc_list_entry *entry = &al_array_at(list->entries, list->current); - parse_list_entry(packet, entry, id); - break; - } - } + case LIANA_META_ADDED_ENTRY: { + u32 id = nn_packet_read_u32(packet); + struct cmc_list_entry *entry = al_alloc_object(struct cmc_list_entry); + read_list_entry(packet, entry, id); + al_array_push(list->entries, entry); cmc_ui_queue_render(&c->ui); break; } - case LIANA_META_ADDED_ENTRY: { - str name; - nn_packet_read_str(packet, &name); + case LIANA_META_REMOVED_ENTRY: { + break; + } + case LIANA_META_CURRENT_CHANGED: { + list->current = nn_packet_read_s32(packet); u32 id = nn_packet_read_u32(packet); - struct cmc_list_entry entry; - parse_list_entry(packet, &entry, id); - struct cmc_list *list; - al_array_foreach(c->lists, i, list) { - if (al_str_eq(&list->name, &name)) { - al_array_push(list->entries, entry); - break; + struct cmc_list_entry *entry = al_array_at(list->entries, list->current); + read_list_entry(packet, entry, id); + cmc_ui_queue_render(&c->ui); + break; + } + case LIANA_META_ORDER_CHANGED: { + struct cmc_list_entry *entry; + u32 count = nn_packet_read_u32(packet); + for (u32 i = 0; i < count; i++) { + u32 id = nn_packet_read_u32(packet); + al_array_foreach(list->entries, j, entry) { + if (i != j && entry->id == id) { + SWAP(al_array_at(list->entries, i), al_array_at(list->entries, j)); + } } } - cmc_ui_queue_render(&c->ui); break; } case LIANA_META_ENTRY_SEEKED: { - str name; - nn_packet_read_str(packet, &name); - struct cmc_list *list; - al_array_foreach(c->lists, i, list) { - if (al_str_eq(&list->name, &name)) { - u32 id = nn_packet_read_u32(packet); - struct cmc_list_entry *entry; - al_array_foreach_ptr(list->entries, j, entry) { - if (entry->id == id) { - parse_list_entry(packet, entry, id); - break; - } - } + u32 id = nn_packet_read_u32(packet); + struct cmc_list_entry *entry; + al_array_foreach(list->entries, i, entry) { + if (entry->id == id) { + read_list_entry(packet, entry, id); + break; } } break; @@ -183,31 +197,27 @@ static void client_callback(void *userdata, u8 op, void *opaque) static struct cmc c = { 0 }; -#ifdef NAUNET_ON_WINDOWS -static bool parse_cmd(s32 argc, wchar_t **argv) -#else -static bool parse_cmd(s32 argc, char *argv[]) -#endif +static bool parse_command_line(s32 argc, char *argv[]) { if (argc < 2) { - c.command = CLI_OPEN_UI; + c.cli.command = CLI_OPEN_UI; return true; } if (al_str_eq(&al_str_cr(argv[1]), &al_str_c("add"))) { if (argc < 3) return false; - c.command = CLI_ADD; + c.cli.command = CLI_ADD; char path[PATH_MAX]; str arg; for (s32 i = 2; i < argc; i++) { if (realpath(argv[i], path)) { al_str_clone(&arg, &al_str_cs(path)); - al_array_push(c.args, arg); + al_array_push(c.cli.args, arg); } } } else if (al_str_eq(&al_str_cr(argv[1]), &al_str_c("search"))) { if (argc < 3) return false; - c.command = CLI_SEARCH; + c.cli.command = CLI_SEARCH; str query; al_str_from(&query, ""); for (s32 i = 2; i < argc; i++) { @@ -216,24 +226,22 @@ static bool parse_cmd(s32 argc, char *argv[]) al_str_cat(&query, &al_str_c(" ")); } } - al_array_push(c.args, query); + al_array_push(c.cli.args, query); } return true; } -#ifdef NAUNET_ON_WINDOWS -s32 wmain(s32 argc, wchar_t **argv) -#else s32 main(s32 argc, char *argv[]) -#endif { if (!nn_common_init()) return EXIT_FAILURE; - nn_event_loop_init(&c.loop); + al_array_init(c.cli.args); + if (!parse_command_line(argc, argv)) { + return EXIT_FAILURE; + } - al_array_init(c.args); - if (!parse_cmd(argc, argv)) return EXIT_FAILURE; + nn_event_loop_init(&c.loop); al_array_init(c.lists); camu_post_cache_init(&c.cache); @@ -241,7 +249,7 @@ s32 main(s32 argc, char *argv[]) c.client.callback = client_callback; c.client.userdata = &c; - if (!camu_client_login(&c.client, &c.loop, CAMU_TEST_TYPE, &CAMU_TEST_ADDR, CAMU_PORT, &al_str_c("andrew"))) { + if (!camu_client_login(&c.client, &al_str_c("andrew"), &c.loop, CAMU_TEST_TYPE, &CAMU_TEST_ADDR, CAMU_PORT)) { return EXIT_FAILURE; } diff --git a/src/fruits/cmc/cmc.h b/src/fruits/cmc/cmc.h index 0a3cbca..e2cdde3 100644 --- a/src/fruits/cmc/cmc.h +++ b/src/fruits/cmc/cmc.h @@ -33,13 +33,15 @@ struct cmc_list_entry { struct cmc_list { str name; s32 current; - array(struct cmc_list_entry) entries; + array(struct cmc_list_entry *) entries; }; struct cmc { + struct { + u8 command; + array(str) args; + } cli; struct nn_event_loop loop; - u8 command; - array(str) args; struct camu_client client; array(struct cmc_list *) lists; struct camu_post_cache cache; diff --git a/src/fruits/cmc/ui/pane_list.c b/src/fruits/cmc/ui/pane_list.c index 5fc9f81..557f5f3 100644 --- a/src/fruits/cmc/ui/pane_list.c +++ b/src/fruits/cmc/ui/pane_list.c @@ -26,58 +26,146 @@ void cmc_lp_add_list(struct cmc_ui *ui, struct cmc_list *list) { struct cmc_list_tab tab = { .list = list, - .selected = 0 + .selected = list->current, + .leader_pressed = false }; al_array_push(ui->lp.tabs, tab); } bool cmc_lp_handle_input(struct cmc_ui *ui, struct ncinput *input) { - if (!ui->lp.tabs.count) { - return false; - } + if (!ui->lp.tabs.count) return false; struct cmc_list_tab *tab = &al_array_at(ui->lp.tabs, ui->lp.current); - u32 count = tab->list->entries.count; + s32 count = (s32)tab->list->entries.count; + bool leader = tab->leader_pressed; + if (cmc_ui_consider_input(input, false)) { + tab->leader_pressed = false; + } + switch (input->id) { + case 'g': + CONSIDER_INPUT(); + if (leader) { + if (tab->move.active) { + tab->move.offset = -tab->move.selected; + } else { + tab->selected = 0; + } + } else { + tab->leader_pressed = true; + } + break; + case 'G': + CONSIDER_INPUT(); + if (tab->move.active) { + tab->move.offset = count - 1 - tab->move.selected; + } else { + tab->selected = count - 1; + } + break; + case 'f': + //CONSIDER_INPUT_MOD_CTRL(); + CONSIDER_INPUT_REPEAT(); + if (tab->move.active) { + if (tab->selected + tab->move.offset < count - tab->page_length) { + tab->move.offset += tab->page_length; + } else { + tab->move.offset = count - 1 - tab->move.selected; + } + } else { + if (tab->selected < count - tab->page_length) { + tab->selected += tab->page_length; + } else { + tab->selected = count - 1; + } + } + break; + case 'b': + //CONSIDER_INPUT_MOD_CTRL(); + CONSIDER_INPUT_REPEAT(); + if (tab->move.active) { + if (tab->selected + tab->move.offset > tab->page_length) { + tab->move.offset -= tab->page_length; + } else { + tab->move.offset = -tab->selected; + } + } else { + if (tab->selected > tab->page_length) { + tab->selected -= tab->page_length; + } else { + tab->selected = 0; + } + } + break; case 'j': - if (!cmc_ui_consider_input(input, true) || tab->selected >= count - 1) { - return false; + CONSIDER_INPUT_REPEAT(); + if (tab->move.active) { + if (tab->selected + tab->move.offset < count - 1) { + tab->move.offset++; + } + } else { + if (tab->selected < count - 1) { + tab->selected++; + } } - tab->selected++; break; case 'k': - if (!cmc_ui_consider_input(input, true) || tab->selected == 0) { - return false; + CONSIDER_INPUT_REPEAT(); + if (tab->move.active) { + if (tab->selected + tab->move.offset > 0) { + tab->move.offset--; + } + } else { + if (tab->selected > 0) { + tab->selected--; + } + } + break; + case 'i': + CONSIDER_INPUT(); + if (!tab->move.active) { + tab->move.active = true; + tab->move.selected = tab->selected; + tab->move.offset = 0; + } + break; + case NCKEY_ESC: + CONSIDER_INPUT(); + if (tab->move.active) { + tab->move.active = false; } - tab->selected--; break; case NCKEY_RETURN: - if (!cmc_ui_consider_input(input, false)) { - return false; + CONSIDER_INPUT(); + if (tab->move.active) { + tab->move.active = false; + } else { + camu_client_skipto(&ui->c->client, &tab->list->name, tab->selected); } - camu_client_skipto(&ui->c->client, &tab->list->name, tab->selected); break; - case NCKEY_BUTTON1: { - if (!cmc_ui_consider_input(input, false)) { + case NCKEY_BUTTON1: + CONSIDER_INPUT(); + if (input->x < 0 || input->y < 0) return false; + u32 x = (u32)input->x; + u32 y = (u32)input->y; + ui->last_mouse_x = x; + ui->last_mouse_y = y; + u64 now = nn_get_timestamp(); + u64 last = ui->last_mouse_ts; + if (last != (u64)-1 && now - last < 100000) { return false; } - u32 height = ncplane_dim_y(ui->lp.n); + ui->last_mouse_ts = now; u32 width = ncplane_dim_x(ui->lp.n); - if (input->x > 0 && input->y > 0) { - u32 x = (u32)input->x; - u32 y = (u32)input->y; - if (y > height - 3 && x >= 2 && x <= width) { - struct cmc_list_entry *entry = &al_array_at(tab->list->entries, tab->list->current); - f64 percent = (x - 2) / (f64)(width - 2); - camu_client_seek(&ui->c->client, &tab->list->name, entry->id, percent); - } - ui->last_mouse_x = x; - ui->last_mouse_y = y; + u32 height = ncplane_dim_y(ui->lp.n); + if (x >= 2 && x <= width && y > height - 3) { // @TODO: Make this defined, more to nowplaying. + struct cmc_list_entry *entry = al_array_at(tab->list->entries, tab->list->current); + u64 pos = ((x - 2) / (f64)(width - 2)) * entry->duration; + camu_client_seek(&ui->c->client, &tab->list->name, entry->id, pos); } break; } - } return true; } @@ -87,27 +175,57 @@ void cmc_lp_erase(struct cmc_ui *ui) ncplane_erase(ui->lp.n); } -static void render_list_entries(struct cmc_ui *ui, struct cmc_list_tab *tab, u32 max_height) +static void render_list_entries(struct cmc_ui *ui, struct cmc_list_tab *tab, s32 max_height) { struct cmc_list *list = tab->list; - u32 count = list->entries.count; - u32 index = tab->selected - (tab->selected % max_height); - u32 end = MIN(index + max_height, count); + struct ncplane *n = ui->lp.n; + s32 tracked = tab->move.active ? tab->move.selected + tab->move.offset : tab->selected; + s32 count = (s32)list->entries.count; + s32 midpoint = max_height / 2; + s32 rounded = (max_height + 1) / 2; + s32 top, end; + if (tracked < midpoint) { + top = 0; + end = MIN(top + max_height, count); + } else if (tracked + rounded >= count) { + top = count - max_height; + end = count; + } else { + top = tracked - midpoint; + end = tracked + rounded; + } + s32 index; struct cmc_list_entry *entry; - for (u32 i = index; i < end; i++) { - entry = &al_array_at(list->entries, i); - if (i == tab->selected) { - ncplane_set_styles(ui->lp.n, NCSTYLE_BOLD); - ncplane_set_fg_palindex(ui->lp.n, 6); - } else { - ncplane_set_styles(ui->lp.n, NCSTYLE_NONE); - ncplane_set_fg_default(ui->lp.n); + for (s32 i = top; i < end; i++) { + index = i; + if (tab->move.active) { + if (index == tracked) { + index = tab->move.selected; + } else { + if (index > tracked) index--; + if (index >= tab->move.selected) index++; + } + } + entry = al_array_at(list->entries, index); + 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); } - if (list->current >= 0 && i == (u32)list->current) { - ncplane_putchar_yx(ui->lp.n, i - index, 1, '>'); - cmc_ui_putnwstr_yx(ui->lp.n, i - index, 3, entry->name.length, &entry->name); + s32 y = i - top; + u32 length = entry->name.length; + if (tab->move.active && i == tracked) { + cmc_ui_putnwstr_yx(n, y, 0, length, &entry->name); + } else if (on_current) { + ncplane_putchar_yx(n, y, 1, '>'); + cmc_ui_putnwstr_yx(n, y, 3, length, &entry->name); } else { - cmc_ui_putnwstr_yx(ui->lp.n, i - index, 0, entry->name.length, &entry->name); + cmc_ui_putnwstr_yx(n, y, 1, length, &entry->name); + } + if (styled) { + ncplane_set_styles(n, NCSTYLE_NONE); + ncplane_set_fg_default(n); } } } @@ -117,7 +235,7 @@ static void render_now_playing(struct cmc_ui *ui, struct cmc_list_tab *tab, u32 u32 width = ncplane_dim_x(ui->lp.n); if (tab && tab->list->entries.count > 0) { struct cmc_list *list = tab->list; - struct cmc_list_entry *entry = &al_array_at(list->entries, list->current); + struct cmc_list_entry *entry = al_array_at(list->entries, list->current); f32 percent = 1.0; if (entry->duration > 0) { u64 pos = entry->offset; @@ -128,13 +246,19 @@ static void render_now_playing(struct cmc_ui *ui, struct cmc_list_tab *tab, u32 percent = MIN(pos / (f32)entry->duration, 1.f); } for (u32 i = 0; i < (width - 2) * percent; i++) { - ncplane_putchar_yx(ui->lp.n, height - 2, i + 1, '-'); + ncplane_putchar_yx(ui->lp.n, height - 6, i + 1, '-'); } - cmc_ui_putnwstr_yx(ui->lp.n, height - 4, 1, entry->name.length, &entry->name); + cmc_ui_putnwstr_yx(ui->lp.n, height - 7, 2, entry->name.length, &entry->name); } + ncplane_putchar_yx(ui->lp.n, height - 5, 2, 'A'); + ncplane_putchar_yx(ui->lp.n, height - 4, 2, 'A'); + ncplane_putchar_yx(ui->lp.n, height - 3, 2, 'A'); + ncplane_putchar_yx(ui->lp.n, height - 2, 2, 'A'); + /* char buf[24]; al_snprintf(buf, sizeof(buf), "%u, %u | %u, %u", ui->last_mouse_x, ui->last_mouse_y, width, height); ncplane_putstr_yx(ui->lp.n, height - 5, 1, buf); + */ u64 c = 0; ncchannels_set_fg_default(&c); ncplane_cursor_move_yx(ui->lp.n, y, 0); @@ -150,9 +274,11 @@ void cmc_lp_render(struct cmc_ui *ui) tab = &al_array_at(ui->lp.tabs, ui->lp.current); } + tab->page_length = height - 8; + if (tab) { - render_list_entries(ui, tab, height - 8); + render_list_entries(ui, tab, tab->page_length); } - render_now_playing(ui, tab, height - 8, height); + render_now_playing(ui, tab, tab->page_length, height); } diff --git a/src/fruits/cmc/ui/pane_search.c b/src/fruits/cmc/ui/pane_search.c index 3b427ce..21c9b67 100644 --- a/src/fruits/cmc/ui/pane_search.c +++ b/src/fruits/cmc/ui/pane_search.c @@ -14,9 +14,22 @@ void cmc_sp_layout(struct cmc_ui *ui, struct ncplane *parent) { if (ui->sp.n) ncplane_destroy(ui->sp.n); struct ncplane_options nopts = { 0 }; - nopts.rows = ncplane_dim_y(parent); - nopts.cols = ncplane_dim_x(parent); + nopts.rows = ncplane_dim_y(parent) - 1; + nopts.cols = ncplane_dim_x(parent) - 1; ui->sp.n = ncplane_create(parent, &nopts); + struct cmc_search_tab tab = { + .search = NULL, + }; + nopts.x = 3; + nopts.y = 2; + nopts.rows = 10; + nopts.cols = ncplane_dim_x(ui->sp.n) - 3; + tab.input = ncplane_create(ui->sp.n, &nopts); + tab.cursor = 0; + tab.input_active = false; + tab.input_text = al_wstr_null(); + tab.input_changed = false; + al_array_push(ui->sp.tabs, tab); } void cmc_sp_add_search(struct cmc_ui *ui, struct cmc_search *search) @@ -60,10 +73,11 @@ static bool handle_text_input(struct cmc_search_tab *tab, struct ncinput *input) } break; case NCKEY_RETURN: - tab->input_active = false; - // Erase text on next render. - tab->input_changed = true; entered = true; + // fallthrough + case NCKEY_ESC: + tab->input_active = false; + tab->input_changed = true; // Erase text on next render. break; default: if (ncinput_ctrl_p(input)) { @@ -138,19 +152,17 @@ bool cmc_sp_handle_input(struct cmc_ui *ui, struct ncinput *input) if (tab->input_active) { if (cmc_ui_consider_input(input, true)) { if (handle_text_input(tab, input)) { - notcurses_cursor_disable(ui->nc); str query; al_str_from_wstr(&query, &tab->input_text); camu_client_create_search(&ui->c->client, &al_str_c("youtube"), &query); al_str_free(&query); } + if (!tab->input_active) notcurses_cursor_disable(ui->nc); } } else { switch (input->id) { case 'i': - if (!cmc_ui_consider_input(input, false)) { - return false; - } + CONSIDER_INPUT(); tab->input_active = true; tab->input_changed = true; s32 absx = ncplane_abs_x(tab->input); diff --git a/src/fruits/cmc/ui/ui.c b/src/fruits/cmc/ui/ui.c index 9931620..bd76e56 100644 --- a/src/fruits/cmc/ui/ui.c +++ b/src/fruits/cmc/ui/ui.c @@ -33,21 +33,31 @@ static bool read_input(struct cmc_ui *ui, struct ncinput *input) return !(ret == (u32)-1 || ret == 0); } -static void erase_previous_pane(struct cmc_ui *ui) +static void erase_previous_pane(struct cmc_ui *ui, u8 previous, u8 upcoming) { - switch (ui->pane) { + struct ncplane *pn = NULL; + switch (previous) { + case CMC_PANE_LIST: + pn = ui->lp.n; + break; + case CMC_PANE_SEARCH: + pn = ui->sp.n; + break; + } + ncplane_erase(pn); + switch (upcoming) { case CMC_PANE_LIST: - ncplane_erase(ui->lp.n); + ncplane_move_family_below(pn, ui->lp.n); break; case CMC_PANE_SEARCH: - ncplane_erase(ui->sp.n); + ncplane_move_family_below(pn, ui->sp.n); break; } } static void switch_to_pane(struct cmc_ui *ui, u8 pane) { - erase_previous_pane(ui); + erase_previous_pane(ui, ui->pane, pane); ui->pane = pane; } @@ -68,8 +78,6 @@ void cmc_ui_queue_render(struct cmc_ui *ui) ncplane_erase(ui->oln); } - //notcurses_render(ui->nc); - switch (ui->pane) { case CMC_PANE_LIST: cmc_lp_render(ui); @@ -113,13 +121,8 @@ static void input_poll_callback(void *userdata, s32 revents) (void)revents; bool do_render; struct ncinput input; - for (;;) { - if (!read_input(ui, &input)) { - break; - } - + while (read_input(ui, &input)) { do_render = false; - if (cmc_ui_consider_input(&input, false)) { switch (input.id) { case 'q': @@ -140,7 +143,6 @@ static void input_poll_callback(void *userdata, s32 revents) break; } } - switch (ui->pane) { case CMC_PANE_LIST: if (cmc_lp_handle_input(ui, &input)) { @@ -153,7 +155,6 @@ static void input_poll_callback(void *userdata, s32 revents) } break; } - if (do_render) { cmc_ui_queue_render(ui); notcurses_render(ui->nc); @@ -173,14 +174,13 @@ static void render_timer_callback(void *userdata, struct nn_timer *timer) static bool relayout(struct cmc_ui *ui) { struct ncplane *stdplane = notcurses_stdplane(ui->nc); - notcurses_stddim_yx(ui->nc, &ui->term_rows, &ui->term_cols); if (ui->n) ncplane_destroy(ui->n); struct ncplane_options nopts = { 0 }; - nopts.x = 2; + nopts.x = 1; nopts.y = 1; - nopts.margin_r = 4; + nopts.margin_r = 2; nopts.margin_b = 1; nopts.flags = NCPLANE_OPTION_MARGINALIZED; ui->n = ncplane_create(stdplane, &nopts); @@ -189,13 +189,12 @@ static bool relayout(struct cmc_ui *ui) cmc_sp_layout(ui, ui->n); if (ui->oln) ncplane_destroy(ui->oln); - u32 width = ncplane_dim_x(ui->n); - u32 height = ncplane_dim_y(ui->n); - nopts.margin_r = MAX(6u, width / 2); - nopts.margin_b = MAX(2u, height / 2); + nopts.margin_r = MAX((u32)6, ncplane_dim_x(ui->n) / 2); + nopts.margin_b = MAX((u32)2, ncplane_dim_y(ui->n) / 2); nopts.x = nopts.margin_r / 2; nopts.y = nopts.margin_b / 2; ui->oln = ncplane_create(ui->n, &nopts); + ncplane_move_below(ui->oln, ui->n); return true; } @@ -230,6 +229,10 @@ bool cmc_ui_init(struct cmc_ui *ui, struct nn_event_loop *loop, struct cmc *c) ui->pane = CMC_PANE_SEARCH; ui->overlay_shown = false; + ui->last_mouse_x = 0; + ui->last_mouse_y = 0; + ui->last_mouse_ts = (u64)-1; + relayout(ui); struct ncplane *stdplane = notcurses_stdplane(ui->nc); diff --git a/src/fruits/cmc/ui/ui.h b/src/fruits/cmc/ui/ui.h index 2f73a81..b0ae730 100644 --- a/src/fruits/cmc/ui/ui.h +++ b/src/fruits/cmc/ui/ui.h @@ -14,7 +14,14 @@ enum { struct cmc_list_tab { struct cmc_list *list; - u32 selected; + s32 page_length; + s32 selected; + bool leader_pressed; + struct { + bool active; + s32 selected; + s32 offset; + } move; }; struct cmc_search_tab { @@ -41,6 +48,7 @@ struct cmc_ui { bool overlay_shown; u32 last_mouse_x; u32 last_mouse_y; + u64 last_mouse_ts; struct { struct ncplane *n; array(struct cmc_list_tab) tabs; @@ -56,6 +64,15 @@ struct cmc_ui { struct cmc *c; }; +#define CONSIDER_INPUT() \ + if (!cmc_ui_consider_input(input, false)) return false + +#define CONSIDER_INPUT_REPEAT() \ + if (!cmc_ui_consider_input(input, true)) return false + +#define CONSIDER_INPUT_MOD_CTRL() \ + if (!input->ctrl) return false; + void cmc_ui_putnwstr_yx(struct ncplane *n, u32 y, u32 x, u32 width, wstr *w); void cmc_ui_putnstr_yx(struct ncplane *n, u32 y, u32 x, u32 width, str *s); bool cmc_ui_consider_input(struct ncinput *input, bool repeat); diff --git a/src/fruits/cmc/ui/waveform.h b/src/fruits/cmc/ui/waveform.h new file mode 100644 index 0000000..f3803dd --- /dev/null +++ b/src/fruits/cmc/ui/waveform.h @@ -0,0 +1,104 @@ +/* + +notcurses.h: +Halves + +▄ ▀ + +Quadrants + +▗ ▐ ▖ ▀ ▟ ▌ ▙ + +Sextants + +🬀 🬁 🬂 🬃 🬄 🬅 🬆 🬇 🬈 🬉 🬊 🬋 🬌 🬍 🬎 🬏 🬐 🬑 🬒 🬓 🬔 🬕 🬖 🬗 🬘 🬙 🬚 🬛 🬜 🬝 🬞 + +https://wiki.ourworldoftext.com/wiki/Octant: +Octants + + 🮂 ▘ ▝ ▀ + + + + + + 🮅 + + + +▖ ▌ ▞ ▛ + + + + + + + + + +▗ ▚ ▐ ▜ + + + +▂ + + + + + +▄ ▙ ▟ ▆ █ + +AAAAAAAAAAAAAAAA + +▁ ▂ ▃ ▄ ▅ ▆ ▇ █ + + ▐█ + █ + + ▌ + ▌ + ▌ + + +▂ + + + ▁▂▃▄▅▆▇████▇▆▅▄▃▂▁ +▁▂▃▄▅▆▇████████████████████████████▇▆▅▄▃▂▁ + + +█▇▆▅▄▃▂▁ + +▌▐ +▁▃▂▁▄ + +0 +1 +1 << 1 +1 << 2 +1 << 3 +1 << 4 +1 << 5 +1 << 6 +1 << 7 + + 0b00101011 + +*/ + +static char *bar_lut[] = { + [0] = " ▗▐" , + [1] = "▂", + [2] = "▖▄", + [3] = "▆", + [4] = "▌▙█" +}; + +static char *bar_bottom_lut[] = { + [0] = " ▝▐" , + [1] = "🮂", + [2] = "▘▀▜", + [3] = "🮅", + [4] = "▌▛█" +}; + diff --git a/src/fruits/cmv/cmv.c b/src/fruits/cmv/cmv.c index 274319a..834e95a 100644 --- a/src/fruits/cmv/cmv.c +++ b/src/fruits/cmv/cmv.c @@ -176,7 +176,7 @@ s32 window_system_main(u32 argc, str *argv, void *extra) c.desktop.userdata = &c; } #endif - if (!camu_desktop_connect(&c.desktop, type, &c.loop, &addr, CAMU_PORT)) { + if (!camu_desktop_connect(&c.desktop, &c.loop, type, &addr, CAMU_PORT)) { return EXIT_FAILURE; } diff --git a/src/fruits/ctv/ctv.c b/src/fruits/ctv/ctv.c index d8094c3..55ab773 100644 --- a/src/fruits/ctv/ctv.c +++ b/src/fruits/ctv/ctv.c @@ -26,7 +26,7 @@ static nn_thread_result NNWT_THREADCALL event_loop_thread(void *userdata) prefs->audio_lang = CAMU_LANG_ENGLISH; prefs->subtitle_lang = CAMU_LANG_ENGLISH; - if (!camu_desktop_connect(&c->desktop, NNWT_SOCKET_TCP, &c->loop, &CAMU_TEST_ADDR, CAMU_PORT)) { + if (!camu_desktop_connect(&c->desktop, &c->loop, NNWT_SOCKET_TCP, &CAMU_TEST_ADDR, CAMU_PORT)) { return 0; } |