diff options
Diffstat (limited to 'ui.c')
-rw-r--r-- | ui.c | 248 |
1 files changed, 123 insertions, 125 deletions
@@ -2,50 +2,119 @@ #include <fcntl.h> #endif -static float file_selector_entries_start_y(Ted const *ted, FileSelector const *fs) { - Rect bounds = fs->bounds; - float padding = ted->settings.padding; - float char_height = text_font_char_height(ted->font); - return bounds.pos.y - + char_height * 0.75f + padding // make room for cwd - + char_height * 1.25f + padding; // make room for line buffer +static float selector_entries_start_y(Ted const *ted, Selector const *s) { + (void)ted; + return s->bounds.pos.y; } -// number of file entries that can be displayed on the screen -static u32 file_selector_n_display_entries(Ted const *ted, FileSelector const *fs) { +// number of entries that can be displayed on the screen +static u32 selector_n_display_entries(Ted const *ted, Selector const *s) { float char_height = text_font_char_height(ted->font); - float entries_h = rect_y2(fs->bounds) - file_selector_entries_start_y(ted, fs); + float entries_h = rect_y2(s->bounds) - selector_entries_start_y(ted, s); 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); +static void selector_clamp_scroll(Ted const *ted, Selector *s) { + float max_scroll = (float)s->n_entries - (float)selector_n_display_entries(ted, s); if (max_scroll < 0) max_scroll = 0; - fs->scroll = clampf(fs->scroll, 0, max_scroll); + s->scroll = clampf(s->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); +static void selector_scroll_to_cursor(Ted const *ted, Selector *s) { + u32 n_display_entries = selector_n_display_entries(ted, s); 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); + float min_scroll = (float)s->cursor - ((float)n_display_entries - scrolloff); + float max_scroll = (float)s->cursor - scrolloff; + s->scroll = clampf(s->scroll, min_scroll, max_scroll); + selector_clamp_scroll(ted, s); } -// where is the ith entry in the file selector on the screen? +// where is the ith entry in the selector on the screen? // returns false if it's completely offscreen -static bool file_selector_entry_pos(Ted const *ted, FileSelector const *fs, - u32 i, Rect *r) { - Rect bounds = fs->bounds; +static bool selector_entry_pos(Ted const *ted, Selector const *s, u32 i, Rect *r) { + Rect bounds = s->bounds; float char_height = text_font_char_height(ted->font); - *r = rect(V2(bounds.pos.x, file_selector_entries_start_y(ted, fs) - - char_height * fs->scroll + *r = rect(V2(bounds.pos.x, selector_entries_start_y(ted, s) + - char_height * s->scroll + char_height * (float)i), V2(bounds.size.x, char_height)); return rect_clip_to_rect(r, bounds); } +static void selector_up(Ted const *ted, Selector *s, i64 n) { + if (!s->enable_cursor || s->n_entries == 0) { + // can't do anything + return; + } + s->cursor = (u32)mod_i64(s->cursor - n, s->n_entries); + selector_scroll_to_cursor(ted, s); +} + +static void selector_down(Ted const *ted, Selector *s, i64 n) { + selector_up(ted, s, -n); +} + +// returns index of entry selected, or -1 for none +static int selector_update(Ted *ted, Selector *s) { + int ret = -1; + for (u32 i = 0; i < s->n_entries; ++i) { + // check if this entry was clicked on + Rect entry_rect; + if (selector_entry_pos(ted, s, i, &entry_rect)) { + for (uint c = 0; c < ted->nmouse_clicks[SDL_BUTTON_LEFT]; ++c) { + if (rect_contains_point(entry_rect, ted->mouse_clicks[SDL_BUTTON_LEFT][c])) { + // this option was selected + ret = (int)i; + } + } + } + } + // apply scroll + float scroll_speed = 2.5f; + s->scroll += scroll_speed * (float)ted->scroll_total_y; + + return ret; +} + +static void selector_render(Ted *ted, Selector *s) { + Settings const *settings = &ted->settings; + u32 const *colors = settings->colors; + Font *font = ted->font; + + Rect bounds = s->bounds; + + for (u32 i = 0; i < s->n_entries; ++i) { + // highlight entry user is hovering over/selecting + Rect entry_rect; + if (selector_entry_pos(ted, s, i, &entry_rect)) { + rect_clip_to_rect(&entry_rect, bounds); + if (rect_contains_point(entry_rect, ted->mouse_pos) || (s->enable_cursor && s->cursor == i)) { + // highlight it + gl_geometry_rect(entry_rect, colors[COLOR_MENU_HL]); + } + } + } + gl_geometry_draw(); + + TextRenderState text_state = text_render_state_default; + rect_coords(bounds, &text_state.min_x, &text_state.min_y, &text_state.max_x, &text_state.max_y); + text_state.render = true; + + // render entries themselves + SelectorEntry *entries = s->entries; + for (u32 i = 0; i < s->n_entries; ++i) { + Rect r; + if (selector_entry_pos(ted, s, i, &r)) { + float x = r.pos.x, y = r.pos.y; + text_state.x = x; text_state.y = y; + rgba_u32_to_floats(entries[i].color, text_state.color); + text_utf8_with_state(font, &text_state, entries[i].name); + } + } + text_render(font); +} + + // clear the entries in the file selector static void file_selector_clear_entries(FileSelector *fs) { for (u32 i = 0; i < fs->n_entries; ++i) { @@ -53,8 +122,9 @@ static void file_selector_clear_entries(FileSelector *fs) { free(fs->entries[i].path); } free(fs->entries); + arr_free(fs->sel.entries); fs->entries = NULL; - fs->n_entries = 0; + fs->n_entries = fs->sel.n_entries = 0; } // returns true if there are any directory entries @@ -72,19 +142,6 @@ static void file_selector_free(FileSelector *fs) { memset(fs, 0, sizeof *fs); } -static void file_selector_up(Ted const *ted, FileSelector *fs, i64 n) { - if (fs->n_entries == 0) { - // can't do anything - return; - } - fs->selected = (u32)mod_i64(fs->selected - n, fs->n_entries); - file_selector_scroll_to_selected(ted, fs); -} - -static void file_selector_down(Ted const *ted, FileSelector *fs, i64 n) { - file_selector_up(ted, fs, -n); -} - static int qsort_file_entry_cmp(void *search_termv, void const *av, void const *bv) { char const *search_term = search_termv; FileEntry const *a = av, *b = bv; @@ -218,16 +275,14 @@ static Status file_selector_cd_(Ted const *ted, FileSelector *fs, char const *pa // other members of ALL_PATH_SEPARATORS // returns false if this path doesn't exist or isn't a directory static bool file_selector_cd(Ted const *ted, FileSelector *fs, char const *path) { - fs->selected = 0; - fs->scroll = 0; + fs->sel.cursor = 0; + fs->sel.scroll = 0; return file_selector_cd_(ted, fs, path, 0); } // returns the name of the selected file, or NULL // if none was selected. the returned pointer should be freed. static char *file_selector_update(Ted *ted, FileSelector *fs) { - fs->open = true; - TextBuffer *line_buffer = &ted->line_buffer; String32 search_term32 = buffer_get_line(line_buffer, 0); char *const cwd = fs->cwd; @@ -273,36 +328,8 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { char *search_term = search_term32.len ? str32_to_utf8_cstr(search_term32) : NULL; - for (u32 i = 0; i < fs->n_entries; ++i) { - Rect r = {0}; - FileEntry *entry = &fs->entries[i]; - char *name = entry->name, *path = entry->path; - FsType type = entry->type; - // check if this entry was clicked on - if (file_selector_entry_pos(ted, fs, i, &r)) { - for (u32 c = 0; c < ted->nmouse_clicks[SDL_BUTTON_LEFT]; ++c) { - if (rect_contains_point(r, ted->mouse_clicks[SDL_BUTTON_LEFT][c])) { - // this option was selected - switch (type) { - case FS_FILE: - free(search_term); - if (path) return str_dup(path); - break; - case FS_DIRECTORY: - file_selector_cd(ted, fs, name); - buffer_clear(line_buffer); // clear search term - break; - default: break; - } - } - } - } - - } - - bool submitted = fs->submitted; - fs->submitted = false; + bool submitted = ted->line_buffer_submitted; // user pressed enter in search bar if (submitted) { @@ -313,8 +340,8 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { free(search_term); return str_dup(path); } else { - if (fs->selected < fs->n_entries) { - FileEntry *entry = &fs->entries[fs->selected]; + if (fs->sel.cursor < fs->n_entries) { + FileEntry *entry = &fs->entries[fs->sel.cursor]; switch (entry->type) { case FS_FILE: free(search_term); @@ -373,7 +400,7 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { FileEntry *entries = ted_calloc(ted, nfiles, sizeof *entries); if (entries) { fs->n_entries = nfiles; - if (fs->selected >= fs->n_entries) fs->selected = nfiles - 1; + if (fs->sel.cursor >= fs->n_entries) fs->sel.cursor = nfiles - 1; fs->entries = entries; for (u32 i = 0; i < nfiles; ++i) { char *name = files[i]; @@ -401,11 +428,6 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { ted_seterr(ted, "Couldn't list directory '%s'.", cwd); } - // apply scroll - float scroll_speed = 2.5f; - fs->scroll += scroll_speed * (float)ted->scroll_total_y; - file_selector_clamp_scroll(ted, fs); - free(search_term); return NULL; } @@ -414,8 +436,6 @@ static void file_selector_render(Ted *ted, FileSelector *fs) { Settings const *settings = &ted->settings; u32 const *colors = settings->colors; Rect bounds = fs->bounds; - u32 n_entries = fs->n_entries; - FileEntry const *entries = fs->entries; Font *font = ted->font; float padding = settings->padding; float char_height = text_font_char_height(font); @@ -431,52 +451,30 @@ static void file_selector_render(Ted *ted, FileSelector *fs) { buffer_render(&ted->line_buffer, rect4(x1, y1, x2, y1 + line_buffer_height)); y1 += line_buffer_height; - - Rect text_bounds = rect4(x1, y1, x2, y2); - for (u32 i = 0; i < n_entries; ++i) { - // highlight entry user is hovering over/selecting - Rect r; - if (file_selector_entry_pos(ted, fs, i, &r)) { - rect_clip_to_rect(&r, text_bounds); - if (rect_contains_point(r, ted->mouse_pos) || - ((!fs->create_menu || buffer_empty(&ted->line_buffer)) // only highlight selected for create menus if there is no search term (because that will be the name of the file) - && fs->selected == i)) { - gl_geometry_rect(r, colors[COLOR_MENU_HL]); - } + // render selector + Selector *sel = &fs->sel; + sel->bounds = rect4(x1, y1, x2, y2); // selector takes up remaining space + arr_clear(sel->entries); + for (u32 i = 0; i < fs->n_entries; ++i) { + ColorSetting color = 0; + switch (fs->entries[i].type) { + case FS_FILE: + color = COLOR_TEXT; + break; + case FS_DIRECTORY: + color = COLOR_TEXT_FOLDER; + break; + default: + color = COLOR_TEXT_OTHER; + break; } + SelectorEntry entry = {.name = fs->entries[i].name, .color = colors[color]}; + arr_add(sel->entries, entry); } - gl_geometry_draw(); - - TextRenderState text_state = text_render_state_default; - text_state.min_x = x1; - text_state.max_x = x2; - text_state.min_y = y1; - text_state.max_y = y2; - text_state.render = true; + if (sel->entries) + sel->n_entries = fs->n_entries; - // render file names themselves - for (u32 i = 0; i < n_entries; ++i) { - Rect r; - if (file_selector_entry_pos(ted, fs, i, &r)) { - float x = r.pos.x, y = r.pos.y; - ColorSetting color = 0; - switch (entries[i].type) { - case FS_FILE: - color = COLOR_TEXT; - break; - case FS_DIRECTORY: - color = COLOR_TEXT_FOLDER; - break; - default: - color = COLOR_TEXT_OTHER; - break; - } - text_state.x = x; text_state.y = y; - rgba_u32_to_floats(colors[color], text_state.color); - text_utf8_with_state(font, &text_state, entries[i].name); - } - } - text_render(font); + selector_render(ted, sel); } static void button_render(Ted *ted, Rect button, char const *text, u32 color) { |