Separate styles from UI nodes
This commit is contained in:
@@ -20,13 +20,16 @@ typedef struct BzUINode {
|
|||||||
// Key+generation info
|
// Key+generation info
|
||||||
BzUIKey key;
|
BzUIKey key;
|
||||||
u64 lastFrame;
|
u64 lastFrame;
|
||||||
bool changed;
|
|
||||||
|
|
||||||
// Per-frame info provided by builders
|
// Per-frame info provided by builders
|
||||||
BzUILayout layout;
|
|
||||||
BzUIStyle style;
|
|
||||||
BzUIFlags flags;
|
BzUIFlags flags;
|
||||||
const char *string;
|
BzUILayout layout;
|
||||||
|
|
||||||
|
i32 backgroundStyleIdx;
|
||||||
|
i32 boxShadowStyleIdx;
|
||||||
|
i32 textStyleIdx;
|
||||||
|
i32 textShadowStyleIdx;
|
||||||
|
i32 borderStyleIdx;
|
||||||
|
|
||||||
BzUISize semanticSize[BZ_UI_AXIS_COUNT];
|
BzUISize semanticSize[BZ_UI_AXIS_COUNT];
|
||||||
f32 padding[BZ_UI_AXIS_COUNT * 2];
|
f32 padding[BZ_UI_AXIS_COUNT * 2];
|
||||||
@@ -37,6 +40,7 @@ typedef struct BzUINode {
|
|||||||
f32 computedSize[BZ_UI_AXIS_COUNT];
|
f32 computedSize[BZ_UI_AXIS_COUNT];
|
||||||
|
|
||||||
BzUIInteraction interaction;
|
BzUIInteraction interaction;
|
||||||
|
bool canInteract;
|
||||||
} BzUINode;
|
} BzUINode;
|
||||||
|
|
||||||
typedef struct BzUI {
|
typedef struct BzUI {
|
||||||
@@ -48,6 +52,12 @@ typedef struct BzUI {
|
|||||||
BzUINode **nodeStack;
|
BzUINode **nodeStack;
|
||||||
BzUINode *root;
|
BzUINode *root;
|
||||||
|
|
||||||
|
BzUIBackgroundStyle *backgroundStyles;
|
||||||
|
BzUIBoxShadowStyle *boxShadowStyles;
|
||||||
|
BzUITextStyle *textStyles;
|
||||||
|
BzUITextShadowStyle *textShadowStyles;
|
||||||
|
BzUIBorderStyle *borderStyles;
|
||||||
|
|
||||||
u64 currFrame;
|
u64 currFrame;
|
||||||
u64 keyIdCount; // Per-frame
|
u64 keyIdCount; // Per-frame
|
||||||
} BzUI;
|
} BzUI;
|
||||||
@@ -68,6 +78,14 @@ static void bzUINodeClearLinks(BzUINode *node) {
|
|||||||
node->prev = NULL;
|
node->prev = NULL;
|
||||||
node->next = 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 *bzUICreate() {
|
||||||
BzUI *ui = bzAlloc(sizeof(*ui));
|
BzUI *ui = bzAlloc(sizeof(*ui));
|
||||||
@@ -84,6 +102,12 @@ BzUI *bzUICreate() {
|
|||||||
bzMemSet(ui->root, 0, sizeof(*ui->root));
|
bzMemSet(ui->root, 0, sizeof(*ui->root));
|
||||||
ui->root->key = bzUIKeyFromString("##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);
|
hmput(ui->nodeMap, ui->root->key, ui->root);
|
||||||
return ui;
|
return ui;
|
||||||
}
|
}
|
||||||
@@ -92,7 +116,13 @@ void bzUIDestroy(BzUI *ui) {
|
|||||||
bzObjectPoolDestroy(ui->nodePool);
|
bzObjectPoolDestroy(ui->nodePool);
|
||||||
ui->nodePool = NULL;
|
ui->nodePool = NULL;
|
||||||
bzArrayDestroy(ui->nodeStack);
|
bzArrayDestroy(ui->nodeStack);
|
||||||
ui->nodeStack = NULL;
|
|
||||||
|
bzArrayDestroy(ui->backgroundStyles);
|
||||||
|
bzArrayDestroy(ui->boxShadowStyles);
|
||||||
|
bzArrayDestroy(ui->textStyles);
|
||||||
|
bzArrayDestroy(ui->textShadowStyles);
|
||||||
|
bzArrayDestroy(ui->borderStyles);
|
||||||
|
|
||||||
bzFree(ui);
|
bzFree(ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +131,7 @@ void bzUIBegin(BzUI *ui, i32 width, i32 height) {
|
|||||||
bzArrayPush(ui->nodeStack, ui->root);
|
bzArrayPush(ui->nodeStack, ui->root);
|
||||||
|
|
||||||
bzUINodeClearLinks(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){
|
ui->root->semanticSize[BZ_UI_AXIS_X] = (BzUISize){
|
||||||
.kind = BZ_UI_SIZE_PIXELS,
|
.kind = BZ_UI_SIZE_PIXELS,
|
||||||
@@ -112,6 +142,12 @@ void bzUIBegin(BzUI *ui, i32 width, i32 height) {
|
|||||||
.value = height
|
.value = height
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bzArrayClear(ui->backgroundStyles);
|
||||||
|
bzArrayClear(ui->boxShadowStyles);
|
||||||
|
bzArrayClear(ui->textStyles);
|
||||||
|
bzArrayClear(ui->textShadowStyles);
|
||||||
|
bzArrayClear(ui->borderStyles);
|
||||||
|
|
||||||
ui->currFrame++;
|
ui->currFrame++;
|
||||||
ui->root->lastFrame = ui->currFrame;
|
ui->root->lastFrame = ui->currFrame;
|
||||||
ui->keyIdCount = 1;
|
ui->keyIdCount = 1;
|
||||||
@@ -125,31 +161,38 @@ static Rectangle getNodeRect(const BzUINode *node) {
|
|||||||
.height = node->computedSize[BZ_UI_AXIS_Y],
|
.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;
|
f32 compSize = 0;
|
||||||
switch (node->semanticSize[axis].kind) {
|
switch (node->semanticSize[axis].kind) {
|
||||||
case BZ_UI_SIZE_PIXELS:
|
case BZ_UI_SIZE_PIXELS:
|
||||||
compSize = node->semanticSize[axis].value;
|
compSize = node->semanticSize[axis].value;
|
||||||
break;
|
break;
|
||||||
case BZ_UI_SIZE_FIT:
|
case BZ_UI_SIZE_FIT: {
|
||||||
BZ_ASSERT(node->string);
|
BzUITextStyle style = bzUIGetTextStyle(ui, node);
|
||||||
Vector2 size = MeasureTextEx(node->style.font, node->string, node->style.fontSize, node->style.fontSpacing);
|
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;
|
compSize = (axis == BZ_UI_AXIS_X) ? size.x : size.y;
|
||||||
break;
|
break;
|
||||||
case BZ_UI_SIZE_PARENT_PERCENT:
|
}
|
||||||
|
case BZ_UI_SIZE_REL_PARENT:
|
||||||
BZ_ASSERT(node->parent);
|
BZ_ASSERT(node->parent);
|
||||||
compSize = node->parent->computedSize[axis] * node->semanticSize[axis].value;
|
compSize = node->parent->computedSize[axis] * node->semanticSize[axis].value;
|
||||||
break;
|
break;
|
||||||
|
case BZ_UI_SIZE_AS_PARENT:
|
||||||
|
BZ_ASSERT(node->parent);
|
||||||
|
compSize = node->parent->computedSize[axis];
|
||||||
|
break;
|
||||||
case BZ_UI_SIZE_NULL:
|
case BZ_UI_SIZE_NULL:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (node->computedSize[axis] != compSize) {
|
if (node->computedSize[axis] != compSize) {
|
||||||
node->changed = true;
|
node->canInteract = true;
|
||||||
}
|
}
|
||||||
node->computedSize[axis] = compSize;
|
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;
|
f32 compSize = 0;
|
||||||
switch (node->semanticSize[axis].kind) {
|
switch (node->semanticSize[axis].kind) {
|
||||||
case BZ_UI_SIZE_CHILD_SUM:
|
case BZ_UI_SIZE_CHILD_SUM:
|
||||||
@@ -168,24 +211,30 @@ static void calculateAxisSizePostorder(const BzUIAxis axis, const BzUINode *node
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void calculateSizes(BzUINode *node) {
|
static void calculateSizes(const BzUI *ui, BzUINode *node) {
|
||||||
BzUINode *child = node->first;
|
BzUINode *child = node->first;
|
||||||
|
|
||||||
calculateAxisSizePreorder(BZ_UI_AXIS_X, node);
|
calculateAxisSizePreorder(ui, BZ_UI_AXIS_X, node);
|
||||||
calculateAxisSizePreorder(BZ_UI_AXIS_Y, node);
|
calculateAxisSizePreorder(ui, BZ_UI_AXIS_Y, node);
|
||||||
while (child != NULL) {
|
while (child != NULL) {
|
||||||
calculateSizes(child);
|
calculateSizes(ui, child);
|
||||||
child = child->next;
|
child = child->next;
|
||||||
}
|
}
|
||||||
calculateAxisSizePostorder(BZ_UI_AXIS_X, node);
|
calculateAxisSizePostorder(ui, BZ_UI_AXIS_X, node);
|
||||||
calculateAxisSizePostorder(BZ_UI_AXIS_Y, 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_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];
|
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 calculatePositions(BzUI *ui, BzUINode *node, f32 x, f32 y);
|
||||||
static void calculatePositionsFlexBox(BzUINode *node) {
|
static void calculatePositionsFlexBox(BzUI *ui, BzUINode *node) {
|
||||||
BZ_ASSERT(node->layout.type == BZ_UI_LAYOUT_FLEX_BOX);
|
BZ_ASSERT(node->layout.type == BZ_UI_LAYOUT_FLEX_BOX);
|
||||||
BzUIFlags flags = node->layout.flags;
|
BzUIFlags flags = node->layout.flags;
|
||||||
|
|
||||||
@@ -199,8 +248,7 @@ static void calculatePositionsFlexBox(BzUINode *node) {
|
|||||||
for (BzUINode *child = node->first; child; child = child->next) {
|
for (BzUINode *child = node->first; child; child = child->next) {
|
||||||
totalMainAxisSize += child->computedSize[MAIN_AXIS] +
|
totalMainAxisSize += child->computedSize[MAIN_AXIS] +
|
||||||
child->margin[MAIN_AXIS] +
|
child->margin[MAIN_AXIS] +
|
||||||
child->margin[MAIN_AXIS + 2] +
|
child->margin[MAIN_AXIS + 2];
|
||||||
child->style.borderThickness * 2;
|
|
||||||
numChildren++;
|
numChildren++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,26 +285,24 @@ static void calculatePositionsFlexBox(BzUINode *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
axisOffset[MAIN_AXIS] += child->margin[MAIN_AXIS];
|
axisOffset[MAIN_AXIS] += child->margin[MAIN_AXIS];
|
||||||
axisOffset[MAIN_AXIS] += child->style.borderThickness;
|
calculatePositions(ui, child, axisOffset[BZ_UI_AXIS_X], axisOffset[BZ_UI_AXIS_Y]);
|
||||||
calculatePositions(child, axisOffset[BZ_UI_AXIS_X], axisOffset[BZ_UI_AXIS_Y]);
|
|
||||||
axisOffset[MAIN_AXIS] += child->style.borderThickness;
|
|
||||||
axisOffset[MAIN_AXIS] += child->margin[MAIN_AXIS + 2];
|
axisOffset[MAIN_AXIS] += child->margin[MAIN_AXIS + 2];
|
||||||
axisOffset[MAIN_AXIS] += mainAxisStep;
|
axisOffset[MAIN_AXIS] += mainAxisStep;
|
||||||
axisOffset[MAIN_AXIS] += child->computedSize[MAIN_AXIS];
|
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_X] = x;
|
||||||
node->computedPosition[BZ_UI_AXIS_Y] = y;
|
node->computedPosition[BZ_UI_AXIS_Y] = y;
|
||||||
|
|
||||||
switch (node->layout.type) {
|
switch (node->layout.type) {
|
||||||
case BZ_UI_LAYOUT_FLEX_BOX:
|
case BZ_UI_LAYOUT_FLEX_BOX:
|
||||||
calculatePositionsFlexBox(node);
|
calculatePositionsFlexBox(ui, node);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
for (BzUINode *child = node->first; child; child = child->next) {
|
for (BzUINode *child = node->first; child; child = child->next) {
|
||||||
calculatePositions(child, x, y);
|
calculatePositions(ui, child, x, y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -327,53 +373,63 @@ static void renderNode(BzUI *ui, BzUINode *node) {
|
|||||||
BZ_ASSERT(ui);
|
BZ_ASSERT(ui);
|
||||||
BZ_ASSERT(node);
|
BZ_ASSERT(node);
|
||||||
|
|
||||||
BzUIStyle *style = &node->style;
|
|
||||||
BzUIInteraction *inter = &node->interaction;
|
BzUIInteraction *inter = &node->interaction;
|
||||||
|
|
||||||
Rectangle rect = getNodeRect(node);
|
Rectangle rect = getNodeRect(node);
|
||||||
// Adjust for padding
|
// Adjust for padding
|
||||||
Rectangle drawRect = rect;
|
Rectangle drawRect = rect;
|
||||||
drawRect.x += node->padding[BZ_UI_AXIS_X] + style->borderThickness;
|
drawRect.x += node->padding[BZ_UI_AXIS_X];
|
||||||
drawRect.y += node->padding[BZ_UI_AXIS_Y] + style->borderThickness;
|
drawRect.y += node->padding[BZ_UI_AXIS_Y];
|
||||||
drawRect.width -= (node->padding[BZ_UI_AXIS_X] + node->padding[BZ_UI_AXIS_X + 2] + style->borderThickness);
|
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] + style->borderThickness);
|
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) {
|
if (node->flags & BZ_UI_DRAW_BACKGROUND) {
|
||||||
Color color = style->bgColor;
|
BzUIBackgroundStyle style = bzUIGetBackgroundStyle(ui, node);
|
||||||
if (inter->hovering) color = style->bgHoverColor;
|
Color color = style.normal;
|
||||||
if (inter->down) color = style->bgActiveColor;
|
if (inter->hovering) color = style.hover;
|
||||||
|
if (inter->down) color = style.active;
|
||||||
Rectangle bgRect = rect;
|
Rectangle bgRect = rect;
|
||||||
if (style->roundness > 0) {
|
if (style.roundness > 0) {
|
||||||
bgRect.x -= 1;
|
bgRect.x -= 1;
|
||||||
bgRect.y -= 1;
|
bgRect.y -= 1;
|
||||||
bgRect.width += 2;
|
bgRect.width += 2;
|
||||||
bgRect.height += 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) {
|
if (node->flags & BZ_UI_DRAW_BORDER) {
|
||||||
Color color = style->borderColor;
|
BzUIBorderStyle style = bzUIGetBorderStyle(ui, node);
|
||||||
if (inter->hovering) color = style->borderHoverColor;
|
Color color = style.normal;
|
||||||
if (inter->down) color = style->borderActiveColor;
|
if (inter->hovering) color = style.hover;
|
||||||
DrawRectangleRoundedLines(rect, style->roundness, 0, style->borderThickness, color);
|
if (inter->down) color = style.active;
|
||||||
}
|
DrawRectangleRoundedLines(rect, style.roundness, 0, style.thickness, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
BzUINode *child = node->first;
|
||||||
while (child != NULL) {
|
while (child != NULL) {
|
||||||
@@ -384,8 +440,8 @@ static void renderNode(BzUI *ui, BzUINode *node) {
|
|||||||
|
|
||||||
void bzUIEnd(BzUI *ui) {
|
void bzUIEnd(BzUI *ui) {
|
||||||
pruneStale(ui, ui->root);
|
pruneStale(ui, ui->root);
|
||||||
calculateSizes(ui->root);
|
calculateSizes(ui, ui->root);
|
||||||
calculatePositions(ui->root, 0, 0);
|
calculatePositions(ui, ui->root, 0, 0);
|
||||||
updateNodeInteraction(ui, ui->root, GetMousePosition());
|
updateNodeInteraction(ui, ui->root, GetMousePosition());
|
||||||
renderNode(ui, ui->root);
|
renderNode(ui, ui->root);
|
||||||
}
|
}
|
||||||
@@ -402,7 +458,7 @@ BzUINode *bzUINodeMake(BzUI *ui, BzUIKey key, const BzUINodeDesc *desc) {
|
|||||||
node = bzObjectPool(ui->nodePool);
|
node = bzObjectPool(ui->nodePool);
|
||||||
bzMemSet(node, 0, sizeof(*node));
|
bzMemSet(node, 0, sizeof(*node));
|
||||||
hmput(ui->nodeMap, key, node);
|
hmput(ui->nodeMap, key, node);
|
||||||
node->changed = true;
|
node->canInteract = true;
|
||||||
}
|
}
|
||||||
BZ_ASSERT(node);
|
BZ_ASSERT(node);
|
||||||
node->lastFrame = ui->currFrame;
|
node->lastFrame = ui->currFrame;
|
||||||
@@ -412,6 +468,7 @@ BzUINode *bzUINodeMake(BzUI *ui, BzUIKey key, const BzUINodeDesc *desc) {
|
|||||||
BZ_ASSERT(parent);
|
BZ_ASSERT(parent);
|
||||||
|
|
||||||
bzUINodeClearLinks(node);
|
bzUINodeClearLinks(node);
|
||||||
|
bzUINodeClearStyles(node);
|
||||||
|
|
||||||
if (parent->last) {
|
if (parent->last) {
|
||||||
parent->last->next = node;
|
parent->last->next = node;
|
||||||
@@ -425,9 +482,7 @@ BzUINode *bzUINodeMake(BzUI *ui, BzUIKey key, const BzUINodeDesc *desc) {
|
|||||||
node->parent = parent;
|
node->parent = parent;
|
||||||
|
|
||||||
node->layout = desc->layout;
|
node->layout = desc->layout;
|
||||||
node->style = desc->style;
|
|
||||||
node->flags = desc->flags;
|
node->flags = desc->flags;
|
||||||
node->string = desc->string;
|
|
||||||
|
|
||||||
bzMemCpy(node->semanticSize, desc->semanticSize, sizeof(node->semanticSize));
|
bzMemCpy(node->semanticSize, desc->semanticSize, sizeof(node->semanticSize));
|
||||||
bzMemCpy(node->padding, desc->padding, sizeof(node->padding));
|
bzMemCpy(node->padding, desc->padding, sizeof(node->padding));
|
||||||
@@ -454,52 +509,131 @@ BzUINode *bzUIPopParent(BzUI *ui) {
|
|||||||
return node;
|
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) {
|
void bzUISetParentLayout(BzUI *ui, BzUILayout layout) {
|
||||||
|
BZ_ASSERT(ui);
|
||||||
i32 stackSize = bzArraySize(ui->nodeStack);
|
i32 stackSize = bzArraySize(ui->nodeStack);
|
||||||
BZ_ASSERT(stackSize > 0);
|
BZ_ASSERT(stackSize > 0);
|
||||||
BzUINode *last = bzArrayGet(ui->nodeStack, stackSize - 1);
|
BzUINode *last = bzArrayGet(ui->nodeStack, stackSize - 1);
|
||||||
BZ_ASSERT(last);
|
BZ_ASSERT(last);
|
||||||
last->layout = layout;
|
bzUISetLayout(ui, last, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
BzUIInteraction bzUIGetInteraction(BzUI *ui, BzUINode *node) {
|
BzUIInteraction bzUIGetInteraction(BzUI *ui, BzUINode *node) {
|
||||||
BZ_ASSERT(node);
|
BZ_ASSERT(node);
|
||||||
return node->interaction;
|
return node->interaction;
|
||||||
}
|
}
|
||||||
bool bzUIButton(BzUI *ui, const char *string, BzUIStyle *style) {
|
bool bzUIButton(BzUI *ui, const char *string) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
BzUINode *node = bzUINodeMake(ui, bzUIKeyFromString(string),
|
BzUINode *node = bzUINodeMake(ui, bzUIKeyFromString(string),
|
||||||
&(BzUINodeDesc) {
|
&(BzUINodeDesc) {
|
||||||
.flags = BZ_UI_CLICKABLE | BZ_UI_DRAW_TEXT |
|
.flags = BZ_UI_CLICKABLE | BZ_UI_DRAW_TEXT |
|
||||||
BZ_UI_DRAW_BACKGROUND |
|
BZ_UI_DRAW_BACKGROUND |
|
||||||
BZ_UI_DRAW_BORDER | BZ_UI_ALIGN_CENTER
|
BZ_UI_DRAW_BORDER | BZ_UI_ALIGN_CENTER
|
||||||
});
|
});
|
||||||
node->string = string;
|
|
||||||
node->semanticSize[BZ_UI_AXIS_X] = (BzUISize) {
|
node->semanticSize[BZ_UI_AXIS_X] = (BzUISize) {
|
||||||
.kind = BZ_UI_SIZE_FIT,
|
.kind = BZ_UI_SIZE_FIT,
|
||||||
};
|
};
|
||||||
node->semanticSize[BZ_UI_AXIS_Y] = node->semanticSize[BZ_UI_AXIS_X];
|
node->semanticSize[BZ_UI_AXIS_Y] = node->semanticSize[BZ_UI_AXIS_X];
|
||||||
node->style = s;
|
|
||||||
|
|
||||||
for (i32 i = 0; i < 4; i++) {
|
for (i32 i = 0; i < 4; i++) {
|
||||||
node->padding[i] = 2;
|
node->padding[i] = 2;
|
||||||
node->margin[i] = 4;
|
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;
|
return bzUIGetInteraction(ui, node).clicked;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ typedef enum BzUISizeKind {
|
|||||||
BZ_UI_SIZE_NULL,
|
BZ_UI_SIZE_NULL,
|
||||||
BZ_UI_SIZE_PIXELS,
|
BZ_UI_SIZE_PIXELS,
|
||||||
BZ_UI_SIZE_FIT,
|
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_SUM,
|
||||||
BZ_UI_SIZE_CHILD_MAX,
|
BZ_UI_SIZE_CHILD_MAX,
|
||||||
} BzUISizeKind;
|
} BzUISizeKind;
|
||||||
@@ -86,28 +87,67 @@ typedef struct BzUIStyle {
|
|||||||
enum {
|
enum {
|
||||||
BZ_UI_NONE = 0,
|
BZ_UI_NONE = 0,
|
||||||
BZ_UI_CLICKABLE = (1 << 0),
|
BZ_UI_CLICKABLE = (1 << 0),
|
||||||
BZ_UI_DRAW_TEXT = (1 << 1),
|
BZ_UI_DRAW_BACKGROUND = (1 << 1),
|
||||||
BZ_UI_DRAW_TEXT_SHADOW = (1 << 2),
|
BZ_UI_DRAW_BOX_SHADOW = (1 << 2),
|
||||||
BZ_UI_DRAW_BORDER = (1 << 3),
|
BZ_UI_DRAW_BORDER = (1 << 3),
|
||||||
BZ_UI_DRAW_BACKGROUND = (1 << 4),
|
BZ_UI_DRAW_TEXT = (1 << 4),
|
||||||
//BZ_UI_DRAW_SPRITE = (1 << 5),
|
BZ_UI_DRAW_TEXT_SHADOW = (1 << 5),
|
||||||
BZ_UI_ALIGN_HORIZ_START = (1 << 6),
|
BZ_UI_DRAW_SPRITE = (1 << 6),
|
||||||
BZ_UI_ALIGN_HORIZ_CENTER = (1 << 7),
|
BZ_UI_ALIGN_HORIZ_START = (1 << 7),
|
||||||
BZ_UI_ALIGN_HORIZ_END = (1 << 8),
|
BZ_UI_ALIGN_HORIZ_CENTER = (1 << 8),
|
||||||
BZ_UI_ALIGN_VERT_START = (1 << 9),
|
BZ_UI_ALIGN_HORIZ_END = (1 << 9),
|
||||||
BZ_UI_ALIGN_VERT_CENTER = (1 << 10),
|
BZ_UI_ALIGN_VERT_START = (1 << 10),
|
||||||
BZ_UI_ALIGN_VERT_END = (1 << 11),
|
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,
|
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 BzUINode BzUINode;
|
||||||
|
|
||||||
typedef struct BzUINodeDesc {
|
typedef struct BzUINodeDesc {
|
||||||
BzUILayout layout;
|
BzUILayout layout;
|
||||||
BzUIStyle style;
|
|
||||||
BzUIFlags flags;
|
BzUIFlags flags;
|
||||||
const char *string;
|
|
||||||
|
|
||||||
BzUISize semanticSize[BZ_UI_AXIS_COUNT];
|
BzUISize semanticSize[BZ_UI_AXIS_COUNT];
|
||||||
f32 padding[BZ_UI_AXIS_COUNT * 2];
|
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 *bzUIPushParent(BzUI *ui, BzUINode *node);
|
||||||
BzUINode *bzUIPopParent(BzUI *ui);
|
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);
|
void bzUISetParentLayout(BzUI *ui, BzUILayout layout);
|
||||||
|
|
||||||
BzUIInteraction bzUIGetInteraction(BzUI *ui, BzUINode *node);
|
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
|
#endif //BREEZE_UI_CORE_H
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ void render(float dt, int *game) {
|
|||||||
.type = BZ_UI_LAYOUT_FLEX_BOX,
|
.type = BZ_UI_LAYOUT_FLEX_BOX,
|
||||||
.flags = BZ_UI_FLEX_DIR_COLUMN | BZ_UI_FLEX_ALIGN_CENTER | BZ_UI_FLEX_JUSTIFY_CENTER,
|
.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");
|
bzLogInfo("Hello world");
|
||||||
}
|
}
|
||||||
if (bzUIButton(ui, "foo", NULL)) {
|
if (bzUIButton(ui, "foo")) {
|
||||||
bzLogInfo("foo");
|
bzLogInfo("foo");
|
||||||
}
|
}
|
||||||
if (bzUIButton(ui, "bar", NULL)) {
|
if (bzUIButton(ui, "bar")) {
|
||||||
bzLogInfo("bar");
|
bzLogInfo("bar");
|
||||||
}
|
}
|
||||||
bzUIEnd(ui);
|
bzUIEnd(ui);
|
||||||
|
|||||||
Reference in New Issue
Block a user