|
|
@@ -0,0 +1,271 @@
|
|
|
+#ifndef APP_H
|
|
|
+#define APP_H
|
|
|
+
|
|
|
+#include "da.h"
|
|
|
+#include "font.h"
|
|
|
+
|
|
|
+#include <SDL2/SDL.h>
|
|
|
+
|
|
|
+#include "vec2.h"
|
|
|
+#include "window.h"
|
|
|
+
|
|
|
+#include "buffer.h"
|
|
|
+
|
|
|
+struct app {
|
|
|
+ struct window win;
|
|
|
+ SDL_Renderer *rdr;
|
|
|
+ struct font font;
|
|
|
+ struct buffer buf;
|
|
|
+ bool running;
|
|
|
+ uint64_t target_fps;
|
|
|
+ struct {
|
|
|
+ uint8_t tab_size;
|
|
|
+ } cfg;
|
|
|
+ bool show_fps;
|
|
|
+};
|
|
|
+
|
|
|
+struct app app_create(const char *win_title);
|
|
|
+
|
|
|
+void app_set_text_color(struct app app, uint32_t color);
|
|
|
+uint32_t app_get_text_color(struct app app);
|
|
|
+
|
|
|
+void app_render_cursor_in_pos(struct app app, struct vec2 pos, uint32_t color);
|
|
|
+void app_render_cursor(struct app app, uint32_t color);
|
|
|
+void app_render_char(struct app app, const char c, struct vec2 pos,
|
|
|
+ double scale);
|
|
|
+
|
|
|
+void app_render_buffer(struct app app, struct vec2 pos,
|
|
|
+ uint32_t color, double scale);
|
|
|
+void app_render_text(struct app app, const char *text, size_t text_size,
|
|
|
+ struct vec2 pos, uint32_t color, double scale);
|
|
|
+
|
|
|
+struct vec2 app_calc_cur_pos(struct app app);
|
|
|
+
|
|
|
+#if defined(APP_IMP) || defined(IMP)
|
|
|
+
|
|
|
+#define UNHEX_COLOR(hex) \
|
|
|
+ (uint8_t) ((hex >> 24) & 0xFF), \
|
|
|
+ (uint8_t) ((hex >> 16) & 0xFF), \
|
|
|
+ (uint8_t) ((hex >> 8 ) & 0xFF), \
|
|
|
+ (uint8_t) ((hex >> 0 ) & 0xFF)
|
|
|
+
|
|
|
+#include "sc.h"
|
|
|
+
|
|
|
+struct app
|
|
|
+app_create(const char *win_title)
|
|
|
+{
|
|
|
+ SCE(SDL_Init(SDL_INIT_VIDEO));
|
|
|
+
|
|
|
+ struct app app = {
|
|
|
+ .win = window_create(win_title),
|
|
|
+ .rdr = NULL,
|
|
|
+ .running = true,
|
|
|
+ .buf = buffer_create(),
|
|
|
+ .cfg = {
|
|
|
+ .tab_size = 8
|
|
|
+ },
|
|
|
+ .target_fps = 120,
|
|
|
+ };
|
|
|
+
|
|
|
+ app.rdr = SDL_CreateRenderer(app.win.ptr, -1, SDL_RENDERER_ACCELERATED);
|
|
|
+ if ( app.rdr == NULL ) {
|
|
|
+ printf("Using software acceleration: %s\n", SDL_GetError());
|
|
|
+ app.rdr = SDL_CreateRenderer(app.win.ptr, -1,
|
|
|
+ SDL_RENDERER_SOFTWARE);
|
|
|
+ }
|
|
|
+ SCP(app.rdr);
|
|
|
+
|
|
|
+
|
|
|
+ return app;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+app_render_char(struct app app, const char c, struct vec2 pos, double scale)
|
|
|
+{
|
|
|
+ SDL_Rect dst = {
|
|
|
+ .x = (int32_t) pos.x,
|
|
|
+ .y = (int32_t) pos.y,
|
|
|
+ .w = (int32_t)(app.font.ch_w * scale),
|
|
|
+ .h = (int32_t)(app.font.ch_h * scale)
|
|
|
+ };
|
|
|
+
|
|
|
+ SCE(SDL_RenderCopy(app.rdr, app.font.tex,
|
|
|
+ app.font.glyphs + (c - 32),
|
|
|
+ &dst));
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+app_set_text_color(struct app app, uint32_t color) {
|
|
|
+ uint8_t r = (uint8_t) ((color >> 24) & 0xFF);
|
|
|
+ uint8_t g = (uint8_t) ((color >> 16) & 0xFF);
|
|
|
+ uint8_t b = (uint8_t) ((color >> 8 ) & 0xFF);
|
|
|
+ uint8_t a = (uint8_t) ((color >> 0 ) & 0xFF);
|
|
|
+
|
|
|
+ SCE(SDL_SetTextureColorMod(app.font.tex, r, g, b));
|
|
|
+ SCE(SDL_SetTextureAlphaMod(app.font.tex, a));
|
|
|
+}
|
|
|
+
|
|
|
+uint32_t
|
|
|
+app_get_text_color(struct app app) {
|
|
|
+ uint8_t r = 0;
|
|
|
+ uint8_t g = 0;
|
|
|
+ uint8_t b = 0;
|
|
|
+ uint8_t a = 0;
|
|
|
+
|
|
|
+ SCE(SDL_GetTextureColorMod(app.font.tex, &r, &g, &b));
|
|
|
+ SCE(SDL_GetTextureAlphaMod(app.font.tex, &a));
|
|
|
+
|
|
|
+ return (r << 24) | (g << 16) | (b << 8) | (a << 0);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#define BRANCHLESS_IF(cond, when_true, when_false) \
|
|
|
+ (((cond)) * (when_true) + (!(cond)) * (when_false))
|
|
|
+
|
|
|
+void
|
|
|
+app_render_buffer(struct app app, struct vec2 pos,
|
|
|
+ uint32_t color, double scale)
|
|
|
+{
|
|
|
+ app_set_text_color(app, color);
|
|
|
+
|
|
|
+ struct buffer buf = app.buf;
|
|
|
+ DA_DEF_STRUCT_ITEM(char, da);
|
|
|
+ DA_ASSIGN(da, buf.data);
|
|
|
+
|
|
|
+ struct vec2 pen = pos;
|
|
|
+ size_t i = buf.render_start;
|
|
|
+ char c;
|
|
|
+ for ( ; i < da.size; ++i ) {
|
|
|
+ c = da.items[i];
|
|
|
+ /* bool cond = (pen.x > app.win.w); */
|
|
|
+ /* pen.x = BRANCHLESS_IF(cond, pos.x, pen.x); */
|
|
|
+ /* pen.y += BRANCHLESS_IF(cond, */
|
|
|
+ /* (double) (app.font.ch_h * scale), 0); */
|
|
|
+ switch ( c ) {
|
|
|
+ case '\n': {
|
|
|
+ if ( i == app.buf.cur ) {
|
|
|
+ app_render_cursor_in_pos(app, pen, 0xFF00FFFF);
|
|
|
+ }
|
|
|
+ pen.x = pos.x;
|
|
|
+ pen.y += (double) (app.font.ch_h * scale);
|
|
|
+ continue;
|
|
|
+ } break;
|
|
|
+ case '\t': {
|
|
|
+ if ( i == app.buf.cur ) {
|
|
|
+ app_render_cursor_in_pos(app, pen, 0xFF00FFFF);
|
|
|
+ }
|
|
|
+ pen.x += (double) ((app.font.ch_w * scale)
|
|
|
+ * app.cfg.tab_size);
|
|
|
+ continue;
|
|
|
+ } break;
|
|
|
+ }
|
|
|
+ app_render_char(app, c, pen, scale);
|
|
|
+ if ( i == app.buf.cur ) {
|
|
|
+ app_render_cursor_in_pos(app, pen, 0xFF00FFFF);
|
|
|
+ }
|
|
|
+ pen.x += (double) (app.font.ch_w * scale);
|
|
|
+ }
|
|
|
+ if ( i == app.buf.cur ) {
|
|
|
+ app_render_cursor_in_pos(app, pen, 0xFF00FFFF);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+app_render_text(struct app app, const char *text, size_t text_size,
|
|
|
+ struct vec2 pos, uint32_t color, double scale)
|
|
|
+{
|
|
|
+ app_set_text_color(app, color);
|
|
|
+
|
|
|
+ struct vec2 pen = pos;
|
|
|
+ size_t i = 0;
|
|
|
+ char c;
|
|
|
+ for ( ; i < text_size; ++i ) {
|
|
|
+ c = text[i];
|
|
|
+ switch ( c ) {
|
|
|
+ case '\n': {
|
|
|
+ pen.x = pos.x;
|
|
|
+ pen.y += (double) (app.font.ch_h * scale);
|
|
|
+ continue;
|
|
|
+ } break;
|
|
|
+ case '\t': {
|
|
|
+ pen.x += (double) ((app.font.ch_w * scale)
|
|
|
+ * app.cfg.tab_size);
|
|
|
+ continue;
|
|
|
+ } break;
|
|
|
+ }
|
|
|
+ app_render_char(app, c, pen, scale);
|
|
|
+ pen.x += (double) (app.font.ch_w * scale);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+app_render_cursor_in_pos(struct app app, struct vec2 pos, uint32_t color)
|
|
|
+{
|
|
|
+ SDL_Rect rect = {
|
|
|
+ .x = (int32_t) pos.x,
|
|
|
+ .y = (int32_t) pos.y,
|
|
|
+ .w = (int32_t) (app.font.ch_w * app.font.scale),
|
|
|
+ .h = (int32_t) (app.font.ch_h * app.font.scale)
|
|
|
+ };
|
|
|
+
|
|
|
+ SCE(SDL_SetRenderDrawColor(app.rdr, UNHEX_COLOR(color)));
|
|
|
+ SCE(SDL_RenderFillRect(app.rdr, &rect));
|
|
|
+
|
|
|
+ if ( app.buf.cur < app.buf.data.size ) {
|
|
|
+ char c = app.buf.data.items[app.buf.cur];
|
|
|
+ if ( c == '\n' ) return ;
|
|
|
+
|
|
|
+ uint32_t old_color = app_get_text_color(app);
|
|
|
+ app_set_text_color(app, ((~color) | 0xFF));
|
|
|
+ app_render_char(app, c, pos, app.font.scale);
|
|
|
+ app_set_text_color(app, old_color);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+app_render_cursor(struct app app, uint32_t color)
|
|
|
+{
|
|
|
+ struct vec2 pos = {
|
|
|
+ .x = ((double)(app.buf.cur) * (app.font.ch_w * app.font.scale)),
|
|
|
+ .y = ((double)(app.buf.cur) * (app.font.ch_h * app.font.scale))
|
|
|
+ };
|
|
|
+
|
|
|
+ app_render_cursor_in_pos(app, pos, color);
|
|
|
+}
|
|
|
+
|
|
|
+struct vec2
|
|
|
+app_calc_cur_pos(struct app app)
|
|
|
+{
|
|
|
+ size_t col = 0;
|
|
|
+ size_t row = buffer_calc_cur_row(app.buf);
|
|
|
+ enum buffer_err err;
|
|
|
+ /* RET_UNWRAP2(col, row, */
|
|
|
+ /* struct ret_size_t_size_t, */
|
|
|
+ /* buffer_calc_cur_pos(app.buf)); */
|
|
|
+ size_t start_line;
|
|
|
+ RET_UNWRAP2(start_line, err, struct ret_size_t_err,
|
|
|
+ buffer_index_bw_char(app.buf, app.buf.cur, '\n'));
|
|
|
+ col = (app.buf.cur - start_line) - 1;
|
|
|
+ if ( err == BUFFER_ERR_NOT_FOUND ) {
|
|
|
+ col = app.buf.cur;
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t tabs_n = 0;
|
|
|
+ RET_UNWRAP2(tabs_n, err,
|
|
|
+ struct ret_size_t_err,
|
|
|
+ buffer_count_char_between(app.buf, '\t',
|
|
|
+ start_line, app.buf.cur));
|
|
|
+ col += ( tabs_n > 0 ) * ((tabs_n * app.cfg.tab_size) - tabs_n);
|
|
|
+
|
|
|
+ double row_px = (((double)row)
|
|
|
+ * (app.font.ch_h * app.font.scale));
|
|
|
+ double col_px = (((double) col) *
|
|
|
+ (app.font.ch_w * app.font.scale));
|
|
|
+
|
|
|
+ return vec2(col_px, row_px);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#endif /* defined(APP_IMP) || defined(IMP) */
|
|
|
+
|
|
|
+#endif
|