#ifndef _UG_HEADER #define _UG_HEADER #define UG_STACK(T) struct { T *items; int idx, size, sorted; } #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.i=x, .unit=UG_UNIT_PX } #define SIZE_MM(x) { .size.f=x, .unit=UG_UNIT_MM } #define SIZE_PT(x) { .size.f=x, .unit=UG_UNIT_PT } #define SQUARE(x) .w = x, .h = x // basic types typedef unsigned int ug_id_t; typedef struct { union {int x, w;}; union {int y, h;}; } ug_vec2_t; typedef struct { unsigned char a, b, g, r; } ug_color_t; typedef struct { int x, y, w, h; } ug_rect_t; typedef struct { union {int i; float f;} size; int unit; } ug_size_t; // div has information about the phisical dimension typedef struct { ug_size_t x, y, w, h;} ug_div_t; typedef enum { UG_UNIT_PX = 0, UG_UNIT_MM, UG_UNIT_PT, } ug_unit_t; // element type typedef struct { ug_id_t id; unsigned short int type; unsigned short int flags; ug_rect_t rect, rca; const char *name; union { struct { const char *txt; } btn; }; } ug_element_t; enum { UG_ELEM_BUTTON, // button UG_ELEM_TXTBTN, // textual button, a button but without frame UG_ELEM_CHECK, // checkbox UG_ELEM_RADIO, // radio button UG_ELEM_TOGGLE, // toggle button UG_ELEM_LABEL, // simple text UG_ELEM_UPDOWN, // text with two buttons up and down UG_ELEM_TEXTINPUT, // text input box UG_ELEM_TEXTBOX, // text surrounded by a box UG_ELEM_IMG, // image, icon UG_ELEM_SPACE, // takes up space }; enum { ELEM_CLIPPED = BIT(0), }; // 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 { ug_id_t id; const char *name; ug_rect_t rect; // absolute position rect ug_rect_t rca; unsigned int flags; // layouting and elements // total space used by elements, x and y are the starting coordinates // for elements ug_rect_t space; // origin for in-row and in-column elements ug_vec2_t c_orig, r_orig; UG_STACK(ug_element_t) elem_stack; ug_id_t selected_elem, hover_elem; } ug_container_t; // the container flags enum { UG_CNT_FLOATING = BIT(0), // is on top of everything else UG_CNT_RESIZE_RIGHT = BIT(1), // can be resized from the right border UG_CNT_RESIZE_BOTTOM = BIT(2), // can be resized from the bottom border UG_CNT_RESIZE_LEFT = BIT(3), // can be resized from the left border UG_CNT_RESIZE_TOP = BIT(4), // can be resized from the top border UG_CNT_SCROLL_X = BIT(5), // can have horizontal scrolling UG_CNT_SCROLL_Y = BIT(6), // can have vertical scrolling UG_CNT_MOVABLE = BIT(7), // can be moved around // container state CNT_STATE_NONE = BIT(30), CNT_STATE_MOVING = BIT(29), CNT_STATE_RESIZE_T = BIT(28), CNT_STATE_RESIZE_B = BIT(27), CNT_STATE_RESIZE_L = BIT(26), CNT_STATE_RESIZE_R = BIT(25), CNT_STATE_RESIZE_D = BIT(24), CNT_STATE_DELETE = BIT(23), // The container is marked for removal // layouting CNT_LAYOUT_COLUMN = BIT(22), }; // 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 { struct { ug_color_t bg, fg; } color; ug_size_t margin; struct { ug_color_t color; ug_size_t size; } border; struct { struct { ug_color_t bg, fg; } color; ug_size_t height, font_size; } title; struct { struct { ug_color_t act, bg, fg, sel, br; } color; ug_size_t font_size, border; } btn; } ug_style_t; // render commands struct ug_cmd_rect { int x, y, w, h; ug_color_t color; }; struct ug_cmd_text { int x, y, size; ug_color_t color; const char *str; }; typedef struct { unsigned int type; union { struct ug_cmd_rect rect; struct ug_cmd_text text; }; } ug_cmd_t; typedef enum { UG_CMD_NULL = 0, UG_CMD_RECT, UG_CMD_TEXT, } ug_cmd_type_t; // window side enum { UG_SIDE_TOP = 0, UG_SIDE_BOTTOM, UG_SIDE_LEFT, UG_SIDE_RIGHT, }; // mouse buttons enum { UG_BTN_LEFT = BIT(0), UG_BTN_MIDDLE = BIT(1), UG_BTN_RIGHT = BIT(2), UG_BTN_4 = BIT(3), UG_BTN_5 = BIT(4), }; // 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 ppi, ppm, ppd; float last_ppi, last_ppm, last_ppd; // containers need to know how big the "main container" is so that all // the relative positioning work ug_vec2_t size; ug_rect_t origin; // which context and element we are hovering ug_id_t hover_cnt; // active is updated on mousedown and released on mouseup // 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_cnt, last_active_cnt; // id of the selected container, used for layout // NOTE: since the stacks can be relocated with realloc it is better not // to use a pointer here, even tough it would be better for efficiency ug_id_t selected_cnt; // count the frames for fun unsigned long int frame; // mouse data struct { ug_vec2_t pos; ug_vec2_t last_pos; ug_vec2_t delta; ug_vec2_t scroll_delta; // mouse.update: a mask of the mouse buttons that are being updated unsigned char update; // mouse.hold: a mask of the buttons that are being held unsigned char hold; } mouse; // keyboard key pressed struct { unsigned char update; unsigned char hold; } key; // input text buffer char input_text[32]; // stacks UG_STACK(ug_container_t) cnt_stack; UG_STACK(ug_cmd_t) cmd_stack; // command stack iterator int cmd_it; } ug_ctx_t; // context initialization ug_ctx_t * ug_ctx_new(void); void ug_ctx_free(ug_ctx_t *ctx); // updates the context with user information // ppi: pixels per inch, the scale used for all em/mm to pixel calculations // scale: it is the scale between the physical pixels on the screen and the pixels // on the buffer, if unsure set to 1.0 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); // 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_div_t div); // like a floating container but cannot be resized int ug_container_popup(ug_ctx_t *ctx, const char *name, ug_div_t div); // 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, ug_size_t 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, ug_size_t size, int side); // a body is a container that scales with the window, sits at it's center and cannot // be resized, it also fills all the available space int ug_container_body(ug_ctx_t *ctx, const char *name); // mark a conatiner for removal, it will be freed at the next frame beginning if // name is NULL then use the selected container int ug_container_remove(ug_ctx_t *ctx, const char *name); // get the drawable area of the container, if name is NULL then use the selected // container ug_rect_t ug_container_get_rect(ug_ctx_t *ctx, const char *name); // layouting, the following functions define how different ui elements are placed // inside the selected container. A new element is aligned respective to the // previous element and/or to the container, particularly elements can be placed // in a row or a column. int ug_layout_row(ug_ctx_t *ctx); int ug_layout_column(ug_ctx_t *ctx); int ug_layout_next_row(ug_ctx_t *ctx); int ug_layout_next_column(ug_ctx_t *ctx); // elements int ug_element_button(ug_ctx_t *ctx, const char *name, const char *txt, ug_div_t dim); int ug_element_textbtn(ug_ctx_t *ctx, const char *name, const char *txt, ug_div_t dim); // Input functions int ug_input_mousemove(ug_ctx_t *ctx, int x, int y); int ug_input_mousedown(ug_ctx_t *ctx, unsigned int mask); int ug_input_mouseup(ug_ctx_t *ctx, unsigned int mask); int ug_input_scroll(ug_ctx_t *ctx, int x, int y); // TODO: other input functions // Frame handling int ug_frame_begin(ug_ctx_t *ctx); int ug_frame_end(ug_ctx_t *ctx); // Commands // get the next command, save iteration state inside 'iterator' ug_cmd_t * ug_cmd_next(ug_ctx_t *ctx); #undef UG_STACK #undef BIT #endif