From accf188e7c84ee627d5e4cfe12c141e929699830 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sun, 24 Jan 2021 15:46:08 -0500 Subject: scroll file selector when selected goes offscreen --- buffer.c | 17 +++++++++-------- command.c | 4 ++-- config.c | 6 ++++++ ted.cfg | 2 ++ ted.h | 1 + ui.c | 36 +++++++++++++++++++++++++++--------- 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/buffer.c b/buffer.c index db47e2c..cc97e19 100644 --- a/buffer.c +++ b/buffer.c @@ -150,7 +150,7 @@ static inline Font *buffer_font(TextBuffer *buffer) { } // Get the settings used for this buffer. -static inline Settings *buffer_settings(TextBuffer *buffer) { +static inline Settings const *buffer_settings(TextBuffer *buffer) { return &buffer->ted->settings; } @@ -845,24 +845,25 @@ static bool buffer_clip_rect(TextBuffer *buffer, Rect *r) { // if the cursor is offscreen, this will scroll to make it onscreen. static void buffer_scroll_to_cursor(TextBuffer *buffer) { + Settings const *settings = buffer_settings(buffer); i64 cursor_line = buffer->cursor_pos.line; i64 cursor_col = buffer_index_to_column(buffer, (u32)cursor_line, buffer->cursor_pos.index); i64 display_lines = buffer_display_lines(buffer); i64 display_cols = buffer_display_cols(buffer); double scroll_x = buffer->scroll_x, scroll_y = buffer->scroll_y; - i64 scroll_padding = 5; + i64 scrolloff = settings->scrolloff; // scroll left if cursor is off screen in that direction - double max_scroll_x = (double)(cursor_col - scroll_padding); + double max_scroll_x = (double)(cursor_col - scrolloff); scroll_x = mind(scroll_x, max_scroll_x); // scroll right - double min_scroll_x = (double)(cursor_col - display_cols + scroll_padding); + double min_scroll_x = (double)(cursor_col - display_cols + scrolloff); scroll_x = maxd(scroll_x, min_scroll_x); // scroll up - double max_scroll_y = (double)(cursor_line - scroll_padding); + double max_scroll_y = (double)(cursor_line - scrolloff); scroll_y = mind(scroll_y, max_scroll_y); // scroll down - double min_scroll_y = (double)(cursor_line - display_lines + scroll_padding); + double min_scroll_y = (double)(cursor_line - display_lines + scrolloff); scroll_y = maxd(scroll_y, min_scroll_y); buffer->scroll_x = scroll_x; @@ -1718,8 +1719,8 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) { float header_height = char_height; Ted *ted = buffer->ted; - Settings *settings = buffer_settings(buffer); - u32 *colors = settings->colors; + Settings const *settings = buffer_settings(buffer); + u32 const *colors = settings->colors; float border_thickness = settings->border_thickness; diff --git a/command.c b/command.c index 40636b6..74a624a 100644 --- a/command.c +++ b/command.c @@ -38,11 +38,11 @@ void command_execute(Ted *ted, Command c, i64 argument) { if (buffer) buffer_cursor_move_right(buffer, argument); break; case CMD_UP: - if (file_selector->open) file_selector_up(file_selector, argument); + if (file_selector->open) file_selector_up(ted, file_selector, argument); else if (buffer) buffer_cursor_move_up(buffer, argument); break; case CMD_DOWN: - if (file_selector->open) file_selector_down(file_selector, argument); + if (file_selector->open) file_selector_down(ted, file_selector, argument); else if (buffer) buffer_cursor_move_down(buffer, argument); break; case CMD_SELECT_LEFT: diff --git a/config.c b/config.c index 9a2bed8..39a5d80 100644 --- a/config.c +++ b/config.c @@ -312,6 +312,12 @@ void config_read(Ted *ted, char const *filename) { } else { config_err(cfg, "Invalid padding: %s.", value); } + } else if (streq(key, "scrolloff")) { + if (is_integer && integer >= 1 && integer < 100) { + settings->scrolloff = (u8)integer; + } else { + config_err(cfg, "Invalid scrolloff: %s.", value); + } } else { config_err(cfg, "Unrecognized core setting: %s.", key); } diff --git a/ted.cfg b/ted.cfg index a28424e..623e914 100644 --- a/ted.cfg +++ b/ted.cfg @@ -6,6 +6,8 @@ cursor-width = 1 # set -off to 0 to disable blinking cursor-blink-time-on = 0.5 cursor-blink-time-off = 0.3 +# amount of scroll "padding" (minimum number of lines below the cursor will the bottom of the screen be) +scrolloff = 5 # if you do a bunch of typing, then undo, it will generally # undo the past this many seconds of editing. undo-save-time = 6 diff --git a/ted.h b/ted.h index f1374b3..16fb131 100644 --- a/ted.h +++ b/ted.h @@ -13,6 +13,7 @@ typedef struct { u8 undo_save_time; u8 border_thickness; u8 padding; + u8 scrolloff; } Settings; #define SCANCODE_COUNT 0x120 // SDL scancodes should be less than this value. diff --git a/ui.c b/ui.c index 8184ecd..8f90bbb 100644 --- a/ui.c +++ b/ui.c @@ -12,6 +12,28 @@ static float file_selector_entries_start_y(Ted const *ted, FileSelector const *f + char_height * 1.5f; // make room for line buffer } +// number of file entries that can be displayed on the screen +static u32 file_selector_n_display_entries(Ted const *ted, FileSelector const *fs) { + float char_height = text_font_char_height(ted->font); + float entries_h = rect_y2(fs->bounds) - file_selector_entries_start_y(ted, fs); + return (u32)(entries_h / char_height); +} + +static void file_selector_clamp_scroll(Ted const *ted, FileSelector *fs) { + float max_scroll = (float)fs->n_entries - (float)file_selector_n_display_entries(ted, fs); + if (max_scroll < 0) max_scroll = 0; + fs->scroll = clampf(fs->scroll, 0, max_scroll); +} + +static void file_selector_scroll_to_selected(Ted const *ted, FileSelector *fs) { + u32 n_display_entries = file_selector_n_display_entries(ted, fs); + float scrolloff = ted->settings.scrolloff; + float min_scroll = (float)fs->selected - ((float)n_display_entries - scrolloff); + float max_scroll = (float)fs->selected - scrolloff; + fs->scroll = clampf(fs->scroll, min_scroll, max_scroll); + file_selector_clamp_scroll(ted, fs); +} + // where is the ith entry in the file selector on the screen? // returns false if it's completely offscreen static bool file_selector_entry_pos(Ted const *ted, FileSelector const *fs, @@ -41,16 +63,18 @@ static void file_selector_free(FileSelector *fs) { memset(fs, 0, sizeof *fs); } -static void file_selector_up(FileSelector *fs, i64 n) { +static void file_selector_up(Ted const *ted, FileSelector *fs, i64 n) { i64 selected = fs->selected - n; selected = mod_i64(selected, fs->n_entries); fs->selected = (u32)selected; + file_selector_scroll_to_selected(ted, fs); } -static void file_selector_down(FileSelector *fs, i64 n) { +static void file_selector_down(Ted const *ted, FileSelector *fs, i64 n) { i64 selected = fs->selected + n; selected = mod_i64(selected, fs->n_entries); fs->selected = (u32)selected; + file_selector_scroll_to_selected(ted, fs); } static int qsort_file_entry_cmp(void const *av, void const *bv, void *search_termv) { @@ -351,13 +375,7 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { // apply scroll float scroll_speed = 2.5f; fs->scroll += scroll_speed * (float)ted->scroll_total_y; - // clamp scroll - float char_height = text_font_char_height(ted->font); - float entries_h = rect_y2(fs->bounds) - file_selector_entries_start_y(ted, fs); - u32 n_display_entries = (u32)(entries_h / char_height); - float max_scroll = (float)fs->n_entries - (float)n_display_entries; - if (max_scroll < 0) max_scroll = 0; - fs->scroll = clampf(fs->scroll, 0, max_scroll); + file_selector_clamp_scroll(ted, fs); free(search_term); return NULL; -- cgit v1.2.3