FreeTRX/MDUV380_firmware/application/source/user_interface/menuThemeOptions.c
2026-07-06 08:45:33 +02:00

732 lines
22 KiB
C

/*
* Copyright (C) 2019-2025 Roger Clark, VK3KYY / G4KYF
* Daniel Caujolle-Bert, F1RMB
*
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. Use of this source code or binary releases for commercial purposes is strictly forbidden. This includes, without limitation,
* incorporation in a commercial product or incorporation into a product or project which allows commercial use.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "functions/settings.h"
#include "user_interface/menuSystem.h"
#include "user_interface/uiLocalisation.h"
#include "user_interface/uiUtilities.h"
#include "interfaces/wdog.h"
#include "utils.h"
#if defined(HAS_COLOURS)
static const char *themeEntries[THEME_ITEM_MAX];
static uint16_t userThemeData[THEME_ITEM_MAX] = { 0xDEAD, 0xBEEF };
static int32_t currentThemeEntry = 0;
static DayTime_t currentThemeDaytime = UNDEFINED;
static void updateScreen(bool isFirstRun);
static void handleEvent(uiEvent_t *ev);
static void resetUserThemeData(void);
// ------
#define COLOUR_CHANNEL_UNSET 0xFFFF
#define COLOUR_RGB888_UNSET 0xDEADBEEF
typedef enum
{
COLOUR_CHANNEL_RED = 0,
COLOUR_CHANNEL_GREEN,
COLOUR_CHANNEL_BLUE,
COLOUR_CHANNEL_MAX
} colourChannel_t;
typedef struct
{
const char *name;
int32_t value; // we need to handle < 0 and 0xFFFF
} colourChannelData_t;
static colourChannelData_t colourChannelsData[COLOUR_CHANNEL_MAX] =
{
{ NULL, COLOUR_CHANNEL_UNSET },
{ NULL, COLOUR_CHANNEL_UNSET },
{ NULL, COLOUR_CHANNEL_UNSET }
};
typedef struct
{
uint16_t maxValue;
uint8_t step;
} channelConstraint_t;
static channelConstraint_t channelConstraints[COLOUR_CHANNEL_MAX] =
{
{ 248, 8 }, // RED
{ 252, 4 }, // GREEN
{ 248, 8 }, // BLUE
};
static uint32_t colourToEditRGB888 = COLOUR_RGB888_UNSET;
static void updateBrowerScreen(bool isFirstRun);
static void handleBrowserEvent(uiEvent_t *ev);
static void exitBrowserCallback(void *data);
static void updatePickerScreen(bool isFirstRun);
static void handlePickerEvent(uiEvent_t *ev);
static void exitPickerCallback(void *data);
static void resetColourChannelsData(void);
static menuStatus_t menuOptionsExitCode = MENU_STATUS_SUCCESS;
menuStatus_t menuThemeOptions(uiEvent_t *ev, bool isFirstRun)
{
if (isFirstRun)
{
currentThemeDaytime = (DayTime_t)uiDataGlobal.currentSelectedChannelNumber;
menuDataGlobal.numItems = (NIGHT + 1);
//menuDataGlobal.currentItemIndex = 0;
voicePromptsInit();
voicePromptsAppendPrompt(PROMPT_SILENCE);
voicePromptsAppendLanguageString(currentLanguage->theme_chooser);
voicePromptsAppendLanguageString(currentLanguage->menu);
voicePromptsAppendPrompt(PROMPT_SILENCE);
updateScreen(true);
return (MENU_STATUS_LIST_TYPE | MENU_STATUS_SUCCESS);
}
else
{
menuOptionsExitCode = MENU_STATUS_SUCCESS;
if (ev->hasEvent)
{
handleEvent(ev);
}
}
return menuOptionsExitCode;
}
static void updateScreen(bool isFirstRun)
{
int mNum = 0;
char buf[SCREEN_LINE_BUFFER_SIZE];
const char *leftSide = NULL;// initialize to please the compiler
displayClearBuf();
menuDisplayTitle(currentLanguage->theme_chooser);
for (int i = MENU_START_ITERATION_VALUE; i <= MENU_END_ITERATION_VALUE; i++)
{
if (menuDataGlobal.numItems <= (i + 1))
{
break;
}
mNum = menuGetMenuOffset(menuDataGlobal.numItems, i);
if (mNum == MENU_OFFSET_BEFORE_FIRST_ENTRY)
{
continue;
}
else if (mNum == MENU_OFFSET_AFTER_LAST_ENTRY)
{
break;
}
buf[0] = 0;
buf[2] = 0;
leftSide = NULL;
switch(mNum)
{
default:
leftSide = (const char *)((((DayTime_t)mNum) == DAY) ? currentLanguage->daytime_theme_day : currentLanguage->daytime_theme_night);
break;
}
snprintf(buf, SCREEN_LINE_BUFFER_SIZE, "%s", leftSide);
if (i == 0)
{
bool wasPlaying = voicePromptsIsPlaying();
if (!isFirstRun)
{
voicePromptsInit();
}
if (!wasPlaying || (menuDataGlobal.newOptionSelected || (menuDataGlobal.menuOptionsTimeout > 0)))
{
voicePromptsAppendLanguageString(leftSide);
}
promptsPlayNotAfterTx();
}
menuDisplayEntry(i, mNum, buf, 0, THEME_ITEM_FG_MENU_ITEM, THEME_ITEM_COLOUR_NONE, THEME_ITEM_BG);
}
displayRender();
}
static void handleEvent(uiEvent_t *ev)
{
bool isDirty = false;
if (ev->events & BUTTON_EVENT)
{
if (repeatVoicePromptOnSK1(ev))
{
return;
}
}
if (ev->events & FUNCTION_EVENT)
{
if (ev->function == FUNC_REDRAW)
{
isDirty = true;
//updateScreen(false);
//return;
}
else if ((QUICKKEY_TYPE(ev->function) == QUICKKEY_MENU) && (QUICKKEY_ENTRYID(ev->function) < (NIGHT + 1)))
{
isDirty = true;
menuDataGlobal.currentItemIndex = QUICKKEY_ENTRYID(ev->function);
//updateScreen(false);
}
}
if (ev->events & KEY_EVENT)
{
if (KEYCHECK_PRESS(ev->keys, KEY_DOWN) && (menuDataGlobal.numItems != 0))
{
isDirty = true;
menuSystemMenuIncrement(&menuDataGlobal.currentItemIndex, (NIGHT + 1));
menuDataGlobal.newOptionSelected = true;
menuOptionsExitCode |= MENU_STATUS_LIST_TYPE;
}
else if (KEYCHECK_PRESS(ev->keys, KEY_UP))
{
isDirty = true;
menuSystemMenuDecrement(&menuDataGlobal.currentItemIndex, (NIGHT + 1));
menuDataGlobal.newOptionSelected = true;
menuOptionsExitCode |= MENU_STATUS_LIST_TYPE;
}
else if (KEYCHECK_SHORTUP(ev->keys, KEY_GREEN))
{
currentThemeDaytime = (DayTime_t)menuDataGlobal.currentItemIndex;
menuSystemPushNewMenu(MENU_THEME_ITEMS_BROWSER);
return;
}
else if (KEYCHECK_SHORTUP(ev->keys, KEY_RED))
{
menuSystemPopPreviousMenu();
return;
}
else if (KEYCHECK_SHORTUP_NUMBER(ev->keys) && BUTTONCHECK_DOWN(ev, BUTTON_SK2))
{
saveQuickkeyMenuIndex(ev->keys.key, menuSystemGetCurrentMenuNumber(), menuDataGlobal.currentItemIndex, 0);
isDirty = true;
}
}
if (isDirty)
{
updateScreen(false);
}
}
menuStatus_t menuThemeItemsBrowser(uiEvent_t *ev, bool isFirstRun)
{
if (isFirstRun)
{
menuDataGlobal.menuOptionsSetQuickkey = 0;
menuDataGlobal.menuOptionsTimeout = 0;
menuDataGlobal.newOptionSelected = true;
menuDataGlobal.numItems = THEME_ITEM_MAX;
themeEntries[THEME_ITEM_FG_DEFAULT] = currentLanguage->theme_fg_default;
themeEntries[THEME_ITEM_BG] = currentLanguage->theme_bg;
themeEntries[THEME_ITEM_FG_DECORATION] = currentLanguage->theme_fg_decoration;
themeEntries[THEME_ITEM_FG_TEXT_INPUT] = currentLanguage->theme_fg_text_input;
themeEntries[THEME_ITEM_FG_SPLASHSCREEN] = currentLanguage->theme_fg_splashscreen;
themeEntries[THEME_ITEM_BG_SPLASHSCREEN] = currentLanguage->theme_bg_splashscreen;
themeEntries[THEME_ITEM_FG_NOTIFICATION] = currentLanguage->theme_fg_notification;
themeEntries[THEME_ITEM_FG_WARNING_NOTIFICATION] = currentLanguage->theme_fg_warning_notification;
themeEntries[THEME_ITEM_FG_ERROR_NOTIFICATION] = currentLanguage->theme_fg_error_notification;
themeEntries[THEME_ITEM_BG_NOTIFICATION] = currentLanguage->theme_bg_notification;
themeEntries[THEME_ITEM_FG_MENU_NAME] = currentLanguage->theme_fg_menu_name;
themeEntries[THEME_ITEM_BG_MENU_NAME] = currentLanguage->theme_bg_menu_name;
themeEntries[THEME_ITEM_FG_MENU_ITEM] = currentLanguage->theme_fg_menu_item;
themeEntries[THEME_ITEM_BG_MENU_ITEM_SELECTED] = currentLanguage->theme_fg_menu_item_selected;
themeEntries[THEME_ITEM_FG_OPTIONS_VALUE] = currentLanguage->theme_fg_options_value;
themeEntries[THEME_ITEM_FG_HEADER_TEXT] = currentLanguage->theme_fg_header_text;
themeEntries[THEME_ITEM_BG_HEADER_TEXT] = currentLanguage->theme_bg_header_text;
themeEntries[THEME_ITEM_FG_RSSI_BAR] = currentLanguage->theme_fg_rssi_bar;
themeEntries[THEME_ITEM_FG_RSSI_BAR_S9P] = currentLanguage->theme_fg_rssi_bar_s9p;
themeEntries[THEME_ITEM_FG_CHANNEL_NAME] = currentLanguage->theme_fg_channel_name;
themeEntries[THEME_ITEM_FG_CHANNEL_CONTACT] = currentLanguage->theme_fg_channel_contact;
themeEntries[THEME_ITEM_FG_CHANNEL_CONTACT_INFO] = currentLanguage->theme_fg_channel_contact_info;
themeEntries[THEME_ITEM_FG_ZONE_NAME] = currentLanguage->theme_fg_zone_name;
themeEntries[THEME_ITEM_FG_RX_FREQ] = currentLanguage->theme_fg_rx_freq;
themeEntries[THEME_ITEM_FG_TX_FREQ] = currentLanguage->theme_fg_tx_freq;
themeEntries[THEME_ITEM_FG_CSS_SQL_VALUES] = currentLanguage->theme_fg_css_sql_values;
themeEntries[THEME_ITEM_FG_TX_COUNTER] = currentLanguage->theme_fg_tx_counter;
themeEntries[THEME_ITEM_FG_POLAR_DRAWING] = currentLanguage->theme_fg_polar_drawing;
themeEntries[THEME_ITEM_FG_SATELLITE_COLOUR] = currentLanguage->theme_fg_satellite_colour;
themeEntries[THEME_ITEM_FG_GPS_NUMBER] = currentLanguage->theme_fg_gps_number;
themeEntries[THEME_ITEM_FG_GPS_COLOUR] = currentLanguage->theme_fg_gps_colour;
themeEntries[THEME_ITEM_FG_BD_COLOUR] = currentLanguage->theme_fg_bd_colour;
// Has to make a working copy of the global theme
if ((userThemeData[0] == 0xDEAD) && (userThemeData[1] == 0xBEEF))
{
memcpy(&userThemeData, &themeItems[currentThemeDaytime], (sizeof(uint16_t) * THEME_ITEM_MAX));
}
else
{
// Apply the edited colour to the edited theme entry
if (colourToEditRGB888 != COLOUR_RGB888_UNSET)
{
userThemeData[menuDataGlobal.currentItemIndex] = displayConvertRGB888ToNative(colourToEditRGB888);
colourToEditRGB888 = COLOUR_RGB888_UNSET;
}
}
voicePromptsInit();
voicePromptsAppendPrompt(PROMPT_SILENCE);
voicePromptsAppendLanguageString(currentLanguage->theme_options);
voicePromptsAppendLanguageString(currentLanguage->menu);
voicePromptsAppendPrompt(PROMPT_SILENCE);
menuSystemRegisterExitCallback(exitBrowserCallback, NULL);
updateBrowerScreen(true);
return (MENU_STATUS_LIST_TYPE | MENU_STATUS_SUCCESS);
}
else
{
menuOptionsExitCode = MENU_STATUS_SUCCESS;
if (ev->hasEvent)
{
handleBrowserEvent(ev);
}
}
return menuOptionsExitCode;
}
static void updateBrowerScreen(bool isFirstRun)
{
int mNum = 0;
char buf[SCREEN_LINE_BUFFER_SIZE];
const char *leftSide = NULL;// initialize to please the compiler
displayClearBuf();
menuDisplayTitle(currentLanguage->theme_options);
for (int i = MENU_START_ITERATION_VALUE; i <= MENU_END_ITERATION_VALUE; i++)
{
mNum = menuGetMenuOffset(THEME_ITEM_MAX, i);
if (mNum == MENU_OFFSET_BEFORE_FIRST_ENTRY)
{
continue;
}
else if (mNum == MENU_OFFSET_AFTER_LAST_ENTRY)
{
break;
}
buf[0] = 0;
buf[2] = 0;
leftSide = NULL;
switch(mNum)
{
default:
leftSide = themeEntries[mNum];
break;
}
snprintf(buf, SCREEN_LINE_BUFFER_SIZE, "%s", leftSide);
if (i == 0)
{
bool wasPlaying = voicePromptsIsPlaying();
if (!isFirstRun)
{
voicePromptsInit();
}
if (!wasPlaying || (menuDataGlobal.newOptionSelected || (menuDataGlobal.menuOptionsTimeout > 0)))
{
voicePromptsAppendLanguageString(leftSide);
}
promptsPlayNotAfterTx();
}
menuDisplayEntry(i, mNum, buf, 0, THEME_ITEM_FG_MENU_ITEM, THEME_ITEM_COLOUR_NONE, THEME_ITEM_BG);
// Draw the color rectangle
int16_t x = (DISPLAY_X_POS_MENU_TEXT_OFFSET + (16 * 8) + 2);
int16_t y = DISPLAY_Y_POS_MENU_ENTRY_HIGHLIGHT + (i * MENU_ENTRY_HEIGHT) + 2;
uint16_t fgColour, bgColour;
displayGetForegroundAndBackgroundColours(&fgColour, &bgColour);
displaySetForegroundAndBackgroundColours(userThemeData[mNum], themeItems[DAYTIME_CURRENT][THEME_ITEM_BG]);
displayFillRect(x, y, 14, 12, false);
// Outline the color rectangle when it's equal to background or menu focused colour
if (((i != 0) && (bgColour == userThemeData[mNum])) ||
((i == 0) && (userThemeData[mNum] == themeItems[DAYTIME_CURRENT][THEME_ITEM_BG_MENU_ITEM_SELECTED])))
{
uint32_t invertedColour = (0xFFFFFF - __builtin_bswap16(PLATFORM_COLOUR_FORMAT_TO_RGB888(userThemeData[mNum])));
displaySetForegroundAndBackgroundColours(displayConvertRGB888ToNative(invertedColour), themeItems[DAYTIME_CURRENT][THEME_ITEM_BG_MENU_ITEM_SELECTED]);
displayDrawRect(x, y, 14, 12, true);
}
displayThemeResetToDefault();
}
displayRender();
}
static void handleBrowserEvent(uiEvent_t *ev)
{
bool isDirty = false;
if (ev->events & BUTTON_EVENT)
{
if (repeatVoicePromptOnSK1(ev))
{
return;
}
}
if ((ev->events & FUNCTION_EVENT) && (ev->function == FUNC_REDRAW))
{
updateBrowerScreen(false);
return;
}
if (ev->events & KEY_EVENT)
{
if (KEYCHECK_PRESS(ev->keys, KEY_DOWN) && (menuDataGlobal.numItems != 0))
{
isDirty = true;
menuSystemMenuIncrement(&menuDataGlobal.currentItemIndex, THEME_ITEM_MAX);
menuDataGlobal.newOptionSelected = true;
menuOptionsExitCode |= MENU_STATUS_LIST_TYPE;
}
else if (KEYCHECK_PRESS(ev->keys, KEY_UP))
{
isDirty = true;
menuSystemMenuDecrement(&menuDataGlobal.currentItemIndex, THEME_ITEM_MAX);
menuDataGlobal.newOptionSelected = true;
menuOptionsExitCode |= MENU_STATUS_LIST_TYPE;
}
else if (KEYCHECK_SHORTUP(ev->keys, KEY_GREEN))
{
// User ask to go back to the default (hardcoded) theme
if (BUTTONCHECK_DOWN(ev, BUTTON_SK1))
{
themeInitToDefaultValues(currentThemeDaytime, ((currentThemeDaytime == DAY) ? false : true));
}
else
{
// Apply edited theme
memcpy(&themeItems[currentThemeDaytime], &userThemeData, (sizeof(uint16_t) * THEME_ITEM_MAX));
}
// Save user's theme to flash, as a CustomData block
if (BUTTONCHECK_DOWN(ev, BUTTON_SK2))
{
displayThemeSaveToFlash(currentThemeDaytime);
}
displayThemeResetToDefault();
menuSystemPopAllAndDisplayRootMenu();
return;
}
else if (KEYCHECK_SHORTUP(ev->keys, KEY_RED))
{
menuSystemPopPreviousMenu();
return;
}
else if (KEYCHECK_SHORTUP(ev->keys, KEY_HASH))
{
colourToEditRGB888 = PLATFORM_COLOUR_FORMAT_TO_RGB888(__builtin_bswap16(userThemeData[menuDataGlobal.currentItemIndex]));
currentThemeEntry = menuDataGlobal.currentItemIndex;
menuSystemPushNewMenu(MENU_COLOUR_PICKER);
return;
}
}
if (isDirty)
{
updateBrowerScreen(false);
}
}
static void exitBrowserCallback(void *data)
{
resetUserThemeData();
}
//
// Colour Picker
//
menuStatus_t menuColourPicker(uiEvent_t *ev, bool isFirstRun)
{
if (isFirstRun)
{
menuDataGlobal.menuOptionsSetQuickkey = 0;
menuDataGlobal.menuOptionsTimeout = 0;
menuDataGlobal.newOptionSelected = true;
menuDataGlobal.numItems = COLOUR_CHANNEL_MAX;
if ((colourChannelsData[COLOUR_CHANNEL_RED].value == COLOUR_CHANNEL_UNSET) &&
(colourChannelsData[COLOUR_CHANNEL_GREEN].value == COLOUR_CHANNEL_UNSET) &&
(colourChannelsData[COLOUR_CHANNEL_BLUE].value == COLOUR_CHANNEL_UNSET))
{
colourChannelsData[COLOUR_CHANNEL_RED].name = currentLanguage->theme_colour_picker_red;
colourChannelsData[COLOUR_CHANNEL_RED].value = (colourToEditRGB888 & 0xFF0000) >> 16;
colourChannelsData[COLOUR_CHANNEL_GREEN].name = currentLanguage->theme_colour_picker_green;
colourChannelsData[COLOUR_CHANNEL_GREEN].value = (colourToEditRGB888 & 0xFF00) >> 8;
colourChannelsData[COLOUR_CHANNEL_BLUE].name = currentLanguage->theme_colour_picker_blue;
colourChannelsData[COLOUR_CHANNEL_BLUE].value = (colourToEditRGB888 & 0xFF);
}
voicePromptsInit();
voicePromptsAppendPrompt(PROMPT_SILENCE);
voicePromptsAppendLanguageString(currentLanguage->theme_options);
voicePromptsAppendLanguageString(themeEntries[currentThemeEntry]);
voicePromptsAppendPrompt(PROMPT_SILENCE);
menuSystemRegisterExitCallback(exitPickerCallback, NULL);
updatePickerScreen(true);
return (MENU_STATUS_LIST_TYPE | MENU_STATUS_SUCCESS);
}
else
{
menuOptionsExitCode = MENU_STATUS_SUCCESS;
if (ev->hasEvent)
{
handlePickerEvent(ev);
}
}
return menuOptionsExitCode;
}
static uint32_t getColourInEditionRGB888(void)
{
return ((colourChannelsData[COLOUR_CHANNEL_RED].value << 16) | (colourChannelsData[COLOUR_CHANNEL_GREEN].value << 8) | colourChannelsData[COLOUR_CHANNEL_BLUE].value);
}
static void updatePickerScreen(bool isFirstRun)
{
int mNum = 0;
char buf[SCREEN_LINE_BUFFER_SIZE];
const char *leftSide = NULL;// initialize to please the compiler
char rightSideVar[SCREEN_LINE_BUFFER_SIZE];
displayClearBuf();
menuDisplayTitle(themeEntries[currentThemeEntry]);
for (int i = MENU_START_ITERATION_VALUE; i <= MENU_END_ITERATION_VALUE; i++)
{
mNum = menuGetMenuOffset(COLOUR_CHANNEL_MAX, i);
if (mNum == MENU_OFFSET_BEFORE_FIRST_ENTRY)
{
continue;
}
else if (mNum == MENU_OFFSET_AFTER_LAST_ENTRY)
{
break;
}
buf[0] = 0;
buf[2] = 0;
leftSide = NULL;
rightSideVar[0] = 0;
switch(mNum)
{
default:
leftSide = colourChannelsData[mNum].name;
snprintf(rightSideVar, SCREEN_LINE_BUFFER_SIZE, "%d",
(settingsIsOptionBitSet(BIT_INVERSE_VIDEO) ? (channelConstraints[mNum].maxValue - colourChannelsData[mNum].value) : colourChannelsData[mNum].value));
break;
}
snprintf(buf, SCREEN_LINE_BUFFER_SIZE, "%s:%s", leftSide, rightSideVar);
if (i == 0)
{
bool wasPlaying = voicePromptsIsPlaying();
if (!isFirstRun)
{
voicePromptsInit();
}
if (!wasPlaying || (menuDataGlobal.newOptionSelected || (menuDataGlobal.menuOptionsTimeout > 0)))
{
voicePromptsAppendLanguageString(leftSide);
}
voicePromptsAppendString(rightSideVar);
promptsPlayNotAfterTx();
}
// We're cheating the menu vertical position, moving it to the bottom of the screen.
menuDisplayEntry((i + 2), mNum, buf, (strlen(leftSide) + 1), THEME_ITEM_FG_MENU_ITEM, THEME_ITEM_FG_OPTIONS_VALUE, THEME_ITEM_BG);
// Display color sample.
uint32_t invertedColour = (0xFFFFFF - __builtin_bswap16(PLATFORM_COLOUR_FORMAT_TO_RGB888(userThemeData[THEME_ITEM_BG])));
displaySetForegroundAndBackgroundColours(displayConvertRGB888ToNative(getColourInEditionRGB888()), themeItems[DAYTIME_CURRENT][THEME_ITEM_BG]);
displayFillRect(20, 25, (DISPLAY_SIZE_X - 40), 48, false);
displaySetForegroundAndBackgroundColours(displayConvertRGB888ToNative(invertedColour), themeItems[DAYTIME_CURRENT][THEME_ITEM_BG]);
displayDrawRect(20, 25, (DISPLAY_SIZE_X - 40), 48, true);
displayDrawRect(21, 26, (DISPLAY_SIZE_X - 40) - 2, 46, true);
displayThemeResetToDefault();
}
displayRender();
}
static void handlePickerEvent(uiEvent_t *ev)
{
bool isDirty = false;
bool isInverted = settingsIsOptionBitSet(BIT_INVERSE_VIDEO);
if (ev->events & BUTTON_EVENT)
{
if (repeatVoicePromptOnSK1(ev))
{
return;
}
}
if ((ev->events & FUNCTION_EVENT) && (ev->function == FUNC_REDRAW))
{
isDirty = true;
}
if (ev->events & KEY_EVENT)
{
if (KEYCHECK_PRESS(ev->keys, KEY_DOWN) && (menuDataGlobal.numItems != 0))
{
isDirty = true;
menuSystemMenuIncrement(&menuDataGlobal.currentItemIndex, COLOUR_CHANNEL_MAX);
menuDataGlobal.newOptionSelected = true;
menuOptionsExitCode |= MENU_STATUS_LIST_TYPE;
}
else if (KEYCHECK_PRESS(ev->keys, KEY_UP))
{
isDirty = true;
menuSystemMenuDecrement(&menuDataGlobal.currentItemIndex, COLOUR_CHANNEL_MAX);
menuDataGlobal.newOptionSelected = true;
menuOptionsExitCode |= MENU_STATUS_LIST_TYPE;
}
else if (KEYCHECK_SHORTUP(ev->keys, KEY_GREEN))
{
// Build New Colour
colourToEditRGB888 = getColourInEditionRGB888();
resetColourChannelsData();
menuSystemPopPreviousMenu();
return;
}
else if (KEYCHECK_SHORTUP(ev->keys, KEY_RED))
{
menuSystemPopPreviousMenu();
return;
}
else if (KEYCHECK_PRESS(ev->keys, (isInverted ? KEY_LEFT : KEY_RIGHT))
#if defined(PLATFORM_RT84_DM1701) || defined(PLATFORM_MD2017)
|| KEYCHECK_SHORTUP(ev->keys, (isInverted ? KEY_ROTARY_DECREMENT : KEY_ROTARY_INCREMENT))
#endif
)
{
isDirty = true;
colourChannelsData[menuDataGlobal.currentItemIndex].value += (channelConstraints[menuDataGlobal.currentItemIndex].step * (BUTTONCHECK_DOWN(ev, BUTTON_SK2) ? 3 : 1));
if (colourChannelsData[menuDataGlobal.currentItemIndex].value > channelConstraints[menuDataGlobal.currentItemIndex].maxValue)
{
colourChannelsData[menuDataGlobal.currentItemIndex].value = channelConstraints[menuDataGlobal.currentItemIndex].maxValue;
}
}
else if (KEYCHECK_PRESS(ev->keys, (isInverted ? KEY_RIGHT : KEY_LEFT))
#if defined(PLATFORM_RT84_DM1701) || defined(PLATFORM_MD2017)
|| KEYCHECK_SHORTUP(ev->keys, (isInverted ? KEY_ROTARY_INCREMENT : KEY_ROTARY_DECREMENT))
#endif
)
{
isDirty = true;
colourChannelsData[menuDataGlobal.currentItemIndex].value -= (channelConstraints[menuDataGlobal.currentItemIndex].step * (BUTTONCHECK_DOWN(ev, BUTTON_SK2) ? 3 : 1));
if (colourChannelsData[menuDataGlobal.currentItemIndex].value < 0)
{
colourChannelsData[menuDataGlobal.currentItemIndex].value = 0;
}
}
}
if (isDirty)
{
updatePickerScreen(false);
}
}
static void exitPickerCallback(void *data)
{
if ((colourChannelsData[COLOUR_CHANNEL_RED].value != COLOUR_CHANNEL_UNSET) &&
(colourChannelsData[COLOUR_CHANNEL_GREEN].value != COLOUR_CHANNEL_UNSET) &&
(colourChannelsData[COLOUR_CHANNEL_BLUE].value != COLOUR_CHANNEL_UNSET))
{
colourToEditRGB888 = COLOUR_RGB888_UNSET;
resetColourChannelsData();
}
}
static void resetUserThemeData(void)
{
userThemeData[0] = 0xDEAD;
userThemeData[1] = 0xBEEF;
}
static void resetColourChannelsData(void)
{
colourChannelsData[COLOUR_CHANNEL_RED].value = colourChannelsData[COLOUR_CHANNEL_GREEN].value = colourChannelsData[COLOUR_CHANNEL_BLUE].value = COLOUR_CHANNEL_UNSET;
}
#endif // HAS_COLOURS