seamus

commit fd0908d4955d8552e886eb326fc7120004ff4adb

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;