diff options
-rw-r--r-- | buffer.c | 14 | ||||
-rw-r--r-- | find.c | 19 | ||||
-rw-r--r-- | gl.c | 8 | ||||
-rw-r--r-- | ide-autocomplete.c | 24 | ||||
-rw-r--r-- | ide-rename-symbol.c | 4 | ||||
-rw-r--r-- | main.c | 20 | ||||
-rw-r--r-- | menu.c | 16 | ||||
-rw-r--r-- | node.c | 11 | ||||
-rw-r--r-- | os-posix.c | 4 | ||||
-rw-r--r-- | os-win.c | 7 | ||||
-rw-r--r-- | os.h | 10 | ||||
-rw-r--r-- | ted-internal.h | 2 | ||||
-rw-r--r-- | text.c | 4 | ||||
-rw-r--r-- | ui.c | 38 | ||||
-rw-r--r-- | util.c | 200 | ||||
-rw-r--r-- | util.h | 226 |
16 files changed, 214 insertions, 393 deletions
@@ -956,7 +956,7 @@ vec2 buffer_pos_to_pixels(TextBuffer *buffer, BufferPos pos) { Font *font = buffer_font(buffer); float x = (float)((double)xoff - buffer->scroll_x * text_font_char_width(font, ' ')) + buffer->x1; float y = (float)((double)line - buffer->scroll_y) * text_font_char_height(font) + buffer->y1; - return Vec2(x, y); + return (vec2){x, y}; } bool buffer_pixels_to_pos(TextBuffer *buffer, vec2 pixel_coords, BufferPos *pos) { @@ -992,7 +992,7 @@ bool buffer_clip_rect(TextBuffer *buffer, Rect *r) { float x1, y1, x2, y2; rect_coords(*r, &x1, &y1, &x2, &y2); if (x1 > buffer->x2 || y1 > buffer->y2 || x2 < buffer->x1 || y2 < buffer->y1) { - r->pos = r->size = Vec2(0, 0); + *r = (Rect){0}; return false; } if (x1 < buffer->x1) x1 = buffer->x1; @@ -3062,7 +3062,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { x1 += line_number_width; x1 += 2; // a little bit of padding // line separating line numbers from text - gl_geometry_rect(rect(Vec2(x1, y1), Vec2(border_thickness, y2 - y1)), colors[COLOR_LINE_NUMBERS_SEPARATOR]); + gl_geometry_rect(rect_xywh(x1, y1, border_thickness, y2 - y1), colors[COLOR_LINE_NUMBERS_SEPARATOR]); x1 += border_thickness; } @@ -3099,10 +3099,10 @@ void buffer_render(TextBuffer *buffer, Rect r) { // get screen coordinates of cursor vec2 cursor_display_pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos); // the rectangle that the cursor is rendered as - Rect cursor_rect = rect(cursor_display_pos, Vec2(settings->cursor_width, char_height)); + Rect cursor_rect = rect(cursor_display_pos, (vec2){settings->cursor_width, char_height}); if (!buffer->is_line_buffer) { // highlight line cursor is on - Rect hl_rect = rect(Vec2(x1, cursor_display_pos.y), Vec2(x2-x1-1, char_height)); + Rect hl_rect = rect_xywh(x1, cursor_display_pos.y, x2-x1-1, char_height); buffer_clip_rect(buffer, &hl_rect); gl_geometry_rect(hl_rect, colors[COLOR_CURSOR_LINE_BG]); } @@ -3142,7 +3142,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { vec2 hl_p1 = buffer_pos_to_pixels(buffer, p1); Rect hl_rect = rect( hl_p1, - Vec2((float)highlight_width, char_height) + (vec2){(float)highlight_width, char_height} ); buffer_clip_rect(buffer, &hl_rect); gl_geometry_rect(hl_rect, colors[buffer->view_only ? COLOR_VIEW_ONLY_SELECTION_BG : COLOR_SELECTION_BG]); @@ -3242,7 +3242,7 @@ void buffer_render(TextBuffer *buffer, Rect r) { char32_t c = buffer_pos_move_to_matching_bracket(buffer, &pos); if (c) { vec2 gl_pos = buffer_pos_to_pixels(buffer, pos); - Rect hl_rect = rect(gl_pos, Vec2(text_font_char_width(font, c), char_height)); + Rect hl_rect = rect(gl_pos, (vec2){text_font_char_width(font, c), char_height}); if (buffer_clip_rect(buffer, &hl_rect)) { gl_geometry_rect(hl_rect, colors[COLOR_MATCHING_BRACKET_HL]); } @@ -337,7 +337,7 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) { gl_geometry_rect(menu_bounds, colors[COLOR_MENU_BG]); gl_geometry_rect_border(menu_bounds, border_thickness, colors[COLOR_BORDER]); - menu_bounds = rect_shrink(menu_bounds, border_thickness); + rect_shrink(&menu_bounds, border_thickness); float x1, y1, x2, y2; rect_coords(menu_bounds, &x1, &y1, &x2, &y2); @@ -357,15 +357,15 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) { float x = x1, y = y2 - prev_size.y; // compute positions of buttons - Rect button_prev = rect(Vec2(x, y), prev_size); + Rect button_prev = rect((vec2){x, y}, prev_size); x += button_prev.size.x + padding; - Rect button_next = rect(Vec2(x, y), next_size); + Rect button_next = rect((vec2){x, y}, next_size); x += button_next.size.x + padding; - Rect button_replace = rect(Vec2(x, y), replace_size); + Rect button_replace = rect((vec2){x, y}, replace_size); x += button_replace.size.x + padding; - Rect button_replace_find = rect(Vec2(x, y), replace_find_size); + Rect button_replace_find = rect((vec2){x, y}, replace_find_size); x += button_replace_find.size.x + padding; - Rect button_replace_all = rect(Vec2(x, y), replace_all_size); + Rect button_replace_all = rect((vec2){x, y}, replace_all_size); x += button_replace_all.size.x + padding; @@ -402,7 +402,8 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) { Rect find_buffer_bounds = rect4(x1 + text_width + padding, y1, x2 - padding, y1 + line_buffer_height); - Rect replace_buffer_bounds = rect_translate(find_buffer_bounds, Vec2(0, line_buffer_height + padding)); + Rect replace_buffer_bounds = find_buffer_bounds; + replace_buffer_bounds.pos.y += line_buffer_height + padding; button_render(ted, button_prev, prev_text, colors[COLOR_TEXT]); @@ -440,8 +441,8 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) { text_render(font_bold); x = x1; - x += checkbox_frame(ted, &ted->find_case_sensitive, "Case sensitive", Vec2(x, y1)).x + 2*padding; - x += checkbox_frame(ted, &ted->find_regex, "Regular expression", Vec2(x, y1)).x + 2*padding; + x += checkbox_frame(ted, &ted->find_case_sensitive, "Case sensitive", (vec2){x, y1}).x + 2*padding; + x += checkbox_frame(ted, &ted->find_regex, "Regular expression", (vec2){x, y1}).x + 2*padding; buffer_render(find_buffer, find_buffer_bounds); if (replace) buffer_render(replace_buffer, replace_buffer_bounds); @@ -234,10 +234,10 @@ void gl_geometry_rect(Rect r, u32 color_rgba) { return; vec4 color = rgba_u32_to_vec4(color_rgba); - vec2 p1 = r.pos; - vec2 p2 = vec2_add(r.pos, Vec2(0, r.size.y)); - vec2 p3 = vec2_add(r.pos, Vec2(r.size.x, r.size.y)); - vec2 p4 = vec2_add(r.pos, Vec2(r.size.x, 0)); + vec2 p1 = {rect_x1(r), rect_y1(r)}; + vec2 p2 = {rect_x1(r), rect_y2(r)}; + vec2 p3 = {rect_x2(r), rect_y2(r)}; + vec2 p4 = {rect_x2(r), rect_y1(r)}; GLSimpleTriangle triangle = { {p1, color}, diff --git a/ide-autocomplete.c b/ide-autocomplete.c index ec6c83f..42183ff 100644 --- a/ide-autocomplete.c +++ b/ide-autocomplete.c @@ -610,7 +610,7 @@ void autocomplete_frame(Ted *ted) { else start_y += char_height; // put menu below cursor { - Rect menu_rect = rect(Vec2(x, start_y), Vec2(menu_width, menu_height)); + Rect menu_rect = rect_xywh(x, start_y, menu_width, menu_height); gl_geometry_rect(menu_rect, colors[COLOR_AUTOCOMPLETE_BG]); gl_geometry_rect_border(menu_rect, 1, colors[COLOR_AUTOCOMPLETE_BORDER]); ac->rect = menu_rect; @@ -622,7 +622,7 @@ void autocomplete_frame(Ted *ted) { if (ncompletions) { assert(ac->cursor >= 0 && ac->cursor < (i32)ncompletions); // highlight cursor entry - Rect r = rect(Vec2(x, start_y + (float)(ac->cursor - scroll) * char_height), Vec2(menu_width, char_height)); + Rect r = rect_xywh(x, start_y + (float)(ac->cursor - scroll) * char_height, menu_width, char_height); if (rect_contains_point(ac->rect, rect_center(r))) { gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]); document = &ac->completions[ac->suggested[ac->cursor]]; @@ -631,7 +631,7 @@ void autocomplete_frame(Ted *ted) { if (mouse_entry >= 0 && mouse_entry < (i32)ncompletions && rect_contains_point(ac->rect, ted->mouse_pos)) { // highlight moused over entry - Rect r = rect(Vec2(x, start_y + (float)(mouse_entry - scroll) * char_height), Vec2(menu_width, char_height)); + Rect r = rect_xywh(x, start_y + (float)(mouse_entry - scroll) * char_height, menu_width, char_height); gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_HL]); ted->cursor = ted->cursor_hand; document = &ac->completions[ac->suggested[mouse_entry]]; @@ -656,7 +656,7 @@ void autocomplete_frame(Ted *ted) { float doc_x = open_left ? ac->rect.pos.x - doc_width - padding : ac->rect.pos.x + ac->rect.size.x + padding; float doc_y = ac->rect.pos.y; - Rect r = rect(Vec2(doc_x, doc_y), Vec2(doc_width, doc_height)); + Rect r = rect_xywh(doc_x, doc_y, doc_width, doc_height); gl_geometry_rect(r, colors[COLOR_AUTOCOMPLETE_BG]); gl_geometry_rect_border(r, border_thickness, colors[COLOR_AUTOCOMPLETE_BORDER]); @@ -699,8 +699,8 @@ void autocomplete_frame(Ted *ted) { state.x = x; state.y = y; if (i != ncompletions_visible-1) { - gl_geometry_rect(rect(Vec2(x, y + char_height), - Vec2(menu_width, border_thickness)), + gl_geometry_rect(rect_xywh(x, y + char_height, + menu_width, border_thickness), colors[COLOR_AUTOCOMPLETE_BORDER]); } @@ -715,7 +715,7 @@ void autocomplete_frame(Ted *ted) { state.x += padding; text_utf8_with_state(font, &state, icon_text); state.x += padding; - gl_geometry_rect(rect(Vec2((float)state.x, (float)state.y), Vec2(border_thickness, char_height)), + gl_geometry_rect(rect_xywh((float)state.x, (float)state.y, border_thickness, char_height), colors[COLOR_AUTOCOMPLETE_BORDER]); state.x += padding; @@ -753,9 +753,13 @@ void autocomplete_frame(Ted *ted) { } if (completion->deprecated) { - gl_geometry_rect(rect(Vec2(label_x, y + (char_height - border_thickness) * 0.5f), - Vec2((float)state.x - label_x, 1)), - colors[label_color]); + gl_geometry_rect( + rect_xywh( + label_x, y + (char_height - border_thickness) * 0.5f, + (float)state.x - label_x, 1 + ), + colors[label_color] + ); } y += char_height; diff --git a/ide-rename-symbol.c b/ide-rename-symbol.c index 7d1e2ad..6f320ae 100644 --- a/ide-rename-symbol.c +++ b/ide-rename-symbol.c @@ -98,10 +98,10 @@ static void rename_symbol_menu_render(Ted *ted) { gl_geometry_rect(bounds, colors[COLOR_MENU_BG]); gl_geometry_rect_border(bounds, settings->border_thickness, colors[COLOR_BORDER]); gl_geometry_draw(); - bounds = rect_shrink(bounds, padding); + rect_shrink(&bounds, padding); const char *text = "Rename symbol to..."; text_utf8(ted->font_bold, text, bounds.pos.x, bounds.pos.y, colors[COLOR_TEXT]); - bounds = rect_shrink_left(bounds, text_get_size_vec2(ted->font_bold, text).x + padding); + rect_shrink_left(&bounds, text_get_size_vec2(ted->font_bold, text).x + padding); text_render(ted->font_bold); buffer_render(&ted->line_buffer, bounds); @@ -1,4 +1,6 @@ /* +TODO: + - remove rect_translate? FUTURE FEATURES: - autodetect indentation (tabs vs spaces) - robust find (results shouldn't move around when you type things) @@ -89,8 +91,8 @@ static Rect message_box_rect(Ted *ted) { float padding = settings->padding; float window_width = ted->window_width, window_height = ted->window_height; float char_height = text_font_char_height(font); - return rect_centered(Vec2(window_width * 0.5f, window_height * 0.9f), - Vec2(ted_get_menu_width(ted), 3 * char_height + 2 * padding)); + return rect_centered((vec2){window_width * 0.5f, window_height * 0.9f}, + (vec2){ted_get_menu_width(ted), 3 * char_height + 2 * padding}); } #if DEBUG @@ -602,7 +604,7 @@ int main(int argc, char **argv) { { // get mouse position int mouse_x = 0, mouse_y = 0; ted->mouse_state = SDL_GetMouseState(&mouse_x, &mouse_y); - ted->mouse_pos = Vec2((float)mouse_x, (float)mouse_y); + ted->mouse_pos = (vec2){(float)mouse_x, (float)mouse_y}; } for (size_t i = 0; i < arr_count(ted->mouse_clicks); ++i) @@ -663,7 +665,7 @@ int main(int argc, char **argv) { if (button >= arr_count(ted->mouse_clicks)) break; - vec2 pos = Vec2(x, y); + vec2 pos = {x, y}; bool add = true; if (*ted->message_shown) { if (rect_contains_point(message_box_rect(ted), pos)) { @@ -715,7 +717,7 @@ int main(int argc, char **argv) { Uint8 button = event.button.button; if (button >= arr_count(ted->mouse_releases)) break; - vec2 pos = Vec2((float)event.button.x, (float)event.button.y); + vec2 pos = {(float)event.button.x, (float)event.button.y}; MouseRelease release = { .pos = pos }; @@ -732,7 +734,7 @@ int main(int argc, char **argv) { BufferPos pos = {0}; // drag to select // we don't check the return value here, because it's okay to drag off the screen. - buffer_pixels_to_pos(ted->drag_buffer, Vec2(x, y), &pos); + buffer_pixels_to_pos(ted->drag_buffer, (vec2){x, y}, &pos); buffer_select_to_pos(ted->drag_buffer, pos); } hover_reset_timer(ted); @@ -784,7 +786,7 @@ int main(int argc, char **argv) { { int mx = 0, my = 0; ted->mouse_state = SDL_GetMouseState(&mx, &my); - ted->mouse_pos = Vec2((float)mx, (float)my); + ted->mouse_pos = (vec2){(float)mx, (float)my}; } // default to arrow cursor ted->cursor = ted->cursor_arrow; @@ -1102,8 +1104,8 @@ int main(int argc, char **argv) { const char *text = "Recording macro..."; vec2 size = text_get_size_vec2(font_bold, text); Rect r = { - .pos = vec2_sub(Vec2(window_width - 3 * padding, window_height - 3 * padding), size), - .size = vec2_add(size, Vec2(padding, padding)), + .pos = vec2_sub((vec2){window_width - 3 * padding, window_height - 3 * padding}, size), + .size = vec2_add(size, (vec2){padding, padding}), }; gl_geometry_rect(r, bg_color); Rect full_screen = { @@ -64,7 +64,7 @@ void menu_open_with_context(Ted *ted, const char *menu_name, void *context) { ted->menu_context = context; TextBuffer *prev_buf = ted->prev_active_buffer = ted->active_buffer; if (prev_buf) - ted->prev_active_buffer_scroll = Vec2d(prev_buf->scroll_x, prev_buf->scroll_y); + ted->prev_active_buffer_scroll = (dvec2) {prev_buf->scroll_x, prev_buf->scroll_y}; ted_switch_to_buffer(ted, NULL); *ted->warn_overwrite = 0; // clear warn_overwrite @@ -102,9 +102,9 @@ Rect selection_menu_render_bg(Ted *ted) { const float padding = settings->padding; const u32 *colors = settings->colors; const float window_width = ted->window_width, window_height = ted->window_height; - Rect bounds = rect( - Vec2(window_width * 0.5f - 0.5f * menu_width, padding), - Vec2(menu_width, window_height - 2 * padding) + Rect bounds = rect_xywh( + window_width * 0.5f - 0.5f * menu_width, padding, + menu_width, window_height - 2 * padding ); float x1, y1, x2, y2; @@ -128,7 +128,7 @@ void menu_render(Ted *ted) { const float window_width = ted->window_width, window_height = ted->window_height; const MenuInfo *info = &ted->all_menus[ted->menu_open_idx]; // render backdrop - gl_geometry_rect(rect(Vec2(0, 0), Vec2(window_width, window_height)), colors[COLOR_MENU_BACKDROP]); + gl_geometry_rect(rect_xywh(0, 0, window_width, window_height), colors[COLOR_MENU_BACKDROP]); gl_geometry_draw(); if (info->render) @@ -477,7 +477,7 @@ static void goto_line_menu_render(Ted *ted) { Font *font_bold = ted->font_bold; float menu_height = ted_line_buffer_height(ted) + 2 * padding; - Rect r = rect(Vec2(padding, window_height - menu_height - padding), Vec2(window_width - 2 * padding, menu_height)); + Rect r = rect_xywh(padding, window_height - menu_height - padding, window_width - 2 * padding, menu_height); gl_geometry_rect(r, colors[COLOR_MENU_BG]); gl_geometry_rect_border(r, settings->border_thickness, colors[COLOR_BORDER]); const char *text = "Go to line..."; @@ -535,10 +535,10 @@ static void shell_menu_render(Ted *ted) { gl_geometry_rect(bounds, colors[COLOR_MENU_BG]); gl_geometry_rect_border(bounds, settings->border_thickness, colors[COLOR_BORDER]); gl_geometry_draw(); - bounds = rect_shrink(bounds, padding); + rect_shrink(&bounds, padding); const char *text = "Run"; text_utf8(ted->font_bold, text, bounds.pos.x, bounds.pos.y, colors[COLOR_TEXT]); - bounds = rect_shrink_left(bounds, text_get_size_vec2(ted->font_bold, text).x + padding); + rect_shrink_left(&bounds, text_get_size_vec2(ted->font_bold, text).x + padding); text_render(ted->font_bold); buffer_render(&ted->line_buffer, bounds); } @@ -295,7 +295,7 @@ void node_frame(Ted *ted, Node *node, Rect r) { TextBuffer *buffer = &ted->buffers[node->tabs[i]]; char tab_title[256]; const char *filename = buffer_display_filename(buffer); - Rect tab_rect = rect(Vec2(r.pos.x + tab_width * i, r.pos.y), Vec2(tab_width, tab_bar_height)); + Rect tab_rect = rect_xywh(r.pos.x + tab_width * i, r.pos.y, tab_width, tab_bar_height); if (i > 0) { // make sure tab borders overlap (i.e. don't double the border thickness between tabs) @@ -310,7 +310,7 @@ void node_frame(Ted *ted, Node *node, Rect r) { // tab border gl_geometry_rect_border(tab_rect, border_thickness, colors[COLOR_BORDER]); - tab_rect = rect_shrink(tab_rect, border_thickness); + rect_shrink(&tab_rect, border_thickness); // tab title { @@ -343,7 +343,8 @@ void node_frame(Ted *ted, Node *node, Rect r) { u16 buffer_index = node->tabs[node->active_tab]; TextBuffer *buffer = &ted->buffers[buffer_index]; assert(ted->buffers_used[buffer_index]); - Rect buffer_rect = rect_translate(r, Vec2(0, tab_bar_height)); + Rect buffer_rect = r; + buffer_rect.pos.y += tab_bar_height; // make sure buffer border and tab border overlap buffer_rect.pos.y -= border_thickness; @@ -378,13 +379,13 @@ void node_frame(Ted *ted, Node *node, Rect r) { r1.size.y = split_pos - padding; r2.pos.y += split_pos + padding; r2.size.y = r.size.y - split_pos - padding; - r_between = rect(Vec2(r.pos.x, r.pos.y + split_pos - padding), Vec2(r.size.x, 2 * padding)); + r_between = rect_xywh(r.pos.x, r.pos.y + split_pos - padding, r.size.x, 2 * padding); } else { float split_pos = r.size.x * node->split_pos; r1.size.x = split_pos - padding; r2.pos.x += split_pos + padding; r2.size.x = r.size.x - split_pos - padding; - r_between = rect(Vec2(r.pos.x + split_pos - padding, r.pos.y), Vec2(2 * padding, r.size.y)); + r_between = rect_xywh(r.pos.x + split_pos - padding, r.pos.y, 2 * padding, r.size.y); } if (rect_contains_point(r_between, ted->mouse_pos)) { ted->cursor = resize_cursor; @@ -408,3 +408,7 @@ bool open_with_default_application(const char *path) { return true; } } + +bool change_directory(const char *path) { + return chdir(path) == 0; +} @@ -414,5 +414,10 @@ int process_check_status(Process **pprocess, ProcessExitInfo *info) { bool open_with_default_application(const char *path) { - todo + todo ShellExecuteW? +} + + +bool change_directory(const char *path) { + return _chdir(path) == 0; } @@ -54,6 +54,12 @@ struct timespec time_get(void); /// sleep for a certain number of nanoseconds void time_sleep_ns(u64 ns); +/// runs xdg-open or equivalent on the given path, which can be a URL. +/// +/// returns `true` on success. +bool open_with_default_application(const char *path); +/// equivalent to POSIX function chdir, but returns `true` on success and `false` on failure. +bool change_directory(const char *path); /// free the entries generated by fs_list_directory. static void fs_dir_entries_free(FsDirectoryEntry **entries) { @@ -155,10 +161,6 @@ int process_check_status(Process **process, ProcessExitInfo *info); /// `*process` will be set to NULL. void process_kill(Process **process); -/// runs xdg-open or equivalent on the given path, which can be a URL. -/// -/// returns `true` on success. -bool open_with_default_application(const char *path); #endif // OS_H_ diff --git a/ted-internal.h b/ted-internal.h index b2f54bf..40d87f8 100644 --- a/ted-internal.h +++ b/ted-internal.h @@ -508,7 +508,7 @@ struct Ted { u32 build_error; /// used by menus to keep track of the scroll position so we can return to it. - vec2d prev_active_buffer_scroll; + dvec2 prev_active_buffer_scroll; SDL_Cursor *cursor_arrow, *cursor_ibeam, *cursor_wait, *cursor_resize_h, *cursor_resize_v, *cursor_hand, *cursor_move; @@ -489,10 +489,10 @@ static vec2 text_render_utf8_internal(Font *font, const char *text, double x, do render_state.y = y; rgba_u32_to_floats(color, render_state.color); text_utf8_with_state(font, &render_state, text); - return Vec2( + return (vec2){ maxf(0.0f, (float)(render_state.x_largest - x)), maxf(0.0f, (float)(render_state.y_largest - y)) - ); + }; } void text_utf8(Font *font, const char *text, double x, double y, u32 color) { @@ -43,10 +43,10 @@ static void selector_scroll_to_cursor(Ted *ted, Selector *s) { static bool selector_entry_pos(Ted *ted, const Selector *s, u32 i, Rect *r) { Rect bounds = s->bounds; float char_height = text_font_char_height(ted->font); - *r = rect(Vec2(bounds.pos.x, selector_entries_start_y(ted, s) + *r = rect_xywh(bounds.pos.x, selector_entries_start_y(ted, s) - char_height * s->scroll - + char_height * (float)i), - Vec2(bounds.size.x, char_height)); + + char_height * (float)i, + bounds.size.x, char_height); return rect_clip_to_rect(r, bounds); } @@ -498,7 +498,7 @@ void file_selector_render(Ted *ted, FileSelector *fs) { if (*fs->title) { text_utf8(font_bold, fs->title, bounds.pos.x, bounds.pos.y, colors[COLOR_TEXT]); - bounds = rect_shrink_top(bounds, text_font_char_height(font_bold) * 0.75f + padding); + rect_shrink_top(&bounds, text_font_char_height(font_bold) * 0.75f + padding); } // current working directory @@ -518,7 +518,7 @@ void file_selector_render(Ted *ted, FileSelector *fs) { state.max_x = rect_x2(bounds); text_utf8_with_state(font, &state, fs->cwd); - bounds = rect_shrink_top(bounds, char_height + padding); + rect_shrink_top(&bounds, char_height + padding); } // render selector @@ -577,23 +577,23 @@ bool button_update(Ted *ted, Rect button) { static void popup_get_rects(Ted const *ted, u32 options, Rect *popup, Rect *button_yes, Rect *button_no, Rect *button_cancel) { float window_width = ted->window_width, window_height = ted->window_height; - *popup = rect_centered(Vec2(window_width * 0.5f, window_height * 0.5f), Vec2(300, 200)); + *popup = rect_centered((vec2){window_width * 0.5f, window_height * 0.5f}, (vec2){300, 200}); float button_height = 30; u16 nbuttons = util_popcount(options); float button_width = popup->size.x / nbuttons; - popup->size = vec2_clamp(popup->size, Vec2(0, 0), Vec2(window_width, window_height)); - Rect r = rect(Vec2(popup->pos.x, rect_y2(*popup) - button_height), Vec2(button_width, button_height)); + popup->size = vec2_clamp(popup->size, (vec2){0, 0}, (vec2){window_width, window_height}); + Rect r = rect_xywh(popup->pos.x, rect_y2(*popup) - button_height, button_width, button_height); if (options & POPUP_YES) { *button_yes = r; - r = rect_translate(r, Vec2(button_width, 0)); + r.pos.x += button_width; } if (options & POPUP_NO) { *button_no = r; - r = rect_translate(r, Vec2(button_width, 0)); + r.pos.x += button_width; } if (options & POPUP_CANCEL) { *button_cancel = r; - r = rect_translate(r, Vec2(button_width, 0)); + r.pos.x += button_width; } } @@ -629,7 +629,7 @@ void popup_render(Ted *ted, u32 options, const char *title, const char *body) { gl_geometry_rect(r, colors[COLOR_MENU_BG]); gl_geometry_rect_border(r, border_thickness, colors[COLOR_BORDER]); // line separating text from body - gl_geometry_rect(rect(Vec2(r.pos.x, y + char_height_bold), Vec2(r.size.x, border_thickness)), colors[COLOR_BORDER]); + gl_geometry_rect(rect_xywh(r.pos.x, y + char_height_bold, r.size.x, border_thickness), colors[COLOR_BORDER]); if (options & POPUP_YES) button_render(ted, button_yes, "Yes", colors[COLOR_YES]); if (options & POPUP_NO) button_render(ted, button_no, "No", colors[COLOR_NO]); @@ -638,7 +638,7 @@ void popup_render(Ted *ted, u32 options, const char *title, const char *body) { // title text vec2 title_size = {0}; text_get_size(font_bold, title, &title_size.x, &title_size.y); - vec2 title_pos = vec2_sub(Vec2(window_width * 0.5f, y), Vec2(title_size.x * 0.5f, 0)); + vec2 title_pos = {(window_width - title_size.x) * 0.5f, y}; text_utf8(font_bold, title, title_pos.x, title_pos.y, colors[COLOR_TEXT]); text_render(font_bold); @@ -668,23 +668,25 @@ vec2 checkbox_frame(Ted *ted, bool *value, const char *label, vec2 pos) { float padding = settings->padding; float border_thickness = settings->border_thickness; - Rect checkbox_rect = rect(pos, Vec2(checkbox_size, checkbox_size)); + Rect checkbox_rect = rect(pos, (vec2){checkbox_size, checkbox_size}); if (ted_clicked_in_rect(ted, checkbox_rect)) { *value = !*value; } - checkbox_rect.pos = vec2_add(checkbox_rect.pos, Vec2(0.5f, 0.5f)); + checkbox_rect.pos = vec2_add(checkbox_rect.pos, (vec2){0.5f, 0.5f}); gl_geometry_rect_border(checkbox_rect, border_thickness, colors[COLOR_TEXT]); if (*value) { - gl_geometry_rect(rect_shrink(checkbox_rect, border_thickness + 2), colors[COLOR_TEXT]); + Rect r = checkbox_rect; + rect_shrink(&r, border_thickness + 2); + gl_geometry_rect(r, colors[COLOR_TEXT]); } - vec2 text_pos = vec2_add(pos, Vec2(checkbox_size + padding * 0.5f, 0)); + vec2 text_pos = vec2_add(pos, (vec2){checkbox_size + padding * 0.5f, 0}); vec2 size = text_get_size_vec2(font, label); text_utf8(font, label, text_pos.x, text_pos.y, colors[COLOR_TEXT]); gl_geometry_draw(); text_render(font); - return vec2_add(size, Vec2(checkbox_size + padding * 0.5f, 0)); + return vec2_add(size, (vec2){checkbox_size + padding * 0.5f, 0}); } @@ -412,6 +412,7 @@ bool path_is_absolute(const char *path) { void path_full(const char *dir, const char *relpath, char *abspath, size_t abspath_size) { assert(abspath_size); assert(dir[0]); + assert(path_is_absolute(dir)); abspath[0] = '\0'; if (path_is_absolute(relpath)) { @@ -478,14 +479,6 @@ bool paths_eq(const char *path1, const char *path2) { #endif } -void change_directory(const char *path) { -#if _WIN32 - _chdir(path); -#else - chdir(path); -#endif -} - bool copy_file(const char *src, const char *dst) { bool success = false; FILE *src_file = fopen(src, "rb"); @@ -512,19 +505,10 @@ bool copy_file(const char *src, const char *dst) { #define MATH_GL 1 #endif -float degrees(float r) { - return r * (180.0f / PIf); -} -float radians(float r) { - return r * (PIf / 180.f); -} - -// map x from the interval [0, 1] to the interval [a, b]. does NOT clamp. float lerpf(float x, float a, float b) { return x * (b-a) + a; } -// opposite of lerp; map x from the interval [a, b] to the interval [0, 1]. does NOT clamp. float normf(float x, float a, float b) { return (x-a) / (b-a); } @@ -644,11 +628,13 @@ i64 max_i64(i64 a, i64 b) { } i64 mod_i64(i64 a, i64 b) { + assert(b > 0); i64 ret = a % b; if (ret < 0) ret += b; return ret; } i32 mod_i32(i32 a, i32 b) { + assert(b > 0); i32 ret = a % b; if (ret < 0) ret += b; return ret; @@ -670,139 +656,67 @@ float sgnf(float x) { return 0; } -float smoothstepf(float x) { - if (x <= 0) return 0; - if (x >= 1) return 1; - return x * x * (3 - 2 * x); -} - -float randf(void) { - return (float)rand() / (float)((ulong)RAND_MAX + 1); -} - -u32 rand_u32(void) { - return ((u32)rand() & 0xfff) - | ((u32)rand() & 0xfff) << 12 - | ((u32)rand() & 0xff) << 24; -} - -float rand_uniform(float from, float to) { - return lerpf(randf(), from, to); -} - -float sigmoidf(float x) { - return 1.0f / (1.0f + expf(-x)); -} - -// returns ⌈x/y⌉ (x/y rounded up) -i32 ceildivi32(i32 x, i32 y) { - if (y < 0) { - // negating both operands doesn't change the answer - x = -x; - y = -y; - } - if (x < 0) { - // truncation is the same as ceiling for negative numbers - return x / y; - } else { - return (x + (y-1)) / y; - } -} - -vec2 Vec2(float x, float y) { - vec2 v; - v.x = x; - v.y = y; - return v; -} - vec2 vec2_add(vec2 a, vec2 b) { - return Vec2(a.x + b.x, a.y + b.y); + return (vec2){a.x + b.x, a.y + b.y}; } vec2 vec2_add_const(vec2 a, float c) { - return Vec2(a.x + c, a.y + c); + return (vec2){a.x + c, a.y + c}; } vec2 vec2_sub(vec2 a, vec2 b) { - return Vec2(a.x - b.x, a.y - b.y); + return (vec2){a.x - b.x, a.y - b.y}; } vec2 vec2_scale(vec2 v, float s) { - return Vec2(v.x * s, v.y * s); + return (vec2){v.x * s, v.y * s}; } vec2 vec2_mul(vec2 a, vec2 b) { - return Vec2(a.x * b.x, a.y * b.y); + return (vec2){a.x * b.x, a.y * b.y}; } vec2 vec2_clamp(vec2 x, vec2 a, vec2 b) { - return Vec2(clampf(x.x, a.x, b.x), clampf(x.y, a.y, b.y)); + return (vec2){clampf(x.x, a.x, b.x), clampf(x.y, a.y, b.y)}; } float vec2_dot(vec2 a, vec2 b) { return a.x * b.x + a.y * b.y; } -float vec2_len(vec2 v) { +float vec2_norm(vec2 v) { return sqrtf(vec2_dot(v, v)); } vec2 vec2_lerp(float x, vec2 a, vec2 b) { - return Vec2(lerpf(x, a.x, b.x), lerpf(x, a.y, b.y)); + return (vec2){lerpf(x, a.x, b.x), lerpf(x, a.y, b.y)}; } // rotate v theta radians counterclockwise vec2 vec2_rotate(vec2 v, float theta) { float c = cosf(theta), s = sinf(theta); - return Vec2( + return (vec2){ c * v.x - s * v.y, s * v.x + c * v.y - ); + }; } vec2 vec2_normalize(vec2 v) { - float len = vec2_len(v); + float len = vec2_norm(v); float mul = len == 0.0f ? 1.0f : 1.0f/len; return vec2_scale(v, mul); } -float vec2_dist(vec2 a, vec2 b) { - return vec2_len(vec2_sub(a, b)); -} - -float vec2_dist_squared(vec2 a, vec2 b) { - vec2 diff = vec2_sub(a, b); - return vec2_dot(diff, diff); +float vec2_distance(vec2 a, vec2 b) { + return vec2_norm(vec2_sub(a, b)); } void vec2_print(vec2 v) { printf("(%f, %f)\n", v.x, v.y); } -vec2 vec2_rand_unit(void) { - float theta = rand_uniform(0, TAUf); - return Vec2(cosf(theta), sinf(theta)); -} - vec2 vec2_polar(float r, float theta) { - return Vec2(r * cosf(theta), r * sinf(theta)); -} - -vec4 Vec4(float x, float y, float z, float w) { - vec4 v; - v.x = x; - v.y = y; - v.z = z; - v.w = w; - return v; -} - -vec2d Vec2d(double x, double y) { - return (vec2d) { - .x = x, - .y = y - }; + return (vec2){r * cosf(theta), r * sinf(theta)}; } void rgba_u32_to_floats(u32 rgba, float floats[4]) { @@ -815,7 +729,7 @@ void rgba_u32_to_floats(u32 rgba, float floats[4]) { vec4 rgba_u32_to_vec4(u32 rgba) { float c[4]; rgba_u32_to_floats(rgba, c); - return Vec4(c[0], c[1], c[2], c[3]); + return (vec4){c[0], c[1], c[2], c[3]}; } u32 rgba_vec4_to_u32(vec4 color) { @@ -825,12 +739,6 @@ u32 rgba_vec4_to_u32(vec4 color) { | (u32)(color.w * 255); } -// returns average of red green and blue components of color -float rgba_brightness(u32 color) { - u8 r = (u8)(color >> 24), g = (u8)(color >> 16), b = (u8)(color >> 8); - return ((float)r+(float)g+(float)b) * (1.0f / 3); -} - bool rect_contains_point_v2(vec2 pos, vec2 size, vec2 point) { float x1 = pos.x, y1 = pos.y, x2 = pos.x + size.x, y2 = pos.y + size.y, x = point.x, y = point.y; @@ -858,13 +766,13 @@ Rect rect_endpoints(vec2 e1, vec2 e2) { Rect rect4(float x1, float y1, float x2, float y2) { assert(x2 >= x1); assert(y2 >= y1); - return rect(Vec2(x1,y1), Vec2(x2-x1, y2-y1)); + return rect_xywh(x1, y1, x2-x1, y2-y1); } Rect rect_xywh(float x, float y, float w, float h) { assert(w >= 0); assert(h >= 0); - return rect(Vec2(x, y), Vec2(w, h)); + return rect((vec2){x, y}, (vec2){w, h}); } Rect rect_centered(vec2 center, vec2 size) { @@ -925,51 +833,45 @@ bool rect_clip_to_rect(Rect *clipped, Rect clipper) { return clipped->size.x > 0 && clipped->size.y > 0; } -Rect rect_shrink(Rect r, float amount) { - r.pos.x += amount; - r.pos.y += amount; - r.size.x -= 2 * amount; - r.size.y -= 2 * amount; - r.size.x = maxf(r.size.x, 0); - r.size.y = maxf(r.size.y, 0); - return r; +void rect_shrink(Rect *r, float amount) { + r->pos.x += amount; + r->pos.y += amount; + r->size.x -= 2 * amount; + r->size.y -= 2 * amount; + r->size.x = maxf(r->size.x, 0); + r->size.y = maxf(r->size.y, 0); } -Rect rect_shrink_left(Rect r, float amount) { - r.pos.x += amount; - r.size.x -= amount; - r.size.x = maxf(r.size.x, 0); - return r; +void rect_shrink_left(Rect *r, float amount) { + r->pos.x += amount; + r->size.x -= amount; + r->size.x = maxf(r->size.x, 0); } -Rect rect_shrink_top(Rect r, float amount) { - r.pos.y += amount; - r.size.y -= amount; - r.size.y = maxf(r.size.y, 0); - return r; +void rect_shrink_top(Rect *r, float amount) { + r->pos.y += amount; + r->size.y -= amount; + r->size.y = maxf(r->size.y, 0); } -Rect rect_shrink_right(Rect r, float amount) { - r.size.x -= amount; - r.size.x = maxf(r.size.x, 0); - return r; +void rect_shrink_right(Rect *r, float amount) { + r->size.x -= amount; + r->size.x = maxf(r->size.x, 0); } -Rect rect_shrink_bottom(Rect r, float amount) { - r.size.y -= amount; - r.size.y = maxf(r.size.y, 0); - return r; +void rect_shrink_bottom(Rect *r, float amount) { + r->size.y -= amount; + r->size.y = maxf(r->size.y, 0); } -Rect rect_grow(Rect r, float amount) { - r.pos.x -= amount; - r.pos.y -= amount; - r.size.x += 2 * amount; - r.size.y += 2 * amount; - return r; +void rect_grow(Rect *r, float amount) { + r->pos.x -= amount; + r->pos.y -= amount; + r->size.x += 2 * amount; + r->size.y += 2 * amount; } -vec4 color_rgba_to_hsva(vec4 rgba) { +static vec4 color_rgba_to_hsva(vec4 rgba) { float R = rgba.x, G = rgba.y, B = rgba.z, A = rgba.w; float M = maxf(R, maxf(G, B)); float m = minf(R, minf(G, B)); @@ -986,10 +888,10 @@ vec4 color_rgba_to_hsva(vec4 rgba) { H *= 60; float V = M; float S = V == 0 ? 0 : C / V; - return Vec4(H, S, V, A); + return (vec4){H, S, V, A}; } -vec4 color_hsva_to_rgba(vec4 hsva) { +static vec4 color_hsva_to_rgba(vec4 hsva) { float H = hsva.x, S = hsva.y, V = hsva.z, A = hsva.w; H /= 60; float C = S * V; @@ -1012,7 +914,7 @@ vec4 color_hsva_to_rgba(vec4 hsva) { R += m; G += m; B += m; - return Vec4(R, G, B, A); + return (vec4){R, G, B, A}; } u32 color_interpolate(float x, u32 color1, u32 color2) { @@ -1041,7 +943,7 @@ u32 color_interpolate(float x, u32 color1, u32 color2) { } h_out = fmodf(h_out, 360); - vec4 c_out = Vec4(h_out, s_out, v_out, a_out); + vec4 c_out = (vec4){h_out, s_out, v_out, a_out}; c_out = color_hsva_to_rgba(c_out); return rgba_vec4_to_u32(c_out); } @@ -20,13 +20,6 @@ #define PIf 3.14159265358979f -#define HALF_PIf 1.5707963267948966f -#define TAUf 6.283185307179586f -#define SQRT2f 1.4142135623730951f -#define HALF_SQRT2f 0.7071067811865476f -#define SQRT3f 1.7320508075688772f -#define HALF_SQRT3f 0.8660254037844386f - typedef struct { float x, y; @@ -36,7 +29,7 @@ typedef struct { } vec4; typedef struct { double x, y; -} vec2d; +} dvec2; typedef struct { vec2 pos, size; @@ -49,19 +42,27 @@ typedef struct { } String32; -/// ctype functions for 32-bit chars. +/// `isword` for 32-bit chars. bool is32_word(char32_t c); +/// `isspace` for 32-bit chars. bool is32_space(char32_t c); +/// `isalpha` for 32-bit chars. bool is32_alpha(char32_t c); +/// `isalnum` for 32-bit chars. bool is32_alnum(char32_t c); +/// `isdigit` for 32-bit chars. bool is32_digit(char32_t c); +/// `isgraph` for 32-bit chars. bool is32_graph(char32_t c); +/// cross-platform `isatty` bool is_a_tty(FILE *out); -/// terminal colors. if `out` is a TTY, these will return the appropriate escape sequences. -/// if `out` is not a TTY, these will return "". +/// returns terminal escape sequence for italics, or `""` if `out` is not a TTY. const char *term_italics(FILE *out); +/// returns terminal escape sequence for bold, or `""` if `out` is not a TTY. const char *term_bold(FILE *out); +/// returns terminal escape sequence for yellow, or `""` if `out` is not a TTY. const char *term_yellow(FILE *out); +/// returns terminal escape sequence to clear, or `""` if `out` is not a TTY. const char *term_clear(FILE *out); /// number of 1 bits in x. u8 util_popcount(u64 x); @@ -119,6 +120,7 @@ bool streq_case_insensitive(const char *a, const char *b); /// function to be passed into qsort for case insensitive sorting int str_qsort_case_insensitive_cmp(const void *av, const void *bv); /// the actual file name part of the path; get rid of the containing directory. +/// /// NOTE: the returned string is part of path, so you don't need to free it or anything. const char *path_filename(const char *path); /// is this an absolute path? @@ -126,12 +128,11 @@ bool path_is_absolute(const char *path); /// assuming `dir` is an absolute path, returns the absolute path of `relpath`, relative to `dir`. void path_full(const char *dir, const char *relpath, char *abspath, size_t abspath_size); /// returns true if the paths are the same. -/// handles the fact that paths are case insensitive on windows and that \ is the same as /. +/// +/// handles the fact that paths are case insensitive on windows and that `\\` is the same as `/`. /// a symbolic link is considered different from the file it points to, as are two hard /// links to the same file. bool paths_eq(const char *path1, const char *path2); -/// equivalent to POSIX function chdir. -void change_directory(const char *path); /// copy file from src to dest /// returns true on success bool copy_file(const char *src, const char *dst); @@ -139,44 +140,68 @@ bool copy_file(const char *src, const char *dst); void qsort_with_context(void *base, size_t nmemb, size_t size, int (*compar)(void *, const void *, const void *), void *arg); -float degrees(float r); -float radians(float r); +/// map x from the interval [0, 1] to the interval [a, b]. does NOT clamp. +/// +/// note that the order is different from the usual convention because i like this order better. float lerpf(float x, float a, float b); +/// opposite of lerp; map x from the interval [a, b] to the interval [0, 1]. does NOT clamp. float normf(float x, float a, float b); +/// clamp `x` to the range [a, b]. float clampf(float x, float a, float b); +/// clamp `x` to the range [a, b]. double clampd(double x, double a, double b); +/// clamp `x` to the range [a, b]. int clampi(int x, int a, int b); +/// clamp `x` to the range [a, b]. i16 clamp_i16(i16 x, i16 a, i16 b); +/// clamp `x` to the range [a, b]. u16 clamp_u16(u16 x, u16 a, u16 b); +/// clamp `x` to the range [a, b]. i32 clamp_i32(i32 x, i32 a, i32 b); +/// clamp `x` to the range [a, b]. u32 clamp_u32(u32 x, u32 a, u32 b); +/// number of digits in the decimal representation `x` u8 ndigits_u64(u64 x); +/// linearly remap `x` from the interval [`from_a`, `from_b`] to the interval [`to_a`, `to_b`] float remapf(float x, float from_a, float from_b, float to_a, float to_b); +/// minimum of `a` and `b` float minf(float a, float b); float maxf(float a, float b); double maxd(double a, double b); +/// minimum of `a` and `b` double mind(double a, double b); +/// minimum of `a` and `b` u32 min_u32(u32 a, u32 b); +/// maximum of `a` and `b` u32 max_u32(u32 a, u32 b); +/// set `a` to the minimum of `a` and `b` and `b` to the maximum. void sort2_u32(u32 *a, u32 *b); +/// minimum of `a` and `b` i32 min_i32(i32 a, i32 b); +/// maximum of `a` and `b` i32 max_i32(i32 a, i32 b); +/// minimum of `a` and `b` u64 min_u64(u64 a, u64 b); +/// maximum of `a` and `b` u64 max_u64(u64 a, u64 b); +/// minimum of `a` and `b` i64 min_i64(i64 a, i64 b); +/// maximum of `a` and `b` i64 max_i64(i64 a, i64 b); +/// returns `a` modulo `b`. for `b > 0`, this will be between `0` and `b - 1`. +/// +/// if `b <= 0`, the return value is unspecified. i64 mod_i64(i64 a, i64 b); +/// returns `a` modulo `b`. for `b > 0`, this will be between `0` and `b - 1`. +/// +/// if `b <= 0`, the return value is unspecified. i32 mod_i32(i32 a, i32 b); +/// absolute value i64 abs_i64(i64 x); +/// `-1` if `x < 0`, `0` if `x == 0`, and `1` if `x > 0` i64 sgn_i64(i64 x); +/// `-1` if `x < 0`, `0` if `x == 0`, and `1` if `x > 0` float sgnf(float x); -float smoothstepf(float x); -float randf(void); -u32 rand_u32(void); -float rand_uniform(float from, float to); -float sigmoidf(float x); -i32 ceildivi32(i32 x, i32 y); -vec2 Vec2(float x, float y); vec2 vec2_add(vec2 a, vec2 b); vec2 vec2_add_const(vec2 a, float c); vec2 vec2_sub(vec2 a, vec2 b); @@ -184,20 +209,16 @@ vec2 vec2_scale(vec2 v, float s); vec2 vec2_mul(vec2 a, vec2 b); vec2 vec2_clamp(vec2 x, vec2 a, vec2 b); float vec2_dot(vec2 a, vec2 b); -float vec2_len(vec2 v); +float vec2_norm(vec2 v); vec2 vec2_lerp(float x, vec2 a, vec2 b); vec2 vec2_rotate(vec2 v, float theta); vec2 vec2_normalize(vec2 v); -float vec2_dist(vec2 a, vec2 b); -float vec2_dist_squared(vec2 a, vec2 b); +float vec2_distance(vec2 a, vec2 b); void vec2_print(vec2 v); -vec2 vec2_rand_unit(void); vec2 vec2_polar(float r, float theta); -vec4 Vec4(float x, float y, float z, float w); void rgba_u32_to_floats(u32 rgba, float floats[4]); vec4 rgba_u32_to_vec4(u32 rgba); u32 rgba_vec4_to_u32(vec4 color); -float rgba_brightness(u32 color); bool rect_contains_point_v2(vec2 pos, vec2 size, vec2 point); bool centered_rect_contains_point(vec2 center, vec2 size, vec2 point); Rect rect(vec2 pos, vec2 size); @@ -209,150 +230,27 @@ vec2 rect_center(Rect r); bool rect_contains_point(Rect r, vec2 point); Rect rect_translate(Rect r, vec2 by); void rect_coords(Rect r, float *x1, float *y1, float *x2, float *y2); -void rect_print(Rect r); -float rects_intersect(Rect r1, Rect r2); -bool rect_clip_to_rect(Rect *clipped, Rect clipper); -/// removes `amount` from all sides of r -Rect rect_shrink(Rect r, float amount); -/// removes `amount` from the left side of r -Rect rect_shrink_left(Rect r, float amount); -/// removes `amount` from the top side of r -Rect rect_shrink_top(Rect r, float amount); -/// removes `amount` from the right side of r -Rect rect_shrink_right(Rect r, float amount); -/// removes `amount` from the bottom side of r -Rect rect_shrink_bottom(Rect r, float amount); -/// adds `amount` to all sides of r -Rect rect_grow(Rect r, float amount); -vec4 color_rgba_to_hsva(vec4 rgba); -vec4 color_hsva_to_rgba(vec4 hsva); -u32 color_interpolate(float x, u32 color1, u32 color2); -int timespec_cmp(struct timespec a, struct timespec b); -bool timespec_eq(struct timespec a, struct timespec b); -struct timespec timespec_max(struct timespec a, struct timespec b); -double timespec_to_seconds(struct timespec ts); -bool is32_word(char32_t c); -bool is32_space(char32_t c); -bool is32_alpha(char32_t c); -bool is32_alnum(char32_t c); -bool is32_digit(char32_t c); -bool is32_graph(char32_t c); -bool is_a_tty(FILE *out); -const char *term_italics(FILE *out); -const char *term_bold(FILE *out); -const char *term_yellow(FILE *out); -const char *term_clear(FILE *out); -u8 util_popcount(u64 x); -u8 util_count_leading_zeroes32(u32 x); -bool util_is_power_of_2(u64 x); -char32_t *util_mem32chr(char32_t *s, char32_t c, size_t n); -const char32_t *util_mem32chr_const(const char32_t *s, char32_t c, size_t n); -bool str_has_prefix(const char *str, const char *prefix); -bool str_has_path_prefix(const char *path, const char *prefix); -bool streq(const char *a, const char *b); -size_t strn_len(const char *src, size_t n); -char *strn_dup(const char *src, size_t n); -char *str_dup(const char *src); -void strn_cat(char *dst, size_t dst_sz, const char *src, size_t src_len); -void str_cat(char *dst, size_t dst_sz, const char *src); -void strn_cpy(char *dst, size_t dst_sz, const char *src, size_t src_len); -void str_cpy(char *dst, size_t dst_sz, const char *src); -char *a_sprintf(const char *fmt, ...); -char *strstr_case_insensitive(const char *haystack, const char *needle); -void print_bytes(const u8 *bytes, size_t n); -int strcmp_case_insensitive(const char *a, const char *b); -int str_qsort_case_insensitive_cmp(const void *av, const void *bv); -int qsort_with_context_cmp(const void *a, const void *b, void *context); -const char *path_filename(const char *path); -bool path_is_absolute(const char *path); -void path_full(const char *dir, const char *relpath, char *abspath, size_t abspath_size); -bool paths_eq(const char *path1, const char *path2); -void change_directory(const char *path); -bool copy_file(const char *src, const char *dst); -float degrees(float r); -float radians(float r); -float lerpf(float x, float a, float b); -float normf(float x, float a, float b); -float clampf(float x, float a, float b); -int clampi(int x, int a, int b); -i16 clamp_i16(i16 x, i16 a, i16 b); -u16 clamp_u16(u16 x, u16 a, u16 b); -i32 clamp_i32(i32 x, i32 a, i32 b); -u32 clamp_u32(u32 x, u32 a, u32 b); -u8 ndigits_u64(u64 x); -float remapf(float x, float from_a, float from_b, float to_a, float to_b); -float minf(float a, float b); -float maxf(float a, float b); -double maxd(double a, double b); -double mind(double a, double b); -u32 min_u32(u32 a, u32 b); -u32 max_u32(u32 a, u32 b); -void sort2_u32(u32 *a, u32 *b); -i32 min_i32(i32 a, i32 b); -i32 max_i32(i32 a, i32 b); -u64 min_u64(u64 a, u64 b); -u64 max_u64(u64 a, u64 b); -i64 min_i64(i64 a, i64 b); -i64 max_i64(i64 a, i64 b); -i64 mod_i64(i64 a, i64 b); -i32 mod_i32(i32 a, i32 b); -i64 abs_i64(i64 x); -i64 sgn_i64(i64 x); -float sgnf(float x); -float smoothstepf(float x); -float randf(void); -float rand_gauss(void); -u32 rand_u32(void); -float rand_uniform(float from, float to); -float sigmoidf(float x); -i32 ceildivi32(i32 x, i32 y); -vec2 Vec2(float x, float y); -vec2 vec2_add(vec2 a, vec2 b); -vec2 vec2_add_const(vec2 a, float c); -vec2 vec2_sub(vec2 a, vec2 b); -vec2 vec2_scale(vec2 v, float s); -vec2 vec2_mul(vec2 a, vec2 b); -vec2 vec2_clamp(vec2 x, vec2 a, vec2 b); -float vec2_dot(vec2 a, vec2 b); -float vec2_len(vec2 v); -vec2 vec2_lerp(float x, vec2 a, vec2 b); -vec2 vec2_rotate(vec2 v, float theta); -vec2 vec2_normalize(vec2 v); -float vec2_dist(vec2 a, vec2 b); -float vec2_dist_squared(vec2 a, vec2 b); -void vec2_print(vec2 v); -vec2 vec2_rand_unit(void); -vec2 vec2_polar(float r, float theta); -vec4 Vec4(float x, float y, float z, float w); -vec2d Vec2d(double x, double y); -void rgba_u32_to_floats(u32 rgba, float floats[4]); -vec4 rgba_u32_to_vec4(u32 rgba); -u32 rgba_vec4_to_u32(vec4 color); -float rgba_brightness(u32 color); -bool rect_contains_point_v2(vec2 pos, vec2 size, vec2 point); -bool centered_rect_contains_point(vec2 center, vec2 size, vec2 point); -Rect rect(vec2 pos, vec2 size); -Rect rect_endpoints(vec2 e1, vec2 e2); -Rect rect4(float x1, float y1, float x2, float y2); -Rect rect_xywh(float x, float y, float w, float h); -Rect rect_centered(vec2 center, vec2 size); float rect_x1(Rect r); float rect_y1(Rect r); float rect_x2(Rect r); float rect_y2(Rect r); float rect_xmid(Rect r); float rect_ymid(Rect r); -vec2 rect_center(Rect r); -bool rect_contains_point(Rect r, vec2 point); -Rect rect_translate(Rect r, vec2 by); -void rect_coords(Rect r, float *x1, float *y1, float *x2, float *y2); void rect_print(Rect r); float rects_intersect(Rect r1, Rect r2); bool rect_clip_to_rect(Rect *clipped, Rect clipper); -Rect rect_shrink(Rect r, float amount); -Rect rect_grow(Rect r, float amount); -vec4 color_rgba_to_hsva(vec4 rgba); -vec4 color_hsva_to_rgba(vec4 hsva); +/// removes `amount` from all sides of r +void rect_shrink(Rect *r, float amount); +/// removes `amount` from the left side of r +void rect_shrink_left(Rect *r, float amount); +/// removes `amount` from the top side of r +void rect_shrink_top(Rect *r, float amount); +/// removes `amount` from the right side of r +void rect_shrink_right(Rect *r, float amount); +/// removes `amount` from the bottom side of r +void rect_shrink_bottom(Rect *r, float amount); +/// adds `amount` to all sides of r +void rect_grow(Rect *r, float amount); u32 color_interpolate(float x, u32 color1, u32 color2); int timespec_cmp(struct timespec a, struct timespec b); bool timespec_eq(struct timespec a, struct timespec b); |