Dropdown test.
This commit is contained in:
@@ -11,8 +11,8 @@ msgstr ""
|
|||||||
"Welcome"
|
"Welcome"
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.tabs.gameplay"
|
msgid "ui.settings.tabs.general"
|
||||||
msgstr "Gameplay"
|
msgstr "General"
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.tabs.input"
|
msgid "ui.settings.tabs.input"
|
||||||
@@ -29,6 +29,13 @@ msgstr "Audio"
|
|||||||
msgid "ui.settings.input.deadzone"
|
msgid "ui.settings.input.deadzone"
|
||||||
msgstr "Deadzone"
|
msgstr "Deadzone"
|
||||||
|
|
||||||
|
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
|
||||||
|
msgid "ui.settings.general.language"
|
||||||
|
msgstr "Language"
|
||||||
|
|
||||||
|
msgid "ui.settings.general.language_detail"
|
||||||
|
msgstr "Takes effect after restarting the application."
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.apply"
|
msgid "ui.settings.apply"
|
||||||
msgstr "Apply"
|
msgstr "Apply"
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ msgstr ""
|
|||||||
"Bienvenido"
|
"Bienvenido"
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.tabs.gameplay"
|
msgid "ui.settings.tabs.general"
|
||||||
msgstr "Jugabilidad"
|
msgstr "General"
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.tabs.input"
|
msgid "ui.settings.tabs.input"
|
||||||
@@ -29,6 +29,10 @@ msgstr "Audio"
|
|||||||
msgid "ui.settings.input.deadzone"
|
msgid "ui.settings.input.deadzone"
|
||||||
msgstr "Zona muerta"
|
msgstr "Zona muerta"
|
||||||
|
|
||||||
|
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
|
||||||
|
msgid "ui.settings.general.language"
|
||||||
|
msgstr "Idioma"
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.apply"
|
msgid "ui.settings.apply"
|
||||||
msgstr "Aplicar"
|
msgstr "Aplicar"
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ msgstr ""
|
|||||||
"歓迎"
|
"歓迎"
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.tabs.gameplay"
|
msgid "ui.settings.tabs.general"
|
||||||
msgstr "ゲームプレイ"
|
msgstr "一般"
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.tabs.input"
|
msgid "ui.settings.tabs.input"
|
||||||
@@ -29,6 +29,10 @@ msgstr "オーディオ"
|
|||||||
msgid "ui.settings.input.deadzone"
|
msgid "ui.settings.input.deadzone"
|
||||||
msgstr "デッドゾーン"
|
msgstr "デッドゾーン"
|
||||||
|
|
||||||
|
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
|
||||||
|
msgid "ui.settings.general.language"
|
||||||
|
msgstr "言語"
|
||||||
|
|
||||||
#: src/dusk/ui/frame/settings/uisettings.c
|
#: src/dusk/ui/frame/settings/uisettings.c
|
||||||
msgid "ui.settings.apply"
|
msgid "ui.settings.apply"
|
||||||
msgstr "適用"
|
msgstr "適用"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
uisettings.c
|
uisettings.c
|
||||||
uisettingsgameplay.c
|
uisettingsgeneral.c
|
||||||
uisettingsinput.c
|
uisettingsinput.c
|
||||||
uisettingsdisplay.c
|
uisettingsdisplay.c
|
||||||
uisettingsaudio.c
|
uisettingsaudio.c
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uisettings.h"
|
#include "uisettings.h"
|
||||||
#include "uisettingsgameplay.h"
|
#include "uisettingsgeneral.h"
|
||||||
#include "uisettingsinput.h"
|
#include "uisettingsinput.h"
|
||||||
#include "uisettingsdisplay.h"
|
#include "uisettingsdisplay.h"
|
||||||
#include "uisettingsaudio.h"
|
#include "uisettingsaudio.h"
|
||||||
@@ -24,12 +24,12 @@ uisettings_t UI_SETTINGS;
|
|||||||
|
|
||||||
uisettingstabdef_t UI_SETTINGS_TAB_DEFS[UI_SETTINGS_TAB_COUNT] = {
|
uisettingstabdef_t UI_SETTINGS_TAB_DEFS[UI_SETTINGS_TAB_COUNT] = {
|
||||||
{
|
{
|
||||||
.localeId = "ui.settings.tabs.gameplay",
|
.localeId = "ui.settings.tabs.general",
|
||||||
.init = uiSettingsGameplayInit,
|
.init = uiSettingsGeneralInit,
|
||||||
.menu = &UI_SETTINGS_GAMEPLAY.menu,
|
.menu = &UI_SETTINGS_GENERAL.menu,
|
||||||
.load = uiSettingsGameplayLoad,
|
.load = uiSettingsGeneralLoad,
|
||||||
.apply = uiSettingsGameplayApply,
|
.apply = uiSettingsGeneralApply,
|
||||||
.hasChanges = uiSettingsGameplayHasChanges
|
.hasChanges = uiSettingsGeneralHasChanges
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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 uiSettingsGameplaySelected(
|
|
||||||
const uimenu_t *menu,
|
|
||||||
const uint8_t index,
|
|
||||||
const uimenuitem_t *item
|
|
||||||
) {
|
|
||||||
switch(index) {
|
|
||||||
case UI_SETTINGS_GAMEPLAY_INDEX_APPLY:
|
|
||||||
uiSettingsGameplayApply();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t uiSettingsGameplayInit(void) {
|
|
||||||
memoryZero(&UI_SETTINGS_GAMEPLAY, sizeof(uisettingsgameplay_t));
|
|
||||||
|
|
||||||
MENU_BEGIN(
|
|
||||||
&UI_SETTINGS_GAMEPLAY.menu, UI_SETTINGS_GAMEPLAY.items,
|
|
||||||
uiSettingsGameplaySelected, uiSettingsDiscardMenuClosed, NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
MENU_BUTTON(UI_SETTINGS.applyLabel);
|
|
||||||
MENU_END(UI_SETTINGS_GAMEPLAY.items, 1);
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiSettingsGameplayLoad(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiSettingsGameplayApply(void) {
|
|
||||||
uiMenuClose(&UI_SETTINGS_GAMEPLAY.menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t uiSettingsGameplayHasChanges(void) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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"
|
|
||||||
#include "uisettings.h"
|
|
||||||
|
|
||||||
#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];
|
|
||||||
} uisettingsgameplay_t;
|
|
||||||
|
|
||||||
extern uisettingsgameplay_t UI_SETTINGS_GAMEPLAY;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the gameplay settings page.
|
|
||||||
*
|
|
||||||
* @return Any error that occurs.
|
|
||||||
*/
|
|
||||||
errorret_t uiSettingsGameplayInit(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);
|
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uisettingsgeneral.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
#include "locale/localemanager.h"
|
||||||
|
#include "locale/localeinfo.h"
|
||||||
|
#include "asset/loader/locale/assetlocaleloader.h"
|
||||||
|
|
||||||
|
static const localeinfo_t *const UI_SETTINGS_GENERAL_LOCALES[
|
||||||
|
UI_SETTINGS_GENERAL_LOCALE_COUNT
|
||||||
|
] = {
|
||||||
|
&LOCALE_EN_US,
|
||||||
|
&LOCALE_JP_JP,
|
||||||
|
&LOCALE_ES_MX
|
||||||
|
};
|
||||||
|
|
||||||
|
uisettingsgeneral_t UI_SETTINGS_GENERAL;
|
||||||
|
|
||||||
|
void uiSettingsGeneralSelected(
|
||||||
|
const uimenu_t *menu,
|
||||||
|
const uint8_t index,
|
||||||
|
const uimenuitem_t *item
|
||||||
|
) {
|
||||||
|
switch(index) {
|
||||||
|
case UI_SETTINGS_GENERAL_INDEX_APPLY:
|
||||||
|
uiSettingsGeneralApply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t uiSettingsGeneralInit(void) {
|
||||||
|
memoryZero(&UI_SETTINGS_GENERAL, sizeof(uisettingsgeneral_t));
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < UI_SETTINGS_GENERAL_LOCALE_COUNT; i++) {
|
||||||
|
UI_SETTINGS_GENERAL.localeNames[i] = UI_SETTINGS_GENERAL_LOCALES[i]->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorChain(assetLocaleGetString(
|
||||||
|
&LOCALE.entry->data.locale,
|
||||||
|
"ui.settings.general.language",
|
||||||
|
0,
|
||||||
|
UI_SETTINGS_GENERAL.languageLabel,
|
||||||
|
UI_SETTINGS_GENERAL_LABEL_MAX
|
||||||
|
));
|
||||||
|
errorChain(assetLocaleGetString(
|
||||||
|
&LOCALE.entry->data.locale,
|
||||||
|
"ui.settings.general.language_detail",
|
||||||
|
0,
|
||||||
|
UI_SETTINGS_GENERAL.labelInfo,
|
||||||
|
UI_SETTINGS_GENERAL_INFO_MAX
|
||||||
|
));
|
||||||
|
|
||||||
|
MENU_BEGIN(
|
||||||
|
&UI_SETTINGS_GENERAL.menu, UI_SETTINGS_GENERAL.items,
|
||||||
|
uiSettingsGeneralSelected, uiSettingsDiscardMenuClosed, NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
MENU_DROPDOWN(
|
||||||
|
UI_SETTINGS_GENERAL.languageLabel, UI_SETTINGS_GENERAL.localeNames,
|
||||||
|
UI_SETTINGS_GENERAL_LOCALE_COUNT, 0
|
||||||
|
);
|
||||||
|
MENU_LABEL(UI_SETTINGS_GENERAL.labelInfo);
|
||||||
|
|
||||||
|
MENU_BUTTON(UI_SETTINGS.applyLabel);
|
||||||
|
MENU_END(UI_SETTINGS_GENERAL.items, 1);
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiSettingsGeneralLoad(void) {
|
||||||
|
uint8_t index = 0;
|
||||||
|
for(uint8_t i = 0; i < UI_SETTINGS_GENERAL_LOCALE_COUNT; i++) {
|
||||||
|
if(stringCompare(LOCALE.locale->file, UI_SETTINGS_GENERAL_LOCALES[i]->file) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uiDropdownSetSelectedIndex(
|
||||||
|
&UI_SETTINGS_GENERAL.items[UI_SETTINGS_GENERAL_INDEX_LANGUAGE].dropdown,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiSettingsGeneralApply(void) {
|
||||||
|
uint8_t index = uiDropdownGetSelectedIndex(
|
||||||
|
&UI_SETTINGS_GENERAL.items[UI_SETTINGS_GENERAL_INDEX_LANGUAGE].dropdown
|
||||||
|
);
|
||||||
|
errorCatch(localeManagerSetLocale(UI_SETTINGS_GENERAL_LOCALES[index]));
|
||||||
|
|
||||||
|
uiMenuClose(&UI_SETTINGS_GENERAL.menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t uiSettingsGeneralHasChanges(void) {
|
||||||
|
uint8_t index = uiDropdownGetSelectedIndex(
|
||||||
|
&UI_SETTINGS_GENERAL.items[UI_SETTINGS_GENERAL_INDEX_LANGUAGE].dropdown
|
||||||
|
);
|
||||||
|
return stringCompare(
|
||||||
|
LOCALE.locale->file, UI_SETTINGS_GENERAL_LOCALES[index]->file
|
||||||
|
) != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* 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"
|
||||||
|
#include "uisettings.h"
|
||||||
|
|
||||||
|
#define UI_SETTINGS_GENERAL_ITEM_COUNT 3
|
||||||
|
|
||||||
|
#define UI_SETTINGS_GENERAL_INDEX_LANGUAGE 0
|
||||||
|
#define UI_SETTINGS_GENERAL_INDEX_LANGUAGE_DETAIL 1
|
||||||
|
#define UI_SETTINGS_GENERAL_INDEX_APPLY 2
|
||||||
|
|
||||||
|
#define UI_SETTINGS_GENERAL_LOCALE_COUNT 3
|
||||||
|
#define UI_SETTINGS_GENERAL_LABEL_MAX 32
|
||||||
|
#define UI_SETTINGS_GENERAL_INFO_MAX 64
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uimenu_t menu;
|
||||||
|
uimenuitem_t items[UI_SETTINGS_GENERAL_ITEM_COUNT];
|
||||||
|
const char_t *localeNames[UI_SETTINGS_GENERAL_LOCALE_COUNT];
|
||||||
|
char_t languageLabel[UI_SETTINGS_GENERAL_LABEL_MAX];
|
||||||
|
char_t labelInfo[UI_SETTINGS_GENERAL_INFO_MAX];
|
||||||
|
} uisettingsgeneral_t;
|
||||||
|
|
||||||
|
extern uisettingsgeneral_t UI_SETTINGS_GENERAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the general settings page.
|
||||||
|
*
|
||||||
|
* @return Any error that occurs.
|
||||||
|
*/
|
||||||
|
errorret_t uiSettingsGeneralInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the page's widgets from the current engine general settings.
|
||||||
|
*/
|
||||||
|
void uiSettingsGeneralLoad(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the page's widget values to the engine general settings.
|
||||||
|
*/
|
||||||
|
void uiSettingsGeneralApply(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether any widget's value differs from what was loaded.
|
||||||
|
*
|
||||||
|
* @returns True if there are unsaved changes.
|
||||||
|
*/
|
||||||
|
bool_t uiSettingsGeneralHasChanges(void);
|
||||||
@@ -9,5 +9,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
uicheckbox.c
|
uicheckbox.c
|
||||||
uitab.c
|
uitab.c
|
||||||
uislider.c
|
uislider.c
|
||||||
|
uidropdown.c
|
||||||
uimenu.c
|
uimenu.c
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uidropdown.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
#include "display/text/text.h"
|
||||||
|
#include "display/color.h"
|
||||||
|
|
||||||
|
void uiDropdownInit(
|
||||||
|
uidropdown_t *dropdown,
|
||||||
|
const char_t *label,
|
||||||
|
const char_t *const *options,
|
||||||
|
const uint8_t optionCount,
|
||||||
|
const uint8_t selectedIndex
|
||||||
|
) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
assertNotNull(label, "Label cannot be NULL");
|
||||||
|
assertNotNull(options, "Options cannot be NULL");
|
||||||
|
assertTrue(optionCount > 0, "Dropdown must have at least one option");
|
||||||
|
|
||||||
|
memoryZero(dropdown, sizeof(uidropdown_t));
|
||||||
|
dropdown->label = label;
|
||||||
|
dropdown->options = options;
|
||||||
|
dropdown->optionCount = optionCount;
|
||||||
|
dropdown->selectedIndex = selectedIndex < optionCount ? selectedIndex : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t uiDropdownGetSelectedIndex(const uidropdown_t *dropdown) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
return dropdown->selectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char_t *uiDropdownGetSelectedOption(const uidropdown_t *dropdown) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
return dropdown->options[dropdown->selectedIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDropdownSetSelectedIndex(uidropdown_t *dropdown, const uint8_t index) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
assertTrue(index < dropdown->optionCount, "Dropdown index out of range");
|
||||||
|
dropdown->selectedIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDropdownStepNext(uidropdown_t *dropdown) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
dropdown->selectedIndex =
|
||||||
|
(dropdown->selectedIndex + 1) % dropdown->optionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDropdownStepPrev(uidropdown_t *dropdown) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
dropdown->selectedIndex = dropdown->selectedIndex == 0 ?
|
||||||
|
dropdown->optionCount - 1 : dropdown->selectedIndex - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t uiDropdownIsHighlighted(const uidropdown_t *dropdown) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
return dropdown->highlighted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDropdownSetHighlighted(
|
||||||
|
uidropdown_t *dropdown,
|
||||||
|
const bool_t highlighted
|
||||||
|
) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
dropdown->highlighted = highlighted;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t uiDropdownDraw(
|
||||||
|
const uidropdown_t *dropdown,
|
||||||
|
const float_t x,
|
||||||
|
const float_t y
|
||||||
|
) {
|
||||||
|
assertNotNull(dropdown, "Dropdown cannot be NULL");
|
||||||
|
|
||||||
|
color_t color = dropdown->highlighted ? COLOR_RED : COLOR_WHITE;
|
||||||
|
|
||||||
|
errorChain(textDraw(x, y, dropdown->label, color, &FONT_DEFAULT));
|
||||||
|
|
||||||
|
int32_t labelW, labelH;
|
||||||
|
textMeasure(dropdown->label, &FONT_DEFAULT, &labelW, &labelH);
|
||||||
|
|
||||||
|
char_t valueText[UI_DROPDOWN_VALUE_TEXT_MAX];
|
||||||
|
stringFormat(
|
||||||
|
valueText, UI_DROPDOWN_VALUE_TEXT_MAX - 1, "< %s >",
|
||||||
|
uiDropdownGetSelectedOption(dropdown)
|
||||||
|
);
|
||||||
|
|
||||||
|
errorChain(textDraw(
|
||||||
|
x + (float_t)labelW + UI_DROPDOWN_GAP, y, valueText, color, &FONT_DEFAULT
|
||||||
|
));
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
|
||||||
|
#define UI_DROPDOWN_GAP 4.0f
|
||||||
|
#define UI_DROPDOWN_VALUE_TEXT_MAX 64
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char_t *label;
|
||||||
|
const char_t *const *options;
|
||||||
|
uint8_t optionCount;
|
||||||
|
uint8_t selectedIndex;
|
||||||
|
bool_t highlighted;
|
||||||
|
} uidropdown_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a dropdown.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to initialize.
|
||||||
|
* @param label Display label.
|
||||||
|
* @param options Array of option display strings; caller-owned, must
|
||||||
|
* outlive the dropdown.
|
||||||
|
* @param optionCount Number of entries in options. Must be > 0.
|
||||||
|
* @param selectedIndex Initial selected option index, clamped to
|
||||||
|
* [0, optionCount - 1].
|
||||||
|
*/
|
||||||
|
void uiDropdownInit(
|
||||||
|
uidropdown_t *dropdown,
|
||||||
|
const char_t *label,
|
||||||
|
const char_t *const *options,
|
||||||
|
const uint8_t optionCount,
|
||||||
|
const uint8_t selectedIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the currently selected option.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to query.
|
||||||
|
* @returns The selected option index.
|
||||||
|
*/
|
||||||
|
uint8_t uiDropdownGetSelectedIndex(const uidropdown_t *dropdown);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently selected option's display string.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to query.
|
||||||
|
* @returns The selected option string.
|
||||||
|
*/
|
||||||
|
const char_t *uiDropdownGetSelectedOption(const uidropdown_t *dropdown);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the selected option by index.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to update.
|
||||||
|
* @param index The new selected option index. Must be < optionCount.
|
||||||
|
*/
|
||||||
|
void uiDropdownSetSelectedIndex(uidropdown_t *dropdown, const uint8_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the next option, wrapping around to the first option past
|
||||||
|
* the last.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to update.
|
||||||
|
*/
|
||||||
|
void uiDropdownStepNext(uidropdown_t *dropdown);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the previous option, wrapping around to the last option
|
||||||
|
* before the first.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to update.
|
||||||
|
*/
|
||||||
|
void uiDropdownStepPrev(uidropdown_t *dropdown);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the dropdown is highlighted.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to query.
|
||||||
|
* @returns True if highlighted.
|
||||||
|
*/
|
||||||
|
bool_t uiDropdownIsHighlighted(const uidropdown_t *dropdown);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the highlighted state of the dropdown.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to update.
|
||||||
|
* @param highlighted The new highlighted state.
|
||||||
|
*/
|
||||||
|
void uiDropdownSetHighlighted(
|
||||||
|
uidropdown_t *dropdown,
|
||||||
|
const bool_t highlighted
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the dropdown at the given screen position: label, then the
|
||||||
|
* currently selected option surrounded by cycle arrows.
|
||||||
|
*
|
||||||
|
* @param dropdown The dropdown to draw.
|
||||||
|
* @param x Screen x position.
|
||||||
|
* @param y Screen y position.
|
||||||
|
* @return Any error that occurs.
|
||||||
|
*/
|
||||||
|
errorret_t uiDropdownDraw(
|
||||||
|
const uidropdown_t *dropdown,
|
||||||
|
const float_t x,
|
||||||
|
const float_t y
|
||||||
|
);
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "ui/widget/uibutton.h"
|
#include "ui/widget/uibutton.h"
|
||||||
#include "ui/widget/uitab.h"
|
#include "ui/widget/uitab.h"
|
||||||
#include "ui/widget/uislider.h"
|
#include "ui/widget/uislider.h"
|
||||||
|
#include "ui/widget/uidropdown.h"
|
||||||
|
|
||||||
void uiMenuInit(
|
void uiMenuInit(
|
||||||
uimenu_t *menu,
|
uimenu_t *menu,
|
||||||
@@ -138,6 +139,10 @@ errorret_t uiMenuDraw(
|
|||||||
errorChain(uiSliderDraw(&item->slider, ix, iy));
|
errorChain(uiSliderDraw(&item->slider, ix, iy));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case UI_MENU_WIDGET_TYPE_DROPDOWN:
|
||||||
|
errorChain(uiDropdownDraw(&item->dropdown, ix, iy));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -235,6 +240,15 @@ bool_t uiMenuFocusDirection(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(item->type == UI_MENU_WIDGET_TYPE_DROPDOWN) {
|
||||||
|
if(right) {
|
||||||
|
uiDropdownStepNext(&item->dropdown);
|
||||||
|
} else {
|
||||||
|
uiDropdownStepPrev(&item->dropdown);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,5 +283,7 @@ void uiMenuItemSetHighlighted(uimenuitem_t *item, const bool_t highlighted) {
|
|||||||
uiTabSetActive(&item->tab, highlighted);
|
uiTabSetActive(&item->tab, highlighted);
|
||||||
} else if(item->type == UI_MENU_WIDGET_TYPE_SLIDER) {
|
} else if(item->type == UI_MENU_WIDGET_TYPE_SLIDER) {
|
||||||
uiSliderSetHighlighted(&item->slider, highlighted);
|
uiSliderSetHighlighted(&item->slider, highlighted);
|
||||||
|
} else if(item->type == UI_MENU_WIDGET_TYPE_DROPDOWN) {
|
||||||
|
uiDropdownSetHighlighted(&item->dropdown, highlighted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "ui/widget/uicheckbox.h"
|
#include "ui/widget/uicheckbox.h"
|
||||||
#include "ui/widget/uitab.h"
|
#include "ui/widget/uitab.h"
|
||||||
#include "ui/widget/uislider.h"
|
#include "ui/widget/uislider.h"
|
||||||
|
#include "ui/widget/uidropdown.h"
|
||||||
|
|
||||||
#define UI_MENU_LABEL_MAX UI_CHECKBOX_LABEL_MAX
|
#define UI_MENU_LABEL_MAX UI_CHECKBOX_LABEL_MAX
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ typedef enum {
|
|||||||
UI_MENU_WIDGET_TYPE_BUTTON,
|
UI_MENU_WIDGET_TYPE_BUTTON,
|
||||||
UI_MENU_WIDGET_TYPE_TAB,
|
UI_MENU_WIDGET_TYPE_TAB,
|
||||||
UI_MENU_WIDGET_TYPE_SLIDER,
|
UI_MENU_WIDGET_TYPE_SLIDER,
|
||||||
|
UI_MENU_WIDGET_TYPE_DROPDOWN,
|
||||||
} uimenuwidgettype_t;
|
} uimenuwidgettype_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -35,6 +37,7 @@ typedef struct {
|
|||||||
uibutton_t button;
|
uibutton_t button;
|
||||||
uitab_t tab;
|
uitab_t tab;
|
||||||
uislider_t slider;
|
uislider_t slider;
|
||||||
|
uidropdown_t dropdown;
|
||||||
};
|
};
|
||||||
} uimenuitem_t;
|
} uimenuitem_t;
|
||||||
|
|
||||||
@@ -266,6 +269,15 @@ bool_t uiMenuFocusDirection(
|
|||||||
); \
|
); \
|
||||||
++menuIndex
|
++menuIndex
|
||||||
|
|
||||||
|
#define MENU_DROPDOWN(label, options, optionCount, selectedIndex) \
|
||||||
|
assertTrue(menuIndex < menuCapacity, "Menu item count exceeds capacity"); \
|
||||||
|
menu->items[menuIndex].type = UI_MENU_WIDGET_TYPE_DROPDOWN; \
|
||||||
|
uiDropdownInit( \
|
||||||
|
&menu->items[menuIndex].dropdown, label, options, optionCount, \
|
||||||
|
selectedIndex \
|
||||||
|
); \
|
||||||
|
++menuIndex
|
||||||
|
|
||||||
#define MENU_END(itemsArray, columns) \
|
#define MENU_END(itemsArray, columns) \
|
||||||
uiMenuSetItems(menu, (itemsArray), menuIndex, (columns))
|
uiMenuSetItems(menu, (itemsArray), menuIndex, (columns))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user