Settings improvements
This commit is contained in:
@@ -25,3 +25,10 @@ msgstr "Display"
|
||||
#: 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/uiconfirm.c
|
||||
msgid "ui.confirm.discard_changes"
|
||||
msgstr "Discard unsaved changes?"
|
||||
@@ -17,6 +17,7 @@ input_t INPUT;
|
||||
|
||||
errorret_t inputInit(void) {
|
||||
memoryZero(&INPUT, sizeof(input_t));
|
||||
INPUT.deadzone = INPUT_DEADZONE_DEFAULT;
|
||||
|
||||
for(uint8_t i = 0; i < INPUT_ACTION_COUNT; i++) {
|
||||
INPUT.actions[i].action = (inputaction_t)i;
|
||||
|
||||
@@ -12,11 +12,15 @@
|
||||
|
||||
#define INPUT_LISTENER_PRESSED_MAX 16
|
||||
#define INPUT_LISTENER_RELEASED_MAX INPUT_LISTENER_PRESSED_MAX
|
||||
#define INPUT_DEADZONE_DEFAULT 0.1f
|
||||
|
||||
typedef struct {
|
||||
inputactiondata_t actions[INPUT_ACTION_COUNT];
|
||||
|
||||
inputplatform_t platform;
|
||||
|
||||
/** User-configured gamepad axis deadzone (0.0f to 1.0f). */
|
||||
float_t deadzone;
|
||||
} input_t;
|
||||
|
||||
extern input_t INPUT;
|
||||
|
||||
@@ -29,20 +29,13 @@ void uiGameMenuSelected(
|
||||
errorret_t uiGameMenuInit(void) {
|
||||
memoryZero(&UI_GAME_MENU, sizeof(uigamemenu_t));
|
||||
|
||||
uimenu_t *menu = &UI_GAME_MENU.menu;
|
||||
uiMenuInit(menu, uiGameMenuSelected, NULL, NULL);
|
||||
menu->items = UI_GAME_MENU.items;
|
||||
|
||||
MENU_BEGIN();
|
||||
MENU_BEGIN(
|
||||
&UI_GAME_MENU.menu, UI_GAME_MENU.items, uiGameMenuSelected, NULL, NULL
|
||||
);
|
||||
MENU_BUTTON("Characters");
|
||||
MENU_BUTTON("Settings");
|
||||
|
||||
assertTrue(
|
||||
menuIndex <= UI_GAME_MENU_ITEM_COUNT,
|
||||
"Game menu item count mismatch"
|
||||
);
|
||||
|
||||
uiMenuSetItems(menu, UI_GAME_MENU.items, menuIndex, 1);
|
||||
MENU_END(UI_GAME_MENU.items, 1);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
uisettings.c
|
||||
uisettingsdiscard.c
|
||||
uisettingsgameplay.c
|
||||
uisettingsinput.c
|
||||
uisettingsdisplay.c
|
||||
|
||||
@@ -19,6 +19,68 @@
|
||||
#include "locale/localemanager.h"
|
||||
#include "asset/loader/locale/assetlocaleloader.h"
|
||||
|
||||
typedef struct {
|
||||
const char_t *localeId;
|
||||
errorret_t (*init)(void);
|
||||
errorret_t (*draw)(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const float_t width,
|
||||
const float_t height
|
||||
);
|
||||
errorret_t (*update)(void);
|
||||
void (*open)(void);
|
||||
void (*load)(void);
|
||||
void (*apply)(void);
|
||||
bool_t (*hasChanges)(void);
|
||||
} uisettingstabdef_t;
|
||||
|
||||
static const uisettingstabdef_t UI_SETTINGS_TAB_DEFS[UI_SETTINGS_TAB_COUNT] = {
|
||||
[UI_SETTINGS_TAB_GAMEPLAY] = {
|
||||
.localeId = "ui.settings.tabs.gameplay",
|
||||
.init = uiSettingsGameplayInit,
|
||||
.draw = uiSettingsGameplayDraw,
|
||||
.update = uiSettingsGameplayUpdate,
|
||||
.open = uiSettingsGameplayOpen,
|
||||
.load = uiSettingsGameplayLoad,
|
||||
.apply = uiSettingsGameplayApply,
|
||||
.hasChanges = uiSettingsGameplayHasChanges
|
||||
},
|
||||
|
||||
[UI_SETTINGS_TAB_INPUT] = {
|
||||
.localeId = "ui.settings.tabs.input",
|
||||
.init = uiSettingsInputInit,
|
||||
.draw = uiSettingsInputDraw,
|
||||
.update = uiSettingsInputUpdate,
|
||||
.open = uiSettingsInputOpen,
|
||||
.load = uiSettingsInputLoad,
|
||||
.apply = uiSettingsInputApply,
|
||||
.hasChanges = uiSettingsInputHasChanges
|
||||
},
|
||||
|
||||
[UI_SETTINGS_TAB_DISPLAY] = {
|
||||
.localeId = "ui.settings.tabs.display",
|
||||
.init = uiSettingsDisplayInit,
|
||||
.draw = uiSettingsDisplayDraw,
|
||||
.update = uiSettingsDisplayUpdate,
|
||||
.open = uiSettingsDisplayOpen,
|
||||
.load = uiSettingsDisplayLoad,
|
||||
.apply = uiSettingsDisplayApply,
|
||||
.hasChanges = uiSettingsDisplayHasChanges
|
||||
},
|
||||
|
||||
[UI_SETTINGS_TAB_AUDIO] = {
|
||||
.localeId = "ui.settings.tabs.audio",
|
||||
.init = uiSettingsAudioInit,
|
||||
.draw = uiSettingsAudioDraw,
|
||||
.update = uiSettingsAudioUpdate,
|
||||
.open = uiSettingsAudioOpen,
|
||||
.load = uiSettingsAudioLoad,
|
||||
.apply = uiSettingsAudioApply,
|
||||
.hasChanges = uiSettingsAudioHasChanges
|
||||
}
|
||||
};
|
||||
|
||||
uisettings_t UI_SETTINGS;
|
||||
|
||||
void uiSettingsTabSelected(
|
||||
@@ -26,81 +88,44 @@ void uiSettingsTabSelected(
|
||||
const uint8_t index,
|
||||
const uimenuitem_t *item
|
||||
) {
|
||||
switch(index) {
|
||||
case UI_SETTINGS_TAB_GAMEPLAY:
|
||||
uiSettingsGameplayOpen();
|
||||
break;
|
||||
if(index >= UI_SETTINGS_TAB_COUNT) return;
|
||||
UI_SETTINGS_TAB_DEFS[index].open();
|
||||
}
|
||||
|
||||
case UI_SETTINGS_TAB_INPUT:
|
||||
uiSettingsInputOpen();
|
||||
break;
|
||||
|
||||
case UI_SETTINGS_TAB_DISPLAY:
|
||||
uiSettingsDisplayOpen();
|
||||
break;
|
||||
|
||||
case UI_SETTINGS_TAB_AUDIO:
|
||||
uiSettingsAudioOpen();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
void uiSettingsTabsClosed(const uimenu_t *menu) {
|
||||
uiSettingsDiscardClosed(&UI_SETTINGS.discard);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsInit(void) {
|
||||
memoryZero(&UI_SETTINGS, sizeof(uisettings_t));
|
||||
|
||||
for(uint8_t i = 0; i < UI_SETTINGS_TAB_COUNT; i++) {
|
||||
errorChain(assetLocaleGetString(
|
||||
&LOCALE.entry->data.locale,
|
||||
"ui.settings.tabs.gameplay",
|
||||
UI_SETTINGS_TAB_DEFS[i].localeId,
|
||||
0,
|
||||
UI_SETTINGS.tabLabels[UI_SETTINGS_TAB_GAMEPLAY],
|
||||
UI_SETTINGS_TAB_LABEL_MAX
|
||||
));
|
||||
errorChain(assetLocaleGetString(
|
||||
&LOCALE.entry->data.locale,
|
||||
"ui.settings.tabs.input",
|
||||
0,
|
||||
UI_SETTINGS.tabLabels[UI_SETTINGS_TAB_INPUT],
|
||||
UI_SETTINGS_TAB_LABEL_MAX
|
||||
));
|
||||
errorChain(assetLocaleGetString(
|
||||
&LOCALE.entry->data.locale,
|
||||
"ui.settings.tabs.display",
|
||||
0,
|
||||
UI_SETTINGS.tabLabels[UI_SETTINGS_TAB_DISPLAY],
|
||||
UI_SETTINGS_TAB_LABEL_MAX
|
||||
));
|
||||
errorChain(assetLocaleGetString(
|
||||
&LOCALE.entry->data.locale,
|
||||
"ui.settings.tabs.audio",
|
||||
0,
|
||||
UI_SETTINGS.tabLabels[UI_SETTINGS_TAB_AUDIO],
|
||||
UI_SETTINGS.tabLabels[i],
|
||||
UI_SETTINGS_TAB_LABEL_MAX
|
||||
));
|
||||
}
|
||||
|
||||
uimenu_t *menu = &UI_SETTINGS.tabsMenu;
|
||||
uiMenuInit(menu, uiSettingsTabSelected, NULL, NULL);
|
||||
menu->items = UI_SETTINGS.tabs;
|
||||
MENU_BEGIN(
|
||||
&UI_SETTINGS.tabsMenu, UI_SETTINGS.tabs, uiSettingsTabSelected,
|
||||
uiSettingsTabsClosed, NULL
|
||||
);
|
||||
for(uint8_t i = 0; i < UI_SETTINGS_TAB_COUNT; i++) {
|
||||
MENU_TAB(UI_SETTINGS.tabLabels[i]);
|
||||
}
|
||||
MENU_END(UI_SETTINGS.tabs, menuIndex);
|
||||
|
||||
MENU_BEGIN();
|
||||
MENU_TAB(UI_SETTINGS.tabLabels[UI_SETTINGS_TAB_GAMEPLAY]);
|
||||
MENU_TAB(UI_SETTINGS.tabLabels[UI_SETTINGS_TAB_INPUT]);
|
||||
MENU_TAB(UI_SETTINGS.tabLabels[UI_SETTINGS_TAB_DISPLAY]);
|
||||
MENU_TAB(UI_SETTINGS.tabLabels[UI_SETTINGS_TAB_AUDIO]);
|
||||
|
||||
assertTrue(
|
||||
menuIndex <= UI_SETTINGS_TAB_COUNT,
|
||||
"Settings tab count mismatch"
|
||||
uiSettingsDiscardInit(
|
||||
&UI_SETTINGS.discard, &UI_SETTINGS.tabsMenu, uiSettingsHasChanges,
|
||||
uiSettingsLoad
|
||||
);
|
||||
|
||||
uiMenuSetItems(menu, UI_SETTINGS.tabs, menuIndex, menuIndex);
|
||||
|
||||
errorChain(uiSettingsGameplayInit());
|
||||
errorChain(uiSettingsInputInit());
|
||||
errorChain(uiSettingsDisplayInit());
|
||||
errorChain(uiSettingsAudioInit());
|
||||
for(uint8_t i = 0; i < UI_SETTINGS_TAB_COUNT; i++) {
|
||||
errorChain(UI_SETTINGS_TAB_DEFS[i].init());
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -108,8 +133,8 @@ errorret_t uiSettingsInit(void) {
|
||||
errorret_t uiSettingsDraw(void) {
|
||||
if(!uiMenuIsActive(&UI_SETTINGS.tabsMenu)) errorOk();
|
||||
|
||||
const float_t width = 220.0f;
|
||||
const float_t height = 150.0f;
|
||||
const float_t width = SCREEN.width;
|
||||
const float_t height = SCREEN.height;
|
||||
const float_t x = (float_t)SCREEN.scanX +
|
||||
((float_t)SCREEN.scanWidth - width) * 0.5f;
|
||||
const float_t y = (float_t)SCREEN.scanY +
|
||||
@@ -134,25 +159,32 @@ errorret_t uiSettingsDraw(void) {
|
||||
const float_t pageY = contentY + tabsRowHeight + UI_FRAME_PADDING_Y;
|
||||
const float_t pageHeight = contentHeight - tabsRowHeight - UI_FRAME_PADDING_Y;
|
||||
|
||||
if(uiTabIsActive(&UI_SETTINGS.tabs[UI_SETTINGS_TAB_GAMEPLAY].tab)) {
|
||||
errorChain(uiSettingsGameplayDraw(contentX, pageY, contentWidth, pageHeight));
|
||||
} else if(uiTabIsActive(&UI_SETTINGS.tabs[UI_SETTINGS_TAB_INPUT].tab)) {
|
||||
errorChain(uiSettingsInputDraw(contentX, pageY, contentWidth, pageHeight));
|
||||
} else if(uiTabIsActive(&UI_SETTINGS.tabs[UI_SETTINGS_TAB_DISPLAY].tab)) {
|
||||
errorChain(uiSettingsDisplayDraw(contentX, pageY, contentWidth, pageHeight));
|
||||
} else if(uiTabIsActive(&UI_SETTINGS.tabs[UI_SETTINGS_TAB_AUDIO].tab)) {
|
||||
errorChain(uiSettingsAudioDraw(contentX, pageY, contentWidth, pageHeight));
|
||||
for(uint8_t i = 0; i < UI_SETTINGS_TAB_COUNT; i++) {
|
||||
if(!uiTabIsActive(&UI_SETTINGS.tabs[i].tab)) continue;
|
||||
errorChain(UI_SETTINGS_TAB_DEFS[i].draw(
|
||||
contentX, pageY, contentWidth, pageHeight
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
||||
errorChain(spriteBatchFlush());
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t uiSettingsUpdate(void) {
|
||||
for(uint8_t i = 0; i < UI_SETTINGS_TAB_COUNT; i++) {
|
||||
errorChain(UI_SETTINGS_TAB_DEFS[i].update());
|
||||
}
|
||||
|
||||
return uiSettingsDiscardUpdate(&UI_SETTINGS.discard);
|
||||
}
|
||||
|
||||
bool_t uiSettingsIsOpen(void) {
|
||||
return uiMenuIsActive(&UI_SETTINGS.tabsMenu);
|
||||
}
|
||||
|
||||
void uiSettingsOpen() {
|
||||
uiSettingsLoad();
|
||||
uiMenuOpen(&UI_SETTINGS.tabsMenu);
|
||||
}
|
||||
|
||||
@@ -163,3 +195,22 @@ void uiSettingsClose() {
|
||||
errorret_t uiSettingsDispose(void) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void uiSettingsLoad(void) {
|
||||
for(uint8_t i = 0; i < UI_SETTINGS_TAB_COUNT; i++) {
|
||||
UI_SETTINGS_TAB_DEFS[i].load();
|
||||
}
|
||||
}
|
||||
|
||||
void uiSettingsApply(void) {
|
||||
for(uint8_t i = 0; i < UI_SETTINGS_TAB_COUNT; i++) {
|
||||
UI_SETTINGS_TAB_DEFS[i].apply();
|
||||
}
|
||||
}
|
||||
|
||||
bool_t uiSettingsHasChanges(void) {
|
||||
for(uint8_t i = 0; i < UI_SETTINGS_TAB_COUNT; i++) {
|
||||
if(UI_SETTINGS_TAB_DEFS[i].hasChanges()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "ui/widget/uimenu.h"
|
||||
#include "uisettingsdiscard.h"
|
||||
|
||||
#define UI_SETTINGS_TAB_GAMEPLAY 0
|
||||
#define UI_SETTINGS_TAB_INPUT 1
|
||||
@@ -20,6 +21,7 @@ typedef struct {
|
||||
uimenu_t tabsMenu;
|
||||
uimenuitem_t tabs[UI_SETTINGS_TAB_COUNT];
|
||||
char_t tabLabels[UI_SETTINGS_TAB_COUNT][UI_SETTINGS_TAB_LABEL_MAX];
|
||||
uisettingsdiscard_t discard;
|
||||
} uisettings_t;
|
||||
|
||||
extern uisettings_t UI_SETTINGS;
|
||||
@@ -38,6 +40,14 @@ errorret_t uiSettingsInit(void);
|
||||
*/
|
||||
errorret_t uiSettingsDraw(void);
|
||||
|
||||
/**
|
||||
* Updates the settings panel. Shows a discard-changes confirmation if
|
||||
* the panel was just closed with unsaved changes.
|
||||
*
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t uiSettingsUpdate(void);
|
||||
|
||||
/**
|
||||
* Returns true when the settings panel is currently open.
|
||||
*
|
||||
@@ -61,3 +71,23 @@ void uiSettingsClose();
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t uiSettingsDispose(void);
|
||||
|
||||
/**
|
||||
* Loads every category page's widgets from the current engine settings.
|
||||
* Called automatically by uiSettingsOpen.
|
||||
*/
|
||||
void uiSettingsLoad(void);
|
||||
|
||||
/**
|
||||
* Applies every category page's widget values to the engine settings.
|
||||
* Called automatically when a page's own Apply button is pressed.
|
||||
*/
|
||||
void uiSettingsApply(void);
|
||||
|
||||
/**
|
||||
* Returns whether any category page has a widget value that differs
|
||||
* from what was loaded.
|
||||
*
|
||||
* @returns True if there are unsaved changes.
|
||||
*/
|
||||
bool_t uiSettingsHasChanges(void);
|
||||
|
||||
@@ -6,21 +6,40 @@
|
||||
*/
|
||||
|
||||
#include "uisettingsaudio.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
uisettingsaudio_t UI_SETTINGS_AUDIO;
|
||||
|
||||
void uiSettingsAudioSelected(
|
||||
const uimenu_t *menu,
|
||||
const uint8_t index,
|
||||
const uimenuitem_t *item
|
||||
) {
|
||||
if(index != UI_SETTINGS_AUDIO_INDEX_APPLY) return;
|
||||
uiSettingsAudioApply();
|
||||
}
|
||||
|
||||
void uiSettingsAudioClosed(const uimenu_t *menu) {
|
||||
uiSettingsDiscardClosed(&UI_SETTINGS_AUDIO.discard);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsAudioInit(void) {
|
||||
memoryZero(&UI_SETTINGS_AUDIO, sizeof(uisettingsaudio_t));
|
||||
|
||||
uimenu_t *menu = &UI_SETTINGS_AUDIO.menu;
|
||||
uiMenuInit(menu, NULL, NULL, NULL);
|
||||
menu->items = UI_SETTINGS_AUDIO.items;
|
||||
|
||||
MENU_BEGIN();
|
||||
MENU_BEGIN(
|
||||
&UI_SETTINGS_AUDIO.menu, UI_SETTINGS_AUDIO.items,
|
||||
uiSettingsAudioSelected, uiSettingsAudioClosed, NULL
|
||||
);
|
||||
MENU_LABEL("No audio settings yet");
|
||||
MENU_BUTTON("Apply");
|
||||
|
||||
uiMenuSetItems(menu, UI_SETTINGS_AUDIO.items, menuIndex, 1);
|
||||
MENU_END(UI_SETTINGS_AUDIO.items, 1);
|
||||
|
||||
uiSettingsDiscardInit(
|
||||
&UI_SETTINGS_AUDIO.discard, &UI_SETTINGS_AUDIO.menu,
|
||||
uiSettingsAudioHasChanges, uiSettingsAudioLoad
|
||||
);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -45,3 +64,17 @@ void uiSettingsAudioOpen(void) {
|
||||
void uiSettingsAudioClose(void) {
|
||||
uiMenuClose(&UI_SETTINGS_AUDIO.menu);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsAudioUpdate(void) {
|
||||
return uiSettingsDiscardUpdate(&UI_SETTINGS_AUDIO.discard);
|
||||
}
|
||||
|
||||
void uiSettingsAudioLoad(void) {
|
||||
}
|
||||
|
||||
void uiSettingsAudioApply(void) {
|
||||
}
|
||||
|
||||
bool_t uiSettingsAudioHasChanges(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,12 +8,15 @@
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "ui/widget/uimenu.h"
|
||||
#include "uisettingsdiscard.h"
|
||||
|
||||
#define UI_SETTINGS_AUDIO_ITEM_COUNT 1
|
||||
#define UI_SETTINGS_AUDIO_ITEM_COUNT 2
|
||||
#define UI_SETTINGS_AUDIO_INDEX_APPLY 1
|
||||
|
||||
typedef struct {
|
||||
uimenu_t menu;
|
||||
uimenuitem_t items[UI_SETTINGS_AUDIO_ITEM_COUNT];
|
||||
uisettingsdiscard_t discard;
|
||||
} uisettingsaudio_t;
|
||||
|
||||
extern uisettingsaudio_t UI_SETTINGS_AUDIO;
|
||||
@@ -41,6 +44,14 @@ errorret_t uiSettingsAudioDraw(
|
||||
const float_t height
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the audio settings page. Shows a discard-changes
|
||||
* confirmation if the page was just backed out of with unsaved changes.
|
||||
*
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t uiSettingsAudioUpdate(void);
|
||||
|
||||
/**
|
||||
* Returns true when the audio settings page is currently open.
|
||||
*
|
||||
@@ -57,3 +68,20 @@ void uiSettingsAudioOpen(void);
|
||||
* Closes the audio settings page. No-op when already closed.
|
||||
*/
|
||||
void uiSettingsAudioClose(void);
|
||||
|
||||
/**
|
||||
* Loads the page's widgets from the current engine audio settings.
|
||||
*/
|
||||
void uiSettingsAudioLoad(void);
|
||||
|
||||
/**
|
||||
* Applies the page's widget values to the engine audio settings.
|
||||
*/
|
||||
void uiSettingsAudioApply(void);
|
||||
|
||||
/**
|
||||
* Returns whether any widget's value differs from what was loaded.
|
||||
*
|
||||
* @returns True if there are unsaved changes.
|
||||
*/
|
||||
bool_t uiSettingsAudioHasChanges(void);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uisettingsdiscard.h"
|
||||
#include "ui/frame/uiconfirm.h"
|
||||
#include "locale/localemanager.h"
|
||||
#include "asset/loader/locale/assetlocaleloader.h"
|
||||
|
||||
void uiSettingsDiscardInit(
|
||||
uisettingsdiscard_t *discard,
|
||||
uimenu_t *menu,
|
||||
uisettingshaschangesfn_t hasChanges,
|
||||
uisettingsloadfn_t load
|
||||
) {
|
||||
discard->menu = menu;
|
||||
discard->hasChanges = hasChanges;
|
||||
discard->load = load;
|
||||
discard->pending = false;
|
||||
}
|
||||
|
||||
void uiSettingsDiscardClosed(uisettingsdiscard_t *discard) {
|
||||
if(discard->hasChanges()) discard->pending = true;
|
||||
}
|
||||
|
||||
errorret_t uiSettingsDiscardUpdate(uisettingsdiscard_t *discard) {
|
||||
if(!discard->pending) errorOk();
|
||||
discard->pending = false;
|
||||
|
||||
char_t text[UI_SETTINGS_DISCARD_TEXT_MAX];
|
||||
errorChain(assetLocaleGetString(
|
||||
&LOCALE.entry->data.locale,
|
||||
"ui.confirm.discard_changes",
|
||||
0,
|
||||
text,
|
||||
UI_SETTINGS_DISCARD_TEXT_MAX
|
||||
));
|
||||
|
||||
uiConfirmOpen(text, uiSettingsDiscardConfirmResult, discard);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void uiSettingsDiscardConfirmResult(const bool_t result, void *user) {
|
||||
uisettingsdiscard_t *discard = (uisettingsdiscard_t *)user;
|
||||
|
||||
if(!result) {
|
||||
// Cancel means "keep editing" - reopen without reloading so the
|
||||
// unsaved widget values the user had are preserved.
|
||||
uiMenuOpen(discard->menu);
|
||||
return;
|
||||
}
|
||||
|
||||
// Confirmed - reload the widgets back to the actual engine values.
|
||||
discard->load();
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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_SETTINGS_DISCARD_TEXT_MAX 128
|
||||
|
||||
/**
|
||||
* Returns true if the owning settings page/panel has unsaved changes.
|
||||
*
|
||||
* @returns True if there are unsaved changes.
|
||||
*/
|
||||
typedef bool_t (*uisettingshaschangesfn_t)(void);
|
||||
|
||||
/**
|
||||
* Reloads the owning settings page/panel's widgets from the current
|
||||
* engine settings.
|
||||
*/
|
||||
typedef void (*uisettingsloadfn_t)(void);
|
||||
|
||||
typedef struct {
|
||||
uimenu_t *menu;
|
||||
uisettingshaschangesfn_t hasChanges;
|
||||
uisettingsloadfn_t load;
|
||||
bool_t pending;
|
||||
} uisettingsdiscard_t;
|
||||
|
||||
/**
|
||||
* Initializes a discard-changes confirmation helper for a settings
|
||||
* page or panel.
|
||||
*
|
||||
* @param discard The helper state to initialize.
|
||||
* @param menu The menu to reopen if the user cancels discarding.
|
||||
* @param hasChanges Callback returning true if there are unsaved
|
||||
* changes.
|
||||
* @param load Callback that reloads the widgets from the current
|
||||
* engine settings, called if the user confirms discarding changes.
|
||||
*/
|
||||
void uiSettingsDiscardInit(
|
||||
uisettingsdiscard_t *discard,
|
||||
uimenu_t *menu,
|
||||
uisettingshaschangesfn_t hasChanges,
|
||||
uisettingsloadfn_t load
|
||||
);
|
||||
|
||||
/**
|
||||
* Call from the owning menu's closed callback. Flags a pending
|
||||
* confirmation if hasChanges() reports unsaved changes.
|
||||
*
|
||||
* @param discard The helper state.
|
||||
*/
|
||||
void uiSettingsDiscardClosed(uisettingsdiscard_t *discard);
|
||||
|
||||
/**
|
||||
* Call every frame from the owning page/panel's update function. Shows
|
||||
* the discard-changes confirmation dialog if one is pending.
|
||||
*
|
||||
* @param discard The helper state.
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t uiSettingsDiscardUpdate(uisettingsdiscard_t *discard);
|
||||
|
||||
/**
|
||||
* Callback passed to uiConfirmOpen by uiSettingsDiscardUpdate. Reopens
|
||||
* the menu if the user chose to keep editing.
|
||||
*
|
||||
* @param result True if the user confirmed discarding changes, false
|
||||
* to keep editing. On true, the widgets are reloaded via load().
|
||||
* @param user The uisettingsdiscard_t* this confirmation belongs to.
|
||||
*/
|
||||
void uiSettingsDiscardConfirmResult(const bool_t result, void *user);
|
||||
@@ -6,21 +6,40 @@
|
||||
*/
|
||||
|
||||
#include "uisettingsdisplay.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
uisettingsdisplay_t UI_SETTINGS_DISPLAY;
|
||||
|
||||
void uiSettingsDisplaySelected(
|
||||
const uimenu_t *menu,
|
||||
const uint8_t index,
|
||||
const uimenuitem_t *item
|
||||
) {
|
||||
if(index != UI_SETTINGS_DISPLAY_INDEX_APPLY) return;
|
||||
uiSettingsDisplayApply();
|
||||
}
|
||||
|
||||
void uiSettingsDisplayClosed(const uimenu_t *menu) {
|
||||
uiSettingsDiscardClosed(&UI_SETTINGS_DISPLAY.discard);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsDisplayInit(void) {
|
||||
memoryZero(&UI_SETTINGS_DISPLAY, sizeof(uisettingsdisplay_t));
|
||||
|
||||
uimenu_t *menu = &UI_SETTINGS_DISPLAY.menu;
|
||||
uiMenuInit(menu, NULL, NULL, NULL);
|
||||
menu->items = UI_SETTINGS_DISPLAY.items;
|
||||
|
||||
MENU_BEGIN();
|
||||
MENU_BEGIN(
|
||||
&UI_SETTINGS_DISPLAY.menu, UI_SETTINGS_DISPLAY.items,
|
||||
uiSettingsDisplaySelected, uiSettingsDisplayClosed, NULL
|
||||
);
|
||||
MENU_LABEL("No display settings yet");
|
||||
MENU_BUTTON("Apply");
|
||||
|
||||
uiMenuSetItems(menu, UI_SETTINGS_DISPLAY.items, menuIndex, 1);
|
||||
MENU_END(UI_SETTINGS_DISPLAY.items, 1);
|
||||
|
||||
uiSettingsDiscardInit(
|
||||
&UI_SETTINGS_DISPLAY.discard, &UI_SETTINGS_DISPLAY.menu,
|
||||
uiSettingsDisplayHasChanges, uiSettingsDisplayLoad
|
||||
);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -45,3 +64,17 @@ void uiSettingsDisplayOpen(void) {
|
||||
void uiSettingsDisplayClose(void) {
|
||||
uiMenuClose(&UI_SETTINGS_DISPLAY.menu);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsDisplayUpdate(void) {
|
||||
return uiSettingsDiscardUpdate(&UI_SETTINGS_DISPLAY.discard);
|
||||
}
|
||||
|
||||
void uiSettingsDisplayLoad(void) {
|
||||
}
|
||||
|
||||
void uiSettingsDisplayApply(void) {
|
||||
}
|
||||
|
||||
bool_t uiSettingsDisplayHasChanges(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,12 +8,15 @@
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "ui/widget/uimenu.h"
|
||||
#include "uisettingsdiscard.h"
|
||||
|
||||
#define UI_SETTINGS_DISPLAY_ITEM_COUNT 1
|
||||
#define UI_SETTINGS_DISPLAY_ITEM_COUNT 2
|
||||
#define UI_SETTINGS_DISPLAY_INDEX_APPLY 1
|
||||
|
||||
typedef struct {
|
||||
uimenu_t menu;
|
||||
uimenuitem_t items[UI_SETTINGS_DISPLAY_ITEM_COUNT];
|
||||
uisettingsdiscard_t discard;
|
||||
} uisettingsdisplay_t;
|
||||
|
||||
extern uisettingsdisplay_t UI_SETTINGS_DISPLAY;
|
||||
@@ -41,6 +44,14 @@ errorret_t uiSettingsDisplayDraw(
|
||||
const float_t height
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the display settings page. Shows a discard-changes
|
||||
* confirmation if the page was just backed out of with unsaved changes.
|
||||
*
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t uiSettingsDisplayUpdate(void);
|
||||
|
||||
/**
|
||||
* Returns true when the display settings page is currently open.
|
||||
*
|
||||
@@ -57,3 +68,20 @@ void uiSettingsDisplayOpen(void);
|
||||
* Closes the display settings page. No-op when already closed.
|
||||
*/
|
||||
void uiSettingsDisplayClose(void);
|
||||
|
||||
/**
|
||||
* Loads the page's widgets from the current engine display settings.
|
||||
*/
|
||||
void uiSettingsDisplayLoad(void);
|
||||
|
||||
/**
|
||||
* Applies the page's widget values to the engine display settings.
|
||||
*/
|
||||
void uiSettingsDisplayApply(void);
|
||||
|
||||
/**
|
||||
* Returns whether any widget's value differs from what was loaded.
|
||||
*
|
||||
* @returns True if there are unsaved changes.
|
||||
*/
|
||||
bool_t uiSettingsDisplayHasChanges(void);
|
||||
|
||||
@@ -22,33 +22,44 @@ void uiSettingsGameplaySelected(
|
||||
const uint8_t index,
|
||||
const uimenuitem_t *item
|
||||
) {
|
||||
if(index != UI_SETTINGS_GAMEPLAY_INDEX_SHOW_CONFIRM) return;
|
||||
if(index == UI_SETTINGS_GAMEPLAY_INDEX_SHOW_CONFIRM) {
|
||||
uiConfirmOpen(
|
||||
"Are you sure?", uiSettingsGameplayShowConfirmResult, NULL
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if(index == UI_SETTINGS_GAMEPLAY_INDEX_APPLY) {
|
||||
uiSettingsGameplayApply();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void uiSettingsGameplayClosed(const uimenu_t *menu) {
|
||||
uiSettingsDiscardClosed(&UI_SETTINGS_GAMEPLAY.discard);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsGameplayInit(void) {
|
||||
memoryZero(&UI_SETTINGS_GAMEPLAY, sizeof(uisettingsgameplay_t));
|
||||
|
||||
uimenu_t *menu = &UI_SETTINGS_GAMEPLAY.menu;
|
||||
uiMenuInit(menu, uiSettingsGameplaySelected, NULL, NULL);
|
||||
menu->items = UI_SETTINGS_GAMEPLAY.items;
|
||||
|
||||
MENU_BEGIN();
|
||||
MENU_BEGIN(
|
||||
&UI_SETTINGS_GAMEPLAY.menu, UI_SETTINGS_GAMEPLAY.items,
|
||||
uiSettingsGameplaySelected, uiSettingsGameplayClosed, NULL
|
||||
);
|
||||
MENU_BUTTON("Do thing");
|
||||
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");
|
||||
MENU_BUTTON("Apply");
|
||||
|
||||
assertTrue(
|
||||
menuIndex <= UI_SETTINGS_GAMEPLAY_ITEM_COUNT,
|
||||
"Gameplay settings item count mismatch"
|
||||
MENU_END(UI_SETTINGS_GAMEPLAY.items, 1);
|
||||
|
||||
uiSettingsDiscardInit(
|
||||
&UI_SETTINGS_GAMEPLAY.discard, &UI_SETTINGS_GAMEPLAY.menu,
|
||||
uiSettingsGameplayHasChanges, uiSettingsGameplayLoad
|
||||
);
|
||||
|
||||
uiMenuSetItems(menu, UI_SETTINGS_GAMEPLAY.items, menuIndex, 1);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -72,3 +83,41 @@ void uiSettingsGameplayOpen(void) {
|
||||
void uiSettingsGameplayClose(void) {
|
||||
uiMenuClose(&UI_SETTINGS_GAMEPLAY.menu);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsGameplayUpdate(void) {
|
||||
return uiSettingsDiscardUpdate(&UI_SETTINGS_GAMEPLAY.discard);
|
||||
}
|
||||
|
||||
void uiSettingsGameplayLoad(void) {
|
||||
UI_SETTINGS_GAMEPLAY.loadedEnableThing = uiCheckboxIsChecked(
|
||||
&UI_SETTINGS_GAMEPLAY.items[UI_SETTINGS_GAMEPLAY_INDEX_ENABLE_THING].checkbox
|
||||
);
|
||||
UI_SETTINGS_GAMEPLAY.loadedTestValue = uiSliderGetFloat(
|
||||
&UI_SETTINGS_GAMEPLAY.items[UI_SETTINGS_GAMEPLAY_INDEX_TEST_SLIDER].slider
|
||||
);
|
||||
}
|
||||
|
||||
void uiSettingsGameplayApply(void) {
|
||||
UI_SETTINGS_GAMEPLAY.loadedEnableThing = uiCheckboxIsChecked(
|
||||
&UI_SETTINGS_GAMEPLAY.items[UI_SETTINGS_GAMEPLAY_INDEX_ENABLE_THING].checkbox
|
||||
);
|
||||
UI_SETTINGS_GAMEPLAY.loadedTestValue = uiSliderGetFloat(
|
||||
&UI_SETTINGS_GAMEPLAY.items[UI_SETTINGS_GAMEPLAY_INDEX_TEST_SLIDER].slider
|
||||
);
|
||||
}
|
||||
|
||||
bool_t uiSettingsGameplayHasChanges(void) {
|
||||
if(
|
||||
uiCheckboxIsChecked(
|
||||
&UI_SETTINGS_GAMEPLAY.items[UI_SETTINGS_GAMEPLAY_INDEX_ENABLE_THING].checkbox
|
||||
) != UI_SETTINGS_GAMEPLAY.loadedEnableThing
|
||||
) return true;
|
||||
|
||||
if(
|
||||
uiSliderGetFloat(
|
||||
&UI_SETTINGS_GAMEPLAY.items[UI_SETTINGS_GAMEPLAY_INDEX_TEST_SLIDER].slider
|
||||
) != UI_SETTINGS_GAMEPLAY.loadedTestValue
|
||||
) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,13 +8,20 @@
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "ui/widget/uimenu.h"
|
||||
#include "uisettingsdiscard.h"
|
||||
|
||||
#define UI_SETTINGS_GAMEPLAY_ITEM_COUNT 5
|
||||
#define UI_SETTINGS_GAMEPLAY_ITEM_COUNT 6
|
||||
#define UI_SETTINGS_GAMEPLAY_INDEX_ENABLE_THING 2
|
||||
#define UI_SETTINGS_GAMEPLAY_INDEX_TEST_SLIDER 3
|
||||
#define UI_SETTINGS_GAMEPLAY_INDEX_SHOW_CONFIRM 4
|
||||
#define UI_SETTINGS_GAMEPLAY_INDEX_APPLY 5
|
||||
|
||||
typedef struct {
|
||||
uimenu_t menu;
|
||||
uimenuitem_t items[UI_SETTINGS_GAMEPLAY_ITEM_COUNT];
|
||||
uisettingsdiscard_t discard;
|
||||
bool_t loadedEnableThing;
|
||||
float_t loadedTestValue;
|
||||
} uisettingsgameplay_t;
|
||||
|
||||
extern uisettingsgameplay_t UI_SETTINGS_GAMEPLAY;
|
||||
@@ -42,6 +49,14 @@ errorret_t uiSettingsGameplayDraw(
|
||||
const float_t height
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the gameplay settings page. Shows a discard-changes
|
||||
* confirmation if the page was just backed out of with unsaved changes.
|
||||
*
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t uiSettingsGameplayUpdate(void);
|
||||
|
||||
/**
|
||||
* Returns true when the gameplay settings page is currently open.
|
||||
*
|
||||
@@ -58,3 +73,20 @@ void uiSettingsGameplayOpen(void);
|
||||
* Closes the gameplay settings page. No-op when already closed.
|
||||
*/
|
||||
void uiSettingsGameplayClose(void);
|
||||
|
||||
/**
|
||||
* Loads the page's widgets from the current engine gameplay settings.
|
||||
*/
|
||||
void uiSettingsGameplayLoad(void);
|
||||
|
||||
/**
|
||||
* Applies the page's widget values to the engine gameplay settings.
|
||||
*/
|
||||
void uiSettingsGameplayApply(void);
|
||||
|
||||
/**
|
||||
* Returns whether any widget's value differs from what was loaded.
|
||||
*
|
||||
* @returns True if there are unsaved changes.
|
||||
*/
|
||||
bool_t uiSettingsGameplayHasChanges(void);
|
||||
|
||||
@@ -6,21 +6,55 @@
|
||||
*/
|
||||
|
||||
#include "uisettingsinput.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "locale/localemanager.h"
|
||||
#include "asset/loader/locale/assetlocaleloader.h"
|
||||
#include "input/input.h"
|
||||
|
||||
uisettingsinput_t UI_SETTINGS_INPUT;
|
||||
|
||||
void uiSettingsInputSelected(
|
||||
const uimenu_t *menu,
|
||||
const uint8_t index,
|
||||
const uimenuitem_t *item
|
||||
) {
|
||||
if(index != UI_SETTINGS_INPUT_INDEX_APPLY) return;
|
||||
uiSettingsInputApply();
|
||||
}
|
||||
|
||||
void uiSettingsInputClosed(const uimenu_t *menu) {
|
||||
uiSettingsDiscardClosed(&UI_SETTINGS_INPUT.discard);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsInputInit(void) {
|
||||
memoryZero(&UI_SETTINGS_INPUT, sizeof(uisettingsinput_t));
|
||||
|
||||
uimenu_t *menu = &UI_SETTINGS_INPUT.menu;
|
||||
uiMenuInit(menu, NULL, NULL, NULL);
|
||||
menu->items = UI_SETTINGS_INPUT.items;
|
||||
|
||||
MENU_BEGIN();
|
||||
MENU_BEGIN(
|
||||
&UI_SETTINGS_INPUT.menu, UI_SETTINGS_INPUT.items,
|
||||
uiSettingsInputSelected, uiSettingsInputClosed, NULL
|
||||
);
|
||||
#ifdef DUSK_INPUT_GAMEPAD
|
||||
errorChain(assetLocaleGetString(
|
||||
&LOCALE.entry->data.locale,
|
||||
"ui.settings.input.deadzone",
|
||||
0,
|
||||
UI_SETTINGS_INPUT.deadzoneLabel,
|
||||
UI_SETTINGS_INPUT_LABEL_MAX
|
||||
));
|
||||
MENU_SLIDER_FLOAT(
|
||||
UI_SETTINGS_INPUT.deadzoneLabel, INPUT_DEADZONE_DEFAULT, 0.0f, 1.0f, 0.05f
|
||||
);
|
||||
#else
|
||||
MENU_LABEL("No input settings yet");
|
||||
#endif
|
||||
MENU_BUTTON("Apply");
|
||||
MENU_END(UI_SETTINGS_INPUT.items, 1);
|
||||
|
||||
uiMenuSetItems(menu, UI_SETTINGS_INPUT.items, menuIndex, 1);
|
||||
uiSettingsDiscardInit(
|
||||
&UI_SETTINGS_INPUT.discard, &UI_SETTINGS_INPUT.menu,
|
||||
uiSettingsInputHasChanges, uiSettingsInputLoad
|
||||
);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -45,3 +79,33 @@ void uiSettingsInputOpen(void) {
|
||||
void uiSettingsInputClose(void) {
|
||||
uiMenuClose(&UI_SETTINGS_INPUT.menu);
|
||||
}
|
||||
|
||||
errorret_t uiSettingsInputUpdate(void) {
|
||||
return uiSettingsDiscardUpdate(&UI_SETTINGS_INPUT.discard);
|
||||
}
|
||||
|
||||
void uiSettingsInputLoad(void) {
|
||||
#ifdef DUSK_INPUT_GAMEPAD
|
||||
uiSliderSetFloat(
|
||||
&UI_SETTINGS_INPUT.items[UI_SETTINGS_INPUT_INDEX_DEADZONE].slider,
|
||||
INPUT.deadzone
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
void uiSettingsInputApply(void) {
|
||||
#ifdef DUSK_INPUT_GAMEPAD
|
||||
INPUT.deadzone = uiSliderGetFloat(
|
||||
&UI_SETTINGS_INPUT.items[UI_SETTINGS_INPUT_INDEX_DEADZONE].slider
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool_t uiSettingsInputHasChanges(void) {
|
||||
#ifdef DUSK_INPUT_GAMEPAD
|
||||
if(uiSliderGetFloat(
|
||||
&UI_SETTINGS_INPUT.items[UI_SETTINGS_INPUT_INDEX_DEADZONE].slider
|
||||
) != INPUT.deadzone) return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,12 +8,18 @@
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "ui/widget/uimenu.h"
|
||||
#include "uisettingsdiscard.h"
|
||||
|
||||
#define UI_SETTINGS_INPUT_ITEM_COUNT 1
|
||||
#define UI_SETTINGS_INPUT_ITEM_COUNT 2
|
||||
#define UI_SETTINGS_INPUT_LABEL_MAX 32
|
||||
#define UI_SETTINGS_INPUT_INDEX_DEADZONE 0
|
||||
#define UI_SETTINGS_INPUT_INDEX_APPLY 1
|
||||
|
||||
typedef struct {
|
||||
uimenu_t menu;
|
||||
uimenuitem_t items[UI_SETTINGS_INPUT_ITEM_COUNT];
|
||||
uisettingsdiscard_t discard;
|
||||
char_t deadzoneLabel[UI_SETTINGS_INPUT_LABEL_MAX];
|
||||
} uisettingsinput_t;
|
||||
|
||||
extern uisettingsinput_t UI_SETTINGS_INPUT;
|
||||
@@ -41,6 +47,14 @@ errorret_t uiSettingsInputDraw(
|
||||
const float_t height
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the input settings page. Shows a discard-changes confirmation
|
||||
* if the page was just backed out of with unsaved changes.
|
||||
*
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t uiSettingsInputUpdate(void);
|
||||
|
||||
/**
|
||||
* Returns true when the input settings page is currently open.
|
||||
*
|
||||
@@ -57,3 +71,20 @@ void uiSettingsInputOpen(void);
|
||||
* Closes the input settings page. No-op when already closed.
|
||||
*/
|
||||
void uiSettingsInputClose(void);
|
||||
|
||||
/**
|
||||
* Loads the page's widgets from the current engine input settings.
|
||||
*/
|
||||
void uiSettingsInputLoad(void);
|
||||
|
||||
/**
|
||||
* Applies the page's widget values to the engine input settings.
|
||||
*/
|
||||
void uiSettingsInputApply(void);
|
||||
|
||||
/**
|
||||
* Returns whether any widget's value differs from what was loaded.
|
||||
*
|
||||
* @returns True if there are unsaved changes.
|
||||
*/
|
||||
bool_t uiSettingsInputHasChanges(void);
|
||||
|
||||
@@ -40,20 +40,13 @@ void uiConfirmClosed(const uimenu_t *menu) {
|
||||
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_BEGIN(
|
||||
&UI_CONFIRM.menu, UI_CONFIRM.items, uiConfirmSelected, uiConfirmClosed, NULL
|
||||
);
|
||||
MENU_BUTTON("Confirm");
|
||||
MENU_BUTTON("Cancel");
|
||||
|
||||
assertTrue(
|
||||
menuIndex <= UI_CONFIRM_ITEM_COUNT,
|
||||
"Confirm item count mismatch"
|
||||
);
|
||||
|
||||
uiMenuSetItems(menu, UI_CONFIRM.items, menuIndex, menuIndex);
|
||||
MENU_END(UI_CONFIRM.items, menuIndex);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ uielement_t UI_ELEMENTS[] = {
|
||||
|
||||
{
|
||||
.init = uiSettingsInit,
|
||||
.update = uiSettingsUpdate,
|
||||
.draw = uiSettingsDraw,
|
||||
.dispose = uiSettingsDispose
|
||||
},
|
||||
|
||||
@@ -212,33 +212,44 @@ bool_t uiMenuFocusDirection(
|
||||
);
|
||||
|
||||
// Helper macros
|
||||
#define MENU_BEGIN() uint8_t menuIndex = 0
|
||||
#define MENU_BEGIN(menuPtr, itemsArray, selected, closed, changed) \
|
||||
uimenu_t *menu = (menuPtr); \
|
||||
uiMenuInit(menu, selected, closed, changed); \
|
||||
menu->items = (itemsArray); \
|
||||
uint8_t menuIndex = 0; \
|
||||
uint8_t menuCapacity = sizeof(itemsArray) / sizeof((itemsArray)[0])
|
||||
|
||||
#define MENU_LABEL(text) \
|
||||
assertTrue(menuIndex < menuCapacity, "Menu item count exceeds capacity"); \
|
||||
menu->items[menuIndex].type = UI_MENU_WIDGET_TYPE_LABEL; \
|
||||
menu->items[menuIndex].label = text; \
|
||||
++menuIndex
|
||||
|
||||
#define MENU_SPACER() \
|
||||
assertTrue(menuIndex < menuCapacity, "Menu item count exceeds capacity"); \
|
||||
menu->items[menuIndex].type = UI_MENU_WIDGET_TYPE_SPACER; \
|
||||
++menuIndex
|
||||
|
||||
#define MENU_CHECKBOX(label) \
|
||||
assertTrue(menuIndex < menuCapacity, "Menu item count exceeds capacity"); \
|
||||
menu->items[menuIndex].type = UI_MENU_WIDGET_TYPE_CHECKBOX; \
|
||||
uiCheckboxInit(&menu->items[menuIndex].checkbox, label); \
|
||||
++menuIndex
|
||||
|
||||
#define MENU_BUTTON(label) \
|
||||
assertTrue(menuIndex < menuCapacity, "Menu item count exceeds capacity"); \
|
||||
menu->items[menuIndex].type = UI_MENU_WIDGET_TYPE_BUTTON; \
|
||||
uiButtonInit(&menu->items[menuIndex].button, label); \
|
||||
++menuIndex
|
||||
|
||||
#define MENU_TAB(label) \
|
||||
assertTrue(menuIndex < menuCapacity, "Menu item count exceeds capacity"); \
|
||||
menu->items[menuIndex].type = UI_MENU_WIDGET_TYPE_TAB; \
|
||||
uiTabInit(&menu->items[menuIndex].tab, label); \
|
||||
++menuIndex
|
||||
|
||||
#define MENU_SLIDER_FLOAT(label, value, min, max, step) \
|
||||
assertTrue(menuIndex < menuCapacity, "Menu item count exceeds capacity"); \
|
||||
menu->items[menuIndex].type = UI_MENU_WIDGET_TYPE_SLIDER; \
|
||||
uiSliderInitFloat( \
|
||||
&menu->items[menuIndex].slider, label, value, min, max, step \
|
||||
@@ -246,10 +257,14 @@ bool_t uiMenuFocusDirection(
|
||||
++menuIndex
|
||||
|
||||
#define MENU_SLIDER_INT(label, value, min, max, step) \
|
||||
assertTrue(menuIndex < menuCapacity, "Menu item count exceeds capacity"); \
|
||||
menu->items[menuIndex].type = UI_MENU_WIDGET_TYPE_SLIDER; \
|
||||
uiSliderInitInt( \
|
||||
&menu->items[menuIndex].slider, label, value, min, max, step \
|
||||
); \
|
||||
++menuIndex
|
||||
|
||||
#define MENU_END(itemsArray, columns) \
|
||||
uiMenuSetItems(menu, (itemsArray), menuIndex, (columns))
|
||||
|
||||
//EOF
|
||||
|
||||
Reference in New Issue
Block a user