From bf9a22bfff4051a70dcebbcd471eddb7b7724f7a Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Mon, 25 Jan 2021 20:12:55 -0500 Subject: clip selector, save as --- command.c | 8 ++++++- command.h | 2 ++ main.c | 3 +++ math.c | 3 +++ menu.c | 18 ++++++++++++++- ted.cfg | 1 + ted.h | 4 +++- ui.c | 78 ++++++++++++++++++++++++++++++++++++--------------------------- 8 files changed, 81 insertions(+), 36 deletions(-) diff --git a/command.c b/command.c index 2364442..a2c424d 100644 --- a/command.c +++ b/command.c @@ -123,6 +123,11 @@ void command_execute(Ted *ted, Command c, i64 argument) { case CMD_SAVE: if (buffer) buffer_save(buffer); break; + case CMD_SAVE_AS: + if (buffer && !buffer->is_line_buffer) { + menu_open(ted, MENU_SAVE_AS); + } + break; case CMD_UNDO: if (buffer) buffer_undo(buffer, argument); break; @@ -173,7 +178,8 @@ void command_execute(Ted *ted, Command c, i64 argument) { case MENU_NONE: assert(0); break; - case MENU_OPEN: { + case MENU_OPEN: + case MENU_SAVE_AS: { ted->file_selector.submitted = true; } break; } diff --git a/command.h b/command.h index 2372e37..79d8a1d 100644 --- a/command.h +++ b/command.h @@ -36,6 +36,7 @@ ENUM_U16 { CMD_OPEN, // open a file CMD_SAVE, // save current buffer + CMD_SAVE_AS, CMD_UNDO, CMD_REDO, CMD_COPY, @@ -88,6 +89,7 @@ static CommandName const command_names[CMD_COUNT] = { {"delete-word", CMD_DELETE_WORD}, {"open", CMD_OPEN}, {"save", CMD_SAVE}, + {"save-as", CMD_SAVE_AS}, {"undo", CMD_UNDO}, {"redo", CMD_REDO}, {"copy", CMD_COPY}, diff --git a/main.c b/main.c index 142942b..747c95f 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,8 @@ // @TODO: // - save as +// - warn on: +// - overwrite (from save as menu) +// - unsaved changes // - auto-indent // - Windows installation #include "base.h" diff --git a/math.c b/math.c index 9d72aa2..78f1ecc 100644 --- a/math.c +++ b/math.c @@ -771,8 +771,11 @@ static float rects_intersect(Rect r1, Rect r2) { // returns whether or not there is any of the clipped rectangle left static bool rect_clip_to_rect(Rect *clipped, Rect clipper) { + v2 start_pos = clipped->pos; clipped->pos.x = maxf(clipped->pos.x, clipper.pos.x); clipped->pos.y = maxf(clipped->pos.y, clipper.pos.y); + clipped->size = v2_add(clipped->size, v2_sub(start_pos, clipped->pos)); + clipped->size.x = clampf(clipped->size.x, 0, clipper.pos.x + clipper.size.x - clipped->pos.x); clipped->size.y = clampf(clipped->size.y, 0, clipper.pos.y + clipper.size.y - clipped->pos.y); return clipped->size.x > 0 && clipped->size.y > 0; diff --git a/menu.c b/menu.c index c98fbc8..40742cf 100644 --- a/menu.c +++ b/menu.c @@ -8,6 +8,10 @@ static void menu_open(Ted *ted, Menu menu) { case MENU_OPEN: ted->active_buffer = &ted->line_buffer; break; + case MENU_SAVE_AS: + ted->active_buffer = &ted->line_buffer; + ted->file_selector.create_menu = true; + break; } } @@ -39,6 +43,18 @@ static Rect menu_rect(Ted *ted) { static void menu_update(Ted *ted, Menu menu) { switch (menu) { case MENU_NONE: break; + case MENU_SAVE_AS: { + char *selected_file = file_selector_update(ted, &ted->file_selector); + if (selected_file) { + TextBuffer *buffer = ted->prev_active_buffer; + if (buffer) { + buffer_save_as(buffer, selected_file); + menu_close(ted, true); + file_selector_free(&ted->file_selector); + } + free(selected_file); + } + } break; case MENU_OPEN: { char *selected_file = file_selector_update(ted, &ted->file_selector); if (selected_file) { @@ -65,7 +81,7 @@ static void menu_render(Ted *ted, Menu menu) { glEnd(); - if (menu == MENU_OPEN) { + if (menu == MENU_OPEN || menu == MENU_SAVE_AS) { float padding = settings->padding; Rect rect = menu_rect(ted); float menu_x1, menu_y1, menu_x2, menu_y2; diff --git a/ted.cfg b/ted.cfg index 8660f04..8abc633 100644 --- a/ted.cfg +++ b/ted.cfg @@ -59,6 +59,7 @@ Ctrl+PageDown = 10 :page-down Ctrl+o = :open Ctrl+s = :save +Ctrl+Shift+s = :save-as Ctrl+z = :undo Ctrl+Shift+z = :redo Ctrl+c = :copy diff --git a/ted.h b/ted.h index bdc2f60..e1f6498 100644 --- a/ted.h +++ b/ted.h @@ -76,7 +76,8 @@ typedef struct { ENUM_U16 { MENU_NONE, - MENU_OPEN + MENU_OPEN, + MENU_SAVE_AS } ENUM_U16_END(Menu); // file entries for file selectors @@ -95,6 +96,7 @@ typedef struct { char cwd[TED_PATH_MAX]; bool open; // is the file selector on screen? bool submitted; // set to true if the line buffer was just submitted this frame. + bool create_menu; // this is for creating files, not opening files } FileSelector; typedef struct Ted { diff --git a/ui.c b/ui.c index 7cabdc6..0619e21 100644 --- a/ui.c +++ b/ui.c @@ -271,7 +271,6 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { bool submitted = fs->submitted; fs->submitted = false; - bool on_screen = true; for (u32 i = 0; i < fs->n_entries; ++i) { Rect r = {0}; FileEntry *entry = &fs->entries[i]; @@ -279,7 +278,7 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { FsType type = entry->type; // check if this entry was clicked on - if (on_screen && file_selector_entry_pos(ted, fs, i, &r)) { + 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 @@ -296,23 +295,32 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) { } } } - } else on_screen = false; + } } // user pressed enter in search bar - if (submitted && fs->selected < fs->n_entries) { - FileEntry *entry = &fs->entries[fs->selected]; - switch (entry->type) { - case FS_FILE: + if (submitted) { + if (fs->create_menu) { + char path[TED_PATH_MAX]; + strbuf_printf(path, "%s%s%s", cwd, cwd[strlen(cwd)-1] == PATH_SEPARATOR ? "" : PATH_SEPARATOR_STR, search_term); free(search_term); - if (entry->path) return str_dup(entry->path); - break; - case FS_DIRECTORY: - file_selector_cd(ted, fs, entry->name); - buffer_clear(line_buffer); // clear search term - break; - default: break; + return str_dup(path); + } else { + if (fs->selected && fs->selected < fs->n_entries) { + FileEntry *entry = &fs->entries[fs->selected]; + switch (entry->type) { + case FS_FILE: + free(search_term); + if (entry->path) return str_dup(entry->path); + break; + case FS_DIRECTORY: + file_selector_cd(ted, fs, entry->name); + buffer_clear(line_buffer); // clear search term + break; + default: break; + } + } } } @@ -418,15 +426,18 @@ static void file_selector_render(Ted *ted, FileSelector *fs) { 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)) break; - if (rect_contains_point(r, ted->mouse_pos) || fs->selected == i) { - glBegin(GL_QUADS); - gl_color_rgba(colors[COLOR_MENU_HL]); - rect_render(r); - glEnd(); + 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->selected == i) { + glBegin(GL_QUADS); + gl_color_rgba(colors[COLOR_MENU_HL]); + rect_render(r); + glEnd(); + } } } @@ -434,20 +445,21 @@ static void file_selector_render(Ted *ted, FileSelector *fs) { // render file names themselves for (u32 i = 0; i < n_entries; ++i) { Rect r; - if (!file_selector_entry_pos(ted, fs, i, &r)) break; - float x = r.pos.x, y = r.pos.y; - switch (entries[i].type) { - case FS_FILE: - gl_color_rgba(colors[COLOR_TEXT]); - break; - case FS_DIRECTORY: - gl_color_rgba(colors[COLOR_TEXT_FOLDER]); - break; - default: - gl_color_rgba(colors[COLOR_TEXT_OTHER]); - break; + if (file_selector_entry_pos(ted, fs, i, &r)) { + float x = r.pos.x, y = r.pos.y; + switch (entries[i].type) { + case FS_FILE: + gl_color_rgba(colors[COLOR_TEXT]); + break; + case FS_DIRECTORY: + gl_color_rgba(colors[COLOR_TEXT_FOLDER]); + break; + default: + gl_color_rgba(colors[COLOR_TEXT_OTHER]); + break; + } + text_render_with_state(font, &text_render_state, entries[i].name, x, y); } - text_render_with_state(font, &text_render_state, entries[i].name, x, y); } } -- cgit v1.2.3