Rebuild uiconfirm on top of uimodal, add quit confirmation

uiconfirm no longer duplicates its own backdrop/frame/text/menu drawing
- it now just opens the shared uimodal_t with a Confirm/Cancel option
pair and translates the result back to a bool. uimodal itself gains an
optional title (NULL skips the title row entirely) so a title-less
confirm dialog doesn't reserve blank space.

Main menu's Quit option now opens a confirm dialog instead of exiting
immediately.

Drops es_MX.po/jp_JP.po locale files.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 22:41:06 -05:00
parent 475c865e33
commit 27b6ddf5cb
9 changed files with 66 additions and 527 deletions
+14
View File
@@ -24,6 +24,7 @@ msgstr "Try again"
msgid "initial.no_device.continue" msgid "initial.no_device.continue"
msgstr "Continue without saving" msgstr "Continue without saving"
# Main Menu Scene # Main Menu Scene
msgid "main_menu.new_game" msgid "main_menu.new_game"
msgstr "New Game" msgstr "New Game"
@@ -37,6 +38,19 @@ msgstr "Options"
msgid "main_menu.quit" msgid "main_menu.quit"
msgstr "Quit Game" msgstr "Quit Game"
msgid "main_menu.quit_confirm"
msgstr "Are you sure you want to quit?"
#: ui/menu.c:10 #: ui/menu.c:10
msgid "ui.title" msgid "ui.title"
msgstr "" msgstr ""
-194
View File
@@ -1,194 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: ExampleApp 1.0\n"
"Language: es\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n==1 ? 0 : 1);\n"
#: ui/menu.c:10
msgid "ui.title"
msgstr ""
"Bienvenido"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.general"
msgstr "General"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.input"
msgstr "Entrada"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.display"
msgstr "Pantalla"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.audio"
msgstr "Audio"
msgid "ui.settings.input.deadzone"
msgstr "Deadzone"
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language"
msgstr "Idioma"
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language_detail"
msgstr "Se aplica después de reiniciar la aplicación."
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.apply"
msgstr "Aplicar"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.discard_changes"
msgstr "¿Descartar los cambios no guardados?"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.characters"
msgstr "Personajes"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.items"
msgstr "Objetos"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.settings"
msgstr "Configuración"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save"
msgstr "Guardar"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_success"
msgstr "Partida guardada."
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_cancelled"
msgstr "Guardado cancelado."
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_unavailable"
msgstr "No se puede guardar: no se encontró ningún dispositivo de guardado."
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_temporary"
msgstr "Esta sesión es temporal - no se encontró ningún dispositivo de guardado, por lo que guardar está deshabilitado."
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_create_confirm"
msgstr "No se encontraron datos guardados. ¿Crear una partida nueva?"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_failed_format"
msgstr "Error al guardar: %s"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_check_failed_format"
msgstr "No se puede guardar: %s"
#: src/dusk/ui/frame/initial/uiinitialnocard.c
msgid "ui.initial.no_card.message"
msgstr "No se encontró ningún dispositivo de guardado. Puedes continuar, pero\nel progreso no se guardará."
#: src/dusk/ui/frame/initial/uiinitialnocard.c
msgid "ui.initial.no_card.retry"
msgstr "Reintentar"
#: src/dusk/ui/frame/initial/uiinitialnocard.c
msgid "ui.initial.no_card.continue"
msgstr "Continuar de todos modos"
#: src/dusk/ui/frame/initial/uiinitialcreatesave.c
msgid "ui.initial.create_save.message"
msgstr "No se encontraron datos guardados. ¿Crear una partida nueva?"
#: src/dusk/ui/frame/initial/uiinitialcreatesave.c
msgid "ui.initial.create_save.yes"
msgstr "Sí"
#: src/dusk/ui/frame/initial/uiinitialcreatesave.c
msgid "ui.initial.create_save.no"
msgstr "No"
#: src/dusk/ui/frame/mainmenu/uimainmenu.c
msgid "ui.main_menu.new_game"
msgstr "Nueva Partida"
#: src/dusk/ui/frame/mainmenu/uimainmenu.c
msgid "ui.main_menu.load_game"
msgstr "Cargar Partida"
#: src/dusk/ui/frame/mainmenu/uimainmenu.c
msgid "ui.main_menu.options"
msgstr "Opciones"
#: src/dusk/ui/frame/mainmenu/uimainmenu.c
msgid "ui.main_menu.quit"
msgstr "Salir del Juego"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.confirm"
msgstr "Confirmar"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.cancel"
msgstr "Cancelar"
#: src/dusk/ui/frame/battle/uibattlemenu.c
msgid "ui.battle.menu.attack"
msgstr "Atacar"
#: src/dusk/ui/frame/battle/uibattlemenu.c
msgid "ui.battle.menu.flee"
msgstr "Huir"
#: src/dusk/ui/frame/battle/uibattlemenu.c
msgid "ui.battle.menu.target_format"
msgstr "Enemigo %u (%u/%u PS)"
#: src/dusk/ui/frame/battle/uibattlehud.c
msgid "ui.battle.hud.hp_format"
msgstr "PS %u/%u"
#: src/dusk/ui/frame/battle/uibattlehud.c
msgid "ui.battle.hud.mp_format"
msgstr "PM %u/%u"
#: src/dusk/ui/frame/settings/uisettingsaudio.c
msgid "ui.settings.audio.placeholder"
msgstr "Aún no hay opciones de audio"
#: src/dusk/ui/frame/settings/uisettingsdisplay.c
msgid "ui.settings.display.placeholder"
msgstr "Aún no hay opciones de pantalla"
#: src/dusk/ui/frame/settings/uisettingsinput.c
msgid "ui.settings.input.placeholder"
msgstr "Aún no hay opciones de entrada"
#: src/dusk/ui/frame/backpack/uibackpack.c
msgid "ui.backpack.category_format"
msgstr "Categoría %u"
#: src/dusk/ui/overlay/uiloading.c
msgid "ui.loading.text"
msgstr "cargando"
#: src/dusk/ui/overlay/uiautosave.c
msgid "ui.autosave.saving"
msgstr "GUARDANDO"
#: src/dusk/rpg/item/item.json
msgid "item.potion.name"
msgstr "Poción"
#: src/dusk/rpg/item/item.json
msgid "item.potato.name"
msgstr "Papa"
#: src/dusk/rpg/item/item.json
msgid "item.apple.name"
msgstr "Manzana"
-194
View File
@@ -1,194 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: ExampleApp 1.0\n"
"Language: ja\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=1; plural=(0);\n"
#: ui/menu.c:10
msgid "ui.title"
msgstr ""
"歓迎"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.general"
msgstr "一般"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.input"
msgstr "入力"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.display"
msgstr "表示"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.audio"
msgstr "オーディオ"
msgid "ui.settings.input.deadzone"
msgstr "デッドゾーン"
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language"
msgstr "言語"
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language_detail"
msgstr "アプリケーションを再起動すると適用されます。"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.apply"
msgstr "適用"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.discard_changes"
msgstr "未保存の変更を破棄しますか?"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.characters"
msgstr "キャラクター"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.items"
msgstr "アイテム"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.settings"
msgstr "設定"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save"
msgstr "セーブ"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_success"
msgstr "セーブしました。"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_cancelled"
msgstr "セーブをキャンセルしました。"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_unavailable"
msgstr "セーブできません - セーブデバイスが見つかりません。"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_temporary"
msgstr "このセッションは一時的です - セーブデバイスが見つからなかったため、セーブは無効になっています。"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_create_confirm"
msgstr "セーブデータが見つかりません。新しいセーブを作成しますか?"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_failed_format"
msgstr "セーブに失敗しました: %s"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.save_check_failed_format"
msgstr "セーブできません: %s"
#: src/dusk/ui/frame/initial/uiinitialnocard.c
msgid "ui.initial.no_card.message"
msgstr "セーブデバイスが見つかりません。続行できますが、\n進行状況は保存されません。"
#: src/dusk/ui/frame/initial/uiinitialnocard.c
msgid "ui.initial.no_card.retry"
msgstr "再試行"
#: src/dusk/ui/frame/initial/uiinitialnocard.c
msgid "ui.initial.no_card.continue"
msgstr "続行する"
#: src/dusk/ui/frame/initial/uiinitialcreatesave.c
msgid "ui.initial.create_save.message"
msgstr "セーブデータが見つかりません。新しいセーブを作成しますか?"
#: src/dusk/ui/frame/initial/uiinitialcreatesave.c
msgid "ui.initial.create_save.yes"
msgstr "はい"
#: src/dusk/ui/frame/initial/uiinitialcreatesave.c
msgid "ui.initial.create_save.no"
msgstr "いいえ"
#: src/dusk/ui/frame/mainmenu/uimainmenu.c
msgid "ui.main_menu.new_game"
msgstr "ニューゲーム"
#: src/dusk/ui/frame/mainmenu/uimainmenu.c
msgid "ui.main_menu.load_game"
msgstr "ロードゲーム"
#: src/dusk/ui/frame/mainmenu/uimainmenu.c
msgid "ui.main_menu.options"
msgstr "オプション"
#: src/dusk/ui/frame/mainmenu/uimainmenu.c
msgid "ui.main_menu.quit"
msgstr "ゲームを終了"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.confirm"
msgstr "確認"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.cancel"
msgstr "キャンセル"
#: src/dusk/ui/frame/battle/uibattlemenu.c
msgid "ui.battle.menu.attack"
msgstr "攻撃"
#: src/dusk/ui/frame/battle/uibattlemenu.c
msgid "ui.battle.menu.flee"
msgstr "逃げる"
#: src/dusk/ui/frame/battle/uibattlemenu.c
msgid "ui.battle.menu.target_format"
msgstr "敵%u (%u/%u HP)"
#: src/dusk/ui/frame/battle/uibattlehud.c
msgid "ui.battle.hud.hp_format"
msgstr "HP %u/%u"
#: src/dusk/ui/frame/battle/uibattlehud.c
msgid "ui.battle.hud.mp_format"
msgstr "MP %u/%u"
#: src/dusk/ui/frame/settings/uisettingsaudio.c
msgid "ui.settings.audio.placeholder"
msgstr "オーディオ設定はまだありません"
#: src/dusk/ui/frame/settings/uisettingsdisplay.c
msgid "ui.settings.display.placeholder"
msgstr "表示設定はまだありません"
#: src/dusk/ui/frame/settings/uisettingsinput.c
msgid "ui.settings.input.placeholder"
msgstr "入力設定はまだありません"
#: src/dusk/ui/frame/backpack/uibackpack.c
msgid "ui.backpack.category_format"
msgstr "カテゴリー%u"
#: src/dusk/ui/overlay/uiloading.c
msgid "ui.loading.text"
msgstr "読み込み中"
#: src/dusk/ui/overlay/uiautosave.c
msgid "ui.autosave.saving"
msgstr "保存中"
#: src/dusk/rpg/item/item.json
msgid "item.potion.name"
msgstr "ポーション"
#: src/dusk/rpg/item/item.json
msgid "item.potato.name"
msgstr "ジャガイモ"
#: src/dusk/rpg/item/item.json
msgid "item.apple.name"
msgstr "リンゴ"
+7 -2
View File
@@ -15,6 +15,7 @@
#include "assert/assert.h" #include "assert/assert.h"
#include "locale/localemanager.h" #include "locale/localemanager.h"
#include "asset/loader/locale/assetlocaleloader.h" #include "asset/loader/locale/assetlocaleloader.h"
#include "ui/frame/uiconfirm.h"
#define UI_MAIN_MENU_INDEX_NEW_GAME 0 #define UI_MAIN_MENU_INDEX_NEW_GAME 0
#define UI_MAIN_MENU_INDEX_LOAD_GAME 1 #define UI_MAIN_MENU_INDEX_LOAD_GAME 1
@@ -23,15 +24,19 @@
uimainmenu_t UI_MAIN_MENU; uimainmenu_t UI_MAIN_MENU;
void uiMainMenuQuitConfirmed(const bool_t result, void *user) {
if(result) ENGINE.running = false;
}
void uiMainMenuSelected( void uiMainMenuSelected(
const uimenu_t *menu, const uimenu_t *menu,
const uint8_t index, const uint8_t index,
const uimenuitem_t *item const uimenuitem_t *item
) { ) {
uiMenuClose(&UI_MAIN_MENU.menu);
switch(index) { switch(index) {
case UI_MAIN_MENU_INDEX_NEW_GAME: case UI_MAIN_MENU_INDEX_NEW_GAME:
uiMenuClose(&UI_MAIN_MENU.menu);
testBattleStart(); testBattleStart();
break; break;
@@ -44,7 +49,7 @@ void uiMainMenuSelected(
break; break;
case UI_MAIN_MENU_INDEX_QUIT: case UI_MAIN_MENU_INDEX_QUIT:
ENGINE.running = false; uiConfirmOpen("main_menu.quit_confirm", uiMainMenuQuitConfirmed, NULL);
break; break;
default: default:
+18 -99
View File
@@ -6,117 +6,29 @@
*/ */
#include "uiconfirm.h" #include "uiconfirm.h"
#include "ui/widget/uiframe.h" #include "ui/widget/uimodal.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "util/memory.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"
#include "locale/localemanager.h"
#include "asset/loader/locale/assetlocaleloader.h"
#define UI_CONFIRM_BACKDROP_COLOR color4b(0, 0, 0, 160) #define UI_CONFIRM_INDEX_CONFIRM 0
#define UI_CONFIRM_INDEX_CANCEL 1
uiconfirm_t UI_CONFIRM; uiconfirm_t UI_CONFIRM;
void uiConfirmSelected( void uiConfirmModalCallback(const uint8_t optionIndex, void *user) {
const uimenu_t *menu, UI_CONFIRM.result = optionIndex == UI_CONFIRM_INDEX_CONFIRM;
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) { if(UI_CONFIRM.callback != NULL) {
UI_CONFIRM.callback(UI_CONFIRM.result, UI_CONFIRM.user); UI_CONFIRM.callback(UI_CONFIRM.result, user);
} }
} }
errorret_t uiConfirmInit(void) { errorret_t uiConfirmInit(void) {
memoryZero(&UI_CONFIRM, sizeof(uiconfirm_t)); memoryZero(&UI_CONFIRM, sizeof(uiconfirm_t));
errorChain(assetLocaleGetString(
&LOCALE.entry->data.locale,
"ui.confirm.confirm",
0,
UI_CONFIRM.confirmLabel,
UI_CONFIRM_LABEL_MAX
));
errorChain(assetLocaleGetString(
&LOCALE.entry->data.locale,
"ui.confirm.cancel",
0,
UI_CONFIRM.cancelLabel,
UI_CONFIRM_LABEL_MAX
));
MENU_BEGIN(
&UI_CONFIRM.menu, UI_CONFIRM.items, uiConfirmSelected, uiConfirmClosed, NULL
);
MENU_BUTTON(UI_CONFIRM.confirmLabel);
MENU_BUTTON(UI_CONFIRM.cancelLabel);
MENU_END(UI_CONFIRM.items, 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(); errorOk();
} }
bool_t uiConfirmIsOpen(void) { bool_t uiConfirmIsOpen(void) {
return uiMenuIsActive(&UI_CONFIRM.menu); return uiModalIsOpen();
} }
bool_t uiConfirmGetResult(void) { bool_t uiConfirmGetResult(void) {
@@ -129,15 +41,22 @@ void uiConfirmOpen(
void *user void *user
) { ) {
assertNotNull(question, "Question cannot be NULL"); assertNotNull(question, "Question cannot be NULL");
stringCopy(UI_CONFIRM.text, question, UI_CONFIRM_TEXT_MAX);
UI_CONFIRM.callback = callback; UI_CONFIRM.callback = callback;
UI_CONFIRM.user = user;
UI_CONFIRM.result = false; UI_CONFIRM.result = false;
uiMenuOpen(&UI_CONFIRM.menu);
const char_t *options[] = {
"ui.confirm.confirm",
"ui.confirm.cancel"
};
uiModalOpen(
NULL, question, options, sizeof(options) / sizeof(options[0]),
uiConfirmModalCallback, NULL, user
);
} }
void uiConfirmClose(void) { void uiConfirmClose(void) {
uiMenuClose(&UI_CONFIRM.menu); uiModalClose(NULL);
} }
errorret_t uiConfirmDispose(void) { errorret_t uiConfirmDispose(void) {
+6 -27
View File
@@ -7,14 +7,6 @@
#pragma once #pragma once
#include "error/error.h" #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
#define UI_CONFIRM_LABEL_MAX 32
/** /**
* Callback invoked once a confirm dialog is dismissed. * Callback invoked once a confirm dialog is dismissed.
@@ -26,14 +18,8 @@
typedef void (*uiconfirmcallback_t)(const bool_t result, void *user); typedef void (*uiconfirmcallback_t)(const bool_t result, void *user);
typedef struct { typedef struct {
char_t text[UI_CONFIRM_TEXT_MAX];
uimenu_t menu;
uimenuitem_t items[UI_CONFIRM_ITEM_COUNT];
uiconfirmcallback_t callback; uiconfirmcallback_t callback;
void *user;
bool_t result; bool_t result;
char_t confirmLabel[UI_CONFIRM_LABEL_MAX];
char_t cancelLabel[UI_CONFIRM_LABEL_MAX];
} uiconfirm_t; } uiconfirm_t;
extern uiconfirm_t UI_CONFIRM; extern uiconfirm_t UI_CONFIRM;
@@ -45,15 +31,6 @@ extern uiconfirm_t UI_CONFIRM;
*/ */
errorret_t uiConfirmInit(void); 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 when the confirm dialog is currently open.
* *
@@ -69,11 +46,13 @@ bool_t uiConfirmIsOpen(void);
bool_t uiConfirmGetResult(void); bool_t uiConfirmGetResult(void);
/** /**
* Opens the confirm dialog with the given question text. callback is * Opens a confirm dialog, backed by the shared uimodal_t, with the given
* invoked exactly once with the result, whether the dialog was * question text and Confirm/Cancel buttons. callback is invoked exactly
* dismissed by selecting a button or by pressing cancel/back. * 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 question Display text, or a locale message ID; copied
* internally by uimodal, safe to be transient.
* @param callback Called with the result once the dialog closes. May be * @param callback Called with the result once the dialog closes. May be
* NULL. * NULL.
* @param user Arbitrary pointer passed through to callback. * @param user Arbitrary pointer passed through to callback.
-1
View File
@@ -86,7 +86,6 @@ uielement_t UI_ELEMENTS[] = {
// =========================================================================== // ===========================================================================
{ {
.init = uiConfirmInit, .init = uiConfirmInit,
.draw = uiConfirmDraw,
.dispose = uiConfirmDispose .dispose = uiConfirmDispose
}, },
{ {
+18 -9
View File
@@ -85,7 +85,8 @@ errorret_t uiModalDraw(void) {
); );
float_t width = contentWidth + (UI_FRAME_START_X * 2); float_t width = contentWidth + (UI_FRAME_START_X * 2);
float_t height = (UI_FRAME_START_Y * 2) float_t height = (UI_FRAME_START_Y * 2)
+ (float_t)UI_MODAL.titleLabel.height + UI_FRAME_PADDING_Y + (UI_MODAL.hasTitle ?
(float_t)UI_MODAL.titleLabel.height + UI_FRAME_PADDING_Y : 0.0f)
+ (float_t)UI_MODAL.messageLabel.height + (float_t)UI_MODAL.messageLabel.height
+ (hasOptions ? UI_FRAME_PADDING_Y + rowHeight : 0.0f); + (hasOptions ? UI_FRAME_PADDING_Y + rowHeight : 0.0f);
@@ -99,12 +100,16 @@ errorret_t uiModalDraw(void) {
float_t contentX = x + UI_FRAME_START_X; float_t contentX = x + UI_FRAME_START_X;
float_t contentY = y + UI_FRAME_START_Y; float_t contentY = y + UI_FRAME_START_Y;
uiLabelSetX(&UI_MODAL.titleLabel, contentX); float_t messageY = contentY;
uiLabelSetY(&UI_MODAL.titleLabel, contentY); if(UI_MODAL.hasTitle) {
errorChain(uiLabelRender(&UI_MODAL.titleLabel, COLOR_WHITE)); uiLabelSetX(&UI_MODAL.titleLabel, contentX);
uiLabelSetY(&UI_MODAL.titleLabel, contentY);
errorChain(uiLabelRender(&UI_MODAL.titleLabel, COLOR_WHITE));
messageY = contentY + (float_t)UI_MODAL.titleLabel.height +
UI_FRAME_PADDING_Y;
}
float_t messageY = contentY + (float_t)UI_MODAL.titleLabel.height +
UI_FRAME_PADDING_Y;
uiLabelSetX(&UI_MODAL.messageLabel, contentX); uiLabelSetX(&UI_MODAL.messageLabel, contentX);
uiLabelSetY(&UI_MODAL.messageLabel, messageY); uiLabelSetY(&UI_MODAL.messageLabel, messageY);
errorChain(uiLabelRender(&UI_MODAL.messageLabel, COLOR_WHITE)); errorChain(uiLabelRender(&UI_MODAL.messageLabel, COLOR_WHITE));
@@ -152,7 +157,6 @@ void uiModalOpen(
uimodalopenedcallback_t onOpen, uimodalopenedcallback_t onOpen,
void *user void *user
) { ) {
assertNotNull(title, "Title cannot be NULL");
assertNotNull(message, "Message cannot be NULL"); assertNotNull(message, "Message cannot be NULL");
assertTrue( assertTrue(
options != NULL || optionCount == 0, options != NULL || optionCount == 0,
@@ -165,8 +169,13 @@ void uiModalOpen(
float_t maxContentWidth = ((float_t)SCREEN.scanWidth * UI_MODAL_MAX_WIDTH_RATIO) float_t maxContentWidth = ((float_t)SCREEN.scanWidth * UI_MODAL_MAX_WIDTH_RATIO)
- (UI_FRAME_START_X * 2.0f); - (UI_FRAME_START_X * 2.0f);
uiModalLocalize(title, UI_MODAL.titleText, UI_MODAL_TITLE_TEXT_MAX); UI_MODAL.hasTitle = title != NULL;
textWrap(UI_MODAL.titleText, &FONT_DEFAULT, maxContentWidth); if(UI_MODAL.hasTitle) {
uiModalLocalize(title, UI_MODAL.titleText, UI_MODAL_TITLE_TEXT_MAX);
textWrap(UI_MODAL.titleText, &FONT_DEFAULT, maxContentWidth);
} else {
UI_MODAL.titleText[0] = '\0';
}
UI_MODAL.titleLabel.dirty = true; UI_MODAL.titleLabel.dirty = true;
uiLabelRebuffer(&UI_MODAL.titleLabel); uiLabelRebuffer(&UI_MODAL.titleLabel);
+3 -1
View File
@@ -66,6 +66,7 @@ typedef struct {
void *user; void *user;
uint8_t result; uint8_t result;
bool_t open; bool_t open;
bool_t hasTitle;
} uimodal_t; } uimodal_t;
extern uimodal_t UI_MODAL; extern uimodal_t UI_MODAL;
@@ -111,7 +112,8 @@ uint8_t uiModalGetResult(void);
* verbatim. See uiModalLocalize. * verbatim. See uiModalLocalize.
* *
* @param title Display title, or a locale message ID; copied * @param title Display title, or a locale message ID; copied
* internally, safe to be transient. * internally, safe to be transient. May be NULL for a dialog with no
* title row.
* @param message Display message, or a locale message ID; copied * @param message Display message, or a locale message ID; copied
* internally, safe to be transient. * internally, safe to be transient.
* @param options Array of option label strings/locale message IDs; * @param options Array of option label strings/locale message IDs;