This commit is contained in:
Alessandro Mauri 2022-12-05 23:19:37 +01:00
parent 14def875d6
commit 894b2763c0
3 changed files with 354 additions and 522 deletions

495
ugui.h
View file

@ -1,243 +1,121 @@
#ifndef _UGUI_H
#define _UGUI_H
#ifndef _UG_HEADER
#define _UG_HEADER
#define UG_STACK(T) struct { T *items; int idx; int size; }
#define BIT(n) (1 << n)
#define RGBA_FORMAT(x) { .a=x&0xff, .b=(x>>8)&0xff, .g=(x>>16)&0xff, .r=(x>>24)&0xff }
#define RGB_FORMAT(x) { .a=0xff, .b=x&0xff, .g=(x>>8)&0xff, .r=(x>>16)&0xff }
#define SIZE_PX(x) { .size=x, .unit=UG_UNIT_PX }
#define SIZE_MM(x) { .size=x, .unit=UG_UNIT_MM }
#define SIZE_PT(x) { .size=x, .unit=UG_UNIT_PT }
// Macros
#define UG_STACK(T) struct { T *items; int idx; int size; }
// basic types
typedef unsigned int ug_id_t;
typedef struct { union {int x, w;}; union {int y, h;}; } ug_vec2_t;
typedef struct { int x, y, w, h; } ug_rect_t;
typedef struct { unsigned char a, b, g, r; } ug_color_t;
typedef struct { int size, unit; } ug_size_t;
/* Point Coordinate */
// coordinate type, or how it is measured
enum {
UG_CTYPE_PX = 0x0,
UG_CTYPE_MM = 0x1,
UG_CTYPE_REL = 0x2,
};
// coordinate anchor, or where it refers
enum {
UG_CANCHOR_TOP = 0x0, // x coordinates
UG_CANCHOR_LEFT = 0x0,
UG_CANCHOR_BOTTOM = 0x1, // y coordinates
UG_CANCHOR_RIGHT = 0x1,
UG_CANCHOR_VCENTER = 0x2, // for positions it should be centered
UG_CANCHOR_HCENTER = 0x2,
};
struct _ug_pt_flags {
unsigned long int _:56;
unsigned long int t:4;
unsigned long int a:4;
};
typedef enum {
UG_UNIT_PX = 0,
UG_UNIT_MM,
UG_UNIT_PT,
} ug_unit_t;
// container type, a container is an entity that contains layouts, a container has
// a haight a width and their maximum values, in essence a container is a rectangular
// area that can be resized and sits somewhere on the drawable region
// the z index of a container is determined by it's position on the stack
typedef struct {
// first coordinate
union {
union {
int x;
struct _ug_pt_flags fx;
};
union {
int w;
struct _ug_pt_flags fw;
};
union {
int m;
struct _ug_pt_flags fm;
};
};
// second coordinate
union {
union {
int y;
struct _ug_pt_flags fy;
};
union {
int h;
struct _ug_pt_flags fh;
};
union {
int a;
struct _ug_pt_flags fa;
};
};
} ug_coord_t;
// TODO: define stroke style (f.s)
typedef struct {
int size;
struct {
// type of size
unsigned char t:4;
// stroke style
unsigned char s:4;
} f;
} ug_stroke_t;
//---//
/* RGBA Color type */
typedef struct {
unsigned char a;
unsigned char b;
unsigned char g;
unsigned char r;
} ug_color_t;
//---//
/* simple position structure */
struct ug_vec2 {
int x, y;
};
typedef struct {
int x, y;
int w, h;
} ug_rect_t;
//---//
/* Mouse button mask */
enum ug_mouse_btn {
UG_MOUSEBTN_LEFT = 1,
UG_MOUSEBTN_MIDDLE = 2,
UG_MOUSEBTN_RIGHT = 4,
UG_MOUSEBTN_4 = 8,
UG_MOUSEBTN_5 = 16,
};
//---//
/* event structure */
typedef enum {
UG_EV_WINDOWMOVE,
UG_EV_WINDOWRESIZE,
UG_EV_WINDOWSHOW,
UG_EV_MOUSEMOVE,
UG_EV_MOUSEDOWN,
UG_EV_MOUSEUP,
UG_EV_KEYDOWN,
UG_EV_KEYUP,
} ug_event_type_t;
typedef struct {
ug_event_type_t type;
union {
int x;
int w;
unsigned int code;
};
union {
int y;
int h;
unsigned int mask;
};
} ug_event_t;
//---//
/* Primitive element type */
typedef enum {
UG_E_RECT = 0,
UG_E_TRIANGLE,
UG_E_DOT,
UG_E_LINE,
UG_E_ARC,
UG_E_TEXT,
UG_E_SPRITE,
} ug_element_type_t;
typedef struct {
ug_coord_t size;
ug_coord_t pos;
ug_color_t color;
} ug_rect_t;
typedef struct {
ug_coord_t size;
ug_coord_t pos;
ug_color_t color;
} ug_triangle_t;
typedef struct {
ug_stroke_t stroke;
ug_coord_t pos;
ug_color_t color;
} ug_dot_t;
typedef struct {
ug_stroke_t stroke;
ug_coord_t vert[2];
ug_color_t color;
} ug_line_t;
typedef struct {
ug_stroke_t stroke;
ug_coord_t vert[3];
ug_color_t color;
} ug_arc_t;
// draw text from view[start] to view[end]
typedef struct {
ug_stroke_t stroke;
ug_coord_t pos;
ug_color_t color;
const char *view;
int start;
int end;
} ug_text_t;
// all sprites have to be mapped into memory, map is an array of width x height
// bytes, the type is specified by the user
typedef struct {
ug_coord_t pos;
void *map;
int width;
int height;
} ug_sprite_t;
// data is the actual element data, it has to be cast to the right element specified
// by type and is variable size so that no memory is wasted, size is the size in
// bytes of data + id + size + type
typedef struct {
ug_element_type_t type;
unsigned int size;
unsigned int id;
unsigned char data[];
} ug_element_t;
//---//
/* Layout region */
typedef struct {
ug_id_t id;
ug_unit_t unit;
ug_rect_t rect;
// FIXME: is this needed?
unsigned int id;
// indentation level, used in trees
// FIXME: is this needed?
unsigned int indent;
} ug_layout_region_t;
//---//s
ug_vec2_t max_size;
unsigned int flags;
} ug_container_t;
/* Global context */
// one context per phisical window
// a phisical window can be anything, but here it basically represents the true
// surface where things are drawn into, a window has a scale, dpi and ppm
// (pixel per mm), only the latter is truly needed, the user sets these variables
// and has to take care of updating them when needed
// the container flags
enum {
UG_CNT_MOVABLE = BIT(0), // can be moved
UG_CNT_RESIZABLE = BIT(1), // can be resized
UG_CNT_SCROLL_X = BIT(2), // can have horizontal scrolling
UG_CNT_SCROLL_Y = BIT(3), // can have vertical scrolling
};
// style, defines default height, width, color, margins, borders, etc
// all dimensions should be taken as a reference when doing the layout since
// ultimately it's the layout that decides them. For example when deciding how to
// allocate space one can say that the default size of a region that allocates a
// slider has the style's default dimensions for a slider
typedef struct {
unsigned int window_id;
float scale, dpi, ppm;
// the user pushes the things that he wants to draw onto the element stack,
// which contains all the primitives needed to draw the wanted element
UG_STACK(unsigned char) e_stack;
// the element which has focus
unsigned int focus_id;
// the element that we are hovering
unsigned int hover_id;
struct {
ug_color_t color, alt_color;
ug_size_t size, alt_size;
} text;
ug_color_t bg_color;
// base sizes for all elements, some elements should be different, like
// buttons and other things that need to stand out
struct {
ug_size_t width, height, border_width;
ug_color_t color, hover_color, active_color;
} base;
// a button should stand out, hence the different colors
struct {
ug_color_t bg_color, hover_color, active_color;
} button;
// a checkbox should be smaller than a button
struct {
ug_size_t width, height, tick_size;
ug_color_t tick_color;
} checkbox;
// a slider can be thinner and generally wider than a button
struct {
ug_size_t width, height;
} slider;
// the text color, dimension and the background of a text display can be
// different
struct {
ug_color_t text_color, bg_color;
ug_size_t text_size;
} textdisplay;
} ug_style_t;
// context
typedef struct {
// some style information
const ug_style_t *style;
// style_px is a style cache where all measurements are already in pixels
const ug_style_t *style_px;
// ppi: pixels per inch
// ppm: pixels per millimeter
// ppd: pixels per dot
float scale, ppi, ppm, ppd;
// containers need to know how big the "main container" is so that all
// the relative positioning work
ug_vec2_t size;
// which context and element we are hovering
struct {
ug_id_t cnt, elem;
} hover;
// the id of the "active" element, active means different things for
// different elements, for exaple active for a button means to be pressed,
// and for a text box it means to be focused
ug_id_t active;
// count the frames for fun
unsigned long int frame;
// current measurement unit
ug_unit_t unit;
// mouse data
struct {
struct ug_vec2 pos;
struct ug_vec2 last_pos;
struct ug_vec2 delta;
struct ug_vec2 scroll_delta;
ug_vec2_t pos;
ug_vec2_t last_pos;
ug_vec2_t delta;
ug_vec2_t scroll_delta;
// down/pressed masks get updated on mousedown, whereas down_mask
// only on mouseup, so the masks differ by the buttons that were
// released
@ -252,146 +130,39 @@ typedef struct {
} key;
// input text buffer
char input_text[32];
// stacks
UG_STACK(ug_container_t) container_stack;
} ug_ctx_t;
//---//
// creates a new context, fills with default values, ctx is ready for ug_start()
// context initialization
ug_ctx_t *ug_new_ctx(void);
void ug_free_ctx(ug_ctx_t *ctx);
// updates the context with user information
int ug_update_ctx(ug_ctx_t *ctx,
unsigned int window_id,
float scale,
float dpi,
float ppm
);
// register inputs
void ug_input_mousedown(ug_ctx_t *ctx, int x, int y, unsigned char btn);
void ug_input_mouseup(ug_ctx_t *ctx, int x, int y, unsigned char btn);
void ug_input_mousemove(ug_ctx_t *ctx, int x, int y);
void ug_input_scroll(ug_ctx_t *ctx, int x, int y);
void ug_input_keydown(ug_ctx_t *ctx, int key);
void ug_input_keyup(ug_ctx_t *ctx, int key);
void ug_input_text(ug_ctx_t *ctx, const char *text);
// between begin and end the user draws
int ug_begin(ug_ctx_t *ctx);
int ug_end(ug_ctx_t *ctx);
// layout control
// Split the layout vertically and horizontally, n times each time with the
// supplied width/height
/* Window space
* +-----------------------------+
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* +-----------------------------+
*
* ug_layout_vsplit(ctx, 2, (int[]){10, 20});
* create two vertical zones
* +-----------------------------+
* | } 10px |
* +-----------------------------+
* | |> 20px |
* | | |
* +-----------------------------+
* | |
* | |
* | remainder |
* | |
* | |
* | |
* +-----------------------------+
*
* ug_layout_hsplit(ctx, 3, NULL);
* equally spaced divisions
* +-----------------------------+
* | | | |
* +-----------------------------+
* | |> 20px |
* | | |
* +-----------------------------+
* | |
* | |
* | remainder |
* | |
* | |
* | |
* +-----------------------------+
*
* ug_button(ctx, "ciao");
* ug_layout_next(ctx); // skip second square
* ug_button(ctx, "quit");
* float val = 0.3
* ug_slider(ctx, &val, 0, 1);
* ug_text(ctx, "lorem ipsum\ndolor et");
*
* +-----------------------------+
* | ciao | | quit |
* +-----------------------------+
* | # 0.3 |
* | # |
* +-----------------------------+
* | lorem ipsum |
* | dolor et |
* | |
* | |
* | |
* | |
* +-----------------------------+
*
* ug_layout_popup(ctx, {100x50, centrato});
* ug_layout_vsplit(ctx, 1, NULL);
* ug_button(ctx, "btn1");
* ug_button(ctx, "btn2");
*
* +-----------------------------+
* | ciao | | quit |
* +-----------------------------+
* | # 0.3 |
* | # +----------+ |
* +--------| btn1 |---------+
* | lorem i| | |
* | dolor e+----------+ |
* | | btn2 | |
* | | | |
* | +----------+ |
* | |
* | |
* +-----------------------------+
*/
int ug_layout_vsplit(ug_ctx_t *ctx, int n, const int *heights);
int ug_layout_hsplit(ug_ctx_t *ctx, int n, const int *widths);
// popup layout, create a rectangle that sits over the view and has a higher
// z-index, this allows it to have any position and have focus priority
// creating a popup selects it as current layout
int ug_layout_popup(ug_ctx_t *ctx, ug_rect_t rect);
// get the next rectangular region in the layout context
ug_rect_t ug_layout_next(ug_ctx_t *ctx);
// get the current layout rectangle area, but do not pop it (select the next)
// this is useful to get information about the area's width height and position
ug_rect_t ug_layout_get_current(ug_ctx_t *ctx);
// set the unit of the dimensions, in the context all units are pixels but
// when regions are defined units can be in pixels, millimiters, etc
int ui_layout_set_mm(ug_ctx_t *ctx);
int ui_layout_set_px(ug_ctx_t *ctx);
// ui elements
int ug_slider(ug_ctx_t *ctx, float *stat, float min, float max);
int ug_ctx_set_displayinfo(ug_ctx_t *ctx, float scale, float ppi);
int ug_ctx_set_drawableregion(ug_ctx_t *ctx, ug_vec2_t size);
int ug_ctx_set_style(ug_ctx_t *ctx, const ug_style_t *style);
int ug_ctx_set_unit(ug_ctx_t *ctx, ug_unit_t unit);
// un-define macros that we don't want the user to access
// define containers, name is used as a salt for the container id, all sizes are
// the default ones, resizing is done automagically with internal state
// a floating container can be placed anywhere and can be resized, acts like a
// window inside another window
int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_rect_t rect);
// like a floating container but cannot be resized
int ug_container_popup(ug_ctx_t *ctx, const char *name, ug_rect_t rect);
// a menu bar is a container of fixed height, cannot be resized and sits at the
// top of the window
int ug_container_menu_bar(ug_ctx_t *ctx, const char *name, int height);
// a sidebar is a variable size container anchored to one side of the window
int ug_container_sidebar(ug_ctx_t *ctx, const char *name, int width);
// a body is a container that scales with the window, sits at it's center and cannot
// be resized
int ug_container_body(ug_ctx_t *ctx, const char *name);
#undef UG_STACK
#undef BIT
#endif
#endif