summaryrefslogtreecommitdiff
path: root/ui.c
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-02-21 12:40:26 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-02-21 12:40:26 -0500
commit617907fb4731d67f6e7aca17b9dd7881f2093aad (patch)
treede7378592c0ccd7d37a08cab05dfb4092efcd745 /ui.c
parent34fa190c3d490dd8cfec37d27bc03182f2a725a2 (diff)
started to generalize selector code
Diffstat (limited to 'ui.c')
-rw-r--r--ui.c248
1 files changed, 123 insertions, 125 deletions
diff --git a/ui.c b/ui.c
index 7640215..39a4dc2 100644
--- a/ui.c
+++ b/ui.c
@@ -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) {