summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-01-06 17:36:07 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-01-06 17:36:07 -0500
commit132dcb648981050990e34a44925e6b54d0dc008c (patch)
tree7a41a97308b1921c62d2f5afd12c7cf475f14247
parent9e055b2e25455fc4fa0376495ccc9335059f3131 (diff)
more open menu, border thickness setting, fixed small text clipping issue
-rw-r--r--buffer.c36
-rw-r--r--colors.h2
-rw-r--r--config.c6
-rw-r--r--filesystem-posix.c68
-rw-r--r--filesystem-win.c63
-rw-r--r--filesystem.c19
-rw-r--r--main.c47
-rw-r--r--math.c3
-rw-r--r--menu.c55
-rw-r--r--ted.cfg4
-rw-r--r--ted.h2
-rw-r--r--text.c8
-rw-r--r--util.c9
13 files changed, 264 insertions, 58 deletions
diff --git a/buffer.c b/buffer.c
index 3445595..f86eeaa 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1603,10 +1603,13 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
float char_width = text_font_char_width(font),
char_height = text_font_char_height(font);
float header_height = char_height;
+
Ted *ted = buffer->ted;
Settings *settings = buffer_settings(buffer);
u32 *colors = settings->colors;
+ float border_thickness = settings->border_thickness;
+
// get screen coordinates of cursor
v2 cursor_display_pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos);
// the rectangle that the cursor is rendered as
@@ -1614,15 +1617,15 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
u32 border_color = colors[COLOR_BORDER]; // color of border around buffer
- // bounding box around buffer & header
+ // bounding box around buffer
+ glBegin(GL_QUADS);
gl_color_rgba(border_color);
- glBegin(GL_LINE_STRIP);
- glVertex2f(x1,y1);
- glVertex2f(x1,y2);
- glVertex2f(x2,y2);
- glVertex2f(x2,y1);
- glVertex2f(x1-1,y1);
+ rect_render_border(rect4(x1, y1, x2, y2), border_thickness);
glEnd();
+ x1 += border_thickness * 0.5f;
+ y1 += border_thickness * 0.5f;
+ x2 -= border_thickness * 0.5f;
+ y2 -= border_thickness * 0.5f;
TextRenderState text_state = {
.x = 0, .y = 0,
@@ -1645,17 +1648,22 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
x = x2 - checksum_w;
text_render_with_state(font, &text_state, checksum, x, y);
#endif
+
+ y1 += header_height + 0.5f * border_thickness;
+
+ // line separating header from buffer proper
+ glBegin(GL_QUADS);
+ gl_color_rgba(border_color);
+ glVertex2f(x1, y1 - 0.5f * border_thickness);
+ glVertex2f(x2, y1 - 0.5f * border_thickness);
+ glVertex2f(x2, y1 + 0.5f * border_thickness);
+ glVertex2f(x1, y1 + 0.5f * border_thickness);
+ glEnd();
+ y1 += 0.5f * border_thickness;
}
- y1 += header_height;
buffer->x1 = x1; buffer->y1 = y1; buffer->x2 = x2; buffer->y2 = y2;
- // line separating header from buffer proper
- glBegin(GL_LINES);
- gl_color_rgba(border_color);
- glVertex2f(x1, y1);
- glVertex2f(x2, y1);
- glEnd();
// highlight line cursor is on
diff --git a/colors.h b/colors.h
index c3b978d..d51d7e7 100644
--- a/colors.h
+++ b/colors.h
@@ -7,6 +7,7 @@ ENUM_U16 {
COLOR_BORDER,
COLOR_TEXT,
COLOR_SELECTION_BG,
+ COLOR_MENU_BACKDROP,
COLOR_MENU_BG,
COLOR_COUNT
@@ -25,6 +26,7 @@ static ColorName const color_names[COLOR_COUNT] = {
{COLOR_BORDER, "border"},
{COLOR_TEXT, "text"},
{COLOR_SELECTION_BG, "selection-bg"},
+ {COLOR_MENU_BACKDROP, "menu-backdrop"},
{COLOR_MENU_BG, "menu-bg"}
};
diff --git a/config.c b/config.c
index 4847aad..57a69f4 100644
--- a/config.c
+++ b/config.c
@@ -292,6 +292,12 @@ void config_read(Ted *ted, char const *filename) {
} else {
config_err(cfg, "Invalid text size: %s.", value);
}
+ } else if (streq(key, "border-thickness")) {
+ if (is_integer && integer > 0 && integer < 30) {
+ settings->border_thickness = (u8)integer;
+ } else {
+ config_err(cfg, "Invalid border thickness: %s.", value);
+ }
} else {
config_err(cfg, "Unrecognized core setting: %s.", key);
}
diff --git a/filesystem-posix.c b/filesystem-posix.c
new file mode 100644
index 0000000..4913e30
--- /dev/null
+++ b/filesystem-posix.c
@@ -0,0 +1,68 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+
+// Does this file exist? Returns false for directories.
+static bool fs_file_exists(char const *path) {
+ struct stat statbuf = {0};
+ if (stat(path, &statbuf) != 0)
+ return false;
+ return S_ISREG(statbuf.st_mode);
+}
+
+// Returns a NULL-terminated array of the files in this directory, or NULL if the directory does not exist.
+// When you're done with the file names, call free on each one, then on the array.
+// NOTE: The files aren't returned in any particular order!
+static char **fs_list_directory(char const *dirname) {
+ char **ret = NULL;
+ DIR *dir = opendir(dirname);
+ if (dir) {
+ struct dirent *ent;
+ char **filenames = NULL;
+ size_t nentries = 0;
+ size_t filename_idx = 0;
+
+ while (readdir(dir)) ++nentries;
+ rewinddir(dir);
+ filenames = (char **)calloc(nentries+1, sizeof *filenames);
+
+ while ((ent = readdir(dir))) {
+ if (ent->d_type == DT_REG) {
+ char const *filename = ent->d_name;
+ size_t len = strlen(filename);
+ char *filename_copy = (char *)malloc(len+1);
+ if (!filename_copy) break;
+ strcpy(filename_copy, filename);
+ if (filename_idx < nentries) // this could actually fail if someone creates files between calculating nentries and here.
+ filenames[filename_idx++] = filename_copy;
+ }
+ }
+ ret = filenames;
+ closedir(dir);
+ }
+ return ret;
+}
+
+static int fs_mkdir(char const *path) {
+ if (mkdir(path, 0755) == 0) {
+ // directory created successfully
+ return 1;
+ } else if (errno == EEXIST) {
+ struct stat statbuf = {0};
+ if (stat(path, &statbuf) == 0) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ // already exists, and it's a directory
+ return 0;
+ } else {
+ // already exists, but not a directory
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+}
diff --git a/filesystem-win.c b/filesystem-win.c
new file mode 100644
index 0000000..4a66c09
--- /dev/null
+++ b/filesystem-win.c
@@ -0,0 +1,63 @@
+// see filesystem-posix.c for function documentation
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static bool fs_file_exists(char const *path) {
+ struct _stat statbuf = {0};
+ if (_stat(path, &statbuf) != 0)
+ return false;
+ return statbuf.st_mode == _S_IFREG;
+}
+
+static char **fs_list_directory(char const *dirname) {
+ char file_pattern[256] = {0};
+ char **ret = NULL;
+ WIN32_FIND_DATA find_data;
+ HANDLE fhandle;
+ sprintf_s(file_pattern, sizeof file_pattern, "%s\\*", dirname);
+ fhandle = FindFirstFileA(file_pattern, &find_data);
+ if (fhandle != INVALID_HANDLE_VALUE) {
+ // first, figure out number of files
+ int nfiles = 1, idx = 0;
+ char **files;
+ while (FindNextFile(fhandle, &find_data)) {
+ if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ ++nfiles;
+ }
+ }
+ FindClose(fhandle);
+ // now, fill out files array
+ files = malloc((nfiles + 1) * sizeof *files);
+ if (files) {
+ fhandle = FindFirstFileA(file_pattern, &find_data);
+ if (fhandle != INVALID_HANDLE_VALUE) {
+ do {
+ if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ if (idx < nfiles) {
+ char *dup = _strdup(find_data.cFileName);
+ if (dup) {
+ files[idx++] = dup;
+ } else break; // stop now
+ }
+ }
+ } while (FindNextFile(fhandle, &find_data));
+ files[idx] = NULL;
+ FindClose(fhandle);
+ ret = files;
+ }
+ }
+ }
+ return ret;
+}
+
+static int fs_mkdir(char const *path) {
+ if (CreateDirectoryA(path, NULL)) {
+ // directory created successfully
+ return 1;
+ } else {
+ if (GetLastError() == ERROR_ALREADY_EXISTS) // directory already exists
+ return 0;
+ else
+ return -1; // some other error
+ }
+}
diff --git a/filesystem.c b/filesystem.c
deleted file mode 100644
index f68fe72..0000000
--- a/filesystem.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#if __unix__
-#include <unistd.h>
-#endif
-
-static bool fs_file_exists(char const *path) {
-#if _WIN32
- struct _stat statbuf = {0};
- if (_stat(path, &statbuf) != 0)
- return false;
- return statbuf.st_mode == _S_IFREG;
-#else
- struct stat statbuf = {0};
- if (stat(path, &statbuf) != 0)
- return false;
- return S_ISREG(statbuf.st_mode);
-#endif
-}
diff --git a/main.c b/main.c
index 06269ab..85fe7b3 100644
--- a/main.c
+++ b/main.c
@@ -21,12 +21,18 @@ no_warn_end
#include "util.c"
#define MATH_GL
#include "math.c"
+#if _WIN32
+#include "filesystem-win.c"
+#elif __unix__
+#include "filesystem-posix.c"
+#else
+#error "Unrecognized operating system."
+#endif
#include "unicode.h"
#include "command.h"
#include "colors.h"
#include "ted.h"
-#include "filesystem.c"
#include "time.c"
#include "string32.c"
#include "arr.c"
@@ -34,6 +40,7 @@ no_warn_end
#include "ted-base.c"
#include "command.c"
#include "config.c"
+#include "menu.c"
static void die(char const *fmt, ...) {
char buf[256] = {0};
@@ -80,8 +87,12 @@ int main(int argc, char **argv) {
// @TODO(windows): GetModuleFileNameW
#else
ssize_t len = readlink("/proc/self/exe", executable_path, sizeof executable_path - 1);
- executable_path[len] = '\0';
- ted_search_cwd = !str_is_prefix(executable_path, "/usr");
+ if (len == -1) {
+ // some posix systems don't have /proc/self/exe. oh well.
+ } else {
+ executable_path[len] = '\0';
+ ted_search_cwd = !str_is_prefix(executable_path, "/usr");
+ }
#endif
}
@@ -173,7 +184,7 @@ int main(int argc, char **argv) {
}
- u32 *colors = settings->colors;
+ u32 *colors = settings->colors; (void)colors;
Uint32 time_at_last_frame = SDL_GetTicks();
@@ -186,6 +197,14 @@ int main(int argc, char **argv) {
//printf("\033[H\033[2J");
#endif
+ {
+ int window_width_int = 0, window_height_int = 0;
+ SDL_GetWindowSize(window, &window_width_int, &window_height_int);
+ ted->window_width = (float)window_width_int;
+ ted->window_height = (float)window_height_int;
+ }
+ float window_width = ted->window_width, window_height = ted->window_height;
+
SDL_Event event;
Uint8 const *keyboard_state = SDL_GetKeyboardState(NULL);
@@ -338,14 +357,11 @@ int main(int argc, char **argv) {
}
- int window_width = 0, window_height = 0;
- SDL_GetWindowSize(window, &window_width, &window_height);
- float window_widthf = (float)window_width, window_heightf = (float)window_height;
// set up GL
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glViewport(0, 0, window_width, window_height);
+ glViewport(0, 0, (GLsizei)window_width, (GLsizei)window_height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// pixel coordinates; down is positive y
@@ -358,7 +374,7 @@ int main(int argc, char **argv) {
glClear(GL_COLOR_BUFFER_BIT);
{
- float x1 = 50, y1 = 50, x2 = window_widthf-50, y2 = window_heightf-50;
+ float x1 = 50, y1 = 50, x2 = window_width-50, y2 = window_height-50;
buffer_render(&text_buffer, x1, y1, x2, y2);
if (text_has_err()) {
die("Text error: %s\n", text_get_err());
@@ -366,16 +382,9 @@ int main(int argc, char **argv) {
}
}
- if (ted->menu) {
- glBegin(GL_QUADS);
- gl_color_rgba(colors[COLOR_MENU_BG]);
- rect_render(rect(V2(0, 0), V2(window_widthf, window_heightf)));
- glEnd();
- switch (ted->menu) {
- case MENU_NONE: assert(0); break;
- case MENU_OPEN:
- break;
- }
+ Menu menu = ted->menu;
+ if (menu) {
+ menu_render(ted, menu);
}
#if DEBUG
diff --git a/math.c b/math.c
index d4adf73..c76e3cc 100644
--- a/math.c
+++ b/math.c
@@ -655,7 +655,8 @@ static void rect_render(Rect r) {
glVertex2f(x1, y2);
}
-static void rect_render_border(Rect r, float border_radius) {
+static void rect_render_border(Rect r, float border_thickness) {
+ float border_radius = border_thickness * 0.5f;
float x1 = r.pos.x, y1 = r.pos.y, x2 = x1 + r.size.x, y2 = y1 + r.size.y;
//float a = 0.3f; // for debugging
diff --git a/menu.c b/menu.c
new file mode 100644
index 0000000..6862d0e
--- /dev/null
+++ b/menu.c
@@ -0,0 +1,55 @@
+
+static void menu_render(Ted *ted, Menu menu) {
+ Settings *settings = &ted->settings;
+ u32 *colors = settings->colors;
+ Font *font = ted->font;
+ float window_width = ted->window_width, window_height = ted->window_height;
+ float char_height = text_font_char_height(font);
+
+ // render backdrop
+ glBegin(GL_QUADS);
+ gl_color_rgba(colors[COLOR_MENU_BACKDROP]);
+ rect_render(rect(V2(0, 0), V2(window_width, window_height)));
+ glEnd();
+
+ if (menu == MENU_OPEN) {
+ char const *directory = ".";
+ float padding = 20;
+ float menu_x1 = window_width * 0.5f - 300;
+ float menu_x2 = window_width * 0.5f + 300;
+ menu_x1 = maxf(menu_x1, padding);
+ menu_x2 = minf(menu_x2, window_width - padding);
+ float menu_y1 = padding;
+ float menu_y2 = window_height - padding;
+ Rect menu_rect = rect4(menu_x1, menu_y1, menu_x2, menu_y2);
+
+ // menu rectangle & border
+ glBegin(GL_QUADS);
+ gl_color_rgba(colors[COLOR_MENU_BG]);
+ rect_render(menu_rect);
+ gl_color_rgba(colors[COLOR_BORDER]);
+ rect_render_border(menu_rect, settings->border_thickness);
+ glEnd();
+
+ char **files = fs_list_directory(directory);
+ if (files) {
+ u32 nfiles = 0;
+ for (char **p = files; *p; ++p) ++nfiles;
+ qsort(files, nfiles, sizeof *files, str_qsort_case_insensitive_cmp);
+
+ { // render file names
+ float x = menu_x1 + 10, y = menu_y1 + char_height * 0.75f + 10;
+ TextRenderState text_render_state = {.min_x = menu_x1, .max_x = menu_x2, .min_y = menu_y1, .max_y = menu_y2};
+ gl_color_rgba(colors[COLOR_TEXT]);
+ for (u32 i = 0; i < nfiles; ++i) {
+ text_render_with_state(font, &text_render_state, files[i], x, y);
+ y += char_height;
+ }
+ }
+
+ for (u32 i = 0; i < nfiles; ++i) free(files[i]);
+ free(files);
+ }
+
+ }
+}
diff --git a/ted.cfg b/ted.cfg
index f18dc12..be0ed17 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -10,6 +10,7 @@ cursor-blink-time-off = 0.3
# undo the past this many seconds of editing.
undo-save-time = 6
text-size = 16
+border-thickness = 1
[keyboard]
# motion and selection
@@ -68,4 +69,5 @@ text = #fff
bg = #001
# The entire screen gets filled with this color when a menu (e.g. the "open" menu) is shown.
# By making it transparent, we can dim everything else while the menu is open.
-menu-bg = #0004
+menu-backdrop = #0004
+menu-bg = #222
diff --git a/ted.h b/ted.h
index 8c475a9..5cc5f4e 100644
--- a/ted.h
+++ b/ted.h
@@ -8,6 +8,7 @@ typedef struct {
u8 tab_width;
u8 cursor_width;
u8 undo_save_time;
+ u8 border_thickness;
} Settings;
#define SCANCODE_COUNT 0x120 // SDL scancodes should be less than this value.
@@ -77,6 +78,7 @@ typedef struct Ted {
// the old active buffer needs to be restored. that's what this stores.
TextBuffer *prev_active_buffer;
Settings settings;
+ float window_width, window_height;
Menu menu;
KeyAction key_actions[KEY_COMBO_COUNT];
char error[256];
diff --git a/text.c b/text.c
index 3044ecb..09b5778 100644
--- a/text.c
+++ b/text.c
@@ -210,8 +210,8 @@ void text_render_char(Font *font, TextRenderState *state, char32_t c) {
}
if (x1 >= max_x) {
// right side of character is clipped
- s1 = (max_x-x0) / (x1-x0) * (s1-s0) + s0;
- x1 = max_x;
+ s1 = (max_x-1-x0) / (x1-x0) * (s1-s0) + s0;
+ x1 = max_x-1;
}
if (y0 < min_y) {
// top side of character is clipped
@@ -220,8 +220,8 @@ void text_render_char(Font *font, TextRenderState *state, char32_t c) {
}
if (y1 >= max_y) {
// bottom side of character is clipped
- t1 = (max_y-y0) / (y1-y0) * (t1-t0) + t0;
- y1 = max_y;
+ t1 = (max_y-1-y0) / (y1-y0) * (t1-t0) + t0;
+ y1 = max_y-1;
}
glTexCoord2f(s0,t0); glVertex2f(x0,y0);
glTexCoord2f(s0,t1); glVertex2f(x0,y1);
diff --git a/util.c b/util.c
index aa4a737..5bde9b6 100644
--- a/util.c
+++ b/util.c
@@ -146,3 +146,12 @@ static bool str_satisfies(char const *s, int (*predicate)(int)) {
return true;
}
+// function to be passed into qsort for case insensitive sorting
+static int str_qsort_case_insensitive_cmp(const void *av, const void *bv) {
+ char const *const *a = av, *const *b = bv;
+#if _WIN32
+ return _stricmp(*a, *b);
+#else
+ return strcasecmp(*a, *b);
+#endif
+}