From e9e7126b6ab59ab16e34c2a05f1c85e06397dd1a Mon Sep 17 00:00:00 2001 From: rexim Date: Thu, 9 Feb 2023 13:01:19 +0700 Subject: [PATCH] Go inside folders --- src/common.c | 21 +++++++++++++++++++ src/common.h | 16 ++++++++++---- src/editor.c | 18 +++++++++++----- src/file_browser.c | 49 +++++++++++++++++++++++++++++++++++++++++++ src/file_browser.h | 4 ++++ src/main.c | 48 ++++++++++++++++++++++++++++++++++-------- src/simple_renderer.c | 6 ++++++ src/simple_renderer.h | 4 ++++ 8 files changed, 148 insertions(+), 18 deletions(-) diff --git a/src/common.c b/src/common.c index 3889e58..7c4fd17 100644 --- a/src/common.c +++ b/src/common.c @@ -8,6 +8,9 @@ # include #else # include +# include +# include +# include #endif // _WIN32 #include "common.h" @@ -124,3 +127,21 @@ Vec4f hex_to_vec4f(uint32_t color) result.w = a/255.0f; return result; } + +Errno type_of_file(const char *file_path, File_Type *ft) +{ +#ifdef _WIN32 +#error "TODO: type_of_file() is not implemented for Windows" +#else + struct stat sb = {0}; + if (stat(file_path, &sb) < 0) return errno; + if (S_ISREG(sb.st_mode)) { + *ft = FT_REGULAR; + } else if (S_ISDIR(sb.st_mode)) { + *ft = FT_DIRECTORY; + } else { + *ft = FT_OTHER; + } +#endif + return 0; +} diff --git a/src/common.h b/src/common.h index 4134865..c35258b 100644 --- a/src/common.h +++ b/src/common.h @@ -68,10 +68,11 @@ typedef struct { } String_Builder; #define sb_append_buf da_append_many -#define sb_append_cstr(sb, cstr) \ - do { \ - size_t n = strlen(cstr); \ - da_append_many(sb, cstr, n); \ +#define sb_append_cstr(sb, cstr) \ + do { \ + const char *s = (cstr); \ + size_t n = strlen(s); \ + da_append_many(sb, s, n); \ } while (0) #define sb_append_null(sb) da_append_many(sb, "", 1) @@ -81,6 +82,13 @@ typedef struct { size_t capacity; } Files; +typedef enum { + FT_REGULAR, + FT_DIRECTORY, + FT_OTHER, +} File_Type; + +Errno type_of_file(const char *file_path, File_Type *ft); Errno read_entire_file(const char *file_path, String_Builder *sb); Errno write_entire_file(const char *file_path, const char *buf, size_t buf_size); Errno read_entire_dir(const char *dir_path, Files *files); diff --git a/src/editor.c b/src/editor.c index 073471c..28c8e47 100644 --- a/src/editor.c +++ b/src/editor.c @@ -53,6 +53,8 @@ Errno editor_save(const Editor *e) Errno editor_load_from_file(Editor *e, const char *file_path) { + printf("Loading %s\n", file_path); + e->data.count = 0; Errno err = read_entire_file(file_path, &e->data); if (err != 0) return err; @@ -308,20 +310,26 @@ void editor_render(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer // Update camera { - float target_scale = 3.0f; if (max_line_len > 1000.0f) { max_line_len = 1000.0f; } - if (max_line_len > 0.0f) { - target_scale = SCREEN_WIDTH / max_line_len; - } + + // TODO: SCREEN_WIDTH has to be variable cause window my resize + float target_scale = SCREEN_WIDTH / max_line_len; + + Vec2f target = cursor_pos; + float offset = 0.0f; if (target_scale > 3.0f) { target_scale = 3.0f; + } else { + offset = cursor_pos.x - SCREEN_WIDTH/sr->camera_scale; + if (offset < 0.0f) offset = 0.0f; + target = vec2f(SCREEN_WIDTH/sr->camera_scale + offset, cursor_pos.y); } sr->camera_vel = vec2f_mul( - vec2f_sub(cursor_pos, sr->camera_pos), + vec2f_sub(target, sr->camera_pos), vec2fs(2.0f)); sr->camera_scale_vel = (target_scale - sr->camera_scale) * 2.0f; diff --git a/src/file_browser.c b/src/file_browser.c index 4695e79..9e1b4bf 100644 --- a/src/file_browser.c +++ b/src/file_browser.c @@ -17,6 +17,39 @@ Errno fb_open_dir(File_Browser *fb, const char *dir_path) return err; } qsort(fb->files.items, fb->files.count, sizeof(*fb->files.items), file_cmp); + + fb->dir_path.count = 0; + sb_append_cstr(&fb->dir_path, dir_path); + sb_append_null(&fb->dir_path); + + return 0; +} + +Errno fb_change_dir(File_Browser *fb) +{ + assert(fb->dir_path.count > 0 && "You need to call fb_open_dir() before fb_change_dir()"); + assert(fb->dir_path.items[fb->dir_path.count - 1] == '\0'); + + if (fb->cursor >= fb->files.count) return 0; + + const char *dir_name = fb->files.items[fb->cursor]; + + fb->dir_path.count -= 1; + + // TODO: fb_change_dir() does not support .. and . properly + sb_append_cstr(&fb->dir_path, "/"); + sb_append_cstr(&fb->dir_path, dir_name); + sb_append_null(&fb->dir_path); + + fb->files.count = 0; + fb->cursor = 0; + Errno err = read_entire_dir(fb->dir_path.items, &fb->files); + + if (err != 0) { + return err; + } + qsort(fb->files.items, fb->files.count, sizeof(*fb->files.items), file_cmp); + return 0; } @@ -81,3 +114,19 @@ void fb_render(const File_Browser *fb, SDL_Window *window, Free_Glyph_Atlas *atl sr->camera_scale = sr->camera_scale + sr->camera_scale_vel * DELTA_TIME; } } + +const char *fb_file_path(File_Browser *fb) +{ + assert(fb->dir_path.count > 0 && "You need to call fb_open_dir() before fb_file_path()"); + assert(fb->dir_path.items[fb->dir_path.count - 1] == '\0'); + + if (fb->cursor >= fb->files.count) return NULL; + + fb->file_path.count = 0; + sb_append_buf(&fb->file_path, fb->dir_path.items, fb->dir_path.count - 1); + sb_append_buf(&fb->file_path, "/", 1); + sb_append_cstr(&fb->file_path, fb->files.items[fb->cursor]); + sb_append_null(&fb->file_path); + + return fb->file_path.items; +} diff --git a/src/file_browser.h b/src/file_browser.h index 7bae2dc..f83497c 100644 --- a/src/file_browser.h +++ b/src/file_browser.h @@ -9,9 +9,13 @@ typedef struct { Files files; size_t cursor; + String_Builder dir_path; + String_Builder file_path; } File_Browser; Errno fb_open_dir(File_Browser *fb, const char *dir_path); +Errno fb_change_dir(File_Browser *fb); void fb_render(const File_Browser *fb, SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer *sr); +const char *fb_file_path(File_Browser *fb); #endif // FILE_BROWSER_H_ diff --git a/src/main.c b/src/main.c index 2ecf20e..a0e4feb 100644 --- a/src/main.c +++ b/src/main.c @@ -50,7 +50,7 @@ static Editor editor = {0}; static File_Browser fb = {0}; // TODO: display errors reported via flash_error right in the text editor window somehow -#define flash_error(...) fprintf(stderr, __VA_ARGS__) +#define flash_error(...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while(0) int main(int argc, char **argv) { @@ -197,16 +197,42 @@ int main(int argc, char **argv) break; case SDLK_RETURN: { - if (fb.cursor < fb.files.count) { - // TODO: go inside folders - const char *file_path = fb.files.items[fb.cursor]; - // TODO: before opening a new file make sure you don't have unsaved changes - // And if you do, annoy the user about it. (just like all the other editors do) - err = editor_load_from_file(&editor, file_path); + const char *file_path = fb_file_path(&fb); + if (file_path) { + File_Type ft; + err = type_of_file(file_path, &ft); if (err != 0) { - flash_error("Could not open file %s: %s", file_path, strerror(err)); + flash_error("Could not determine type of file %s: %s", file_path, strerror(err)); } else { - file_browser = false; + switch (ft) { + case FT_DIRECTORY: { + err = fb_change_dir(&fb); + if (err != 0) { + flash_error("Could not change directory to %s: %s", file_path, strerror(err)); + } + } + break; + + case FT_REGULAR: { + // TODO: before opening a new file make sure you don't have unsaved changes + // And if you do, annoy the user about it. (just like all the other editors do) + err = editor_load_from_file(&editor, file_path); + if (err != 0) { + flash_error("Could not open file %s: %s", file_path, strerror(err)); + } else { + file_browser = false; + } + } + break; + + case FT_OTHER: { + flash_error("%s is neither a regular file nor a directory. We can't open it.", file_path); + } + break; + + default: + UNREACHABLE("unknown File_Type"); + } } } } @@ -335,3 +361,7 @@ int main(int argc, char **argv) return 0; } + +// TODO: ability to search within file browser +// Very useful when you have a lot of files +// TODO: ability to search with the text editor diff --git a/src/simple_renderer.c b/src/simple_renderer.c index 5bfe58b..ec3567f 100644 --- a/src/simple_renderer.c +++ b/src/simple_renderer.c @@ -208,8 +208,14 @@ void simple_renderer_init(Simple_Renderer *sr) // simple_renderer_vertex() for a potentially large amount of verticies in the first place. void simple_renderer_vertex(Simple_Renderer *sr, Vec2f p, Vec4f c, Vec2f uv) { +#if 1 // TODO: flush the renderer on vertex buffer overflow instead firing the assert + if (sr->verticies_count >= SIMPLE_VERTICIES_CAP) simple_renderer_flush(sr); +#else + // NOTE: it is better to just crash the app in this case until the culling described + // above is sorted out. assert(sr->verticies_count < SIMPLE_VERTICIES_CAP); +#endif Simple_Vertex *last = &sr->verticies[sr->verticies_count]; last->position = p; last->color = c; diff --git a/src/simple_renderer.h b/src/simple_renderer.h index e6119d2..baa9655 100644 --- a/src/simple_renderer.h +++ b/src/simple_renderer.h @@ -1,6 +1,8 @@ #ifndef SIMPLE_RENDERER_H_ #define SIMPLE_RENDERER_H_ +#include + #define GLEW_STATIC #include @@ -31,6 +33,8 @@ typedef struct { #define SIMPLE_VERTICIES_CAP (3*640*1000) +static_assert(SIMPLE_VERTICIES_CAP%3 == 0, "Simple renderer vertex capacity must be divisible by 3. We are rendring triangles after all."); + typedef enum { SHADER_FOR_COLOR = 0, SHADER_FOR_IMAGE,