diff options
Diffstat (limited to 'Fuse/fuse.c')
| -rw-r--r-- | Fuse/fuse.c | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/Fuse/fuse.c b/Fuse/fuse.c new file mode 100644 index 0000000..401b06e --- /dev/null +++ b/Fuse/fuse.c @@ -0,0 +1,436 @@ +#ifndef _FUSE_C_ +#define _FUSE_C_ + /* __________________________________________________________________________ + * | CmdType | CmdRect | CmdType | CmdRectBorder | ... + * -------------------------------------------------------------------------- + */ + + +#include "fuse.h" +#include "fuse_internal.h" +#include "fuse_backend.h" + +#include "fuse_tween.c" + +#include "allocators.c" +#include <stdint.h> +#include <string.h> + +#define FUSE_MIN(a, b) ((a < b) ? a : b) +#define FUSE_MAX(a, b) ((a > b) ? a : b) +#define FUSE_LIMIT(n, a, b) (FUSE_MAX(a, FUSE_MIN(b, n))) +#define FUSE_IS_HOVERED(x, y, w, h) (\ + f__canvas->pointer_x >= x && f__canvas->pointer_x <= x + w &&\ + f__canvas->pointer_y >= y && f__canvas->pointer_y <= y + h) + +static inline size_t fuse__element(); // "base class" of all UI widgets +static inline void fuse__cmdbuffer_push(FuseCmd cmd); +static void fuse__cmdbuffer_print(); + +static const char* fuse__cmd_name(uint8_t type); + +extern FuseCanvas +fuse_canvas_create(size_t memory_limit, FuseStyle base_style) +{ + (void) base_style; + + FuseCanvas new = malloc(sizeof *new); + memset(new, 0, sizeof *new); + + new->memory = malloc(memory_limit); + + al_arena_create(&new->arena, new->memory, memory_limit); + + size_t cmdbuffer_mem = (memory_limit * 8) / 10; + cmdbuffer_mem -= (cmdbuffer_mem % sizeof *new->cmdbuffer_ptr); // remove remainder + + FuseCmd *cmdbuffer_ptr = al_arena_alloc(&new->arena, cmdbuffer_mem); + new->cmdbuffer_ptr = cmdbuffer_ptr; + new->cmdbuffer_size = cmdbuffer_mem / sizeof (*cmdbuffer_ptr); + new->cmdbuffer_head = 0; + + size_t element_data_mem = memory_limit - cmdbuffer_mem; + void *element_data_ptr = al_arena_alloc(&new->arena, element_data_mem); + + al_arena_create(&new->element_data_arena, element_data_ptr, element_data_mem); + + fuse_canvas_set(new); + return new; +} + +extern void +fuse_canvas_set(FuseCanvas canvas) +{ + f__canvas = canvas; +} + +extern void +fuse_canvas_debug(FuseCanvas canvas, bool debug) +{ + canvas->debug = debug; +} + +extern void +fuse_canvas_clear(FuseCanvas canvas) +{ + canvas->cmdbuffer_head = 0; + canvas->current_id = 0; + canvas->current_frame++; +} + +extern void +fuse_canvas_draw(FuseCanvas canvas, FuseRendererCallback callback, void* data) +{ + for (size_t u = 0; u < f__canvas->cmdbuffer_head; u++) { + FuseCmd cmd = f__canvas->cmdbuffer_ptr[u]; + assert(cmd.type < FUSE_CMD_COUNT && "[FUSE] WARN: INVALID TYPE IN COMMAND BUFFER"); + callback(canvas, &cmd, data); + } +} + +extern void +fuse_canvas_resize(FuseCanvas canvas, float w, float h) +{ + canvas->width = w; + canvas->height = h; +} + +extern void +fuse_canvas_pointer(FuseCanvas canvas, int pointer_state, float x, float y) +{ + canvas->pointer_state = pointer_state; + canvas->pointer_x = x; + canvas->pointer_y = y; +#ifdef FUSE_DEBUG + const char *pstate[] = { + [FUSE_POINTER_NONE] = "NONE", + [FUSE_POINTER_PRESSED] = "PRESSED", + [FUSE_POINTER_RELEASED] = "RELEASED", + [FUSE_POINTER_ALT] = "ALT" + }; + printf("[DEBUG] [FUSE] px=%f py=%f ps=%s\n", canvas->pointer_x, canvas->pointer_y, pstate[pointer_state]); +#endif +} + +extern void +fuse_canvas_destroy(FuseCanvas canvas) +{ + free(canvas->memory); + free(canvas); +} + +extern bool +fuse_button(float x, float y, float width, float height, uint32_t selected, uint32_t hovered) +{ + size_t id = fuse__element(); + bool clicked = false; + + bool hot = FUSE_IS_HOVERED(x, y, width, height); + + if (hot) f__canvas->hot = id; + + /* are we the active component? */ + if (f__canvas->active == id) { + if (f__canvas->pointer_state == FUSE_POINTER_RELEASED) { + if (hot) clicked = true; + f__canvas->active = 0; + } + } else if (hot && f__canvas->pointer_state == FUSE_POINTER_PRESSED) { + f__canvas->active = id; + } + + FuseCmd cmd = { + .type = FUSE_CMD_RECT, + .rect = { + .color = (hot) ? hovered : selected, + .x = x, + .y = y, + .w = width, + .h = height, + } + }; + + fuse__cmdbuffer_push(cmd); + + return clicked; +} + +extern void +fuse_slider(float x, float y, float width, float height, uint32_t slider, uint32_t nob, float *nob_pos) +{ + size_t id = fuse__element(); + + /* are we the hot component? */ + bool hot = FUSE_IS_HOVERED(x, y, width, height); + + if (hot) f__canvas->hot = id; + + bool is_vert = (width < height); + float nob_width = is_vert ? width : height; + float nob_height = is_vert ? width : height; + float track_len = is_vert ? (height - nob_height) : (width - nob_width); + float p_off = is_vert ? (f__canvas->pointer_y - (y + nob_height * 0.5f)) : (f__canvas->pointer_x - (x + nob_width * 0.5f)); + float val = (track_len > 0.0f) ? (p_off / track_len) : 0.0f; + + /* calculate nob_pos from pointer */ + if (f__canvas->active == id) { + if (f__canvas->pointer_state == FUSE_POINTER_RELEASED) { + if (hot) { /* clicked */ } + f__canvas->active = 0; + } + *nob_pos = FUSE_MAX(0.0f, FUSE_MIN(1.0f, val)); + + } else if (hot && f__canvas->pointer_state == FUSE_POINTER_PRESSED) { + f__canvas->active = id; + *nob_pos = FUSE_MAX(0.0f, FUSE_MIN(1.0f, val)); + + } + + /* clamp nob_pos */ + *nob_pos = FUSE_LIMIT(*nob_pos, 0.0f, 1.0f); + + float nob_x = is_vert ? 0.0f : (*nob_pos * (width - nob_width)); + float nob_y = is_vert ? (*nob_pos * (height - nob_height)) : 0.0f; + + FuseCmd cmd = { + .type = FUSE_CMD_RECT, + .rect = { + .color = slider, + .x = x, + .y = y, + .w = width, + .h = height, + } + }; + + FuseCmd nob_rect = { + .type = FUSE_CMD_RECT, + .rect = { + .color = nob, + .x = x + nob_x, + .y = y + nob_y, + .w = nob_width, + .h = nob_height, + } + }; + + fuse__cmdbuffer_push(cmd); + fuse__cmdbuffer_push(nob_rect); +} + +extern int +fuse_tooltip(const char *text) +{ + FUSE_TODO; + /* NOTE(vasco): this is supposed to add a tooltip when the last element was hovered... + * will probably need to grab the last element's box? + * I mean i need to know it's bounds and add an element that + * shows up after being hovered over a few frames + * so we will need to retain some data via the hashmap + * + * that's the plan for now + */ + (void) text; +} + +static inline size_t +fuse__element() +{ + // we increment first because 0 is used for when no element is + // selected + size_t id = ++f__canvas->current_id; + return id; +} + +static inline void +fuse__cmdbuffer_push(FuseCmd cmd) +{ + if (f__canvas->cmdbuffer_head < f__canvas->cmdbuffer_size) + f__canvas->cmdbuffer_ptr[f__canvas->cmdbuffer_head++] = cmd; +} + +static void +fuse__cmdbuffer_print() +{ + for (size_t u = 0; u < f__canvas->cmdbuffer_head; u++) { + FuseCmd cmd = f__canvas->cmdbuffer_ptr[u]; + assert(cmd.type < FUSE_CMD_COUNT && "[FUSE] WARN: INVALID TYPE IN COMMAND BUFFER"); + + printf("CMD: %s - ", fuse__cmd_name(cmd.type)); + switch (cmd.type) { + case FUSE_CMD_RECT: + printf("x=%f y=%f w=%f h=%f col=%x", cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h, cmd.rect.color); + break; + } + printf("\n"); + } +} + +static const char* +fuse__cmd_name(uint8_t type) +{ + assert(type < FUSE_CMD_COUNT); + return fuse_cmd_name[type]; +} + + +extern bool +fuse_button_text(const char *text, float x, float y, float width, float height, uint32_t selected, uint32_t hovered) +{ + (void) text; (void) x; (void) y; (void) width; (void) height; (void) selected; (void) hovered; + FUSE_TODO; + return false; +} + +extern bool +fuse_checkbox_text(const char *text, bool *value) +{ + (void) text; (void) value; + FUSE_TODO; + return false; +} + +extern bool +fuse_element_is_hovered(const char *text) +{ + (void) text; + FUSE_TODO; + return false; +} + +extern void +fuse_hovered(void (*op)(void*), void *data) +{ + (void) op; (void) data; + FUSE_TODO; +} + +extern void +fuse_hovered_clear() +{ + FUSE_TODO; +} + +extern void +fuse_rotate_rad() +{ + FUSE_TODO; +} + +extern void +fuse_rotate_deg() +{ + FUSE_TODO; +} + +extern void +fuse_layout(FuseLayoutInfo info) +{ + (void) info; + FUSE_TODO; +} + +extern void +fuse_div_begin(float x, float y, float width, float height, uint32_t color) +{ + (void) x; (void) y; (void) width; (void) height; (void) color; + FUSE_TODO; +} + +extern void +fuse_div_end() +{ + FUSE_TODO; +} + +extern void +fuse_flex_begin(float x, float y, float width, float height, uint32_t color) +{ + (void) x; (void) y; (void) width; (void) height; (void) color; + FUSE_TODO; +} + +extern void +fuse_flex_end() +{ + FUSE_TODO; +} + +extern FuseStyle +fuse_style_save(const char *path) +{ + (void) path; + FUSE_TODO; + return NULL; +} + +extern void +fuse_style_set(FuseStyle style) +{ + (void) style; + FUSE_TODO; +} + +extern void +fuse_style_load(const char *path) +{ + (void) path; + FUSE_TODO; +} + +extern void +fuse_window_begin(char *name, float width, float height, uint32_t border_color, uint32_t border_width) +{ + (void) name; (void) width; (void) height; (void) border_color; (void) border_width; + FUSE_TODO; +} + +extern void +fuse_window_end() +{ + FUSE_TODO; +} + +extern void +fuse_grid_begin(uint32_t cols, uint32_t rows, const float *col_ratios, const float *row_ratios) +{ + (void) cols; (void) rows; (void) col_ratios; (void) row_ratios; + FUSE_TODO; +} + +extern void fuse_grid_next_row() { FUSE_TODO; } +extern void fuse_grid_next_col() { FUSE_TODO; } +extern void fuse_grid_prev_row() { FUSE_TODO; } +extern void fuse_grid_prev_col() { FUSE_TODO; } +extern void fuse_grid_next() { FUSE_TODO; } +extern void fuse_grid_prev() { FUSE_TODO; } + +extern void +fuse_grid_goto(uint32_t col, uint32_t row) +{ + (void) col; (void) row; + FUSE_TODO; +} + +extern void fuse_grid_end() { FUSE_TODO; } + +extern void fuse_3d_object() { FUSE_TODO; } +extern void fuse_3d_point_at() { FUSE_TODO; } + +extern int +fuse_animate_i(FuseAnimation anim, int i1, int i2) +{ + (void) anim; (void) i1; (void) i2; + FUSE_TODO; + return 0; +} + +extern float +fuse_animate_f(FuseAnimation anim, float f1, float f2, float f, bool loop) +{ + (void) anim; (void) f1; (void) f2; (void) f; (void) loop; + FUSE_TODO; + return 0.0f; +} + +#endif // _FUSE_C_ |
