Compare commits
No commits in common. "28b5ee16fb3bde66ae7a7456a22a9220ad911cd8" and "99df8ad38d646137bcf871d93ef52f845491bd5a" have entirely different histories.
28b5ee16fb
...
99df8ad38d
@ -88,76 +88,6 @@ multiple +--------v---------+ |
|
|||||||
+--------------+
|
+--------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
### Layouting
|
|
||||||
|
|
||||||
Layouting happens in a dynamic grid, when a new element is inserted in a non-floating
|
|
||||||
manner it reserves a space in the grid, new elements are placed following this grid.
|
|
||||||
|
|
||||||
Every div has two points of origin, one for the row layout and one for the column
|
|
||||||
layout, named origin_r and origin_c respectively
|
|
||||||
|
|
||||||
origin_r is used when the row layout is used and it is used to position the child
|
|
||||||
elements one next to the other, as such it always points to the top-right edge
|
|
||||||
of the last row element
|
|
||||||
|
|
||||||
```text
|
|
||||||
Layout: row
|
|
||||||
#: lost space
|
|
||||||
Parent div
|
|
||||||
x---------------------------------+
|
|
||||||
|[origin_c] |
|
|
||||||
|[origin_r] |
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
+---------------------------------+
|
|
||||||
|
|
||||||
Parent div
|
|
||||||
+-----x---------------------------+
|
|
||||||
| |[origin_r] |
|
|
||||||
| E1 | |
|
|
||||||
| | |
|
|
||||||
x-----+---------------------------+
|
|
||||||
|[origin_c] |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
+-----+---------------------------+
|
|
||||||
|
|
||||||
Parent div
|
|
||||||
+-----+----------+-----x----------+
|
|
||||||
| | E2 | |[origin_r]|
|
|
||||||
| E1 +----------+ | |
|
|
||||||
| |##########| E3 | |
|
|
||||||
+-----+##########| | |
|
|
||||||
|################| | |
|
|
||||||
+----------------x-----+----------+
|
|
||||||
| [origin_c] |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
+----------------+----------------+
|
|
||||||
```
|
|
||||||
|
|
||||||
TODO: handle when the content overflows the div
|
|
||||||
- Use a different concept, like a view or relative space, for example the child
|
|
||||||
div could have position `[0,0]` but in reality it is relative to the origin of the
|
|
||||||
parent div
|
|
||||||
- each div could have a view and a total area of the content, when drawing everything
|
|
||||||
is clipped to the view and scrollbars are shown
|
|
||||||
- individual elements accept dimensions and the x/y coordinates could be interpreted
|
|
||||||
as offset if the layout is row/column or absolute coordinates if the leayout is floating
|
|
||||||
|
|
||||||
A div can be marked resizeable or fixed, and static or dynamic. The difference being
|
|
||||||
that resizeable adds a resize handle to the div and dynamic lets the content overflow
|
|
||||||
causing scrollbars to be drawn
|
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
How elements determine if they have focus or not
|
How elements determine if they have focus or not
|
||||||
@ -176,9 +106,3 @@ if(PARENT_HAS_FOCUS()) {
|
|||||||
fast path to return
|
fast path to return
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
How to get ids:
|
|
||||||
1. use a name for each element
|
|
||||||
2. supply an id for each element
|
|
||||||
3. use a macro and the line position as id and then hash it
|
|
||||||
4. use a macro, get the code line and hash it
|
|
||||||
|
368
ugui.c
368
ugui.c
@ -8,20 +8,6 @@
|
|||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
#include "ugui.h"
|
#include "ugui.h"
|
||||||
|
|
||||||
#define RGBA(u) \
|
|
||||||
(UgColor) \
|
|
||||||
{ \
|
|
||||||
.r = (u >> 24) & 0xff, .g = (u >> 16) & 0xff, .b = (u >> 8) & 0xff, \
|
|
||||||
.a = (u >> 0) & 0xff \
|
|
||||||
}
|
|
||||||
#define DIV_FILL \
|
|
||||||
(UgRect) { .x = 0, .y = 0, .w = 0, .h = 0 }
|
|
||||||
|
|
||||||
#define STACK_STEP 10
|
|
||||||
#define MAX_ELEMS 128
|
|
||||||
#define MAX_CMDS 256
|
|
||||||
#define ROOT_ID 1
|
|
||||||
|
|
||||||
typedef struct _UgCmd {
|
typedef struct _UgCmd {
|
||||||
enum {
|
enum {
|
||||||
CMD_RECT = 0,
|
CMD_RECT = 0,
|
||||||
@ -29,8 +15,8 @@ typedef struct _UgCmd {
|
|||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
UgRect rect;
|
int32_t x, y, w, h;
|
||||||
UgColor color;
|
uint8_t color[4]; // rgba, [0] = r
|
||||||
} rect;
|
} rect;
|
||||||
};
|
};
|
||||||
} UgCmd;
|
} UgCmd;
|
||||||
@ -72,6 +58,8 @@ int ug_stack_free(UgStack *stack)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define STACK_STEP 10
|
||||||
|
|
||||||
int ug_stack_push(UgStack *stack, UgCmd *cmd)
|
int ug_stack_push(UgStack *stack, UgCmd *cmd)
|
||||||
{
|
{
|
||||||
if (stack == NULL || cmd == NULL) {
|
if (stack == NULL || cmd == NULL) {
|
||||||
@ -112,10 +100,6 @@ int ug_stack_pop(UgStack *stack, UgCmd *cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InputEventFlags {
|
|
||||||
INPUT_CTX_SIZE = 1 << 0, // window size was changed
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _UgCtx {
|
struct _UgCtx {
|
||||||
enum {
|
enum {
|
||||||
row = 0,
|
row = 0,
|
||||||
@ -131,29 +115,14 @@ struct _UgCtx {
|
|||||||
int width, height;
|
int width, height;
|
||||||
} size;
|
} size;
|
||||||
|
|
||||||
// input structure, it describes the events received between frames
|
|
||||||
struct {
|
|
||||||
uint32_t flags;
|
|
||||||
} input;
|
|
||||||
|
|
||||||
int div_using; // tree node indicating the current active div
|
int div_using; // tree node indicating the current active div
|
||||||
};
|
};
|
||||||
|
|
||||||
// layouting
|
int ug_div_begin(UgCtx *ctx, const char *name, UgRect div);
|
||||||
int ug_layout_row(void);
|
|
||||||
int ug_layout_column(void);
|
|
||||||
int ug_layout_floating(void);
|
|
||||||
int ug_layout_next_row(void);
|
|
||||||
int ug_layout_next_column(void);
|
|
||||||
|
|
||||||
int ug_div_begin(UgCtx *ctx, const char *label, UgRect div);
|
|
||||||
int ug_div_end(UgCtx *ctx);
|
int ug_div_end(UgCtx *ctx);
|
||||||
int ug_input_window_size(UgCtx *ctx, int width, int height);
|
int ug_input_window_size(UgCtx *ctx, int width, int height);
|
||||||
UgId djb2(const char *str);
|
UgId djb2(const char *str);
|
||||||
|
|
||||||
int ug_button(UgCtx *ctx, const char *label, UgRect size);
|
|
||||||
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
UgCtx ctx;
|
UgCtx ctx;
|
||||||
@ -167,21 +136,18 @@ int main(void)
|
|||||||
// Main loop
|
// Main loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
|
|
||||||
// Input handling
|
// UI handling
|
||||||
|
ug_frame_begin(&ctx);
|
||||||
|
|
||||||
if (IsWindowResized()) {
|
if (IsWindowResized()) {
|
||||||
width = GetScreenWidth();
|
width = GetScreenWidth();
|
||||||
height = GetScreenHeight();
|
height = GetScreenHeight();
|
||||||
ug_input_window_size(&ctx, width, height);
|
ug_input_window_size(&ctx, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI handling
|
// main div, fill the whole window
|
||||||
ug_frame_begin(&ctx);
|
#define DIV_FILL (UgRect) {.x = 0, .y = 0, .w = -1, .h = -1}
|
||||||
|
|
||||||
// main div, fill the whole window
|
|
||||||
ug_div_begin(&ctx, "main", DIV_FILL);
|
ug_div_begin(&ctx, "main", DIV_FILL);
|
||||||
|
|
||||||
ug_button(&ctx, "button0", (UgRect){.w = 100, .h = 16});
|
|
||||||
|
|
||||||
ug_div_end(&ctx);
|
ug_div_end(&ctx);
|
||||||
|
|
||||||
ug_frame_end(&ctx);
|
ug_frame_end(&ctx);
|
||||||
@ -190,30 +156,26 @@ int main(void)
|
|||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(BLACK);
|
ClearBackground(BLACK);
|
||||||
|
|
||||||
|
Rectangle r;
|
||||||
Color c;
|
Color c;
|
||||||
for (UgCmd cmd; ug_stack_pop(&ctx.stack, &cmd) >= 0;) {
|
for (UgCmd cmd; ug_stack_pop(&ctx.stack, &cmd) >= 0;) {
|
||||||
printf("bruh\n");
|
|
||||||
switch (cmd.type) {
|
switch (cmd.type) {
|
||||||
case CMD_RECT:
|
case CMD_RECT:
|
||||||
//printf(
|
printf(
|
||||||
// "rect x=%d y=%d w=%d h=%d\n",
|
"rect x=%d y=%d w=%d h=%d\n",
|
||||||
// cmd.rect.rect.x,
|
cmd.rect.x,
|
||||||
// cmd.rect.rect.y,
|
cmd.rect.y,
|
||||||
// cmd.rect.rect.w,
|
cmd.rect.w,
|
||||||
// cmd.rect.rect.h
|
cmd.rect.h
|
||||||
//);
|
);
|
||||||
c = (Color) {
|
c = (Color) {
|
||||||
.r = cmd.rect.color.r,
|
.r = cmd.rect.color[0],
|
||||||
.g = cmd.rect.color.g,
|
.g = cmd.rect.color[1],
|
||||||
.b = cmd.rect.color.b,
|
.b = cmd.rect.color[2],
|
||||||
.a = cmd.rect.color.a,
|
.a = cmd.rect.color[3],
|
||||||
};
|
};
|
||||||
DrawRectangle(
|
DrawRectangle(
|
||||||
cmd.rect.rect.x,
|
cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h, c
|
||||||
cmd.rect.rect.y,
|
|
||||||
cmd.rect.rect.w,
|
|
||||||
cmd.rect.rect.h,
|
|
||||||
c
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -233,6 +195,9 @@ int main(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_ELEMS 128
|
||||||
|
#define MAX_CMDS 256
|
||||||
|
|
||||||
int ug_init(UgCtx *ctx)
|
int ug_init(UgCtx *ctx)
|
||||||
{
|
{
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
@ -261,80 +226,9 @@ int ug_destroy(UgCtx *ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_tree(UgCtx *ctx)
|
int ug_frame_begin(UgCtx *ctx) { return 0; }
|
||||||
{
|
|
||||||
printf("ctx->tree: [");
|
|
||||||
for (int c = -1, x; (x = ug_tree_level_order_it(&ctx->tree, 0, &c)) != -1;) {
|
|
||||||
printf("%d, ", x);
|
|
||||||
}
|
|
||||||
printf("-1]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int ug_frame_begin(UgCtx *ctx)
|
int ug_frame_end(UgCtx *ctx) { return 0; }
|
||||||
{
|
|
||||||
if (ctx == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. Create the root div element
|
|
||||||
UgRect space = {
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
.w = ctx->size.width,
|
|
||||||
.h = ctx->size.height,
|
|
||||||
};
|
|
||||||
UgElem root = {
|
|
||||||
.id = ROOT_ID,
|
|
||||||
.type = ETYPE_DIV,
|
|
||||||
.flags = 0,
|
|
||||||
.rect = space,
|
|
||||||
.div =
|
|
||||||
{
|
|
||||||
.layout = DIV_LAYOUT_ROW,
|
|
||||||
.origin_r = {0},
|
|
||||||
.origin_c = {0},
|
|
||||||
.color_bg = {0},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// The root should have the updated flag only if the size of the window
|
|
||||||
// was changed between frames, this propagates an element size recalculation
|
|
||||||
// down the element tree
|
|
||||||
if (ctx->input.flags & INPUT_CTX_SIZE) {
|
|
||||||
root.flags |= ELEM_UPDATED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: check errors
|
|
||||||
uint32_t cache_idx;
|
|
||||||
ug_cache_insert(&ctx->cache, &root, &cache_idx);
|
|
||||||
ctx->div_using = ug_tree_add(&ctx->tree, root.id, 0);
|
|
||||||
|
|
||||||
if (ctx->div_using < 0) {
|
|
||||||
printf("why?\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//print_tree(ctx);
|
|
||||||
|
|
||||||
// The root element does not push anything to the stack
|
|
||||||
// TODO: add a background color taken from a theme or config
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ug_frame_end(UgCtx *ctx)
|
|
||||||
{
|
|
||||||
if (ctx == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. clear the tree
|
|
||||||
ug_tree_prune(&ctx->tree, 0);
|
|
||||||
|
|
||||||
// 2. clear input fields
|
|
||||||
ctx->input.flags = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ug_input_window_size(UgCtx *ctx, int width, int height)
|
int ug_input_window_size(UgCtx *ctx, int width, int height)
|
||||||
{
|
{
|
||||||
@ -368,34 +262,28 @@ UgId djb2(const char *str)
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ug_div_begin(UgCtx *ctx, const char *label, UgRect div)
|
int ug_div_begin(UgCtx *ctx, const char *name, UgRect div)
|
||||||
{
|
{
|
||||||
if (ctx == NULL || label == NULL) {
|
if (ctx == NULL || name == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
UgId id = djb2(label);
|
UgId id = djb2(name);
|
||||||
|
|
||||||
// TODO: do layouting if the element is new or the parent has updated
|
|
||||||
int is_new_elem = 0;
|
|
||||||
|
|
||||||
// add the element if it does not exist
|
// add the element if it does not exist
|
||||||
UgElem *c_elem = ug_cache_search(&ctx->cache, id);
|
UgElem *c_elem = ug_cache_search(&ctx->cache, id);
|
||||||
if (c_elem == NULL) {
|
if (c_elem == NULL) {
|
||||||
UgElem elem = {0};
|
UgElem elem = {
|
||||||
|
.id = id,
|
||||||
|
.type = ETYPE_DIV,
|
||||||
|
.rec = (UgRect) {
|
||||||
|
.x = div.x,
|
||||||
|
.y = div.y,
|
||||||
|
.w = div.w >= 0 ? div.w : ctx->size.width,
|
||||||
|
.h = div.h >= 0 ? div.h : ctx->size.height,
|
||||||
|
}};
|
||||||
uint32_t c_idx;
|
uint32_t c_idx;
|
||||||
c_elem = ug_cache_insert(&ctx->cache, &elem, &c_idx);
|
c_elem = ug_cache_insert(&ctx->cache, &elem, &c_idx);
|
||||||
is_new_elem = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// take a reference to the parent
|
|
||||||
// FIXME: if the tree held pointers to the elements then no more
|
|
||||||
// redundant cache search
|
|
||||||
UgId parent_id = ctx->tree.vector[ctx->div_using];
|
|
||||||
UgElem *parent = ug_cache_search(&ctx->cache, parent_id);
|
|
||||||
if (parent == NULL) {
|
|
||||||
// Error, did you forget to do frame_begin()?
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: why save the id in the tree and not something more direct like
|
// FIXME: why save the id in the tree and not something more direct like
|
||||||
@ -407,78 +295,22 @@ int ug_div_begin(UgCtx *ctx, const char *label, UgRect div)
|
|||||||
}
|
}
|
||||||
ctx->div_using = div_node;
|
ctx->div_using = div_node;
|
||||||
|
|
||||||
//print_tree(ctx);
|
// printf(
|
||||||
|
// "elem.rect: x=%d x=%d w=%d h=%d\n",
|
||||||
// layouting
|
// c_elem->rec.x,
|
||||||
// TODO: do layout
|
// c_elem->rec.y,
|
||||||
if (is_new_elem || parent->flags & ELEM_UPDATED) {
|
// c_elem->rec.w,
|
||||||
c_elem->id = id;
|
// c_elem->rec.h
|
||||||
c_elem->type = ETYPE_DIV;
|
// );
|
||||||
|
|
||||||
// 1. Select the right origin offset
|
|
||||||
switch (parent->div.layout) {
|
|
||||||
case DIV_LAYOUT_ROW:
|
|
||||||
c_elem->rect = (UgRect) {
|
|
||||||
.x = parent->div.origin_r.x + div.x,
|
|
||||||
.y = parent->div.origin_r.y + div.y,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case DIV_LAYOUT_COLUMN:
|
|
||||||
c_elem->rect = (UgRect) {
|
|
||||||
.x = parent->div.origin_c.x + div.x,
|
|
||||||
.y = parent->div.origin_c.y + div.y,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case DIV_LAYOUT_FLOATING:
|
|
||||||
c_elem->rect = (UgRect) {
|
|
||||||
.x = div.x,
|
|
||||||
.y = div.y,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Error
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Calculate width & height
|
|
||||||
// TODO: what about negative values?
|
|
||||||
c_elem->rect.w = div.w != 0 ? div.w : parent->rect.w;
|
|
||||||
c_elem->rect.h = div.h != 0 ? div.h : parent->rect.h;
|
|
||||||
|
|
||||||
// 3. Mark the element as updated
|
|
||||||
c_elem->flags |= ELEM_UPDATED;
|
|
||||||
|
|
||||||
// 4. Set div information
|
|
||||||
c_elem->div.layout = parent->div.layout;
|
|
||||||
c_elem->div.origin_c = (UgPoint) {
|
|
||||||
.x = c_elem->rect.x,
|
|
||||||
.y = c_elem->rect.y,
|
|
||||||
};
|
|
||||||
c_elem->div.origin_r = c_elem->div.origin_c;
|
|
||||||
c_elem->div.color_bg = RGBA(0xff0000ff);
|
|
||||||
|
|
||||||
// 4. Update the origins of the parent
|
|
||||||
parent->div.origin_r = (UgPoint) {
|
|
||||||
.x = c_elem->rect.x + c_elem->rect.w,
|
|
||||||
.y = c_elem->rect.y,
|
|
||||||
};
|
|
||||||
parent->div.origin_c = (UgPoint) {
|
|
||||||
.x = c_elem->rect.x,
|
|
||||||
.y = c_elem->rect.y + c_elem->rect.h,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// TODO: check active
|
|
||||||
// TODO: check resizeable
|
|
||||||
// TODO: check scrollbars
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the background to the draw stack
|
|
||||||
UgCmd cmd = {
|
UgCmd cmd = {
|
||||||
.type = CMD_RECT,
|
.type = CMD_RECT,
|
||||||
.rect =
|
.rect =
|
||||||
{
|
{
|
||||||
.rect = c_elem->rect,
|
.x = c_elem->rec.x,
|
||||||
.color = c_elem->div.color_bg,
|
.y = c_elem->rec.y,
|
||||||
|
.w = c_elem->rec.w,
|
||||||
|
.h = c_elem->rec.h,
|
||||||
|
.color = {0xff, 0x00, 0x00, 0xff}, // red
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
ug_stack_push(&ctx->stack, &cmd);
|
ug_stack_push(&ctx->stack, &cmd);
|
||||||
@ -492,99 +324,3 @@ int ug_div_end(UgCtx *ctx)
|
|||||||
ctx->div_using = ug_tree_parentof(&ctx->tree, ctx->div_using);
|
ctx->div_using = ug_tree_parentof(&ctx->tree, ctx->div_using);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ug_button(UgCtx *ctx, const char *label, UgRect size)
|
|
||||||
{
|
|
||||||
if (ctx == NULL || label == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
UgId id = djb2(label);
|
|
||||||
|
|
||||||
// TODO: do layouting if the element is new or the parent has updated
|
|
||||||
int is_new_elem = 0;
|
|
||||||
|
|
||||||
// add the element if it does not exist
|
|
||||||
UgElem *c_elem = ug_cache_search(&ctx->cache, id);
|
|
||||||
if (c_elem == NULL) {
|
|
||||||
UgElem elem = {0};
|
|
||||||
uint32_t c_idx;
|
|
||||||
c_elem = ug_cache_insert(&ctx->cache, &elem, &c_idx);
|
|
||||||
is_new_elem = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// take a reference to the parent
|
|
||||||
// FIXME: if the tree held pointers to the elements then no more
|
|
||||||
// redundant cache search
|
|
||||||
UgId parent_id = ctx->tree.vector[ctx->div_using];
|
|
||||||
UgElem *parent = ug_cache_search(&ctx->cache, parent_id);
|
|
||||||
if (parent == NULL) {
|
|
||||||
// Error, did you forget to do frame_begin()?
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the element is new or the parent was updated then redo layout
|
|
||||||
if (is_new_elem || parent->flags & ELEM_UPDATED) {
|
|
||||||
c_elem->id = id;
|
|
||||||
c_elem->type = ETYPE_BUTTON;
|
|
||||||
|
|
||||||
// 1. Select the right origin offset
|
|
||||||
switch (parent->div.layout) {
|
|
||||||
case DIV_LAYOUT_ROW:
|
|
||||||
c_elem->rect = (UgRect) {
|
|
||||||
.x = parent->div.origin_r.x + size.x,
|
|
||||||
.y = parent->div.origin_r.y + size.y,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case DIV_LAYOUT_COLUMN:
|
|
||||||
c_elem->rect = (UgRect) {
|
|
||||||
.x = parent->div.origin_c.x + size.x,
|
|
||||||
.y = parent->div.origin_c.y + size.y,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case DIV_LAYOUT_FLOATING:
|
|
||||||
c_elem->rect = (UgRect) {
|
|
||||||
.x = size.x,
|
|
||||||
.y = size.y,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Error
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Calculate width & height
|
|
||||||
// TODO: what about negative values?
|
|
||||||
c_elem->rect.w = size.w != 0 ? size.w : parent->rect.w;
|
|
||||||
c_elem->rect.h = size.h != 0 ? size.h : parent->rect.h;
|
|
||||||
|
|
||||||
/// Not a div, so not needed
|
|
||||||
// 3. Mark the element as updated
|
|
||||||
// 4. Set div information
|
|
||||||
|
|
||||||
// 4. Update the origins of the parent
|
|
||||||
parent->div.origin_r = (UgPoint) {
|
|
||||||
.x = c_elem->rect.x + c_elem->rect.w,
|
|
||||||
.y = c_elem->rect.y,
|
|
||||||
};
|
|
||||||
parent->div.origin_c = (UgPoint) {
|
|
||||||
.x = c_elem->rect.x,
|
|
||||||
.y = c_elem->rect.y + c_elem->rect.h,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// TODO: Check for interactions
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the button
|
|
||||||
UgCmd cmd = {
|
|
||||||
.type = CMD_RECT,
|
|
||||||
.rect =
|
|
||||||
{
|
|
||||||
.rect = c_elem->rect,
|
|
||||||
.color = RGBA(0x0000ffff),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
ug_stack_push(&ctx->stack, &cmd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
24
ugui.h
24
ugui.h
@ -20,35 +20,15 @@ typedef uint64_t UgId;
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
ETYPE_NONE = 0,
|
ETYPE_NONE = 0,
|
||||||
ETYPE_DIV,
|
ETYPE_DIV,
|
||||||
ETYPE_BUTTON,
|
|
||||||
} UgElemType;
|
} UgElemType;
|
||||||
|
|
||||||
enum UgElemFlags {
|
|
||||||
ELEM_UPDATED = 1 << 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
UgId id;
|
UgId id;
|
||||||
uint32_t flags;
|
UgRect rec;
|
||||||
UgRect rect;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint32_t type_int;
|
uint32_t type_int;
|
||||||
UgElemType type;
|
UgElemType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
// type-specific fields
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
enum {
|
|
||||||
DIV_LAYOUT_ROW = 0,
|
|
||||||
DIV_LAYOUT_COLUMN,
|
|
||||||
DIV_LAYOUT_FLOATING,
|
|
||||||
} layout;
|
|
||||||
UgPoint origin_r, origin_c;
|
|
||||||
UgColor color_bg;
|
|
||||||
} div; // Div
|
|
||||||
};
|
|
||||||
} UgElem;
|
} UgElem;
|
||||||
|
|
||||||
// TODO: add a packed flag
|
// TODO: add a packed flag
|
||||||
@ -87,9 +67,11 @@ void ug_cache_free(UgElemCache *cache);
|
|||||||
UgElem *ug_cache_search(UgElemCache *cache, UgId id);
|
UgElem *ug_cache_search(UgElemCache *cache, UgId id);
|
||||||
UgElem *ug_cache_insert(UgElemCache *cache, const UgElem *g, uint32_t *index);
|
UgElem *ug_cache_insert(UgElemCache *cache, const UgElem *g, uint32_t *index);
|
||||||
|
|
||||||
|
|
||||||
int ug_init(UgCtx *ctx);
|
int ug_init(UgCtx *ctx);
|
||||||
int ug_destroy(UgCtx *ctx);
|
int ug_destroy(UgCtx *ctx);
|
||||||
int ug_frame_begin(UgCtx *ctx);
|
int ug_frame_begin(UgCtx *ctx);
|
||||||
int ug_frame_end(UgCtx *ctx);
|
int ug_frame_end(UgCtx *ctx);
|
||||||
|
|
||||||
#endif // _UGUI_H
|
#endif // _UGUI_H
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user