UI Confirm

This commit is contained in:
2026-07-07 10:12:22 -05:00
parent 6dee37d8c1
commit 2dcf0d0f0d
6 changed files with 258 additions and 2 deletions
+1
View File
@@ -6,6 +6,7 @@
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
uiframe.c
uiconfirm.c
)
add_subdirectory(game)
@@ -8,14 +8,31 @@
#include "uisettingsgameplay.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "ui/frame/uiconfirm.h"
#include "console/console.h"
uisettingsgameplay_t UI_SETTINGS_GAMEPLAY;
void uiSettingsGameplayShowConfirmResult(const bool_t result, void *user) {
consolePrint("Confirm dialog result: %s", result ? "confirmed" : "cancelled");
}
void uiSettingsGameplaySelected(
const uimenu_t *menu,
const uint8_t index,
const uimenuitem_t *item
) {
if(index != UI_SETTINGS_GAMEPLAY_INDEX_SHOW_CONFIRM) return;
uiConfirmOpen(
"Are you sure?", uiSettingsGameplayShowConfirmResult, NULL
);
}
errorret_t uiSettingsGameplayInit(void) {
memoryZero(&UI_SETTINGS_GAMEPLAY, sizeof(uisettingsgameplay_t));
uimenu_t *menu = &UI_SETTINGS_GAMEPLAY.menu;
uiMenuInit(menu, NULL, NULL, NULL);
uiMenuInit(menu, uiSettingsGameplaySelected, NULL, NULL);
menu->items = UI_SETTINGS_GAMEPLAY.items;
MENU_BEGIN
@@ -23,6 +40,7 @@ errorret_t uiSettingsGameplayInit(void) {
MENU_BUTTON("Do other thing");
MENU_CHECKBOX("Enable thing?");
MENU_SLIDER_FLOAT("test", 1.0f, 1.0f, 4.0f, 0.5f);
MENU_BUTTON("Show confirm");
assertTrue(
menuIndex <= UI_SETTINGS_GAMEPLAY_ITEM_COUNT,
@@ -9,7 +9,8 @@
#include "error/error.h"
#include "ui/widget/uimenu.h"
#define UI_SETTINGS_GAMEPLAY_ITEM_COUNT 4
#define UI_SETTINGS_GAMEPLAY_ITEM_COUNT 5
#define UI_SETTINGS_GAMEPLAY_INDEX_SHOW_CONFIRM 4
typedef struct {
uimenu_t menu;
+135
View File
@@ -0,0 +1,135 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "uiconfirm.h"
#include "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_CONFIRM_BACKDROP_COLOR color4b(0, 0, 0, 160)
uiconfirm_t UI_CONFIRM;
void uiConfirmSelected(
const uimenu_t *menu,
const uint8_t index,
const uimenuitem_t *item
) {
UI_CONFIRM.result = index == UI_CONFIRM_INDEX_CONFIRM;
uiConfirmClose();
}
void uiConfirmClosed(const uimenu_t *menu) {
if(UI_CONFIRM.callback != NULL) {
UI_CONFIRM.callback(UI_CONFIRM.result, UI_CONFIRM.user);
}
}
errorret_t uiConfirmInit(void) {
memoryZero(&UI_CONFIRM, sizeof(uiconfirm_t));
uimenu_t *menu = &UI_CONFIRM.menu;
uiMenuInit(menu, uiConfirmSelected, uiConfirmClosed, NULL);
menu->items = UI_CONFIRM.items;
MENU_BEGIN
MENU_BUTTON("Confirm");
MENU_BUTTON("Cancel");
assertTrue(
menuIndex <= UI_CONFIRM_ITEM_COUNT,
"Confirm item count mismatch"
);
uiMenuSetItems(menu, UI_CONFIRM.items, menuIndex, menuIndex);
errorOk();
}
errorret_t uiConfirmDraw(void) {
if(!uiMenuIsActive(&UI_CONFIRM.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_CONFIRM_BACKDROP_COLOR,
.texture = &TEXTURE_WHITE
}
};
errorChain(
spriteBatchBuffer(&backdropSprite, 1, &SHADER_UNLIT, backdropMaterial)
);
errorChain(spriteBatchFlush());
int32_t textW, textH;
textMeasure(UI_CONFIRM.text, &FONT_DEFAULT, &textW, &textH);
float_t rowHeight = (float_t)FONT_DEFAULT.tileset->tileHeight;
float_t width = mathMax(
(float_t)textW + (UI_FRAME_START_X * 2), UI_CONFIRM_MIN_WIDTH
);
float_t height = (UI_FRAME_START_Y * 2) + rowHeight + 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;
float_t contentWidth = width - (UI_FRAME_START_X * 2);
errorChain(textDraw(contentX, contentY, UI_CONFIRM.text, COLOR_WHITE, &FONT_DEFAULT));
float_t buttonsY = contentY + rowHeight + UI_FRAME_PADDING_Y;
errorChain(uiMenuDraw(&UI_CONFIRM.menu, contentX, buttonsY, contentWidth, rowHeight));
errorChain(spriteBatchFlush());
errorOk();
}
bool_t uiConfirmIsOpen(void) {
return uiMenuIsActive(&UI_CONFIRM.menu);
}
bool_t uiConfirmGetResult(void) {
return UI_CONFIRM.result;
}
void uiConfirmOpen(
const char_t *question,
uiconfirmcallback_t callback,
void *user
) {
assertNotNull(question, "Question cannot be NULL");
stringCopy(UI_CONFIRM.text, question, UI_CONFIRM_TEXT_MAX);
UI_CONFIRM.callback = callback;
UI_CONFIRM.user = user;
UI_CONFIRM.result = false;
uiMenuOpen(&UI_CONFIRM.menu);
}
void uiConfirmClose(void) {
uiMenuClose(&UI_CONFIRM.menu);
}
errorret_t uiConfirmDispose(void) {
errorOk();
}
+94
View File
@@ -0,0 +1,94 @@
/**
* 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/uimenu.h"
#define UI_CONFIRM_TEXT_MAX 256
#define UI_CONFIRM_MIN_WIDTH 160.0f
#define UI_CONFIRM_INDEX_CONFIRM 0
#define UI_CONFIRM_INDEX_CANCEL 1
#define UI_CONFIRM_ITEM_COUNT 2
/**
* Callback invoked once a confirm dialog is dismissed.
*
* @param result True if Confirm was selected, false if Cancel was
* selected or the dialog was backed out of.
* @param user Arbitrary pointer passed to uiConfirmOpen.
*/
typedef void (*uiconfirmcallback_t)(const bool_t result, void *user);
typedef struct {
char_t text[UI_CONFIRM_TEXT_MAX];
uimenu_t menu;
uimenuitem_t items[UI_CONFIRM_ITEM_COUNT];
uiconfirmcallback_t callback;
void *user;
bool_t result;
} uiconfirm_t;
extern uiconfirm_t UI_CONFIRM;
/**
* Initializes the confirm dialog.
*
* @return Any error that occurs.
*/
errorret_t uiConfirmInit(void);
/**
* Draws the confirm dialog: a semi-transparent black backdrop covering
* the whole screen, then its own centered frame with the question text
* and Confirm/Cancel buttons. No-op when not open.
*
* @return Any error that occurs.
*/
errorret_t uiConfirmDraw(void);
/**
* Returns true when the confirm dialog is currently open.
*
* @returns True if open.
*/
bool_t uiConfirmIsOpen(void);
/**
* Returns the result of the most recently dismissed confirm dialog.
*
* @returns True if Confirm was selected, false otherwise.
*/
bool_t uiConfirmGetResult(void);
/**
* Opens the confirm dialog with the given question text. callback is
* invoked exactly once with the result, whether the dialog was
* dismissed by selecting a button or by pressing cancel/back.
*
* @param question Display text; copied internally, safe to be transient.
* @param callback Called with the result once the dialog closes. May be
* NULL.
* @param user Arbitrary pointer passed through to callback.
*/
void uiConfirmOpen(
const char_t *question,
uiconfirmcallback_t callback,
void *user
);
/**
* Closes the confirm dialog. No-op when already closed.
*/
void uiConfirmClose(void);
/**
* Disposes of the confirm dialog.
*
* @return Any error that occurs.
*/
errorret_t uiConfirmDispose(void);
+7
View File
@@ -18,6 +18,7 @@
#include "ui/debug/uiconsole.h"
#include "ui/frame/settings/uisettings.h"
#include "ui/frame/game/uigamemenu.h"
#include "ui/frame/uiconfirm.h"
#include "ui/rpg/uitextboxmain.h"
uielement_t UI_ELEMENTS[] = {
@@ -46,6 +47,12 @@ uielement_t UI_ELEMENTS[] = {
.dispose = uiSettingsDispose
},
{
.init = uiConfirmInit,
.draw = uiConfirmDraw,
.dispose = uiConfirmDispose
},
{
.init = uiTextboxMainInit,
.update = uiTextboxMainUpdate,