Add uimodal dialog; uibutton reuses uilabel
uibutton now embeds a uilabel instead of drawing its text directly, caching glyph sprites since a button's label never changes after init. uimenu.c's item pointer in uiMenuDraw drops its unnecessary const so uiButtonDraw can update the button's cache. Also fixes remaining #include "ui/frame/uiframe.h" references left over from uiframe's move to ui/widget/. uimodal is a new generalized dialog (title + message + up to UI_MODAL_OPTIONS_MAX option buttons) built the same way uiconfirm is, but driven by a caller-supplied option list instead of a fixed confirm/cancel pair. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
uiframe.c
|
|
||||||
uiconfirm.c
|
uiconfirm.c
|
||||||
|
uimodal.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(game)
|
add_subdirectory(game)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uibackpack.h"
|
#include "uibackpack.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
#include "rpg/item/backpack.h"
|
#include "rpg/item/backpack.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uibattlemenu.h"
|
#include "uibattlemenu.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uigamemenu.h"
|
#include "uigamemenu.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
#include "ui/frame/uiconfirm.h"
|
#include "ui/frame/uiconfirm.h"
|
||||||
#include "ui/frame/backpack/uibackpack.h"
|
#include "ui/frame/backpack/uibackpack.h"
|
||||||
#include "ui/rpg/textbox/uitextboxmain.h"
|
#include "ui/rpg/textbox/uitextboxmain.h"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uimainmenu.h"
|
#include "uimainmenu.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "rpg/battle/testbattle/testbattle.h"
|
#include "rpg/battle/testbattle/testbattle.h"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uiconfirm.h"
|
#include "uiconfirm.h"
|
||||||
#include "uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uimodal.h"
|
||||||
|
#include "ui/widget/uiframe.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
#include "util/math.h"
|
||||||
|
#include "display/screen/screen.h"
|
||||||
|
#include "display/text/text.h"
|
||||||
|
#include "display/color.h"
|
||||||
|
#include "display/spritebatch/spritebatch.h"
|
||||||
|
#include "display/texture/texture.h"
|
||||||
|
#include "display/shader/shaderunlit.h"
|
||||||
|
|
||||||
|
#define UI_MODAL_BACKDROP_COLOR color4b(0, 0, 0, 160)
|
||||||
|
|
||||||
|
uimodal_t UI_MODAL;
|
||||||
|
|
||||||
|
void uiModalSelected(
|
||||||
|
const uimenu_t *menu,
|
||||||
|
const uint8_t index,
|
||||||
|
const uimenuitem_t *item
|
||||||
|
) {
|
||||||
|
UI_MODAL.result = index;
|
||||||
|
uiModalClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiModalClosed(const uimenu_t *menu) {
|
||||||
|
if(UI_MODAL.callback != NULL) {
|
||||||
|
UI_MODAL.callback(UI_MODAL.result, UI_MODAL.user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t uiModalInit(void) {
|
||||||
|
memoryZero(&UI_MODAL, sizeof(uimodal_t));
|
||||||
|
|
||||||
|
uiLabelInit(
|
||||||
|
&UI_MODAL.titleLabel, UI_MODAL.titleText,
|
||||||
|
UI_MODAL.titleSprites, UI_MODAL_TITLE_SPRITES_MAX
|
||||||
|
);
|
||||||
|
uiLabelInit(
|
||||||
|
&UI_MODAL.messageLabel, UI_MODAL.messageText,
|
||||||
|
UI_MODAL.messageSprites, UI_MODAL_MESSAGE_SPRITES_MAX
|
||||||
|
);
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t uiModalDraw(void) {
|
||||||
|
if(!uiMenuIsActive(&UI_MODAL.menu)) errorOk();
|
||||||
|
|
||||||
|
spritebatchsprite_t backdropSprite = {
|
||||||
|
.min = { 0.0f, 0.0f, 0.0f },
|
||||||
|
.max = { (float_t)SCREEN.width, (float_t)SCREEN.height, 0.0f },
|
||||||
|
.uvMin = { 0.0f, 0.0f },
|
||||||
|
.uvMax = { 1.0f, 1.0f }
|
||||||
|
};
|
||||||
|
shadermaterial_t backdropMaterial = {
|
||||||
|
.unlit = {
|
||||||
|
.color = UI_MODAL_BACKDROP_COLOR,
|
||||||
|
.texture = &TEXTURE_WHITE
|
||||||
|
}
|
||||||
|
};
|
||||||
|
errorChain(
|
||||||
|
spriteBatchBuffer(&backdropSprite, 1, &SHADER_UNLIT, backdropMaterial)
|
||||||
|
);
|
||||||
|
errorChain(spriteBatchFlush());
|
||||||
|
|
||||||
|
float_t rowHeight = (float_t)FONT_DEFAULT.tileset->tileHeight;
|
||||||
|
float_t contentWidth = mathMax(
|
||||||
|
mathMax(
|
||||||
|
(float_t)UI_MODAL.titleLabel.width, (float_t)UI_MODAL.messageLabel.width
|
||||||
|
),
|
||||||
|
UI_MODAL_MIN_WIDTH - (UI_FRAME_START_X * 2)
|
||||||
|
);
|
||||||
|
float_t width = contentWidth + (UI_FRAME_START_X * 2);
|
||||||
|
float_t height = (UI_FRAME_START_Y * 2)
|
||||||
|
+ (float_t)UI_MODAL.titleLabel.height + UI_FRAME_PADDING_Y
|
||||||
|
+ (float_t)UI_MODAL.messageLabel.height + UI_FRAME_PADDING_Y
|
||||||
|
+ rowHeight;
|
||||||
|
|
||||||
|
float_t x = (float_t)SCREEN.scanX +
|
||||||
|
((float_t)SCREEN.scanWidth - width) * 0.5f;
|
||||||
|
float_t y = (float_t)SCREEN.scanY +
|
||||||
|
((float_t)SCREEN.scanHeight - height) * 0.5f;
|
||||||
|
|
||||||
|
errorChain(uiFrameDraw(x, y, width, height));
|
||||||
|
|
||||||
|
float_t contentX = x + UI_FRAME_START_X;
|
||||||
|
float_t contentY = y + UI_FRAME_START_Y;
|
||||||
|
|
||||||
|
uiLabelSetX(&UI_MODAL.titleLabel, contentX);
|
||||||
|
uiLabelSetY(&UI_MODAL.titleLabel, contentY);
|
||||||
|
errorChain(uiLabelRender(&UI_MODAL.titleLabel, COLOR_WHITE));
|
||||||
|
|
||||||
|
float_t messageY = contentY + (float_t)UI_MODAL.titleLabel.height +
|
||||||
|
UI_FRAME_PADDING_Y;
|
||||||
|
uiLabelSetX(&UI_MODAL.messageLabel, contentX);
|
||||||
|
uiLabelSetY(&UI_MODAL.messageLabel, messageY);
|
||||||
|
errorChain(uiLabelRender(&UI_MODAL.messageLabel, COLOR_WHITE));
|
||||||
|
|
||||||
|
float_t buttonsY = messageY + (float_t)UI_MODAL.messageLabel.height +
|
||||||
|
UI_FRAME_PADDING_Y;
|
||||||
|
errorChain(
|
||||||
|
uiMenuDraw(&UI_MODAL.menu, contentX, buttonsY, contentWidth, rowHeight)
|
||||||
|
);
|
||||||
|
|
||||||
|
errorChain(spriteBatchFlush());
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t uiModalIsOpen(void) {
|
||||||
|
return uiMenuIsActive(&UI_MODAL.menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t uiModalGetResult(void) {
|
||||||
|
return UI_MODAL.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiModalOpen(
|
||||||
|
const char_t *title,
|
||||||
|
const char_t *message,
|
||||||
|
const char_t **options,
|
||||||
|
const uint8_t optionCount,
|
||||||
|
uimodalcallback_t callback,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
|
assertNotNull(title, "Title cannot be NULL");
|
||||||
|
assertNotNull(message, "Message cannot be NULL");
|
||||||
|
assertNotNull(options, "Options cannot be NULL");
|
||||||
|
assertTrue(optionCount > 0, "Must have at least one option");
|
||||||
|
assertTrue(
|
||||||
|
optionCount <= UI_MODAL_OPTIONS_MAX, "Too many options for modal"
|
||||||
|
);
|
||||||
|
|
||||||
|
stringCopy(UI_MODAL.titleText, title, UI_MODAL_TITLE_TEXT_MAX - 1);
|
||||||
|
UI_MODAL.titleLabel.dirty = true;
|
||||||
|
uiLabelRebuffer(&UI_MODAL.titleLabel);
|
||||||
|
|
||||||
|
stringCopy(UI_MODAL.messageText, message, UI_MODAL_MESSAGE_TEXT_MAX - 1);
|
||||||
|
UI_MODAL.messageLabel.dirty = true;
|
||||||
|
uiLabelRebuffer(&UI_MODAL.messageLabel);
|
||||||
|
|
||||||
|
UI_MODAL.callback = callback;
|
||||||
|
UI_MODAL.user = user;
|
||||||
|
UI_MODAL.result = UI_MODAL_RESULT_NONE;
|
||||||
|
|
||||||
|
MENU_BEGIN(
|
||||||
|
&UI_MODAL.menu, UI_MODAL.options, uiModalSelected, uiModalClosed, NULL
|
||||||
|
);
|
||||||
|
for(uint8_t i = 0; i < optionCount; i++) {
|
||||||
|
MENU_BUTTON(options[i]);
|
||||||
|
}
|
||||||
|
MENU_END(UI_MODAL.options, menuIndex);
|
||||||
|
|
||||||
|
uiMenuOpen(&UI_MODAL.menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiModalClose(void) {
|
||||||
|
uiMenuClose(&UI_MODAL.menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t uiModalDispose(void) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
#include "ui/widget/uilabel.h"
|
||||||
|
#include "ui/widget/uimenu.h"
|
||||||
|
|
||||||
|
#define UI_MODAL_TITLE_TEXT_MAX 64
|
||||||
|
#define UI_MODAL_TITLE_SPRITES_MAX UI_MODAL_TITLE_TEXT_MAX
|
||||||
|
#define UI_MODAL_MESSAGE_TEXT_MAX 256
|
||||||
|
#define UI_MODAL_MESSAGE_SPRITES_MAX UI_MODAL_MESSAGE_TEXT_MAX
|
||||||
|
#define UI_MODAL_OPTIONS_MAX 4
|
||||||
|
#define UI_MODAL_MIN_WIDTH 160.0f
|
||||||
|
#define UI_MODAL_RESULT_NONE 0xFF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked once a modal is dismissed.
|
||||||
|
*
|
||||||
|
* @param optionIndex Index into the options array passed to uiModalOpen
|
||||||
|
* that was selected, or UI_MODAL_RESULT_NONE if backed out of without
|
||||||
|
* selecting an option.
|
||||||
|
* @param user Arbitrary pointer passed to uiModalOpen.
|
||||||
|
*/
|
||||||
|
typedef void (*uimodalcallback_t)(const uint8_t optionIndex, void *user);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uilabel_t titleLabel;
|
||||||
|
char_t titleText[UI_MODAL_TITLE_TEXT_MAX];
|
||||||
|
spritebatchsprite_t titleSprites[UI_MODAL_TITLE_SPRITES_MAX];
|
||||||
|
|
||||||
|
uilabel_t messageLabel;
|
||||||
|
char_t messageText[UI_MODAL_MESSAGE_TEXT_MAX];
|
||||||
|
spritebatchsprite_t messageSprites[UI_MODAL_MESSAGE_SPRITES_MAX];
|
||||||
|
|
||||||
|
uimenu_t menu;
|
||||||
|
uimenuitem_t options[UI_MODAL_OPTIONS_MAX];
|
||||||
|
|
||||||
|
uimodalcallback_t callback;
|
||||||
|
void *user;
|
||||||
|
uint8_t result;
|
||||||
|
} uimodal_t;
|
||||||
|
|
||||||
|
extern uimodal_t UI_MODAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the modal dialog.
|
||||||
|
*
|
||||||
|
* @return Any error that occurs.
|
||||||
|
*/
|
||||||
|
errorret_t uiModalInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the modal dialog: a semi-transparent black backdrop covering the
|
||||||
|
* whole screen, then its own centered frame with the title, message, and
|
||||||
|
* option buttons. No-op when not open.
|
||||||
|
*
|
||||||
|
* @return Any error that occurs.
|
||||||
|
*/
|
||||||
|
errorret_t uiModalDraw(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true when the modal dialog is currently open.
|
||||||
|
*
|
||||||
|
* @returns True if open.
|
||||||
|
*/
|
||||||
|
bool_t uiModalIsOpen(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of the most recently dismissed modal.
|
||||||
|
*
|
||||||
|
* @returns The selected option index, or UI_MODAL_RESULT_NONE.
|
||||||
|
*/
|
||||||
|
uint8_t uiModalGetResult(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the modal dialog with the given title, message, and options.
|
||||||
|
* callback is invoked exactly once with the result, whether the dialog
|
||||||
|
* was dismissed by selecting an option or by pressing cancel/back.
|
||||||
|
*
|
||||||
|
* @param title Display title; copied internally, safe to be transient.
|
||||||
|
* @param message Display message; copied internally, safe to be
|
||||||
|
* transient.
|
||||||
|
* @param options Array of option label strings; NOT copied internally,
|
||||||
|
* the pointers are stored directly by the underlying buttons, so they
|
||||||
|
* must remain valid for as long as the modal is open (e.g. string
|
||||||
|
* literals or locale-owned strings).
|
||||||
|
* @param optionCount Number of options, from 1 to UI_MODAL_OPTIONS_MAX.
|
||||||
|
* @param callback Called with the result once the dialog closes. May be
|
||||||
|
* NULL.
|
||||||
|
* @param user Arbitrary pointer passed through to callback.
|
||||||
|
*/
|
||||||
|
void uiModalOpen(
|
||||||
|
const char_t *title,
|
||||||
|
const char_t *message,
|
||||||
|
const char_t **options,
|
||||||
|
const uint8_t optionCount,
|
||||||
|
uimodalcallback_t callback,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the modal dialog. No-op when already closed.
|
||||||
|
*/
|
||||||
|
void uiModalClose(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes of the modal dialog.
|
||||||
|
*
|
||||||
|
* @return Any error that occurs.
|
||||||
|
*/
|
||||||
|
errorret_t uiModalDispose(void);
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#include "display/color.h"
|
#include "display/color.h"
|
||||||
#include "display/spritebatch/spritebatch.h"
|
#include "display/spritebatch/spritebatch.h"
|
||||||
#include "display/shader/shaderunlit.h"
|
#include "display/shader/shaderunlit.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
|
|
||||||
void uiTextboxInit(
|
void uiTextboxInit(
|
||||||
uitextbox_t *box,
|
uitextbox_t *box,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include "display/color.h"
|
#include "display/color.h"
|
||||||
#include "display/spritebatch/spritebatch.h"
|
#include "display/spritebatch/spritebatch.h"
|
||||||
#include "display/shader/shaderunlit.h"
|
#include "display/shader/shaderunlit.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
|
|
||||||
uitextboxmain_t UI_TEXTBOX_MAIN;
|
uitextboxmain_t UI_TEXTBOX_MAIN;
|
||||||
static uifocusitem_t *focusItem = NULL;
|
static uifocusitem_t *focusItem = NULL;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include "rpg/rpgcamera.h"
|
#include "rpg/rpgcamera.h"
|
||||||
#include "display/text/text.h"
|
#include "display/text/text.h"
|
||||||
#include "display/screen/screen.h"
|
#include "display/screen/screen.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
|
|
||||||
void uiTextboxMiniInit(uitextboxmini_t *mini) {
|
void uiTextboxMiniInit(uitextboxmini_t *mini) {
|
||||||
assertNotNull(mini, "Mini textbox cannot be NULL");
|
assertNotNull(mini, "Mini textbox cannot be NULL");
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "uielement.h"
|
#include "uielement.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
|
|
||||||
bool_t uiElementIsNull(const uielement_t *element) {
|
bool_t uiElementIsNull(const uielement_t *element) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uielementlist.h"
|
#include "uielementlist.h"
|
||||||
#include "ui/frame/uiframe.h"
|
#include "ui/widget/uiframe.h"
|
||||||
#include "ui/debug/uifps.h"
|
#include "ui/debug/uifps.h"
|
||||||
#include "ui/overlay/uifullbox.h"
|
#include "ui/overlay/uifullbox.h"
|
||||||
#include "ui/overlay/uiloading.h"
|
#include "ui/overlay/uiloading.h"
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "ui/frame/battle/uibattlehud.h"
|
#include "ui/frame/battle/uibattlehud.h"
|
||||||
#include "ui/frame/backpack/uibackpack.h"
|
#include "ui/frame/backpack/uibackpack.h"
|
||||||
#include "ui/frame/uiconfirm.h"
|
#include "ui/frame/uiconfirm.h"
|
||||||
|
#include "ui/frame/uimodal.h"
|
||||||
#include "ui/rpg/textbox/uitextboxmain.h"
|
#include "ui/rpg/textbox/uitextboxmain.h"
|
||||||
#include "ui/rpg/textbox/uitextboxminilist.h"
|
#include "ui/rpg/textbox/uitextboxminilist.h"
|
||||||
#include "ui/rpg/uiemoji.h"
|
#include "ui/rpg/uiemoji.h"
|
||||||
@@ -89,6 +90,11 @@ uielement_t UI_ELEMENTS[] = {
|
|||||||
.draw = uiConfirmDraw,
|
.draw = uiConfirmDraw,
|
||||||
.dispose = uiConfirmDispose
|
.dispose = uiConfirmDispose
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.init = uiModalInit,
|
||||||
|
.draw = uiModalDraw,
|
||||||
|
.dispose = uiModalDispose
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
.init = uiTextboxMainInit,
|
.init = uiTextboxMainInit,
|
||||||
@@ -133,9 +139,9 @@ uielement_t UI_ELEMENTS[] = {
|
|||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// Debug components, disregards everything else.
|
// Debug components, disregards everything else.
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
{ .draw = uiConsoleDraw },
|
{ .init = uiConsoleInit, .draw = uiConsoleDraw },
|
||||||
{ .draw = uiFPSDraw },
|
{ .init = uiFPSInit, .draw = uiFPSDraw },
|
||||||
{ .draw = uiPlayerPosDraw },
|
{ .init = uiPlayerPosInit, .draw = uiPlayerPosDraw },
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// Null terminator
|
// Null terminator
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
uibutton.c
|
uibutton.c
|
||||||
uicheckbox.c
|
uicheckbox.c
|
||||||
|
uiframe.c
|
||||||
uilabel.c
|
uilabel.c
|
||||||
uitab.c
|
uitab.c
|
||||||
uislider.c
|
uislider.c
|
||||||
|
|||||||
@@ -8,14 +8,15 @@
|
|||||||
#include "uibutton.h"
|
#include "uibutton.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "display/text/text.h"
|
|
||||||
#include "display/color.h"
|
#include "display/color.h"
|
||||||
|
|
||||||
void uiButtonInit(uibutton_t *button, const char_t *label) {
|
void uiButtonInit(uibutton_t *button, const char_t *label) {
|
||||||
assertNotNull(button, "Button cannot be NULL");
|
assertNotNull(button, "Button cannot be NULL");
|
||||||
assertNotNull(label, "Label cannot be NULL");
|
assertNotNull(label, "Label cannot be NULL");
|
||||||
|
|
||||||
memoryZero(button, sizeof(uibutton_t));
|
memoryZero(button, sizeof(uibutton_t));
|
||||||
button->label = label;
|
uiLabelInit(&button->label, label, button->sprites, UI_BUTTON_SPRITES_MAX);
|
||||||
|
button->label.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t uiButtonIsHighlighted(const uibutton_t *button) {
|
bool_t uiButtonIsHighlighted(const uibutton_t *button) {
|
||||||
@@ -29,15 +30,16 @@ void uiButtonSetHighlighted(uibutton_t *button, const bool_t highlighted) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorret_t uiButtonDraw(
|
errorret_t uiButtonDraw(
|
||||||
const uibutton_t *button,
|
uibutton_t *button,
|
||||||
const float_t x,
|
const float_t x,
|
||||||
const float_t y
|
const float_t y
|
||||||
) {
|
) {
|
||||||
assertNotNull(button, "Button cannot be NULL");
|
assertNotNull(button, "Button cannot be NULL");
|
||||||
errorChain(textDraw(
|
|
||||||
x, y, button->label,
|
uiLabelSetX(&button->label, x);
|
||||||
button->highlighted ? COLOR_RED : COLOR_WHITE,
|
uiLabelSetY(&button->label, y);
|
||||||
&FONT_DEFAULT
|
|
||||||
));
|
return uiLabelRender(
|
||||||
errorOk();
|
&button->label, button->highlighted ? COLOR_RED : COLOR_WHITE
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
|
#include "ui/widget/uilabel.h"
|
||||||
|
|
||||||
|
#define UI_BUTTON_SPRITES_MAX 32
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char_t *label;
|
uilabel_t label;
|
||||||
|
spritebatchsprite_t sprites[UI_BUTTON_SPRITES_MAX];
|
||||||
bool_t highlighted;
|
bool_t highlighted;
|
||||||
} uibutton_t;
|
} uibutton_t;
|
||||||
|
|
||||||
@@ -17,7 +21,8 @@ typedef struct {
|
|||||||
* Initializes a button.
|
* Initializes a button.
|
||||||
*
|
*
|
||||||
* @param button The button to initialize.
|
* @param button The button to initialize.
|
||||||
* @param label Display label.
|
* @param label Display label; never written to, safe to be a caller-
|
||||||
|
* owned or immutable string.
|
||||||
*/
|
*/
|
||||||
void uiButtonInit(uibutton_t *button, const char_t *label);
|
void uiButtonInit(uibutton_t *button, const char_t *label);
|
||||||
|
|
||||||
@@ -46,7 +51,7 @@ void uiButtonSetHighlighted(uibutton_t *button, const bool_t highlighted);
|
|||||||
* @return Any error that occurs.
|
* @return Any error that occurs.
|
||||||
*/
|
*/
|
||||||
errorret_t uiButtonDraw(
|
errorret_t uiButtonDraw(
|
||||||
const uibutton_t *button,
|
uibutton_t *button,
|
||||||
const float_t x,
|
const float_t x,
|
||||||
const float_t y
|
const float_t y
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ errorret_t uiMenuDraw(
|
|||||||
uint8_t row = 0;
|
uint8_t row = 0;
|
||||||
|
|
||||||
for(uint8_t i = 0; i < menu->itemCount; i++) {
|
for(uint8_t i = 0; i < menu->itemCount; i++) {
|
||||||
const uimenuitem_t *item = &menu->items[i];
|
uimenuitem_t *item = &menu->items[i];
|
||||||
|
|
||||||
if(item->type == UI_MENU_WIDGET_TYPE_LABEL) {
|
if(item->type == UI_MENU_WIDGET_TYPE_LABEL) {
|
||||||
if(col > 0) { row++; col = 0; }
|
if(col > 0) { row++; col = 0; }
|
||||||
|
|||||||
Reference in New Issue
Block a user