From 6d3e8674c1608cdd2b0916d5472f10590732e97b Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Fri, 22 Dec 2023 12:42:00 +0100 Subject: [PATCH] Separate styles from UI nodes --- engine/breeze/ui/ui.c | 304 +++++++++++++++++++++++++++++------------ engine/breeze/ui/ui.h | 85 ++++++++++-- engine/tests/ui_test.c | 6 +- 3 files changed, 293 insertions(+), 102 deletions(-) diff --git a/engine/breeze/ui/ui.c b/engine/breeze/ui/ui.c index b7281f1..74ee38a 100644 --- a/engine/breeze/ui/ui.c +++ b/engine/breeze/ui/ui.c @@ -20,13 +20,16 @@ typedef struct BzUINode { // Key+generation info BzUIKey key; u64 lastFrame; - bool changed; // Per-frame info provided by builders - BzUILayout layout; - BzUIStyle style; BzUIFlags flags; - const char *string; + BzUILayout layout; + + i32 backgroundStyleIdx; + i32 boxShadowStyleIdx; + i32 textStyleIdx; + i32 textShadowStyleIdx; + i32 borderStyleIdx; BzUISize semanticSize[BZ_UI_AXIS_COUNT]; f32 padding[BZ_UI_AXIS_COUNT * 2]; @@ -37,6 +40,7 @@ typedef struct BzUINode { f32 computedSize[BZ_UI_AXIS_COUNT]; BzUIInteraction interaction; + bool canInteract; } BzUINode; typedef struct BzUI { @@ -48,6 +52,12 @@ typedef struct BzUI { BzUINode **nodeStack; BzUINode *root; + BzUIBackgroundStyle *backgroundStyles; + BzUIBoxShadowStyle *boxShadowStyles; + BzUITextStyle *textStyles; + BzUITextShadowStyle *textShadowStyles; + BzUIBorderStyle *borderStyles; + u64 currFrame; u64 keyIdCount; // Per-frame } BzUI; @@ -68,6 +78,14 @@ static void bzUINodeClearLinks(BzUINode *node) { node->prev = NULL; node->next = NULL; } +static void bzUINodeClearStyles(BzUINode *node) { + BZ_ASSERT(node); + node->backgroundStyleIdx = -1; + node->boxShadowStyleIdx = -1; + node->textStyleIdx = -1; + node->textShadowStyleIdx = -1; + node->borderStyleIdx = -1; +} BzUI *bzUICreate() { BzUI *ui = bzAlloc(sizeof(*ui)); @@ -84,6 +102,12 @@ BzUI *bzUICreate() { bzMemSet(ui->root, 0, sizeof(*ui->root)); ui->root->key = bzUIKeyFromString("##root"); + ui->backgroundStyles = bzArrayCreate(BzUIBackgroundStyle, 10); + ui->boxShadowStyles = bzArrayCreate(BzUIBoxShadowStyle, 10); + ui->textStyles = bzArrayCreate(BzUITextStyle, 10); + ui->textShadowStyles = bzArrayCreate(BzUITextShadowStyle, 10); + ui->borderStyles = bzArrayCreate(BzUIBorderStyle, 10); + hmput(ui->nodeMap, ui->root->key, ui->root); return ui; } @@ -92,7 +116,13 @@ void bzUIDestroy(BzUI *ui) { bzObjectPoolDestroy(ui->nodePool); ui->nodePool = NULL; bzArrayDestroy(ui->nodeStack); - ui->nodeStack = NULL; + + bzArrayDestroy(ui->backgroundStyles); + bzArrayDestroy(ui->boxShadowStyles); + bzArrayDestroy(ui->textStyles); + bzArrayDestroy(ui->textShadowStyles); + bzArrayDestroy(ui->borderStyles); + bzFree(ui); } @@ -101,7 +131,7 @@ void bzUIBegin(BzUI *ui, i32 width, i32 height) { bzArrayPush(ui->nodeStack, ui->root); bzUINodeClearLinks(ui->root); - bzMemSet(&ui->root->style, 0, sizeof(ui->root->style)); + bzUINodeClearStyles(ui->root); ui->root->semanticSize[BZ_UI_AXIS_X] = (BzUISize){ .kind = BZ_UI_SIZE_PIXELS, @@ -112,6 +142,12 @@ void bzUIBegin(BzUI *ui, i32 width, i32 height) { .value = height }; + bzArrayClear(ui->backgroundStyles); + bzArrayClear(ui->boxShadowStyles); + bzArrayClear(ui->textStyles); + bzArrayClear(ui->textShadowStyles); + bzArrayClear(ui->borderStyles); + ui->currFrame++; ui->root->lastFrame = ui->currFrame; ui->keyIdCount = 1; @@ -125,31 +161,38 @@ static Rectangle getNodeRect(const BzUINode *node) { .height = node->computedSize[BZ_UI_AXIS_Y], }; } -static void calculateAxisSizePreorder(const BzUIAxis axis, BzUINode *node) { +static void calculateAxisSizePreorder(const BzUI *ui, const BzUIAxis axis, BzUINode *node) { f32 compSize = 0; switch (node->semanticSize[axis].kind) { case BZ_UI_SIZE_PIXELS: compSize = node->semanticSize[axis].value; break; - case BZ_UI_SIZE_FIT: - BZ_ASSERT(node->string); - Vector2 size = MeasureTextEx(node->style.font, node->string, node->style.fontSize, node->style.fontSpacing); + case BZ_UI_SIZE_FIT: { + BzUITextStyle style = bzUIGetTextStyle(ui, node); + BZ_ASSERT(style.text); + Vector2 size = MeasureTextEx(style.font, style.text, + style.fontSize, style.fontSpacing); compSize = (axis == BZ_UI_AXIS_X) ? size.x : size.y; break; - case BZ_UI_SIZE_PARENT_PERCENT: + } + case BZ_UI_SIZE_REL_PARENT: BZ_ASSERT(node->parent); compSize = node->parent->computedSize[axis] * node->semanticSize[axis].value; break; + case BZ_UI_SIZE_AS_PARENT: + BZ_ASSERT(node->parent); + compSize = node->parent->computedSize[axis]; + break; case BZ_UI_SIZE_NULL: default: break; } if (node->computedSize[axis] != compSize) { - node->changed = true; + node->canInteract = true; } node->computedSize[axis] = compSize; } -static void calculateAxisSizePostorder(const BzUIAxis axis, const BzUINode *node) { +static void calculateAxisSizePostorder(const BzUI *ui, const BzUIAxis axis, const BzUINode *node) { f32 compSize = 0; switch (node->semanticSize[axis].kind) { case BZ_UI_SIZE_CHILD_SUM: @@ -168,24 +211,30 @@ static void calculateAxisSizePostorder(const BzUIAxis axis, const BzUINode *node break; } } -static void calculateSizes(BzUINode *node) { +static void calculateSizes(const BzUI *ui, BzUINode *node) { BzUINode *child = node->first; - calculateAxisSizePreorder(BZ_UI_AXIS_X, node); - calculateAxisSizePreorder(BZ_UI_AXIS_Y, node); + calculateAxisSizePreorder(ui, BZ_UI_AXIS_X, node); + calculateAxisSizePreorder(ui, BZ_UI_AXIS_Y, node); while (child != NULL) { - calculateSizes(child); + calculateSizes(ui, child); child = child->next; } - calculateAxisSizePostorder(BZ_UI_AXIS_X, node); - calculateAxisSizePostorder(BZ_UI_AXIS_Y, node); + calculateAxisSizePostorder(ui, BZ_UI_AXIS_X, node); + calculateAxisSizePostorder(ui, BZ_UI_AXIS_Y, node); node->computedSize[BZ_UI_AXIS_X] += node->padding[BZ_UI_AXIS_X] + node->padding[BZ_UI_AXIS_X + 2]; node->computedSize[BZ_UI_AXIS_Y] += node->padding[BZ_UI_AXIS_Y] + node->padding[BZ_UI_AXIS_Y + 2]; + // Border thickness counts as margin + if (node->flags & BZ_UI_DRAW_BORDER) { + BzUIBorderStyle style = bzUIGetBorderStyle(ui, node); + node->margin[BZ_UI_AXIS_X] += style.thickness * 2; + node->margin[BZ_UI_AXIS_Y] += style.thickness * 2; + } } -static void calculatePositions(BzUINode *node, f32 x, f32 y); -static void calculatePositionsFlexBox(BzUINode *node) { +static void calculatePositions(BzUI *ui, BzUINode *node, f32 x, f32 y); +static void calculatePositionsFlexBox(BzUI *ui, BzUINode *node) { BZ_ASSERT(node->layout.type == BZ_UI_LAYOUT_FLEX_BOX); BzUIFlags flags = node->layout.flags; @@ -199,8 +248,7 @@ static void calculatePositionsFlexBox(BzUINode *node) { for (BzUINode *child = node->first; child; child = child->next) { totalMainAxisSize += child->computedSize[MAIN_AXIS] + child->margin[MAIN_AXIS] + - child->margin[MAIN_AXIS + 2] + - child->style.borderThickness * 2; + child->margin[MAIN_AXIS + 2]; numChildren++; } @@ -237,26 +285,24 @@ static void calculatePositionsFlexBox(BzUINode *node) { } axisOffset[MAIN_AXIS] += child->margin[MAIN_AXIS]; - axisOffset[MAIN_AXIS] += child->style.borderThickness; - calculatePositions(child, axisOffset[BZ_UI_AXIS_X], axisOffset[BZ_UI_AXIS_Y]); - axisOffset[MAIN_AXIS] += child->style.borderThickness; + calculatePositions(ui, child, axisOffset[BZ_UI_AXIS_X], axisOffset[BZ_UI_AXIS_Y]); axisOffset[MAIN_AXIS] += child->margin[MAIN_AXIS + 2]; axisOffset[MAIN_AXIS] += mainAxisStep; axisOffset[MAIN_AXIS] += child->computedSize[MAIN_AXIS]; } } -static void calculatePositions(BzUINode *node, f32 x, f32 y) { +static void calculatePositions(BzUI *ui, BzUINode *node, f32 x, f32 y) { node->computedPosition[BZ_UI_AXIS_X] = x; node->computedPosition[BZ_UI_AXIS_Y] = y; switch (node->layout.type) { case BZ_UI_LAYOUT_FLEX_BOX: - calculatePositionsFlexBox(node); + calculatePositionsFlexBox(ui, node); break; default: for (BzUINode *child = node->first; child; child = child->next) { - calculatePositions(child, x, y); + calculatePositions(ui, child, x, y); } break; } @@ -327,53 +373,63 @@ static void renderNode(BzUI *ui, BzUINode *node) { BZ_ASSERT(ui); BZ_ASSERT(node); - BzUIStyle *style = &node->style; BzUIInteraction *inter = &node->interaction; Rectangle rect = getNodeRect(node); // Adjust for padding Rectangle drawRect = rect; - drawRect.x += node->padding[BZ_UI_AXIS_X] + style->borderThickness; - drawRect.y += node->padding[BZ_UI_AXIS_Y] + style->borderThickness; - drawRect.width -= (node->padding[BZ_UI_AXIS_X] + node->padding[BZ_UI_AXIS_X + 2] + style->borderThickness); - drawRect.height -= (node->padding[BZ_UI_AXIS_Y] + node->padding[BZ_UI_AXIS_Y + 2] + style->borderThickness); + drawRect.x += node->padding[BZ_UI_AXIS_X]; + drawRect.y += node->padding[BZ_UI_AXIS_Y]; + drawRect.width -= (node->padding[BZ_UI_AXIS_X] + node->padding[BZ_UI_AXIS_X + 2]); + drawRect.height -= (node->padding[BZ_UI_AXIS_Y] + node->padding[BZ_UI_AXIS_Y + 2]); + if (node->flags & BZ_UI_DRAW_BOX_SHADOW) { + + } if (node->flags & BZ_UI_DRAW_BACKGROUND) { - Color color = style->bgColor; - if (inter->hovering) color = style->bgHoverColor; - if (inter->down) color = style->bgActiveColor; + BzUIBackgroundStyle style = bzUIGetBackgroundStyle(ui, node); + Color color = style.normal; + if (inter->hovering) color = style.hover; + if (inter->down) color = style.active; Rectangle bgRect = rect; - if (style->roundness > 0) { + if (style.roundness > 0) { bgRect.x -= 1; bgRect.y -= 1; bgRect.width += 2; bgRect.height += 2; } - DrawRectangleRounded(bgRect, style->roundness, 0, color); + DrawRectangleRounded(bgRect, style.roundness, 0, color); } - if (node->flags & BZ_UI_DRAW_BORDER && style->borderThickness > 0) { - Color color = style->borderColor; - if (inter->hovering) color = style->borderHoverColor; - if (inter->down) color = style->borderActiveColor; - DrawRectangleRoundedLines(rect, style->roundness, 0, style->borderThickness, color); - } - if (node->flags & BZ_UI_DRAW_TEXT_SHADOW) { - Color color = style->textShadowColor; - if (inter->hovering) color = style->textShadowHoverColor; - if (inter->down) color = style->textShadowActiveColor; - DrawTextEx(style->font, node->string, (Vector2){ - drawRect.x + style->shadowOffset[BZ_UI_AXIS_X], - drawRect.y + style->shadowOffset[BZ_UI_AXIS_Y] - }, style->fontSize, style->fontSpacing, color); - } - if (node->flags & BZ_UI_DRAW_TEXT) { - Color color = style->textColor; - if (inter->hovering) color = style->textHoverColor; - if (inter->down) color = style->textActiveColor; - DrawTextEx(style->font, node->string, (Vector2){drawRect.x, drawRect.y}, style->fontSize, style->fontSpacing, color); + if (node->flags & BZ_UI_DRAW_BORDER) { + BzUIBorderStyle style = bzUIGetBorderStyle(ui, node); + Color color = style.normal; + if (inter->hovering) color = style.hover; + if (inter->down) color = style.active; + DrawRectangleRoundedLines(rect, style.roundness, 0, style.thickness, color); } - node->changed = false; + if (node->flags & BZ_UI_DRAW_TEXT) { + BzUITextStyle style = bzUIGetTextStyle(ui, node); + BZ_ASSERT(style.text); + if (node->flags & BZ_UI_DRAW_TEXT_SHADOW) { + BzUITextShadowStyle shadowStyle = bzUIGetTextShadowStyle(ui, node); + Color color = shadowStyle.normal; + if (inter->hovering) color = style.hover; + if (inter->down) color = style.active; + DrawTextEx(style.font, style.text, (Vector2) { + drawRect.x + shadowStyle.offset[BZ_UI_AXIS_X], + drawRect.y + shadowStyle.offset[BZ_UI_AXIS_Y], + }, style.fontSize, style.fontSpacing, color); + } + Color color = style.normal; + if (inter->hovering) color = style.hover; + if (inter->down) color = style.active; + DrawTextEx(style.font, style.text, (Vector2) { + drawRect.x, drawRect.y + }, style.fontSize, style.fontSpacing, color); + } + + node->canInteract = false; BzUINode *child = node->first; while (child != NULL) { @@ -384,8 +440,8 @@ static void renderNode(BzUI *ui, BzUINode *node) { void bzUIEnd(BzUI *ui) { pruneStale(ui, ui->root); - calculateSizes(ui->root); - calculatePositions(ui->root, 0, 0); + calculateSizes(ui, ui->root); + calculatePositions(ui, ui->root, 0, 0); updateNodeInteraction(ui, ui->root, GetMousePosition()); renderNode(ui, ui->root); } @@ -402,7 +458,7 @@ BzUINode *bzUINodeMake(BzUI *ui, BzUIKey key, const BzUINodeDesc *desc) { node = bzObjectPool(ui->nodePool); bzMemSet(node, 0, sizeof(*node)); hmput(ui->nodeMap, key, node); - node->changed = true; + node->canInteract = true; } BZ_ASSERT(node); node->lastFrame = ui->currFrame; @@ -412,6 +468,7 @@ BzUINode *bzUINodeMake(BzUI *ui, BzUIKey key, const BzUINodeDesc *desc) { BZ_ASSERT(parent); bzUINodeClearLinks(node); + bzUINodeClearStyles(node); if (parent->last) { parent->last->next = node; @@ -425,9 +482,7 @@ BzUINode *bzUINodeMake(BzUI *ui, BzUIKey key, const BzUINodeDesc *desc) { node->parent = parent; node->layout = desc->layout; - node->style = desc->style; node->flags = desc->flags; - node->string = desc->string; bzMemCpy(node->semanticSize, desc->semanticSize, sizeof(node->semanticSize)); bzMemCpy(node->padding, desc->padding, sizeof(node->padding)); @@ -454,52 +509,131 @@ BzUINode *bzUIPopParent(BzUI *ui) { return node; } +BzUIBackgroundStyle bzUIGetBackgroundStyle(const BzUI *ui, BzUINode *node) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->backgroundStyleIdx != -1); + return ui->backgroundStyles[node->backgroundStyleIdx]; +} +BzUIBoxShadowStyle bzUIGetBoxShadowStyle(const BzUI *ui, BzUINode *node) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->boxShadowStyleIdx != -1); + return ui->boxShadowStyles[node->boxShadowStyleIdx]; +} +BzUITextStyle bzUIGetTextStyle(const BzUI *ui, BzUINode *node) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->textStyleIdx != -1); + return ui->textStyles[node->textStyleIdx]; +} +BzUITextShadowStyle bzUIGetTextShadowStyle(const BzUI *ui, BzUINode *node) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->textShadowStyleIdx != -1); + return ui->textShadowStyles[node->textShadowStyleIdx]; +} +BzUIBorderStyle bzUIGetBorderStyle(const BzUI *ui, BzUINode *node) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->borderStyleIdx != -1); + return ui->borderStyles[node->borderStyleIdx]; +} + +#define BZ_UI_SET_STYLE(ui, node, mIdx, styles, style) \ +do { \ + i32 idx = node->mIdx; \ + if (idx == -1) { \ + idx = bzArraySize(ui->styles); \ + bzArrayPush(ui->styles, style); \ + node->mIdx = idx; \ + } else { \ + bzArraySet(ui->styles, idx, style); \ + } \ +} while (0) + +void bzUISetBackgroundStyle(BzUI *ui, BzUINode *node, BzUIBackgroundStyle style) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->flags & BZ_UI_DRAW_BACKGROUND); + BZ_UI_SET_STYLE(ui, node, backgroundStyleIdx, backgroundStyles, style); +} +void bzUISetBoxShadowStyle(BzUI *ui, BzUINode *node, BzUIBoxShadowStyle style) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->flags & BZ_UI_DRAW_BOX_SHADOW); + BZ_UI_SET_STYLE(ui, node, boxShadowStyleIdx, boxShadowStyles, style); +} +void bzUISetTextStyle(BzUI *ui, BzUINode *node, BzUITextStyle style) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->flags & BZ_UI_DRAW_TEXT); + BZ_UI_SET_STYLE(ui, node, textStyleIdx, textStyles, style); +} +void bzUISetTextShadowStyle(BzUI *ui, BzUINode *node, BzUITextShadowStyle style) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->flags & BZ_UI_DRAW_TEXT_SHADOW); + BZ_UI_SET_STYLE(ui, node, textShadowStyleIdx, textShadowStyles, style); +} +void bzUISetBorderStyle(BzUI *ui, BzUINode *node, BzUIBorderStyle style) { + BZ_ASSERT(ui && node); + BZ_ASSERT(node->flags & BZ_UI_DRAW_BORDER); + BZ_UI_SET_STYLE(ui, node, borderStyleIdx, borderStyles, style); +} +#undef BZ_UI_SET_STYLE + +BzUILayout bzUIGetLayout(const BzUI *ui, BzUINode *node) { + BZ_UNUSED(ui); + BZ_ASSERT(node); + return node->layout; +} +void bzUISetLayout(BzUI *ui, BzUINode *node, BzUILayout layout) { + BZ_UNUSED(ui); + BZ_ASSERT(node); + node->layout = layout; +} + void bzUISetParentLayout(BzUI *ui, BzUILayout layout) { + BZ_ASSERT(ui); i32 stackSize = bzArraySize(ui->nodeStack); BZ_ASSERT(stackSize > 0); BzUINode *last = bzArrayGet(ui->nodeStack, stackSize - 1); BZ_ASSERT(last); - last->layout = layout; + bzUISetLayout(ui, last, layout); } BzUIInteraction bzUIGetInteraction(BzUI *ui, BzUINode *node) { BZ_ASSERT(node); return node->interaction; } -bool bzUIButton(BzUI *ui, const char *string, BzUIStyle *style) { - BzUIStyle s = { - .font = GetFontDefault(), - .fontSize = 24, - .borderThickness = 2.0f, - .roundness = 1.0f, - .bgColor = GRAY, - .borderColor = BLACK, - .borderHoverColor = BLACK, - .borderActiveColor = GRAY, - .textColor = BLACK, - .textHoverColor = RED, - .textActiveColor = ORANGE, - }; - if (style) { - s = *style; - } +bool bzUIButton(BzUI *ui, const char *string) { BzUINode *node = bzUINodeMake(ui, bzUIKeyFromString(string), &(BzUINodeDesc) { .flags = BZ_UI_CLICKABLE | BZ_UI_DRAW_TEXT | BZ_UI_DRAW_BACKGROUND | BZ_UI_DRAW_BORDER | BZ_UI_ALIGN_CENTER }); - node->string = string; node->semanticSize[BZ_UI_AXIS_X] = (BzUISize) { .kind = BZ_UI_SIZE_FIT, }; node->semanticSize[BZ_UI_AXIS_Y] = node->semanticSize[BZ_UI_AXIS_X]; - node->style = s; for (i32 i = 0; i < 4; i++) { node->padding[i] = 2; node->margin[i] = 4; } + bzUISetBackgroundStyle(ui, node, (BzUIBackgroundStyle) { + .normal = GRAY, + .hover = GRAY, + .active = GRAY, + }); + bzUISetBorderStyle(ui, node, (BzUIBorderStyle) { + .thickness = 4.0f, + .normal = BLACK, + .hover = BLACK, + .active = GRAY + }); + bzUISetTextStyle(ui, node, (BzUITextStyle) { + .text = string, + .font = GetFontDefault(), + .fontSize = 24, + .fontSpacing = 2, + .normal = BLACK, + .hover = RED, + .active = ORANGE + }); return bzUIGetInteraction(ui, node).clicked; } diff --git a/engine/breeze/ui/ui.h b/engine/breeze/ui/ui.h index dae5da2..ce0f979 100644 --- a/engine/breeze/ui/ui.h +++ b/engine/breeze/ui/ui.h @@ -12,7 +12,8 @@ typedef enum BzUISizeKind { BZ_UI_SIZE_NULL, BZ_UI_SIZE_PIXELS, BZ_UI_SIZE_FIT, - BZ_UI_SIZE_PARENT_PERCENT, + BZ_UI_SIZE_REL_PARENT, + BZ_UI_SIZE_AS_PARENT, BZ_UI_SIZE_CHILD_SUM, BZ_UI_SIZE_CHILD_MAX, } BzUISizeKind; @@ -86,28 +87,67 @@ typedef struct BzUIStyle { enum { BZ_UI_NONE = 0, BZ_UI_CLICKABLE = (1 << 0), - BZ_UI_DRAW_TEXT = (1 << 1), - BZ_UI_DRAW_TEXT_SHADOW = (1 << 2), + BZ_UI_DRAW_BACKGROUND = (1 << 1), + BZ_UI_DRAW_BOX_SHADOW = (1 << 2), BZ_UI_DRAW_BORDER = (1 << 3), - BZ_UI_DRAW_BACKGROUND = (1 << 4), - //BZ_UI_DRAW_SPRITE = (1 << 5), - BZ_UI_ALIGN_HORIZ_START = (1 << 6), - BZ_UI_ALIGN_HORIZ_CENTER = (1 << 7), - BZ_UI_ALIGN_HORIZ_END = (1 << 8), - BZ_UI_ALIGN_VERT_START = (1 << 9), - BZ_UI_ALIGN_VERT_CENTER = (1 << 10), - BZ_UI_ALIGN_VERT_END = (1 << 11), + BZ_UI_DRAW_TEXT = (1 << 4), + BZ_UI_DRAW_TEXT_SHADOW = (1 << 5), + BZ_UI_DRAW_SPRITE = (1 << 6), + BZ_UI_ALIGN_HORIZ_START = (1 << 7), + BZ_UI_ALIGN_HORIZ_CENTER = (1 << 8), + BZ_UI_ALIGN_HORIZ_END = (1 << 9), + BZ_UI_ALIGN_VERT_START = (1 << 10), + BZ_UI_ALIGN_VERT_CENTER = (1 << 11), + BZ_UI_ALIGN_VERT_END = (1 << 12), BZ_UI_ALIGN_CENTER = BZ_UI_ALIGN_HORIZ_CENTER | BZ_UI_ALIGN_VERT_CENTER, }; +typedef struct BzUIBackgroundStyle { + f32 thickness; + f32 roundness; + Color normal; + Color hover; + Color active; +} BzUIBackgroundStyle; + +typedef struct BzUIBoxShadowStyle { + f32 offset[BZ_UI_AXIS_COUNT]; + BzUIBackgroundStyle bg; +} BzUIBoxShadowStyle; + +typedef struct BzUIBorderStyle { + f32 thickness; + f32 roundness; + Color normal; + Color hover; + Color active; +} BzUIBorderStyle; + +typedef struct BzUITextStyle { + const char *text; + + Font font; + f32 fontSize; + f32 fontSpacing; + Color normal; + Color hover; + Color active; +} BzUITextStyle; + +typedef struct BzUITextShadowStyle { + // Depends on BzUITextStyle + f32 offset[BZ_UI_AXIS_COUNT]; + Color normal; + Color hover; + Color active; +} BzUITextShadowStyle; + typedef struct BzUINode BzUINode; typedef struct BzUINodeDesc { BzUILayout layout; - BzUIStyle style; BzUIFlags flags; - const char *string; BzUISize semanticSize[BZ_UI_AXIS_COUNT]; f32 padding[BZ_UI_AXIS_COUNT * 2]; @@ -142,10 +182,27 @@ BzUINode *bzUIPushDiv(BzUI *ui, BzUISize x, BzUISize y); BzUINode *bzUIPushParent(BzUI *ui, BzUINode *node); BzUINode *bzUIPopParent(BzUI *ui); +// Styles + +BzUIBackgroundStyle bzUIGetBackgroundStyle(const BzUI *ui, BzUINode *node); +BzUIBoxShadowStyle bzUIGetBoxShadowStyle(const BzUI *ui, BzUINode *node); +BzUITextStyle bzUIGetTextStyle(const BzUI *ui, BzUINode *node); +BzUITextShadowStyle bzUIGetTextShadowStyle(const BzUI *ui, BzUINode *node); +BzUIBorderStyle bzUIGetBorderStyle(const BzUI *ui, BzUINode *node); + +void bzUISetBackgroundStyle(BzUI *ui, BzUINode *node, BzUIBackgroundStyle style); +void bzUISetBoxShadowStyle(BzUI *ui, BzUINode *node, BzUIBoxShadowStyle style); +void bzUISetTextStyle(BzUI *ui, BzUINode *node, BzUITextStyle style); +void bzUISetTextShadowStyle(BzUI *ui, BzUINode *node, BzUITextShadowStyle style); +void bzUISetBorderStyle(BzUI *ui, BzUINode *node, BzUIBorderStyle style); + +BzUILayout bzUIGetLayout(const BzUI *ui, BzUINode *node); +void bzUISetLayout(BzUI *ui, BzUINode *node, BzUILayout layout); + void bzUISetParentLayout(BzUI *ui, BzUILayout layout); BzUIInteraction bzUIGetInteraction(BzUI *ui, BzUINode *node); -bool bzUIButton(BzUI *ui, const char *string, BzUIStyle *style); +bool bzUIButton(BzUI *ui, const char *string); #endif //BREEZE_UI_CORE_H diff --git a/engine/tests/ui_test.c b/engine/tests/ui_test.c index 474b34c..eeeaa8c 100644 --- a/engine/tests/ui_test.c +++ b/engine/tests/ui_test.c @@ -23,13 +23,13 @@ void render(float dt, int *game) { .type = BZ_UI_LAYOUT_FLEX_BOX, .flags = BZ_UI_FLEX_DIR_COLUMN | BZ_UI_FLEX_ALIGN_CENTER | BZ_UI_FLEX_JUSTIFY_CENTER, }); - if (bzUIButton(ui, "Hello world", NULL)) { + if (bzUIButton(ui, "Hello world")) { bzLogInfo("Hello world"); } - if (bzUIButton(ui, "foo", NULL)) { + if (bzUIButton(ui, "foo")) { bzLogInfo("foo"); } - if (bzUIButton(ui, "bar", NULL)) { + if (bzUIButton(ui, "bar")) { bzLogInfo("bar"); } bzUIEnd(ui);