From 4018f2c40fe8d616c6595a44879d7b19bbe94f90 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 26 Jan 2015 15:51:50 -0800 Subject: [PATCH] GUAC-803: Update rendering of scrollbar as terminal display is scrolled or resized. Position and scale inner box of scrollbar appropriately. --- src/terminal/scrollbar.c | 128 ++++++++++++++++++++++++++++----------- src/terminal/scrollbar.h | 20 +++++- src/terminal/terminal.c | 22 +++++-- 3 files changed, 128 insertions(+), 42 deletions(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index f75f9d43..7779602a 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -31,7 +31,7 @@ #include guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, - const guac_layer* parent, int parent_width, int parent_height) { + const guac_layer* parent, int parent_width, int parent_height, int visible_area) { /* Allocate scrollbar */ guac_terminal_scrollbar* scrollbar = @@ -49,6 +49,7 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, scrollbar->parent = parent; scrollbar->parent_width = 0; scrollbar->parent_height = 0; + scrollbar->visible_area = 0; /* Allocate and init layers */ scrollbar->container = guac_client_alloc_layer(client); @@ -56,7 +57,7 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, /* Reposition and resize to fit parent */ guac_terminal_scrollbar_parent_resized(scrollbar, - parent_width, parent_height); + parent_width, parent_height, visible_area); return scrollbar; @@ -73,41 +74,37 @@ void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { } -void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, - int min, int max) { - /* STUB */ -} - -void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, - int value) { - /* STUB */ -} - -void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, - int parent_width, int parent_height) { +/** + * Updates the position and size of the scrollbar inner box relative to the + * current scrollbar value, bounds, and parent layer dimensions. + * + * @param scrollbar + * The scrollbar whose inner box should be updated. + */ +static void __update_box(guac_terminal_scrollbar* scrollbar) { guac_socket* socket = scrollbar->client->socket; - /* Calculate container position and dimensions */ - int container_x = parent_width - GUAC_TERMINAL_SCROLLBAR_WIDTH; - int container_y = 0; - int container_width = GUAC_TERMINAL_SCROLLBAR_WIDTH; - int container_height = parent_height; + /* Skip if no scrolling region at all */ + if (scrollbar->min >= scrollbar->max) + return; + + int region_size = scrollbar->max - scrollbar->min; + + /* Calculate box dimensions */ + int box_width = GUAC_TERMINAL_SCROLLBAR_WIDTH - GUAC_TERMINAL_SCROLLBAR_PADDING*2; + int box_height = GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT; + + /* Size box relative to visible area */ + int padded_container_height = (scrollbar->parent_height - GUAC_TERMINAL_SCROLLBAR_PADDING*2); + int proportional_height = padded_container_height * scrollbar->visible_area / (region_size + scrollbar->visible_area); + if (proportional_height > box_height) + box_height = proportional_height; /* Calculate box position and dimensions */ - int box_x = GUAC_TERMINAL_SCROLLBAR_PADDING; - int box_y = GUAC_TERMINAL_SCROLLBAR_PADDING; - int box_width = GUAC_TERMINAL_SCROLLBAR_WIDTH - GUAC_TERMINAL_SCROLLBAR_PADDING*2; - int box_height = 64; /* STUB */ - - /* Reposition container relative to parent dimensions */ - guac_protocol_send_move(socket, - scrollbar->container, scrollbar->parent, - container_x, container_y, 0); - - /* Resize to fit within parent */ - guac_protocol_send_size(socket, scrollbar->container, - container_width, container_height); + int box_x = GUAC_TERMINAL_SCROLLBAR_PADDING; + int box_y = GUAC_TERMINAL_SCROLLBAR_PADDING + + (padded_container_height - box_height) * (scrollbar->value - scrollbar->min) / region_size; /* Reposition box relative to container and current value */ guac_protocol_send_move(socket, @@ -122,9 +119,70 @@ void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, guac_protocol_send_rect(socket, scrollbar->box, 0, 0, box_width, box_height); guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->box, 0xFF, 0xFF, 0xFF, 0x80); - /* Assign new dimensions */ - scrollbar->parent_width = parent_width; - scrollbar->parent_height = parent_height; +} + +void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, + int min, int max) { + + /* Fit value within bounds */ + if (scrollbar->value > max) + scrollbar->value = max; + else if (scrollbar->value < min) + scrollbar->value = min; + + /* Update bounds */ + scrollbar->min = min; + scrollbar->max = max; + + /* Update box position and size */ + __update_box(scrollbar); + +} + +void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, + int value) { + + /* Fit value within bounds */ + if (value > scrollbar->max) + value = scrollbar->max; + else if (value < scrollbar->min) + value = scrollbar->min; + + /* Update value */ + scrollbar->value = value; + + /* Update box position and size */ + __update_box(scrollbar); + +} + +void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, + int parent_width, int parent_height, int visible_area) { + + guac_socket* socket = scrollbar->client->socket; + + /* Calculate container position and dimensions */ + int container_x = parent_width - GUAC_TERMINAL_SCROLLBAR_WIDTH; + int container_y = 0; + int container_width = GUAC_TERMINAL_SCROLLBAR_WIDTH; + int container_height = parent_height; + + /* Reposition container relative to parent dimensions */ + guac_protocol_send_move(socket, + scrollbar->container, scrollbar->parent, + container_x, container_y, 0); + + /* Resize to fit within parent */ + guac_protocol_send_size(socket, scrollbar->container, + container_width, container_height); + + /* Assign new dimensions */ + scrollbar->parent_width = parent_width; + scrollbar->parent_height = parent_height; + scrollbar->visible_area = visible_area; + + /* Update box position and size */ + __update_box(scrollbar); } diff --git a/src/terminal/scrollbar.h b/src/terminal/scrollbar.h index 614a93be..2fc1cce0 100644 --- a/src/terminal/scrollbar.h +++ b/src/terminal/scrollbar.h @@ -91,6 +91,11 @@ typedef struct guac_terminal_scrollbar { */ int max; + /** + * The size of the visible area, in the same units as min and max. + */ + int visible_area; + /** * The current scroll value. */ @@ -119,11 +124,17 @@ typedef struct guac_terminal_scrollbar { * @param parent_height * The height of the parent layer, in pixels. * + * @param visible_area + * The amount of scrollable data that can be shown within the parent layer + * at any given time. This value uses the same units as min, max, and the + * current scroll value. + * * @return * A newly allocated scrollbar. */ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, - const guac_layer* parent, int parent_width, int parent_height); + const guac_layer* parent, int parent_width, int parent_height, + int visible_area); /** * Frees the given scrollbar. @@ -186,8 +197,13 @@ void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, * * @param parent_height * The new height of the parent layer, in pixels. + * + * @param visible_area + * The amount of scrollable data that can be shown within the parent layer + * at any given time. This value uses the same units as min, max, and the + * current scroll value. */ void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, - int parent_width, int parent_height); + int parent_width, int parent_height, int visible_area); #endif diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index a1a9ebfd..0f62cfad 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -167,6 +167,10 @@ void guac_terminal_reset(guac_terminal* term) { term->scroll_end = term->term_height - 1; term->scroll_offset = 0; + /* Reset scrollbar bounds */ + guac_terminal_scrollbar_set_bounds(term->scrollbar, term->term_height - term->buffer->length, 0); + guac_terminal_scrollbar_set_value(term->scrollbar, -term->scroll_offset); + /* Reset flags */ term->text_selected = false; term->application_cursor_keys = false; @@ -251,6 +255,10 @@ guac_terminal* guac_terminal_create(guac_client* client, guac_terminal_display_resize(term->display, term->term_width, term->term_height); + /* Allocate scrollbar */ + term->scrollbar = guac_terminal_scrollbar_alloc(term->client, + GUAC_DEFAULT_LAYER, width, height, term->term_height); + /* Init terminal */ guac_terminal_reset(term); @@ -269,10 +277,6 @@ guac_terminal* guac_terminal_create(guac_client* client, /* Allocate clipboard */ term->clipboard = guac_common_clipboard_alloc(GUAC_TERMINAL_CLIPBOARD_MAX_LENGTH); - /* Allocate scrollbar */ - term->scrollbar = guac_terminal_scrollbar_alloc(term->client, - GUAC_DEFAULT_LAYER, width, height); - return term; } @@ -524,6 +528,9 @@ int guac_terminal_scroll_up(guac_terminal* term, if (term->buffer->length > term->buffer->available) term->buffer->length = term->buffer->available; + /* Reset scrollbar bounds */ + guac_terminal_scrollbar_set_bounds(term->scrollbar, term->term_height - term->buffer->length, 0); + /* Update cursor location if within region */ if (term->visible_cursor_row >= start_row && term->visible_cursor_row <= end_row) @@ -639,6 +646,7 @@ void guac_terminal_scroll_display_down(guac_terminal* terminal, /* Advance by scroll amount */ terminal->scroll_offset -= scroll_amount; + guac_terminal_scrollbar_set_value(terminal->scrollbar, -terminal->scroll_offset); /* Get row range */ end_row = terminal->term_height - terminal->scroll_offset - 1; @@ -703,6 +711,7 @@ void guac_terminal_scroll_display_up(guac_terminal* terminal, /* Advance by scroll amount */ terminal->scroll_offset += scroll_amount; + guac_terminal_scrollbar_set_value(terminal->scrollbar, -terminal->scroll_offset); /* Get row range */ start_row = -terminal->scroll_offset; @@ -1080,6 +1089,7 @@ static void __guac_terminal_resize(guac_terminal* term, int width, int height) { if (term->scroll_offset >= shift_amount) { term->scroll_offset -= shift_amount; + guac_terminal_scrollbar_set_value(term->scrollbar, -term->scroll_offset); /* Draw characters from scroll at bottom */ __guac_terminal_redraw_rect(term, term->term_height, 0, term->term_height + shift_amount - 1, width-1); @@ -1095,6 +1105,7 @@ static void __guac_terminal_resize(guac_terminal* term, int width, int height) { /* Update shift_amount and scroll based on new rows */ shift_amount -= term->scroll_offset; term->scroll_offset = 0; + guac_terminal_scrollbar_set_value(term->scrollbar, -term->scroll_offset); /* If anything remains, move screen as necessary */ if (shift_amount > 0) { @@ -1139,7 +1150,8 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) { guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, width, height); /* Notify scrollbar of resize */ - guac_terminal_scrollbar_parent_resized(terminal->scrollbar, width, height); + guac_terminal_scrollbar_parent_resized(terminal->scrollbar, width, height, rows); + guac_terminal_scrollbar_set_bounds(terminal->scrollbar, rows - terminal->buffer->length, 0); /* Resize terminal if row/column dimensions have changed */ if (columns != terminal->term_width || rows != terminal->term_height) {