diff options
Diffstat (limited to 'src/fruits/cmc/ui/panes')
| -rw-r--r-- | src/fruits/cmc/ui/panes/list.c | 688 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/panes/list.h | 35 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/panes/log.c | 65 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/panes/log.h | 18 | ||||
| -rw-r--r-- | src/fruits/cmc/ui/panes/search.c | 226 |
5 files changed, 1032 insertions, 0 deletions
diff --git a/src/fruits/cmc/ui/panes/list.c b/src/fruits/cmc/ui/panes/list.c new file mode 100644 index 0000000..0e853db --- /dev/null +++ b/src/fruits/cmc/ui/panes/list.c @@ -0,0 +1,688 @@ +#include <nnwt/thread.h> + +#include "../../cmc.h" + +#include "list.h" + +void cmc_list_pane_init(struct cmc_list_pane *lp, struct cmc_ui *ui) +{ + al_array_init(lp->tabs); + lp->selected = -1; + cmc_now_playing_init(&lp->np); + lp->ui = ui; +} + +bool cmc_list_pane_layout(struct cmc_list_pane *lp, struct ncplane *parent) +{ + if (lp->n) ncplane_destroy(lp->n); + struct ncplane_options nopts = { 0 }; + u32 height = ncplane_dim_y(parent); + nopts.rows = height; + nopts.cols = ncplane_dim_x(parent); + lp->n = ncplane_create(parent, &nopts); + lp->page_length = height - 9; + cmc_now_playing_layout(&lp->np, lp->n, lp->page_length); + return true; +} + +void cmc_list_pane_add_list(struct cmc_list_pane *lp, struct cmc_list *list) +{ + struct cmc_list_tab tab = { 0 }; + tab.list = list; + tab.selected = list->current; + al_array_push(lp->tabs, tab); + if (lp->selected == -1) { + lp->selected = lp->tabs.count - 1; + } +} + +bool cmc_list_pane_handle_input(struct cmc_list_pane *lp, struct ncinput *input) +{ + if (lp->selected == -1) return false; + + struct cmc_list_tab *tab = &al_array_at(lp->tabs, lp->selected); + 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) { + if (tab->move.offset != -tab->move.selected) { + tab->move.offset = -tab->move.selected; + return true; + } + } else if (tab->selected != 0) { + tab->selected = 0; + return true; + } + } else { + tab->leader_pressed = true; + } + break; + case 'G': + CONSIDER_INPUT(); + if (tab->move.active) { + if (tab->move.offset != count - 1 - tab->move.selected) { + tab->move.offset = count - 1 - tab->move.selected; + return true; + } + } else if (tab->selected != count - 1) { + tab->selected = count - 1; + return true; + } + break; + case 'f': + CONSIDER_INPUT_REPEAT(); + if (tab->move.active) { + if (tab->selected + tab->move.offset < count - lp->page_length) { + tab->move.offset += lp->page_length; + return true; + } else if (tab->move.offset != count - 1 - tab->move.selected) { + tab->move.offset = count - 1 - tab->move.selected; + return true; + } + } else { + if (tab->selected < count - lp->page_length) { + tab->selected += lp->page_length; + return true; + } else if (tab->selected != count - 1) { + tab->selected = count - 1; + return true; + } + } + break; + case 'b': + CONSIDER_INPUT_REPEAT(); + if (tab->move.active) { + if (tab->selected + tab->move.offset > lp->page_length) { + tab->move.offset -= lp->page_length; + return true; + } else if (tab->move.offset != -tab->selected) { + tab->move.offset = -tab->selected; + return true; + } + } else { + if (tab->selected > lp->page_length) { + tab->selected -= lp->page_length; + return true; + } else if (tab->selected != 0) { + tab->selected = 0; + return true; + } + } + break; + case 'j': + CONSIDER_INPUT_REPEAT(); + if (tab->move.active) { + if (tab->selected + tab->move.offset < count - 1) { + tab->move.offset++; + return true; + } + } else { + if (tab->selected < count - 1) { + tab->selected++; + return true; + } + } + break; + case 'k': + CONSIDER_INPUT_REPEAT(); + if (tab->move.active) { + if (tab->selected + tab->move.offset > 0) { + tab->move.offset--; + return true; + } + } else { + if (tab->selected > 0) { + tab->selected--; + return true; + } + } + break; + case 'i': + CONSIDER_INPUT(); + if (!tab->move.active) { + tab->move.active = true; + tab->move.selected = tab->selected; + tab->move.offset = 0; + return true; + } + break; + case NCKEY_ESC: + CONSIDER_INPUT(); + if (tab->move.active) { + tab->move.active = false; + return true; + } + break; + case NCKEY_RETURN: + CONSIDER_INPUT(); + if (tab->move.active) { + tab->move.active = false; + return true; + } else if (tab->selected != tab->list->current) { + camu_client_skipto(&lp->ui->c->client, &tab->list->name, tab->selected); + } + break; + 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; + } + ui->last_mouse_ts = now; + u32 width = ncplane_dim_x(ui->lp.n); + 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 false; +} + +static struct cmc_list_entry *tab_current_entry(struct cmc_list_tab *tab) +{ + if (tab->list->current >= 0) { + return al_array_at(tab->list->entries, tab->list->current); + } + return NULL; +} + +bool cmc_list_pane_tick(struct cmc_list_pane *lp) +{ + bool tick = false; + if (lp->selected != -1) { + struct cmc_list_tab *tab = &al_array_at(lp->tabs, lp->selected); + if (tab->list->meta_changed) { + tab->list->meta_changed = false; + tick = true; + } + tick |= cmc_now_playing_tick(&lp->np, tab_current_entry(tab)); + } + return tick; +} + +void cmc_list_pane_erase(struct cmc_list_pane *lp) +{ + ncplane_erase(lp->n); + cmc_now_playing_erase(&lp->np); +} + +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; + 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 = MAX(count - max_height, 0); + end = count; + } else { + top = tracked - midpoint; + end = tracked + rounded; + } + s32 index; + struct cmc_list_entry *entry; + 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); + } + 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(n, y, 1, length, &entry->name); + } + if (styled) { + ncplane_set_styles(n, NCSTYLE_NONE); + ncplane_set_fg_default(n); + } + } +} + +void cmc_list_pane_render(struct cmc_list_pane *lp) +{ + if (lp->selected == -1) return; + struct cmc_list_tab *tab = &al_array_at(lp->tabs, lp->selected); + render_list_entries(lp, tab, lp->page_length); + cmc_now_playing_render(&lp->np, tab_current_entry(tab)); +} + +//void cmc_lp_init(struct cmc_ui *ui) +//{ +// al_array_init(ui->lp.tabs); +// ui->lp.current = 0; +//} +// +//void cmc_lp_layout(struct cmc_ui *ui, struct ncplane *parent) +//{ +// if (ui->lp.n) ncplane_destroy(ui->lp.n); +// struct ncplane_options nopts = { 0 }; +// nopts.rows = ncplane_dim_y(parent); +// nopts.cols = ncplane_dim_x(parent); +// ui->lp.n = ncplane_create(parent, &nopts); +//} +// +//void cmc_lp_add_list(struct cmc_ui *ui, struct cmc_list *list) +//{ +// struct cmc_list_tab tab = { +// .list = list, +// .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; +// +// struct cmc_list_tab *tab = &al_array_at(ui->lp.tabs, ui->lp.current); +// 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': +// 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++; +// } +// } +// break; +// case 'k': +// 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; +// } +// break; +// case NCKEY_RETURN: +// CONSIDER_INPUT(); +// if (tab->move.active) { +// tab->move.active = false; +// } else if (tab->selected != tab->list->current) { +// camu_client_skipto(&ui->c->client, &tab->list->name, tab->selected); +// } +// break; +// 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; +// } +// ui->last_mouse_ts = now; +// u32 width = ncplane_dim_x(ui->lp.n); +// 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; +//} +// +//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, s32 max_height) +//{ +// struct cmc_list *list = tab->list; +// 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 (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); +// } +// 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(n, y, 1, length, &entry->name); +// } +// if (styled) { +// ncplane_set_styles(n, NCSTYLE_NONE); +// ncplane_set_fg_default(n); +// } +// } +//} +// +//static void render_now_playing(struct cmc_ui *ui, struct cmc_list_tab *tab, u32 y, u32 height) +//{ +// struct ncplane *n = ui->lp.n; +// u32 width = ncplane_dim_x(n); +// +// struct cmc_list_entry *entry = NULL; +// if (tab->list->entries.count > (u32)tab->list->current) { +// entry = al_array_at(tab->list->entries, tab->list->current); +// } +// +// u64 pos = 0; +// u64 duration = 0; +// u64 remaining = 0; +// u32 y_off = height - 7; +// +// ncplane_set_styles(n, NCSTYLE_BOLD); +// if (entry) { +// 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); +// remaining = duration - pos; +// //ncplane_putstr_yx(n, y_off, 2, "▸"); +// //ncplane_putstr_yx(n, y_off, 2, "▶"); +// //ncplane_putstr_yx(n, y_off, 2, "⏵ "); +// //ncplane_putstr_yx(n, y_off, 2, "|"); +// //ncplane_putstr_yx(n, y_off, 2, "|"); +// //ncplane_putstr_yx(n, y_off, 2, "⏵"); +// //ncplane_putstr_yx(n, y_off, 2, "⏸"); +// if (remaining == 0) { +// ncplane_putstr_yx(n, y_off - 1, 2, "∨"); +// } else { +// ncplane_putstr_yx(n, y_off - 1, 2, paused ? "^": ">"); +// } +// } else { +// ncplane_putstr_yx(n, y_off - 1, 2, "∨"); +// } +// ncplane_set_styles(n, NCSTYLE_NONE); +// +// f32 percent = 1.f; +// if (duration > 0) percent = MIN(pos / (f32)duration, 1.f); +// for (u32 i = 0; i < (width - 2) * percent; i++) { +// ncplane_putchar_yx(n, y_off, i + 1, '-'); +// } +// +// y_off--; +// +// char timestr[16] = { 0 }; // max = 829128280:01:49\0 +// s32 offset = camu_print_time(timestr, sizeof(timestr), pos, true, 4); +// ncplane_putstr_yx(n, y_off, 4, timestr); +// ncplane_putstr_yx(n, y_off, 4 + offset, "⎹"); +// +// if (entry) { +// cmc_ui_putnwstr_yx(n, y_off, 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(n, y_off, width - 4 - offset, "⎸"); +// // "=" Duration, "+" Segment, "-" Remaining. +// if (show_remaining) { +// ncplane_putstr_yx(n, y_off, width - 3 - offset, "-"); +// } else { +// ncplane_putstr_yx(n, y_off, width - 3 - offset, "="); +// } +// ncplane_putstr_yx(n, y_off, width - 2 - offset, timestr); +// +// /* +// ncplane_putchar_yx(n, height - 5, 2, 'A'); +// ncplane_putchar_yx(n, height - 4, 2, 'A'); +// ncplane_putchar_yx(n, height - 3, 2, 'A'); +// ncplane_putchar_yx(n, height - 2, 2, 'A'); +// */ +// +// if (entry && entry->raw.data != NULL) { +// u32 length = width - 2; +// u32 top = height - 6; +// u32 wave_height = 5; +// if (entry->raw.drawing == NULL || entry != ui->lp.blitted) { +// entry->raw.drawing = al_malloc(sizeof(char **) * wave_height); +// for (u32 j = 0; j < wave_height; j++) { +// entry->raw.drawing[j] = al_malloc(sizeof(char *) * length); +// for (u32 i = 0; i < length; i++) { +// entry->raw.drawing[j][i] = al_calloc(1, 6); +// } +// } +// if (!ui->lp.w) { +// struct ncplane_options opts = { 0 }; +// opts.x = 1; +// opts.y = top; +// opts.cols = length; +// opts.rows = wave_height; +// ui->lp.w = ncplane_create(n, &opts); +// } +// /* +// struct nccell ncl; +// nccell_init(&ncl); +// nccell_load(w, &ncl, " "); +// nccell_set_bg_palindex(&ncl, 3); +// ncplane_polyfill_yx(w, 0, 0, &ncl); +// */ +// u32 *rgba; +// u32 pixel_width, pixel_height; +// ncplane_pixel_geom(ui->lp.w, &pixel_height, &pixel_width, NULL, NULL, NULL, NULL); +// //cmc_draw_waveform(entry, length, wave_height, false, entry->raw.drawing, &rgba); +// cmc_draw_waveform(entry, pixel_width, pixel_height, false, entry->raw.drawing, &rgba); +// if (ui->lp.vis) { +// ncvisual_destroy(ui->lp.vis); +// } +// ui->lp.vis = ncvisual_from_rgba(rgba, pixel_height, pixel_width * 4, pixel_width); +// } +// +// if (entry != ui->lp.blitted) { +// ncplane_erase(ui->lp.w); +// struct ncvisual_options vopts = { 0 }; +// vopts.blitter = NCBLIT_PIXEL; +// vopts.scaling = NCSCALE_STRETCH; +// vopts.flags = NCVISUAL_OPTION_NOINTERPOLATE; +// vopts.n = ui->lp.w; +// vopts.x = 0; +// vopts.y = 0; +// ncvisual_blit(ui->nc, ui->lp.vis, &vopts); +// ui->lp.blitted = entry; +// } +// +// /* +// ncplane_set_fg_palindex(n, 5); +// for (u32 j = 0; j < wave_height; j++) { +// for (u32 i = 0; i < length; i++) { +// char *cell = entry->raw.drawing[j][i]; +// if (cell[0] == 'R') { +// ncplane_set_bg_palindex(n, 2); +// } +// ncplane_putstr_yx(n, top + j, 1 + i, cell + 1); +// if (cell[0] == 'R') { +// ncplane_set_bg_default(n); +// } +// } +// } +// ncplane_set_fg_default(n); +// */ +// } +// +// /* +// 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(n, height - 5, 5, buf); +// */ +// +// u64 c = 0; +// ncchannels_set_fg_default(&c); +// ncplane_cursor_move_yx(n, y, 0); +// ncplane_light_box(n, NCSTYLE_NONE, c, height - 1, width - 1, 0); +//} +// +//void cmc_lp_render(struct cmc_ui *ui) +//{ +// u32 height = ncplane_dim_y(ui->lp.n); +// +// if (ui->lp.tabs.count <= ui->lp.current) return; +// struct cmc_list_tab *tab = &al_array_at(ui->lp.tabs, ui->lp.current); +// +// tab->page_length = height - 9; +// render_list_entries(ui, tab, tab->page_length); +// render_now_playing(ui, tab, tab->page_length, height); +//} diff --git a/src/fruits/cmc/ui/panes/list.h b/src/fruits/cmc/ui/panes/list.h new file mode 100644 index 0000000..bfeed59 --- /dev/null +++ b/src/fruits/cmc/ui/panes/list.h @@ -0,0 +1,35 @@ +#pragma once + +#include <al/array.h> +#include <notcurses/notcurses.h> + +#include "../widgets/now_playing.h" + +struct cmc_list; +struct cmc_list_tab { + struct cmc_list *list; + s32 selected; + bool leader_pressed; + struct { + bool active; + s32 selected; + s32 offset; + } move; +}; + +struct cmc_list_pane { + struct ncplane *n; + array(struct cmc_list_tab) tabs; + s32 selected; + s32 page_length; + struct cmc_now_playing np; + struct cmc_ui *ui; +}; + +void cmc_list_pane_init(struct cmc_list_pane *lp, struct cmc_ui *ui); +bool cmc_list_pane_layout(struct cmc_list_pane *lp, struct ncplane *parent); +void cmc_list_pane_add_list(struct cmc_list_pane *lp, struct cmc_list *list); +bool cmc_list_pane_handle_input(struct cmc_list_pane *lp, struct ncinput *input); +bool cmc_list_pane_tick(struct cmc_list_pane *lp); +void cmc_list_pane_erase(struct cmc_list_pane *lp); +void cmc_list_pane_render(struct cmc_list_pane *lp); diff --git a/src/fruits/cmc/ui/panes/log.c b/src/fruits/cmc/ui/panes/log.c new file mode 100644 index 0000000..be9702c --- /dev/null +++ b/src/fruits/cmc/ui/panes/log.c @@ -0,0 +1,65 @@ +#include "log.h" + +void cmc_log_pane_init(struct cmc_log_pane *lp) +{ + lp->new_message = false; + al_array_init(lp->messages); +} + +bool cmc_log_pane_layout(struct cmc_log_pane *lp, struct ncplane *parent) +{ + if (lp->n) ncplane_destroy(lp->n); + struct ncplane_options nopts = { 0 }; + nopts.rows = ncplane_dim_y(parent); + nopts.cols = ncplane_dim_x(parent); + lp->n = ncplane_create(parent, &nopts); + return true; +} + +void cmc_log_pane_push_message(struct cmc_log_pane *lp, char *message) +{ + al_array_push(lp->messages, message); + lp->new_message = true; +} + +bool cmc_log_pane_handle_input(struct cmc_log_pane *lp, struct ncinput *input) +{ + (void)lp; + (void)input; + return false; +} + +bool cmc_log_pane_tick(struct cmc_log_pane *lp) +{ + if (lp->new_message) { + lp->new_message = false; + return true; + } + return false; +} + +void cmc_log_pane_erase(struct cmc_log_pane *lp) +{ + ncplane_erase(lp->n); +} + +void cmc_log_pane_render(struct cmc_log_pane *lp) +{ + struct ncplane *n = lp->n; + + u32 max_height = ncplane_dim_y(n); + + u32 count = lp->messages.count; + u32 index = (count > max_height) ? count - max_height : 0; + for (u32 i = index; i < count; i++) { + // We can't use putnstr to control the width because these messages will have wide characters. + ncplane_putstr_yx(n, i - index, 0, al_array_at(lp->messages, i)); + } + + if (index > 0) { + //for (u32 i = 0; i < index; i++) { + // al_free(al_array_at(lp->messages, i)); + //} + //al_array_remove_range(lp->messages, 0, index); + } +} diff --git a/src/fruits/cmc/ui/panes/log.h b/src/fruits/cmc/ui/panes/log.h new file mode 100644 index 0000000..d79c7e9 --- /dev/null +++ b/src/fruits/cmc/ui/panes/log.h @@ -0,0 +1,18 @@ +#pragma once + +#include <al/array.h> +#include <notcurses/notcurses.h> + +struct cmc_log_pane { + struct ncplane *n; + bool new_message; + array(char *) messages; +}; + +void cmc_log_pane_init(struct cmc_log_pane *lp); +bool cmc_log_pane_layout(struct cmc_log_pane *lp, struct ncplane *parent); +void cmc_log_pane_push_message(struct cmc_log_pane *lp, char *message); +bool cmc_log_pane_handle_input(struct cmc_log_pane *lp, struct ncinput *input); +bool cmc_log_pane_tick(struct cmc_log_pane *lp); +void cmc_log_pane_erase(struct cmc_log_pane *lp); +void cmc_log_pane_render(struct cmc_log_pane *lp); diff --git a/src/fruits/cmc/ui/panes/search.c b/src/fruits/cmc/ui/panes/search.c new file mode 100644 index 0000000..e46c27d --- /dev/null +++ b/src/fruits/cmc/ui/panes/search.c @@ -0,0 +1,226 @@ +#include "../../cmc.h" + +#include "../ui.h" + +AL_ASSERT_TYPE_SIZE(wchar_t, 4); + +//void cmc_sp_init(struct cmc_ui *ui) +//{ +// al_array_init(ui->sp.tabs); +// ui->sp.current = 0; +//} +// +//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) - 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) +//{ +// struct cmc_search_tab tab = { +// .search = search, +// }; +// struct ncplane_options nopts = { 0 }; +// 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); +//} +// +//static bool handle_text_input(struct cmc_search_tab *tab, struct ncinput *input) +//{ +// bool entered = false; +// +// switch (input->id) { +// case NCKEY_BACKSPACE: +// if (tab->cursor > 0) { +// al_wstr_remove_at(&tab->input_text, tab->cursor - 1); +// tab->cursor--; +// tab->input_changed = true; +// } +// break; +// case NCKEY_LEFT: +// if (tab->cursor > 0) { +// tab->cursor--; +// } +// break; +// case NCKEY_RIGHT: +// if (tab->cursor < tab->input_text.length) { +// tab->cursor++; +// } +// break; +// case NCKEY_RETURN: +// 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)) { +// switch (input->id) { +// case 'A': +// tab->cursor = 0; +// break; +// case 'E': +// tab->cursor = tab->input_text.length; +// break; +// case 'B': +// if (tab->cursor > 0) { +// tab->cursor--; +// } +// break; +// case 'F': +// if (tab->cursor < tab->input_text.length) { +// tab->cursor++; +// } +// break; +// case 'U': +// for (u32 i = 1; i <= tab->cursor; i++) { +// al_wstr_remove_at(&tab->input_text, tab->cursor - i); +// } +// tab->cursor = 0; +// tab->input_changed = true; +// break; +// } +// break; +// } +// +// if (ncinput_alt_p(input) || nckey_synthesized_p(input->id)) { +// break; +// } +// +// al_wstr_insert(&tab->input_text, tab->cursor, &al_wstr_w((wchar_t *)input->eff_text, 0, 1)); +// tab->cursor++; +// tab->input_changed = true; +// +// /* +// // https://github.com/dankamongmen/notcurses/blob/c11efe877f2245901f5c9ce110de7a2c83cfa2ed/src/lib/reader.c#L404 +// for (s32 c = 0; input->eff_text[c] != 0; c++){ +// uchar egc[5] = { 0 }; +// if (notcurses_ucs32_to_utf8(&input->eff_text[c], 1, egc, 4) >= 0) { +// // This probably doesn't work on Windows. +// al_wstr_insert(&tab->input_text, tab->cursor, &al_wstr_w((wchar_t *)egc, 0, 1)); +// } +// } +// */ +// +// break; +// } +// +// tab->visual_cursor = 0; +// if (tab->cursor > 0) { +// for (u32 i = 0; i < tab->cursor; i++) { +// tab->visual_cursor += al_wchar_width(al_wstr_at(&tab->input_text, i)); +// } +// } +// +// return entered; +//} +// +//bool cmc_sp_handle_input(struct cmc_ui *ui, struct ncinput *input) +//{ +// struct cmc_search_tab *tab = NULL; +// if (ui->sp.tabs.count > 0) { +// tab = &al_array_at(ui->sp.tabs, ui->sp.current); +// } +// +// if (tab) { +// if (tab->input_active) { +// if (cmc_ui_consider_input(input, true)) { +// if (handle_text_input(tab, input)) { +// 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': +// CONSIDER_INPUT(); +// tab->input_active = true; +// tab->input_changed = true; +// s32 absx = ncplane_abs_x(tab->input); +// s32 absy = ncplane_abs_y(tab->input); +// notcurses_cursor_enable(ui->nc, absy, absx + tab->visual_cursor); +// break; +// } +// } +// } +// +// return true; +//} +// +//void cmc_sp_erase(struct cmc_ui *ui) +//{ +// ncplane_erase(ui->sp.n); +//} +// +//void cmc_sp_render(struct cmc_ui *ui) +//{ +// struct cmc_search_tab *tab = NULL; +// if (ui->sp.tabs.count > 0) { +// tab = &al_array_at(ui->sp.tabs, ui->sp.current); +// } +// +// if (tab) { +// if (tab->input_changed) { +// ncplane_erase(tab->input); +// if (tab->input_active) { +// cmc_ui_putnwstr_yx(tab->input, 0, 0, tab->input_text.length, &tab->input_text); +// } +// tab->input_changed = false; +// } +// if (tab->input_active) { +// s32 absx = ncplane_abs_x(tab->input); +// s32 absy = ncplane_abs_y(tab->input); +// notcurses_cursor_enable(ui->nc, absy, absx + tab->visual_cursor); +// } +// } +// +// /* +// if (ui->overlay_shown) { +// ncplane_erase(ui->oln); +// u32 max_height = ncplane_dim_y(ui->oln) - 2; +// u32 count = ui->c->searches.count; +// u32 index = ui->sp.overlay_index - (ui->sp.overlay_index % max_height); +// u32 end = MIN(index + max_height, count); +// for (u32 i = index; i < end; i++) { +// struct cmc_search *search = al_array_at(ui->c->searches, i); +// if (i == ui->sp.overlay_index) { +// ncplane_set_fg_palindex(ui->oln, 6); +// ncplane_putchar_yx(ui->oln, i - index + 1, 2, '>'); +// cmc_ui_putstr_maxwidth_yx(ui->oln, i - index + 1, 4, search->query.length, &search->query); +// } else { +// ncplane_set_fg_default(ui->oln); +// cmc_ui_putstr_maxwidth_yx(ui->oln, i - index + 1, 2, search->query.length, &search->query); +// } +// } +// } +// */ +//} |