- Commit
- 516bfe358bab5324b5c35c354924bdd683b66c60
- Parent
- a4e9d1a767bff5c4ae81b4ec1e05dfb4a178861d
- Author
- Pablo <pablo-pie@riseup.net>
- Date
Refactored the UI library
Slide-show application for nerds ☝️🤓
Refactored the UI library
6 files changed, 338 insertions, 242 deletions
Status | Name | Changes | Insertions | Deletions |
Modified | nob.c | 2 files changed | 1 | 1 |
Added | src/framer.c | 1 file changed | 126 | 0 |
Modified | src/frames.h | 2 files changed | 42 | 102 |
Deleted | src/main.c | 1 file changed | 0 | 120 |
Modified | src/plug.c | 2 files changed | 16 | 19 |
Added | src/uix.h | 1 file changed | 153 | 0 |
diff --git a/nob.c b/nob.c @@ -21,7 +21,7 @@ int main(int argc, char **argv) const char *output_path = BUILD_PATH "framer"; nob_cmd_append(&cmd, CC, CFLAGS); nob_cmd_append(&cmd, "-o", output_path); - nob_cmd_append(&cmd, SRC_PATH "main.c"); + nob_cmd_append(&cmd, SRC_PATH "framer.c"); if (!nob_cmd_run_sync_and_reset(&cmd)) return EXIT_FAILURE; const char *libplug_path = BUILD_PATH "libplug.so";
diff --git /dev/null b/src/framer.c @@ -0,0 +1,126 @@ +#include <stdlib.h> +#include <stdio.h> +#include <dlfcn.h> + +#include "raylib.h" +#define FRAMES_IMPLEMENTATION +#include "frames.h" + +#define MONITOR_WIDTH 1366 +#define MONITOR_HEIGHT 768 + +static void* libplug = NULL; +void (*plug_load_frames)(Frames* fs); + +bool reload_libplug(char* libplug_path) +{ + if (libplug != NULL) dlclose(libplug); + + libplug = dlopen(libplug_path, RTLD_NOW); + if (libplug == NULL) { + TraceLog(LOG_ERROR, "HOTRELOAD: could not load %s: %s", + libplug_path, dlerror()); + return false; + } + + const char* symbol = "plug_load_frames"; + plug_load_frames = dlsym(libplug, symbol); + if (plug_load_frames == NULL) { + TraceLog(LOG_ERROR, "HOTRELOAD: could not find %s symbol in %s: %s", + symbol, libplug_path, dlerror()); + return false; + } + + return true; +} + +int main(int argc, char **argv) +{ + char * program_name = nob_shift(argv, argc); + + if (argc == 0) { + TraceLog(LOG_ERROR, "No libplug path provided"); + TraceLog(LOG_ERROR, "USAGE: %s <libplug.so>", program_name); + return EXIT_FAILURE; + } + + char* libplug_path = nob_shift(argv, argc); + if (!reload_libplug(libplug_path)) return EXIT_FAILURE; + + int width = 800; + int height = 450; + + float monitor_scale = (float)MONITOR_WIDTH/(float)width; + + Frames fs = {0}; + frames_load(&fs, plug_load_frames); + + InitWindow(width, height, frames_title(&fs)); + SetTargetFPS(60); + SetExitKey(KEY_Q); + + float scale = 1.0; + bool was_g_last_pressed = false; + while (!WindowShouldClose()) { + if (IsWindowFullscreen()) { + scale = monitor_scale; + SetWindowSize(MONITOR_WIDTH, MONITOR_HEIGHT); + } else { + scale = 1.0; + SetWindowSize(width, height); + } + + int pressed = GetCharPressed(); + switch (pressed) { + case 0: break; + case 'G': + frames_last(&fs); + was_g_last_pressed = false; + SetWindowTitle(frames_title(&fs)); + break; + case 'g': + if (was_g_last_pressed) { + frames_first(&fs); + was_g_last_pressed = false; + SetWindowTitle(frames_title(&fs)); + } else { + was_g_last_pressed = true; + } + break; + case 'F': + case 'f': + ToggleFullscreen(); + was_g_last_pressed = false; + break; + case 'J': + case 'j': + case ' ': + frames_next(&fs); + was_g_last_pressed = false; + SetWindowTitle(frames_title(&fs)); + break; + case 'K': + case 'k': + frames_prev(&fs); + was_g_last_pressed = false; + SetWindowTitle(frames_title(&fs)); + break; + case 'r': + case 'R': + if (!reload_libplug(libplug_path)) return EXIT_FAILURE; + frames_load(&fs, plug_load_frames); + was_g_last_pressed = false; + SetWindowTitle(frames_title(&fs)); + break; + default: + was_g_last_pressed = false; + } + + frames_tick(&fs, GetFrameTime()); + frames_draw(&fs, scale); + } + + CloseWindow(); + + return EXIT_SUCCESS; +}
diff --git a/src/frames.h b/src/frames.h @@ -4,13 +4,16 @@ #include <stdlib.h> #include <string.h> #include <stddef.h> +#include <assert.h> +#include "raylib.h" -#include "nob.h" - +#ifdef FRAMES_IMPLEMENTATION +#define NOB_IMPLEMENTATION #define ARENA_IMPLEMENTATION -#include "arena.h" +#endif // FRAMES_IMPLEMENTATION -// == Frames data-structure =================================================== +#include "nob.h" +#include "arena.h" typedef void (*FrameDraw)(float time, float scale); typedef void (*FrameTick)(float time, void* state); @@ -27,6 +30,8 @@ typedef struct { } Frame; typedef struct { + const char* title; + Frame* items; size_t count; size_t capacity; @@ -37,6 +42,31 @@ typedef struct { Arena states; } Frames; +void frames_next(Frames* fs); +void frames_prev(Frames* fs); +void frames_first(Frames* fs); +void frames_last(Frames* fs); + +const char* frames_title(Frames* fs); +void frames_draw(Frames* fs, float scale); +void frames_tick(Frames* fs, float dt); + +void frames_append(Frames* fs, FrameDraw draw, FrameTick tick, + size_t state_size); + +typedef void (*FramesLoad)(Frames* fs); +void frames_load(Frames* fs, FramesLoad load); + +#ifdef FRAMES_IMPLEMENTATION + +size_t frames__fast_log(size_t n) +{ + size_t result = 1, m = n/10; + + while (m > 0) { result += 1; m /= 10; } + return result; +} + void frames_next(Frames* fs) { assert(fs->cursor < fs->count); @@ -73,6 +103,13 @@ void frames_last(Frames* fs) fs->time = 0; } +const char* frames_title(Frames* fs) +{ + size_t current = fs->cursor + 1, total = fs->count; + size_t padding = frames__fast_log(total) - frames__fast_log(current); + return TextFormat("%s [%*zu/%zu]", fs->title, padding, current, total); +} + void frames_draw(Frames* fs, float scale) { assert(fs->cursor < fs->count); @@ -116,8 +153,6 @@ void frames_append(Frames* fs, FrameDraw draw, FrameTick tick, nob_da_append(fs, f); } -typedef void (*FramesLoad)(Frames* fs); - void frames_load(Frames* fs, FramesLoad load) { fs->count = 0; @@ -130,100 +165,5 @@ void frames_load(Frames* fs, FramesLoad load) if (fs->cursor >= fs->count) fs->cursor = fs->count - 1; } -// == Text layout ============================================================= - -typedef enum { - FRAMER_CENTERED, - FRAMER_XY, -} FramerAlignment; - -typedef struct { - const char* text; - Color color; - - size_t width; - size_t x_offset; -} FramerLineSpan; - -typedef struct { - FramerLineSpan* items; - size_t count, capacity; - - size_t width; - int font_size; - - FramerAlignment align; - int y, x; -} FramerLine; - -static FramerLine framer__line = {0}; - -void line_begin(int x, int y, int font_size) -{ - framer__line.count = 0; - framer__line.width = 0; - - framer__line.align = FRAMER_XY; - framer__line.x = x; - framer__line.y = y; - framer__line.font_size = font_size; -} - -void line_begin_centered(int y, int font_size) -{ - framer__line.count = 0; - framer__line.width = 0; - - framer__line.align = FRAMER_CENTERED; - framer__line.y = y; - framer__line.font_size = font_size; -} - -void line_add(const char* text, Color color) -{ - size_t text_width = MeasureText(text, framer__line.font_size); - FramerLineSpan s = { - .text = text, - .color = color, - .width = text_width, - .x_offset = framer__line.width, - }; - - nob_da_append(&framer__line, s); - framer__line.width += text_width; -} - -void line_end(void) -{ - int x, y = framer__line.y; - - switch (framer__line.align) { - case FRAMER_CENTERED: - x = (GetScreenWidth() - framer__line.width)/2; - break; - case FRAMER_XY: - x = framer__line.x; - break; - } - - for (size_t i = 0; i < framer__line.count; i++) { - FramerLineSpan s = framer__line.items[i]; - DrawText(s.text, x + s.x_offset, y, framer__line.font_size, s.color); - } -} - -void line(const char* text, Color color, int x, int y, int font_size) -{ - line_begin(x, y, font_size); - line_add(text, color); - line_end(); -} - -void line_centered(const char* text, Color color, int y, int font_size) -{ - line_begin_centered(y, font_size); - line_add(text, color); - line_end(); -} - +#endif // FRAMES_IMPLEMENTATION #endif // FRAMES_H_
diff --git a/src/main.c /dev/null @@ -1,120 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <dlfcn.h> - -#include "raylib.h" -#include "frames.h" - -#define MONITOR_WIDTH 1366 -#define MONITOR_HEIGHT 768 - -static void* libplug = NULL; -void (*plug_load_frames)(Frames* fs); - -bool reload_libplug(char* libplug_path) -{ - if (libplug != NULL) dlclose(libplug); - - libplug = dlopen(libplug_path, RTLD_NOW); - if (libplug == NULL) { - TraceLog(LOG_ERROR, "HOTRELOAD: could not load %s: %s", - libplug_path, dlerror()); - return false; - } - - const char* symbol = "plug_load_frames"; - plug_load_frames = dlsym(libplug, symbol); - if (plug_load_frames == NULL) { - TraceLog(LOG_ERROR, "HOTRELOAD: could not find %s symbol in %s: %s", - symbol, libplug_path, dlerror()); - return false; - } - - return true; -} - -int main(int argc, char **argv) -{ - char * program_name = nob_shift(argv, argc); - - if (argc == 0) { - TraceLog(LOG_ERROR, "No libplug path provided"); - TraceLog(LOG_ERROR, "USAGE: %s <libplug.so>", program_name); - return EXIT_FAILURE; - } - - char* libplug_path = nob_shift(argv, argc); - if (!reload_libplug(libplug_path)) return EXIT_FAILURE; - - int width = 800; - int height = 450; - - float monitor_scale = (float)MONITOR_WIDTH/(float)width; - - InitWindow(width, height, "\"introdução a assembly\" slides"); - SetTargetFPS(60); - SetExitKey(KEY_Q); - - Frames fs = {0}; - frames_load(&fs, plug_load_frames); - - float scale = 1.0; - bool was_g_last_pressed = false; - while (!WindowShouldClose()) { - if (IsWindowFullscreen()) { - scale = monitor_scale; - SetWindowSize(MONITOR_WIDTH, MONITOR_HEIGHT); - } else { - scale = 1.0; - SetWindowSize(width, height); - } - - int pressed = GetCharPressed(); - switch (pressed) { - case 0: break; - case 'G': - frames_last(&fs); - was_g_last_pressed = false; - break; - case 'g': - if (was_g_last_pressed) { - frames_first(&fs); - was_g_last_pressed = false; - } else { - was_g_last_pressed = true; - } - break; - case 'F': - case 'f': - ToggleFullscreen(); - was_g_last_pressed = false; - break; - case 'J': - case 'j': - case ' ': - frames_next(&fs); - was_g_last_pressed = false; - break; - case 'K': - case 'k': - frames_prev(&fs); - was_g_last_pressed = false; - break; - case 'r': - case 'R': - if (!reload_libplug(libplug_path)) return EXIT_FAILURE; - frames_load(&fs, plug_load_frames); - was_g_last_pressed = false; - break; - default: - was_g_last_pressed = false; - } - - frames_tick(&fs, GetFrameTime()); - frames_draw(&fs, scale); - } - - CloseWindow(); - - return EXIT_SUCCESS; -}
diff --git a/src/plug.c b/src/plug.c @@ -1,5 +1,8 @@ #include "raylib.h" +#define FRAMES_IMPLEMENTATION #include "frames.h" +#define UIX_IMPLEMENTATION +#include "uix.h" #define BACKGROUND BLACK #define FOREGROUND WHITE @@ -8,44 +11,38 @@ void title_frame(float time, float scale) { (void)time; - int height = GetScreenHeight(); int title_size = (int)(50.0 * scale); int subtitle_size = (int)(30.0 * scale); - int title_spacing = (int)(10.0 * scale); - int title_height = title_size + title_spacing + subtitle_size; - - int title_y = (height - title_height)/2; - int subtitle_y = title_y + title_size + title_spacing; - ClearBackground(BACKGROUND); - - line_centered("introdução a assemply", FOREGROUND, title_y, title_size); - line_centered("cripto goma 2020", ACCENT, subtitle_y, subtitle_size); + frame_begin(BACKGROUND); + line("introdução a assemply", title_size, FOREGROUND); + hspan(title_spacing); + line("cripto goma 2020", subtitle_size, ACCENT); + frame_end(); } void oq_frame(float time, float scale) { - int height = GetScreenHeight(); int font_size = (int)(50.0 * scale); const float animation_speed = .5; Color color = FOREGROUND; if ((int)(time / animation_speed) % 2 == 0) color = BACKGROUND; - int y = (height - font_size)/2; - - ClearBackground(BACKGROUND); - line_begin_centered(y, font_size); - line_add("o quê é ", FOREGROUND); - line_add("assembly", ACCENT); - line_add(" ?", color); - line_end(); + frame_begin(BACKGROUND); + line_begin(font_size); + line_add("o quê é ", FOREGROUND); + line_add("assembly", ACCENT); + line_add(" ?", color); + line_end(); + frame_end(); } void plug_load_frames(Frames* fs) { + fs->title = "introdução à assembly"; frames_append(fs, title_frame, FRAMES_EMPTY_TICK, FRAMES_EMPTY_STATE); frames_append(fs, oq_frame, FRAMES_EMPTY_TICK, FRAMES_EMPTY_STATE); }
diff --git /dev/null b/src/uix.h @@ -0,0 +1,153 @@ +#ifndef UIX_H_ +#define UIX_H_ + +#include <assert.h> + +typedef enum { UI_CENTERED, UI_LEFT, } Alignment; + +typedef struct { + const char* text; + Color color; + + size_t width; + size_t x_offset; +} LineSpan; + +typedef struct { + LineSpan* items; + size_t count, capacity; + + size_t width; + int font_size; + + int y_offset; +} Line; + +#define UIX_LINES_MAX 64 + +typedef struct { + int width, height; + int x, y; + int y_offset; + + Alignment align; + + Line lines[UIX_LINES_MAX]; + size_t lines_count; +} Layout; + +void frame_begin(Color background); +void frame_end(void); + +void line(const char* text, int font_size, Color color); +void hspan(int space); + +void line_begin(int font_size); +void line_add(const char* text, Color color); +void line_end(void); + +#ifdef UIX_IMPLEMENTATION + +static Layout uix__layout = {0}; + +Line* uix__get_current_line(void) +{ + assert(uix__layout.lines_count > 0); + assert(uix__layout.lines_count < UIX_LINES_MAX); + return &uix__layout.lines[uix__layout.lines_count-1]; +} + +Line* uix__alloc_new_line(void) +{ + assert(uix__layout.lines_count < UIX_LINES_MAX - 1); + Line* result = &uix__layout.lines[uix__layout.lines_count++]; + + result->width = 0; + result->count = 0; + result->capacity = 0; + + return result; +} + +void line_begin(int font_size) +{ + Line *line = uix__alloc_new_line(); + + line->y_offset = uix__layout.y_offset; + line->font_size = font_size; +} + +void line_add(const char* text, Color color) +{ + Line *line = uix__get_current_line(); + + size_t text_width = MeasureText(text, line->font_size); + LineSpan s = { + .text = text, + .color = color, + .width = text_width, + .x_offset = line->width, + }; + + nob_da_append(line, s); + line->width += text_width; +} + +void line_end(void) +{ + Line *line = uix__get_current_line(); + uix__layout.y_offset += line->font_size; +} + +void line(const char* text, int font_size, Color color) +{ + line_begin(font_size); + line_add(text, color); + line_end(); +} + +void hspan(int space) +{ + uix__layout.y_offset += space; +} + +void frame_begin(Color background) +{ + ClearBackground(background); + + uix__layout.width = GetScreenWidth(); + uix__layout.height = GetScreenHeight(); + + uix__layout.x = 0; + uix__layout.y = 0; + uix__layout.y_offset = 0; + uix__layout.lines_count = 0; + + uix__layout.align = UI_CENTERED; +} + +void frame_end(void) +{ + int y = uix__layout.y; + if (uix__layout.align == UI_CENTERED) { + y += (uix__layout.height - uix__layout.y_offset)/2; + } + + for (size_t j = 0; j < uix__layout.lines_count; j++) { + Line line = uix__layout.lines[j]; + + for (size_t i = 0; i < line.count; i++) { + int x = uix__layout.x; + if (uix__layout.align == UI_CENTERED) { + x += (uix__layout.width - line.width)/2; + } + + LineSpan s = line.items[i]; + DrawText(s.text, + x + s.x_offset, y + line.y_offset, line.font_size, s.color); + } + } +} + +#endif // UIX_IMPLEMENTATION +#endif // UIX_H_