|
@@ -1,6 +1,8 @@
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <stdbool.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <string.h>
|
|
|
|
|
|
#include <SDL2/SDL.h>
|
|
|
#define GLEW_STATIC
|
|
@@ -15,9 +17,11 @@
|
|
|
#include "./sv.h"
|
|
|
|
|
|
#include "./editor.h"
|
|
|
+#include "./file_browser.h"
|
|
|
#include "./la.h"
|
|
|
#include "./free_glyph.h"
|
|
|
#include "./simple_renderer.h"
|
|
|
+#include "./common.h"
|
|
|
|
|
|
#define SCREEN_WIDTH 800
|
|
|
#define SCREEN_HEIGHT 600
|
|
@@ -57,19 +61,81 @@ void MessageCallback(GLenum source,
|
|
|
static Free_Glyph_Atlas atlas = {0};
|
|
|
static Simple_Renderer sr = {0};
|
|
|
static Editor editor = {0};
|
|
|
+static File_Browser fb = {0};
|
|
|
static Uint32 last_stroke = 0;
|
|
|
|
|
|
#define FREE_GLYPH_FONT_SIZE 64
|
|
|
#define ZOOM_OUT_GLYPH_THRESHOLD 30
|
|
|
|
|
|
-void render_editor(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer *sr, Editor *editor)
|
|
|
+void render_file_browser(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer *sr, const File_Browser *fb)
|
|
|
{
|
|
|
+ Vec2f cursor_pos = vec2f(0, -(float)fb->cursor * FREE_GLYPH_FONT_SIZE);
|
|
|
+
|
|
|
int w, h;
|
|
|
SDL_GetWindowSize(window, &w, &h);
|
|
|
|
|
|
float max_line_len = 0.0f;
|
|
|
|
|
|
- simple_renderer_use(sr);
|
|
|
+ sr->resolution = vec2f(w, h);
|
|
|
+ sr->time = (float) SDL_GetTicks() / 1000.0f;
|
|
|
+
|
|
|
+ simple_renderer_set_shader(sr, SHADER_FOR_COLOR);
|
|
|
+ if (fb->cursor < fb->files.count) {
|
|
|
+ const Vec2f begin = vec2f(0, -(float)fb->cursor * FREE_GLYPH_FONT_SIZE);
|
|
|
+ Vec2f end = begin;
|
|
|
+ free_glyph_atlas_render_line_sized(
|
|
|
+ atlas, sr, fb->files.items[fb->cursor], strlen(fb->files.items[fb->cursor]),
|
|
|
+ &end,
|
|
|
+ false);
|
|
|
+ simple_renderer_solid_rect(sr, begin, vec2f(end.x - begin.x, FREE_GLYPH_FONT_SIZE), vec4f(.25, .25, .25, 1));
|
|
|
+ }
|
|
|
+ simple_renderer_flush(sr);
|
|
|
+
|
|
|
+ simple_renderer_set_shader(sr, SHADER_FOR_EPICNESS);
|
|
|
+ for (size_t row = 0; row < fb->files.count; ++row) {
|
|
|
+ const Vec2f begin = vec2f(0, -(float)row * FREE_GLYPH_FONT_SIZE);
|
|
|
+ Vec2f end = begin;
|
|
|
+ free_glyph_atlas_render_line_sized(
|
|
|
+ atlas, sr, fb->files.items[row], strlen(fb->files.items[row]),
|
|
|
+ &end,
|
|
|
+ true);
|
|
|
+ // TODO: the max_line_len should be calculated based on what's visible on the screen right now
|
|
|
+ float line_len = fabsf(end.x - begin.x);
|
|
|
+ if (line_len > max_line_len) {
|
|
|
+ max_line_len = line_len;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ simple_renderer_flush(sr);
|
|
|
+
|
|
|
+ // Update camera
|
|
|
+ {
|
|
|
+ float target_scale = 3.0f;
|
|
|
+ if (max_line_len > 0.0f) {
|
|
|
+ target_scale = SCREEN_WIDTH / max_line_len;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (target_scale > 3.0f) {
|
|
|
+ target_scale = 3.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ sr->camera_vel = vec2f_mul(
|
|
|
+ vec2f_sub(cursor_pos, sr->camera_pos),
|
|
|
+ vec2fs(2.0f));
|
|
|
+ sr->camera_scale_vel = (target_scale - sr->camera_scale) * 2.0f;
|
|
|
+
|
|
|
+ sr->camera_pos = vec2f_add(sr->camera_pos, vec2f_mul(sr->camera_vel, vec2fs(DELTA_TIME)));
|
|
|
+ sr->camera_scale = sr->camera_scale + sr->camera_scale_vel * DELTA_TIME;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void render_editor(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer *sr, Editor *editor)
|
|
|
+{
|
|
|
+ int w, h;
|
|
|
+ SDL_GetWindowSize(window, &w, &h);
|
|
|
+
|
|
|
+ float max_line_len = 0.0f;
|
|
|
|
|
|
sr->resolution = vec2f(w, h);
|
|
|
sr->time = (float) SDL_GetTicks() / 1000.0f;
|
|
@@ -84,7 +150,8 @@ void render_editor(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer
|
|
|
Vec2f end = begin;
|
|
|
free_glyph_atlas_render_line_sized(
|
|
|
atlas, sr, editor->data.items + line.begin, line.end - line.begin,
|
|
|
- &end);
|
|
|
+ &end,
|
|
|
+ true);
|
|
|
// TODO: the max_line_len should be calculated based on what's visible on the screen right now
|
|
|
float line_len = fabsf(end.x - begin.x);
|
|
|
if (line_len > max_line_len) {
|
|
@@ -131,6 +198,9 @@ void render_editor(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;
|
|
|
}
|
|
@@ -149,8 +219,13 @@ void render_editor(SDL_Window *window, Free_Glyph_Atlas *atlas, Simple_Renderer
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// TODO: display errors reported via flash_error right in the text editor window somehow
|
|
|
+#define flash_error(...) fprintf(stderr, __VA_ARGS__)
|
|
|
+
|
|
|
int main(int argc, char **argv)
|
|
|
{
|
|
|
+ Errno err;
|
|
|
+
|
|
|
editor_recompute_lines(&editor);
|
|
|
|
|
|
FT_Library library = {0};
|
|
@@ -182,18 +257,21 @@ int main(int argc, char **argv)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- const char *file_path = NULL;
|
|
|
|
|
|
if (argc > 1) {
|
|
|
- file_path = argv[1];
|
|
|
+ const char *file_path = argv[1];
|
|
|
+ err = editor_load_from_file(&editor, file_path);
|
|
|
+ if (err != 0) {
|
|
|
+ fprintf(stderr, "ERROR: Could ont read file %s: %s\n", file_path, strerror(err));
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (file_path) {
|
|
|
- FILE *file = fopen(file_path, "r");
|
|
|
- if (file != NULL) {
|
|
|
- editor_load_from_file(&editor, file);
|
|
|
- fclose(file);
|
|
|
- }
|
|
|
+ const char *dir_path = ".";
|
|
|
+ err = fb_open_dir(&fb, dir_path);
|
|
|
+ if (err != 0) {
|
|
|
+ fprintf(stderr, "ERROR: Could not read directory %s: %s\n", dir_path, strerror(err));
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
@@ -262,6 +340,7 @@ int main(int argc, char **argv)
|
|
|
free_glyph_atlas_init(&atlas, face);
|
|
|
|
|
|
bool quit = false;
|
|
|
+ bool file_browser = false;
|
|
|
while (!quit) {
|
|
|
const Uint32 start = SDL_GetTicks();
|
|
|
SDL_Event event = {0};
|
|
@@ -273,66 +352,114 @@ int main(int argc, char **argv)
|
|
|
break;
|
|
|
|
|
|
case SDL_KEYDOWN: {
|
|
|
- switch (event.key.keysym.sym) {
|
|
|
- case SDLK_BACKSPACE: {
|
|
|
- editor_backspace(&editor);
|
|
|
- last_stroke = SDL_GetTicks();
|
|
|
- }
|
|
|
- break;
|
|
|
+ if (file_browser) {
|
|
|
+ switch (event.key.keysym.sym) {
|
|
|
+ case SDLK_F3: {
|
|
|
+ file_browser = false;
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
- case SDLK_F2: {
|
|
|
- if (file_path) {
|
|
|
- editor_save_to_file(&editor, file_path);
|
|
|
+ case SDLK_UP: {
|
|
|
+ if (fb.cursor > 0) fb.cursor -= 1;
|
|
|
}
|
|
|
- }
|
|
|
- break;
|
|
|
+ break;
|
|
|
|
|
|
- case SDLK_RETURN: {
|
|
|
- editor_insert_char(&editor, '\n');
|
|
|
- last_stroke = SDL_GetTicks();
|
|
|
- }
|
|
|
- break;
|
|
|
+ case SDLK_DOWN: {
|
|
|
+ if (fb.cursor + 1 < fb.files.count) fb.cursor += 1;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SDLK_RETURN: {
|
|
|
+ if (fb.cursor < fb.files.count) {
|
|
|
+ // TODO: go into folders
|
|
|
+ const char *file_path = fb.files.items[fb.cursor];
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ switch (event.key.keysym.sym) {
|
|
|
+ case SDLK_BACKSPACE: {
|
|
|
+ editor_backspace(&editor);
|
|
|
+ last_stroke = SDL_GetTicks();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SDLK_F2: {
|
|
|
+ if (editor.file_path.count > 0) {
|
|
|
+ err = editor_save(&editor);
|
|
|
+ if (err != 0) {
|
|
|
+ flash_error("Could not save file currently edited file: %s", strerror(err));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // TODO: as the user for the path to save to in this situation
|
|
|
+ flash_error("No where to save the text");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
- case SDLK_DELETE: {
|
|
|
- editor_delete(&editor);
|
|
|
- last_stroke = SDL_GetTicks();
|
|
|
- }
|
|
|
- break;
|
|
|
+ case SDLK_F3: {
|
|
|
+ file_browser = true;
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
- case SDLK_UP: {
|
|
|
- editor_move_line_up(&editor);
|
|
|
- last_stroke = SDL_GetTicks();
|
|
|
- }
|
|
|
- break;
|
|
|
+ case SDLK_RETURN: {
|
|
|
+ editor_insert_char(&editor, '\n');
|
|
|
+ last_stroke = SDL_GetTicks();
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
- case SDLK_DOWN: {
|
|
|
- editor_move_line_down(&editor);
|
|
|
- last_stroke = SDL_GetTicks();
|
|
|
- }
|
|
|
- break;
|
|
|
+ case SDLK_DELETE: {
|
|
|
+ editor_delete(&editor);
|
|
|
+ last_stroke = SDL_GetTicks();
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
- case SDLK_LEFT: {
|
|
|
- editor_move_char_left(&editor);
|
|
|
- last_stroke = SDL_GetTicks();
|
|
|
- }
|
|
|
- break;
|
|
|
+ case SDLK_UP: {
|
|
|
+ editor_move_line_up(&editor);
|
|
|
+ last_stroke = SDL_GetTicks();
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
- case SDLK_RIGHT: {
|
|
|
- editor_move_char_right(&editor);
|
|
|
- last_stroke = SDL_GetTicks();
|
|
|
- }
|
|
|
- break;
|
|
|
+ case SDLK_DOWN: {
|
|
|
+ editor_move_line_down(&editor);
|
|
|
+ last_stroke = SDL_GetTicks();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SDLK_LEFT: {
|
|
|
+ editor_move_char_left(&editor);
|
|
|
+ last_stroke = SDL_GetTicks();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SDLK_RIGHT: {
|
|
|
+ editor_move_char_right(&editor);
|
|
|
+ last_stroke = SDL_GetTicks();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case SDL_TEXTINPUT: {
|
|
|
- const char *text = event.text.text;
|
|
|
- size_t text_len = strlen(text);
|
|
|
- for (size_t i = 0; i < text_len; ++i) {
|
|
|
- editor_insert_char(&editor, text[i]);
|
|
|
+ if (file_browser) {
|
|
|
+ // TODO: file browser keys
|
|
|
+ } else {
|
|
|
+ const char *text = event.text.text;
|
|
|
+ size_t text_len = strlen(text);
|
|
|
+ for (size_t i = 0; i < text_len; ++i) {
|
|
|
+ editor_insert_char(&editor, text[i]);
|
|
|
+ }
|
|
|
+ last_stroke = SDL_GetTicks();
|
|
|
}
|
|
|
- last_stroke = SDL_GetTicks();
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -348,7 +475,11 @@ int main(int argc, char **argv)
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
|
- render_editor(window, &atlas, &sr, &editor);
|
|
|
+ if (file_browser) {
|
|
|
+ render_file_browser(window, &atlas, &sr, &fb);
|
|
|
+ } else {
|
|
|
+ render_editor(window, &atlas, &sr, &editor);
|
|
|
+ }
|
|
|
|
|
|
SDL_GL_SwapWindow(window);
|
|
|
|