From 0bd2491ab7ec70451e8d7f53ec8a4b0730a939ae Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 7 Jul 2026 15:18:33 -0500 Subject: [PATCH] Dropdown test. --- assets/locale/en_US.po | 11 +- assets/locale/es_MX.po | 8 +- assets/locale/jp_JP.po | 8 +- src/dusk/ui/frame/settings/CMakeLists.txt | 2 +- src/dusk/ui/frame/settings/uisettings.c | 14 +-- .../ui/frame/settings/uisettingsgameplay.c | 54 --------- .../ui/frame/settings/uisettingsgameplay.h | 48 -------- .../ui/frame/settings/uisettingsgeneral.c | 112 +++++++++++++++++ .../ui/frame/settings/uisettingsgeneral.h | 55 +++++++++ src/dusk/ui/widget/CMakeLists.txt | 1 + src/dusk/ui/widget/uidropdown.c | 100 ++++++++++++++++ src/dusk/ui/widget/uidropdown.h | 113 ++++++++++++++++++ src/dusk/ui/widget/uimenu.c | 16 +++ src/dusk/ui/widget/uimenu.h | 12 ++ 14 files changed, 438 insertions(+), 116 deletions(-) delete mode 100644 src/dusk/ui/frame/settings/uisettingsgameplay.c delete mode 100644 src/dusk/ui/frame/settings/uisettingsgameplay.h create mode 100644 src/dusk/ui/frame/settings/uisettingsgeneral.c create mode 100644 src/dusk/ui/frame/settings/uisettingsgeneral.h create mode 100644 src/dusk/ui/widget/uidropdown.c create mode 100644 src/dusk/ui/widget/uidropdown.h diff --git a/assets/locale/en_US.po b/assets/locale/en_US.po index bbd3352f..14643432 100644 --- a/assets/locale/en_US.po +++ b/assets/locale/en_US.po @@ -11,8 +11,8 @@ msgstr "" "Welcome" #: src/dusk/ui/frame/settings/uisettings.c -msgid "ui.settings.tabs.gameplay" -msgstr "Gameplay" +msgid "ui.settings.tabs.general" +msgstr "General" #: src/dusk/ui/frame/settings/uisettings.c msgid "ui.settings.tabs.input" @@ -29,6 +29,13 @@ msgstr "Audio" msgid "ui.settings.input.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 msgid "ui.settings.apply" msgstr "Apply" diff --git a/assets/locale/es_MX.po b/assets/locale/es_MX.po index 1459f2ad..6d5ef44a 100644 --- a/assets/locale/es_MX.po +++ b/assets/locale/es_MX.po @@ -11,8 +11,8 @@ msgstr "" "Bienvenido" #: src/dusk/ui/frame/settings/uisettings.c -msgid "ui.settings.tabs.gameplay" -msgstr "Jugabilidad" +msgid "ui.settings.tabs.general" +msgstr "General" #: src/dusk/ui/frame/settings/uisettings.c msgid "ui.settings.tabs.input" @@ -29,6 +29,10 @@ msgstr "Audio" msgid "ui.settings.input.deadzone" msgstr "Zona muerta" +#: src/dusk/ui/frame/settings/uisettingsgeneral.c +msgid "ui.settings.general.language" +msgstr "Idioma" + #: src/dusk/ui/frame/settings/uisettings.c msgid "ui.settings.apply" msgstr "Aplicar" diff --git a/assets/locale/jp_JP.po b/assets/locale/jp_JP.po index dab77d7e..1b23bcfd 100644 --- a/assets/locale/jp_JP.po +++ b/assets/locale/jp_JP.po @@ -11,8 +11,8 @@ msgstr "" "歓迎" #: src/dusk/ui/frame/settings/uisettings.c -msgid "ui.settings.tabs.gameplay" -msgstr "ゲームプレイ" +msgid "ui.settings.tabs.general" +msgstr "一般" #: src/dusk/ui/frame/settings/uisettings.c msgid "ui.settings.tabs.input" @@ -29,6 +29,10 @@ 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/uisettings.c msgid "ui.settings.apply" msgstr "適用" diff --git a/src/dusk/ui/frame/settings/CMakeLists.txt b/src/dusk/ui/frame/settings/CMakeLists.txt index 61e464ab..f0e4b1c2 100644 --- a/src/dusk/ui/frame/settings/CMakeLists.txt +++ b/src/dusk/ui/frame/settings/CMakeLists.txt @@ -6,7 +6,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC uisettings.c - uisettingsgameplay.c + uisettingsgeneral.c uisettingsinput.c uisettingsdisplay.c uisettingsaudio.c diff --git a/src/dusk/ui/frame/settings/uisettings.c b/src/dusk/ui/frame/settings/uisettings.c index 327ef44e..73d65b6d 100644 --- a/src/dusk/ui/frame/settings/uisettings.c +++ b/src/dusk/ui/frame/settings/uisettings.c @@ -6,7 +6,7 @@ */ #include "uisettings.h" -#include "uisettingsgameplay.h" +#include "uisettingsgeneral.h" #include "uisettingsinput.h" #include "uisettingsdisplay.h" #include "uisettingsaudio.h" @@ -24,12 +24,12 @@ uisettings_t UI_SETTINGS; uisettingstabdef_t UI_SETTINGS_TAB_DEFS[UI_SETTINGS_TAB_COUNT] = { { - .localeId = "ui.settings.tabs.gameplay", - .init = uiSettingsGameplayInit, - .menu = &UI_SETTINGS_GAMEPLAY.menu, - .load = uiSettingsGameplayLoad, - .apply = uiSettingsGameplayApply, - .hasChanges = uiSettingsGameplayHasChanges + .localeId = "ui.settings.tabs.general", + .init = uiSettingsGeneralInit, + .menu = &UI_SETTINGS_GENERAL.menu, + .load = uiSettingsGeneralLoad, + .apply = uiSettingsGeneralApply, + .hasChanges = uiSettingsGeneralHasChanges }, { diff --git a/src/dusk/ui/frame/settings/uisettingsgameplay.c b/src/dusk/ui/frame/settings/uisettingsgameplay.c deleted file mode 100644 index eb673125..00000000 --- a/src/dusk/ui/frame/settings/uisettingsgameplay.c +++ /dev/null @@ -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; -} diff --git a/src/dusk/ui/frame/settings/uisettingsgameplay.h b/src/dusk/ui/frame/settings/uisettingsgameplay.h deleted file mode 100644 index 0c1098e9..00000000 --- a/src/dusk/ui/frame/settings/uisettingsgameplay.h +++ /dev/null @@ -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); diff --git a/src/dusk/ui/frame/settings/uisettingsgeneral.c b/src/dusk/ui/frame/settings/uisettingsgeneral.c new file mode 100644 index 00000000..d0e989e9 --- /dev/null +++ b/src/dusk/ui/frame/settings/uisettingsgeneral.c @@ -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; +} diff --git a/src/dusk/ui/frame/settings/uisettingsgeneral.h b/src/dusk/ui/frame/settings/uisettingsgeneral.h new file mode 100644 index 00000000..16c5dfeb --- /dev/null +++ b/src/dusk/ui/frame/settings/uisettingsgeneral.h @@ -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); diff --git a/src/dusk/ui/widget/CMakeLists.txt b/src/dusk/ui/widget/CMakeLists.txt index c33d236f..65825936 100644 --- a/src/dusk/ui/widget/CMakeLists.txt +++ b/src/dusk/ui/widget/CMakeLists.txt @@ -9,5 +9,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} uicheckbox.c uitab.c uislider.c + uidropdown.c uimenu.c ) diff --git a/src/dusk/ui/widget/uidropdown.c b/src/dusk/ui/widget/uidropdown.c new file mode 100644 index 00000000..ae72bd4e --- /dev/null +++ b/src/dusk/ui/widget/uidropdown.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(); +} diff --git a/src/dusk/ui/widget/uidropdown.h b/src/dusk/ui/widget/uidropdown.h new file mode 100644 index 00000000..0c6884ac --- /dev/null +++ b/src/dusk/ui/widget/uidropdown.h @@ -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 +); diff --git a/src/dusk/ui/widget/uimenu.c b/src/dusk/ui/widget/uimenu.c index 2de63ef2..5eb10597 100644 --- a/src/dusk/ui/widget/uimenu.c +++ b/src/dusk/ui/widget/uimenu.c @@ -13,6 +13,7 @@ #include "ui/widget/uibutton.h" #include "ui/widget/uitab.h" #include "ui/widget/uislider.h" +#include "ui/widget/uidropdown.h" void uiMenuInit( uimenu_t *menu, @@ -138,6 +139,10 @@ errorret_t uiMenuDraw( errorChain(uiSliderDraw(&item->slider, ix, iy)); break; + case UI_MENU_WIDGET_TYPE_DROPDOWN: + errorChain(uiDropdownDraw(&item->dropdown, ix, iy)); + break; + default: break; } @@ -235,6 +240,15 @@ bool_t uiMenuFocusDirection( return true; } + if(item->type == UI_MENU_WIDGET_TYPE_DROPDOWN) { + if(right) { + uiDropdownStepNext(&item->dropdown); + } else { + uiDropdownStepPrev(&item->dropdown); + } + return true; + } + return false; } @@ -269,5 +283,7 @@ void uiMenuItemSetHighlighted(uimenuitem_t *item, const bool_t highlighted) { uiTabSetActive(&item->tab, highlighted); } else if(item->type == UI_MENU_WIDGET_TYPE_SLIDER) { uiSliderSetHighlighted(&item->slider, highlighted); + } else if(item->type == UI_MENU_WIDGET_TYPE_DROPDOWN) { + uiDropdownSetHighlighted(&item->dropdown, highlighted); } } diff --git a/src/dusk/ui/widget/uimenu.h b/src/dusk/ui/widget/uimenu.h index cc75b558..870ed130 100644 --- a/src/dusk/ui/widget/uimenu.h +++ b/src/dusk/ui/widget/uimenu.h @@ -12,6 +12,7 @@ #include "ui/widget/uicheckbox.h" #include "ui/widget/uitab.h" #include "ui/widget/uislider.h" +#include "ui/widget/uidropdown.h" #define UI_MENU_LABEL_MAX UI_CHECKBOX_LABEL_MAX @@ -25,6 +26,7 @@ typedef enum { UI_MENU_WIDGET_TYPE_BUTTON, UI_MENU_WIDGET_TYPE_TAB, UI_MENU_WIDGET_TYPE_SLIDER, + UI_MENU_WIDGET_TYPE_DROPDOWN, } uimenuwidgettype_t; typedef struct { @@ -35,6 +37,7 @@ typedef struct { uibutton_t button; uitab_t tab; uislider_t slider; + uidropdown_t dropdown; }; } uimenuitem_t; @@ -266,6 +269,15 @@ bool_t uiMenuFocusDirection( ); \ ++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) \ uiMenuSetItems(menu, (itemsArray), menuIndex, (columns))