#include "ui_widgets.h" #include "game_state.h" #include f32 uiGetScale() { // Assuming 16:9 aspect f32 scaleX = GetScreenWidth() / 1280.0f; f32 scaleY = GetScreenHeight() / 720.0f; return BZ_MIN(scaleX, scaleY); } Font getFont() { static const Game *game = NULL; if (!game) { game = ecs_singleton_get(ECS, Game); } return game->font; } BzUINode *uiPushDivParentPercentage(f32 xPercent, f32 yPercent) { return bzUIPushDiv(UI, (BzUISize) { .kind = BZ_UI_SIZE_REL_PARENT, .value = xPercent, }, (BzUISize) { .kind = BZ_UI_SIZE_REL_PARENT, .value = yPercent }); } void uiBaseLabel(const char *txt, Font font, f32 scl) { BzUINode *node = bzUINodeMake(UI, bzUIKeyFromString(txt), &(BzUINodeDesc) { .flags = BZ_UI_DRAW_TEXT | BZ_UI_DRAW_TEXT_SHADOW | BZ_UI_ALIGN_CENTER, .semanticSize[BZ_UI_AXIS_X] = { .kind = BZ_UI_SIZE_FIT, }, .semanticSize[BZ_UI_AXIS_Y] = { .kind = BZ_UI_SIZE_FIT }, .padding = {5, 5, 5, 5}, }); bzUISetTextStyle(UI, node, (BzUITextStyle) { .text = txt, .font = font, .fontSpacing = 2 * uiGetScale() * scl, .fontSize = 62 * uiGetScale() * scl, .normal = WHITE, .hover = WHITE, .active = WHITE, }); bzUISetTextShadowStyle(UI, node, (BzUITextShadowStyle) { .offset[BZ_UI_AXIS_X] = 2 * uiGetScale() * scl, .offset[BZ_UI_AXIS_Y] = 2 * uiGetScale() * scl, .normal = BLACK, .hover = BLACK, .active = BLACK, }); } bool uiBaseTextButton(const char *txt, Font font, f32 scl) { BzUINode *node = bzUINodeMake(UI, bzUIKeyFromString(txt), &(BzUINodeDesc) { .flags = BZ_UI_DRAW_TEXT | BZ_UI_DRAW_TEXT_SHADOW | BZ_UI_ALIGN_CENTER, .semanticSize[BZ_UI_AXIS_X] = { .kind = BZ_UI_SIZE_FIT, }, .semanticSize[BZ_UI_AXIS_Y] = { .kind = BZ_UI_SIZE_FIT }, .padding = {5, 0, 5, 0}, .margin = {5, 5, 5, 5}, }); bzUISetTextStyle(UI, node, (BzUITextStyle) { .text = txt, .font = font, .fontSpacing = 2 * uiGetScale() * scl, .fontSize = 62 * uiGetScale() * scl, .normal = WHITE, .hover = GRAY, .active = YELLOW }); bzUISetTextShadowStyle(UI, node, (BzUITextShadowStyle) { .offset[BZ_UI_AXIS_X] = 2 * uiGetScale() * scl, .offset[BZ_UI_AXIS_Y] = 2 * uiGetScale() * scl, .normal = BLACK, .hover = BLACK, .active = BLACK, }); return bzUIGetInteraction(UI, node).clicked; } void uiBaseCheckbox(const char *txt, Font font, f32 scl, bool *check) { BZ_ASSERT(check); bzUIPushDiv(UI, (BzUISize) {BZ_UI_SIZE_CHILD_SUM}, (BzUISize) {BZ_UI_SIZE_CHILD_MAX}); bzUISetParentLayout(UI, (BzUILayout) { BZ_UI_LAYOUT_FLEX_BOX, BZ_UI_FLEX_DIR_ROW | BZ_UI_FLEX_ALIGN_CENTER | BZ_UI_FLEX_JUSTIFY_START }); f32 size = 16 * uiGetScale() * scl; BzUINode *checkbox = bzUINodeMake(UI, bzUIGetUniqueKey(UI), &(BzUINodeDesc) { .flags = BZ_UI_CLICKABLE | BZ_UI_DRAW_BACKGROUND | BZ_UI_DRAW_BORDER, .semanticSize[BZ_UI_AXIS_X] = (BzUISize) { BZ_UI_SIZE_PIXELS, size}, .semanticSize[BZ_UI_AXIS_Y] = (BzUISize) { BZ_UI_SIZE_PIXELS, size}, .margin = {0, 0, 10 * uiGetScale() * scl, 0 } }); bzUISetBackgroundStyle(UI, checkbox, (BzUIBackgroundStyle) { .normal = *check ? WHITE : BLACK, .hover = GRAY, .active = YELLOW, }); bzUISetBorderStyle(UI, checkbox, (BzUIBorderStyle) { .thickness = 5.0f * uiGetScale() * scl, .normal = BLACK, .hover = BLACK, .active = BLACK, }); if (bzUIGetInteraction(UI, checkbox).clicked) { *check = !*check; } BzUINode *label = bzUINodeMake(UI, bzUIKeyFromString(txt), &(BzUINodeDesc) { .flags = BZ_UI_DRAW_TEXT | BZ_UI_DRAW_TEXT_SHADOW | BZ_UI_ALIGN_CENTER, .semanticSize[BZ_UI_AXIS_X] = { .kind = BZ_UI_SIZE_FIT, }, .semanticSize[BZ_UI_AXIS_Y] = { .kind = BZ_UI_SIZE_FIT }, }); bzUISetTextStyle(UI, label, (BzUITextStyle) { .text = txt, .font = font, .fontSpacing = 2 * uiGetScale() * scl, .fontSize = 32 * uiGetScale() * scl, .normal = WHITE, .hover = GRAY, .active = YELLOW }); bzUISetTextShadowStyle(UI, label, (BzUITextShadowStyle) { .offset[BZ_UI_AXIS_X] = 2 * uiGetScale() * scl, .offset[BZ_UI_AXIS_Y] = 2 * uiGetScale() * scl, .normal = BLACK, .hover = BLACK, .active = BLACK, }); if (bzUIGetInteraction(UI, label).clicked) { *check = !*check; } bzUIPopParent(UI); } void uiBaseSlider(const char *txt, Font font, f32 scl, f32 *value, f32 min, f32 max) { BZ_ASSERT(value); bzUIPushDiv(UI, (BzUISize) {BZ_UI_SIZE_CHILD_SUM}, (BzUISize) {BZ_UI_SIZE_CHILD_MAX}); bzUISetParentLayout(UI, (BzUILayout) { BZ_UI_LAYOUT_FLEX_BOX, BZ_UI_FLEX_DIR_ROW | BZ_UI_FLEX_ALIGN_CENTER | BZ_UI_FLEX_JUSTIFY_SPACE_BETWEEN }); uiBaseLabel(txt, font, 0.6 * scl); bzUIPushDiv(UI, (BzUISize) {BZ_UI_SIZE_CHILD_SUM}, (BzUISize) { BZ_UI_SIZE_CHILD_MAX}); bzUISetParentLayout(UI, (BzUILayout) { BZ_UI_LAYOUT_FLEX_BOX, BZ_UI_FLEX_DIR_ROW | BZ_UI_FLEX_ALIGN_CENTER | BZ_UI_FLEX_JUSTIFY_END }); char buf[32]; snprintf(buf, sizeof(buf), "-##%s", txt); if (uiBaseTextButton(buf, font, 0.6 * scl)) (*value)--; *value = BZ_MAX(*value, min); snprintf(buf, sizeof(buf), "%2.0f##%s", *value, txt); uiBaseLabel(buf, font, 0.6 * scl); snprintf(buf, sizeof(buf), "+##%s", txt); if (uiBaseTextButton(buf, font, 0.6 * scl)) (*value)++; *value = BZ_MIN(*value, max); bzUIPopParent(UI); bzUIPopParent(UI); } void uiMainMenuLabel(const char *txt) { uiBaseLabel(txt, getFont(), 1.8f); } bool uiMainMenuButton(const char *txt) { return uiBaseTextButton(txt, getFont(), 0.8f); } void uiSettingsLabel(const char *txt) { uiBaseLabel(txt, getFont(), 0.8f); } bool uiSettingsButton(const char *txt) { return uiBaseTextButton(txt, getFont(), 0.7f); } void uiSettingsCheckbox(const char *txt, bool *check) { uiBaseCheckbox(txt, getFont(), 1.0f, check); } void uiSettingsSlider(const char *txt, f32 *value) { uiBaseSlider(txt, getFont(), 1.0f, value, 0, 10); } void uiGameResCount(i32 amount, i32 capacity, Rectangle icon, Texture2D texture) { bzUIPushDiv(UI, (BzUISize) { BZ_UI_SIZE_CHILD_SUM }, (BzUISize) { BZ_UI_SIZE_CHILD_MAX }); bzUISetParentLayout(UI, (BzUILayout) { BZ_UI_LAYOUT_FLEX_BOX, BZ_UI_FLEX_DIR_ROW | BZ_UI_FLEX_ALIGN_CENTER }); char buf[64]; BzUIKey id = bzUIGetUniqueKey(UI); if (capacity == -1) snprintf(buf, sizeof(buf), "%d##%d", amount, id); else snprintf(buf, sizeof(buf), "%d/%d##%d", amount, capacity, id); const f32 scl = 0.4f; uiBaseLabel(buf, getFont(), scl); BzUINode *iconNode = bzUINodeMake(UI, id, &(BzUINodeDesc) { .flags = BZ_UI_DRAW_SPRITE | BZ_UI_ALIGN_CENTER, .semanticSize[BZ_UI_AXIS_X] = { BZ_UI_SIZE_PIXELS, 80 * scl * uiGetScale(), }, .semanticSize[BZ_UI_AXIS_Y] = { BZ_UI_SIZE_PIXELS, 80 * scl * uiGetScale(), }, .margin = {0, 0, 20 * uiGetScale(), 0} }); bzUISetSpriteStyle(UI, iconNode, (BzUISpriteStyle) { .rec = icon, .texture = texture, .tintNormal = WHITE, .tintHover = WHITE, .tintActive = WHITE, }); bzUIPopParent(UI); }