Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>
ui: implement viewport-based scrolling and rendering Replace tickit_window_scroll() with viewport math driven by highlight_index + scroll_offset, update render_queue to only draw visible rows within viewport Also add support for up/down, home/end, g/G and arrow keys, make some decent use of consts/enum
src/ui.c | 189 ++++++++++++++++++++++++++++++++++++++-------------------
diff --git a/src/ui.c b/src/ui.c index 42c973b78665a675b827af62a3139b4a33e7b5d2..db56be26e0cbb14ad05cfc9ec247a7442a8d056b 100644 --- a/src/ui.c +++ b/src/ui.c @@ -4,9 +4,13 @@ #include "ui.h" #include "queue.h" #include "status.h" +#define QUEUE_START_LINE 4 + static int on_key_event(TickitTerm *tt, TickitEventFlags flags, void *_info, void *data); static int toggle_playing_status(struct seamus_frontend *seamus); static int update_scroll_position(struct seamus_frontend *seamus, int direction); +static int scroll_page(struct seamus_frontend *seamus, int direction); +static int scroll_to_extremes(struct seamus_frontend *seamus, int home); static int update_status(Tickit *t, TickitEventFlags flags, void *_info, void *data); static int update_main_window(Tickit *t, TickitEventFlags flags, void *_info, void *data); static int render_root(TickitWindow *win, TickitEventFlags flags, void *_info, void *data); @@ -92,11 +96,11 @@ tickit_window_close(seamus->main_window); tickit_window_close(seamus->status_window); tickit_stop(seamus->t); - } else if (strcmp(key_pressed, "j") == 0) { + } else if (strcmp(key_pressed, "j") == 0 || strcmp(key_pressed, "Down") == 0) { log_info("Scroll down"); update_scroll_position(seamus, +1); - } else if (strcmp(key_pressed, "k") == 0) { + } else if (strcmp(key_pressed, "k") == 0 || strcmp(key_pressed, "Up") == 0) { log_info("Scroll up"); update_scroll_position(seamus, -1); @@ -104,6 +108,22 @@ } else if (strcmp(key_pressed, "Enter") == 0) { log_info("Pressed enter"); toggle_playing_status(seamus); + } else if (strcmp(key_pressed, "PageDown") == 0) { + log_info("Page down"); + + scroll_page(seamus, +1); + } else if (strcmp(key_pressed, "PageUp") == 0) { + log_info("Page up"); + + scroll_page(seamus, -1); + } else if (strcmp(key_pressed, "End") == 0 || (strcmp(key_pressed, "G") == 0)) { + log_info("Go to end"); + + scroll_to_extremes(seamus, 0); + } else if (strcmp(key_pressed, "Home") == 0 || strcmp(key_pressed, "g") == 0) { + log_info("Go to start"); + + scroll_to_extremes(seamus, 1); } else { log_info("Pressed something else %s", key_pressed); } @@ -114,8 +134,8 @@ static int toggle_playing_status(struct seamus_frontend *seamus) { - log_info("Current position %d", seamus->scroll_position); - struct seamus_song song = seamus->queue[seamus->scroll_position]; + log_info("Current position %d", seamus->highlight_index); + struct seamus_song song = seamus->queue[seamus->highlight_index]; log_info("Current song on queue %d - %s", song.song_id, song.title); if (mpd_run_play_id(seamus->conn, song.song_id)) { @@ -133,27 +153,80 @@ static int update_scroll_position(struct seamus_frontend *seamus, int direction) { - log_info("Current position %d, direction: %d, length: %d", seamus->scroll_position, direction, seamus->status->length); + if (seamus->status->length <= 0) { + return 0; + } + + int visible_rows = tickit_window_lines(seamus->main_window) - QUEUE_START_LINE; + if (visible_rows <= 0) visible_rows = 1; + + if (direction == 1) { + if (seamus->highlight_index < seamus->status->length - 1) { + seamus->highlight_index++; + } + } else if (direction == -1) { + if (seamus->highlight_index > 0) { + seamus->highlight_index--; + } + } + + if (seamus->highlight_index < seamus->scroll_offset) { + seamus->scroll_offset = seamus->highlight_index; + } else if (seamus->highlight_index >= seamus->scroll_offset + visible_rows) { + seamus->scroll_offset = seamus->highlight_index - visible_rows + 1; + } + tickit_window_expose(seamus->main_window, NULL); + return 0; +} + +static int +scroll_page(struct seamus_frontend *seamus, int direction) +{ if (seamus->status->length <= 0) { return 0; } - if (seamus->scroll_position == 0 && direction == -1) { - return 0; + int visible_rows = tickit_window_lines(seamus->main_window) - QUEUE_START_LINE; + if (visible_rows <= 0) visible_rows = 1; + + if (direction == 1) { + seamus->scroll_offset += visible_rows; + if (seamus->scroll_offset > seamus->status->length - visible_rows) { + seamus->scroll_offset = seamus->status->length - visible_rows; + } + if (seamus->scroll_offset < 0) seamus->scroll_offset = 0; + seamus->highlight_index = seamus->scroll_offset; + } else if (direction == -1) { + seamus->scroll_offset -= visible_rows; + if (seamus->scroll_offset < 0) seamus->scroll_offset = 0; + seamus->highlight_index = seamus->scroll_offset; } - // Can't go further than whats queued - // TODO: This will cause problems when dealing with the library - // scrolling - if (seamus->scroll_position == seamus->status->length - 1 && direction == 1) { + tickit_window_expose(seamus->main_window, NULL); + return 0; +} + +static int +scroll_to_extremes(struct seamus_frontend *seamus, int home) +{ + if (seamus->status->length <= 0) { return 0; } - seamus->scroll_position += direction; - // TODO: Deal with the current window focused - tickit_window_scroll(seamus->main_window, direction, 0); + int visible_rows = tickit_window_lines(seamus->main_window) - QUEUE_START_LINE; + if (visible_rows <= 0) visible_rows = 1; + + if (home) { + seamus->scroll_offset = 0; + seamus->highlight_index = 0; + } else { + seamus->scroll_offset = seamus->status->length - visible_rows; + if (seamus->scroll_offset < 0) seamus->scroll_offset = 0; + seamus->highlight_index = seamus->status->length - 1; + } + tickit_window_expose(seamus->main_window, NULL); return 0; } @@ -278,7 +351,7 @@ tickit_renderbuffer_restore(render_buffer); } if (seamus->status->length == 0) { - tickit_renderbuffer_goto(render_buffer, 4, 0); + tickit_renderbuffer_goto(render_buffer, QUEUE_START_LINE, 0); tickit_renderbuffer_text(render_buffer, "No songs queued."); } else { log_info("There are items on queue"); @@ -303,65 +376,53 @@ static int render_queue(struct seamus_frontend *seamus, TickitRenderBuffer *render_buffer) { - log_info("Rendering the queue"); - for (int i = 0; i < seamus->queue_size; ++i) { - struct seamus_song *song = &seamus->queue[i]; - - if (song == NULL) { - log_info("Nothing to see here..."); - } else { - int left_padding = 0; - char *song_str = malloc( - sizeof(char) * - (strlen(song->artist) + strlen(song->title) + 6)); + int visible_rows = tickit_window_lines(seamus->main_window) - QUEUE_START_LINE; + if (visible_rows < 0) visible_rows = 0; - sprintf(song_str, "%s - %s", song->artist, song->title); + int start = seamus->scroll_offset; + int end = start + visible_rows; + if (end > seamus->queue_size) end = seamus->queue_size; - if (seamus->status->current_song_id == song->song_id) { - left_padding = 2; - } + log_info("Rendering queue rows %d to %d (highlight: %d)", start, end, seamus->highlight_index); - tickit_renderbuffer_goto(render_buffer, 4 + i, left_padding); - if (seamus->status->current_song_id == song->song_id && seamus->scroll_position == i) { - tickit_renderbuffer_savepen(render_buffer); - TickitPen *scrolling_playing_pen = tickit_pen_clone(seamus->scrolling_pen); - tickit_pen_copy_attr(scrolling_playing_pen, seamus->playing_pen, TICKIT_PEN_BOLD); + for (int i = start; i < end; ++i) { + struct seamus_song *song = &seamus->queue[i]; - tickit_renderbuffer_setpen(render_buffer, scrolling_playing_pen); - tickit_renderbuffer_text(render_buffer, song_str); - tickit_renderbuffer_restore(render_buffer); - } else if (seamus->status->current_song_id == song->song_id) { - tickit_renderbuffer_savepen(render_buffer); - tickit_renderbuffer_setpen(render_buffer, seamus->playing_pen); - tickit_renderbuffer_text(render_buffer, song_str); - tickit_renderbuffer_restore(render_buffer); - } else if (seamus->scroll_position == i) { - tickit_renderbuffer_savepen(render_buffer); - tickit_renderbuffer_setpen(render_buffer, seamus->scrolling_pen); - tickit_renderbuffer_text(render_buffer, song_str); - tickit_renderbuffer_restore(render_buffer); - } else { - tickit_renderbuffer_text(render_buffer, song_str); - } + int left_padding = 0; + char *song_str = malloc( + strlen(song->artist) + strlen(song->title) + 6); + sprintf(song_str, "%s - %s", song->artist, song->title); + if (seamus->status->current_song_id == song->song_id) { + left_padding = 2; + } - // if (seamus->status->current_song_id == song->song_id) { - // tickit_renderbuffer_goto(render_buffer, 4 + i, 2); - // { - // tickit_renderbuffer_savepen(render_buffer); + tickit_renderbuffer_goto(render_buffer, QUEUE_START_LINE + (i - start), left_padding); - // tickit_renderbuffer_setpen(render_buffer, seamus->playing_pen); - // tickit_renderbuffer_text(render_buffer, song_str); - // tickit_renderbuffer_restore(render_buffer); - // } - // } else { - // tickit_renderbuffer_goto(render_buffer, 4 + i, 0); - // tickit_renderbuffer_text(render_buffer, song_str); - // } + if (seamus->status->current_song_id == song->song_id && seamus->highlight_index == i) { + tickit_renderbuffer_savepen(render_buffer); + TickitPen *scrolling_playing_pen = tickit_pen_clone(seamus->scrolling_pen); + tickit_pen_copy_attr(scrolling_playing_pen, seamus->playing_pen, TICKIT_PEN_BOLD); - free(song_str); + tickit_renderbuffer_setpen(render_buffer, scrolling_playing_pen); + tickit_renderbuffer_text(render_buffer, song_str); + tickit_renderbuffer_restore(render_buffer); + } else if (seamus->status->current_song_id == song->song_id) { + tickit_renderbuffer_savepen(render_buffer); + tickit_renderbuffer_setpen(render_buffer, seamus->playing_pen); + tickit_renderbuffer_text(render_buffer, song_str); + tickit_renderbuffer_restore(render_buffer); + } else if (seamus->highlight_index == i) { + tickit_renderbuffer_savepen(render_buffer); + tickit_renderbuffer_setpen(render_buffer, seamus->scrolling_pen); + tickit_renderbuffer_text(render_buffer, song_str); + tickit_renderbuffer_restore(render_buffer); + } else { + tickit_renderbuffer_text(render_buffer, song_str); } + + free(song_str); } return 0;