diff --git a/Makefile b/Makefile index 3b04d461..1c28e9de 100755 --- a/Makefile +++ b/Makefile @@ -95,6 +95,7 @@ OBJS += ui/menu.o OBJS += ui/rssi.o OBJS += ui/scanner.o OBJS += ui/status.o +OBJS += ui/theme.o OBJS += ui/ui.o OBJS += ui/welcome.o OBJS += version.o diff --git a/board.c b/board.c index 620f75ab..3a71e5f0 100644 --- a/board.c +++ b/board.c @@ -43,6 +43,7 @@ #if defined(ENABLE_OVERLAY) #include "sram-overlay.h" #endif +#include "ui/theme.h" static const uint32_t gDefaultFrequencyTable[5] = { 14502500, @@ -706,6 +707,11 @@ void BOARD_EEPROM_Init(void) } } + EEPROM_ReadBuffer(0x1D00, &gUI_Theme, sizeof(gUI_Theme)); + if (gUI_Theme.Aircopy.Status.X0 >= 128 || gUI_Theme.Aircopy.Status.X1 >= 128 || gUI_Theme.Aircopy.Status.W == 255 || !gUI_Theme.Aircopy.Status.W) { + bRestoreTheme = true; + } + bHasCustomAesKey = false; } diff --git a/main.c b/main.c index 01d43787..648d0a6e 100644 --- a/main.c +++ b/main.c @@ -35,6 +35,7 @@ #include "radio.h" #include "settings.h" #include "ui/lock.h" +#include "ui/theme.h" #include "ui/welcome.h" #include "version.h" @@ -89,6 +90,14 @@ void Main(void) BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent); } + if (KEYBOARD_Poll() == KEY_F) { + bRestoreTheme = true; + } + + if (bRestoreTheme) { + gUI_Theme = gUI_ThemeDefault; + } + BATTERY_GetReadings(false); if (!gChargingWithTypeC && !gBatteryDisplayLevel) { FUNCTION_Select(FUNCTION_POWER_SAVE); diff --git a/misc.c b/misc.c index c57504d9..05767421 100644 --- a/misc.c +++ b/misc.c @@ -166,6 +166,8 @@ uint16_t gCurrentRSSI; uint8_t gIsLocked = 0xFF; +bool bRestoreTheme; + // -------- void NUMBER_Get(char *pDigits, uint32_t *pInteger) diff --git a/misc.h b/misc.h index a907ce6b..ede8b1a3 100644 --- a/misc.h +++ b/misc.h @@ -212,6 +212,8 @@ extern uint16_t gCurrentRSSI; extern uint8_t gIsLocked; +extern bool bRestoreTheme; + // -------- void NUMBER_Get(char *pDigits, uint32_t *pInteger); diff --git a/ui/aircopy.c b/ui/aircopy.c index be33ea0d..b17ae4be 100644 --- a/ui/aircopy.c +++ b/ui/aircopy.c @@ -23,6 +23,7 @@ #include "ui/aircopy.h" #include "ui/helper.h" #include "ui/inputbox.h" +#include "ui/theme.h" void UI_DisplayAircopy(void) { @@ -37,14 +38,14 @@ void UI_DisplayAircopy(void) } else { strcpy(String, "AIR COPY(CMP)"); } - UI_PrintString(String, 2, 127, 0, 8, true); + UI_PrintString(String, gUI_Theme.Aircopy.Status.X0, gUI_Theme.Aircopy.Status.X1, gUI_Theme.Aircopy.Status.Y, gUI_Theme.Aircopy.Status.W, true); if (gInputBoxIndex == 0) { NUMBER_ToDigits(gRxVfo->ConfigRX.Frequency, String); - UI_DisplayFrequency(String, 16, 2, 0, 0); - UI_DisplaySmallDigits(2, String + 6, 97, 3); + UI_DisplayFrequency(String, gUI_Theme.Aircopy.Freq.X, gUI_Theme.Aircopy.Freq.Y, false, false); + UI_DisplaySmallDigits(gUI_Theme.Aircopy.Digits.Count, String + 6, gUI_Theme.Aircopy.Digits.X, gUI_Theme.Aircopy.Digits.Y); } else { - UI_DisplayFrequency(gInputBox, 16, 2, 1, 0); + UI_DisplayFrequency(gInputBox, gUI_Theme.Aircopy.Freq.X, gUI_Theme.Aircopy.Freq.Y, true, false); } memset(String, 0, sizeof(String)); @@ -54,7 +55,7 @@ void UI_DisplayAircopy(void) } else if (gAirCopyIsSendMode == 1) { sprintf(String, "SND:%d", gAirCopyBlockNumber); } - UI_PrintString(String, 2, 127, 4, 8, true); + UI_PrintString(String, gUI_Theme.Aircopy.Mode.X0, gUI_Theme.Aircopy.Mode.X1, gUI_Theme.Aircopy.Mode.Y, gUI_Theme.Aircopy.Mode.W, true); ST7565_BlitFullScreen(); } diff --git a/ui/battery.c b/ui/battery.c index 14a888b2..f0c83788 100644 --- a/ui/battery.c +++ b/ui/battery.c @@ -19,13 +19,14 @@ #include "driver/st7565.h" #include "functions.h" #include "ui/battery.h" +#include "ui/theme.h" void UI_DisplayBattery(uint8_t Level) { const uint8_t *pBitmap; bool bClearMode = false; - if (gCurrentFunction != 1) { + if (gCurrentFunction != FUNCTION_TRANSMIT) { switch (Level) { case 0: pBitmap = NULL; @@ -47,7 +48,7 @@ void UI_DisplayBattery(uint8_t Level) pBitmap = BITMAP_BatteryLevel5; break; } - ST7565_DrawLine(110, 0, 18, pBitmap, bClearMode); + ST7565_DrawLine(gUI_Theme.Battery.X, gUI_Theme.Battery.Y, gUI_Theme.Battery.Size, pBitmap, bClearMode); } } diff --git a/ui/fmradio.c b/ui/fmradio.c index 851a0102..2e9cf399 100644 --- a/ui/fmradio.c +++ b/ui/fmradio.c @@ -23,6 +23,7 @@ #include "ui/fmradio.h" #include "ui/helper.h" #include "ui/inputbox.h" +#include "ui/theme.h" #include "ui/ui.h" void UI_DisplayFM(void) @@ -32,10 +33,8 @@ void UI_DisplayFM(void) memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - memset(String, 0, sizeof(String)); - strcpy(String, "FM"); + UI_PrintString("FM", gUI_Theme.FM.Title.X0, gUI_Theme.FM.Title.X1, gUI_Theme.FM.Title.Y, gUI_Theme.FM.Title.W, true); - UI_PrintString(String, 0, 127, 0, 12, true); memset(String, 0, sizeof(String)); if (gAskToSave) { @@ -66,7 +65,8 @@ void UI_DisplayFM(void) } } - UI_PrintString(String, 0, 127, 2, 10, true); + UI_PrintString(String, gUI_Theme.FM.Status.X0, gUI_Theme.FM.Status.X1, gUI_Theme.FM.Status.Y, gUI_Theme.FM.Status.W, true); + memset(String, 0, sizeof(String)); if (gAskToSave || (gEeprom.FM_IsMrMode && gInputBoxIndex)) { @@ -74,9 +74,9 @@ void UI_DisplayFM(void) } else if (!gAskToDelete) { if (gInputBoxIndex == 0) { NUMBER_ToDigits(gEeprom.FM_FrequencyPlaying * 10000, String); - UI_DisplayFrequency(String, 23, 4, false, true); + UI_DisplayFrequency(String, gUI_Theme.FM.Freq.X, gUI_Theme.FM.Freq.Y, false, true); } else { - UI_DisplayFrequency(gInputBox, 23, 4, true, false); + UI_DisplayFrequency(gInputBox, gUI_Theme.FM.Freq.X, gUI_Theme.FM.Freq.Y, true, false); } ST7565_BlitFullScreen(); return; @@ -84,7 +84,7 @@ void UI_DisplayFM(void) sprintf(String, "CH-%02d", gEeprom.FM_SelectedChannel + 1); } - UI_PrintString(String, 0, 127, 4, 10, true); + UI_PrintString(String, gUI_Theme.FM.Channel.X0, gUI_Theme.FM.Channel.X1, gUI_Theme.FM.Channel.Y, gUI_Theme.FM.Channel.W, true); ST7565_BlitFullScreen(); } diff --git a/ui/lock.c b/ui/lock.c index 1b679102..10e647ce 100644 --- a/ui/lock.c +++ b/ui/lock.c @@ -27,6 +27,7 @@ #include "ui/helper.h" #include "ui/inputbox.h" #include "ui/lock.h" +#include "ui/theme.h" static void Render(void) { @@ -36,7 +37,7 @@ static void Render(void) memset(gStatusLine, 0, sizeof(gStatusLine)); memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); strcpy(String, "LOCK"); - UI_PrintString(String, 0, 127, 1, 10, true); + UI_PrintString(String, gUI_Theme.Lock.Title.X0, gUI_Theme.Lock.Title.X1, gUI_Theme.Lock.Title.Y, gUI_Theme.Lock.Title.W, true); for (i = 0; i < 6; i++) { if (gInputBox[i] == 10) { String[i] = '-'; @@ -45,7 +46,7 @@ static void Render(void) } } String[6] = 0; - UI_PrintString(String, 0, 127, 3, 12, true); + UI_PrintString(String, gUI_Theme.Lock.Code.X0, gUI_Theme.Lock.Code.X1, gUI_Theme.Lock.Code.Y, gUI_Theme.Lock.Code.W, true); ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); } diff --git a/ui/main.c b/ui/main.c index e3f64324..db17d8c2 100644 --- a/ui/main.c +++ b/ui/main.c @@ -26,6 +26,9 @@ #include "ui/helper.h" #include "ui/inputbox.h" #include "ui/main.h" +#include "ui/theme.h" + +#define GET_PTR(x) ((uint8_t *)gFrameBuffer + (x)) void UI_DisplayMain(void) { @@ -34,29 +37,16 @@ void UI_DisplayMain(void) memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); if (gEeprom.KEY_LOCK && gKeypadLocked) { - UI_PrintString("Long Press #", 0, 127, 1, 8, true); - UI_PrintString("To Unlock", 0, 127, 3, 8, true); + UI_PrintString("Long Press #", gUI_Theme.Main.Lock0.X0, gUI_Theme.Main.Lock0.X1, gUI_Theme.Main.Lock0.Y, gUI_Theme.Main.Lock0.W, true); + UI_PrintString("To Unlock", gUI_Theme.Main.Lock1.X0, gUI_Theme.Main.Lock1.X1, gUI_Theme.Main.Lock1.Y, gUI_Theme.Main.Lock1.W, true); ST7565_BlitFullScreen(); return; } for (i = 0; i < 2; i++) { - uint8_t *pLine0; - uint8_t *pLine1; - uint8_t Line; uint8_t Channel; bool bIsSameVfo; - if (i == 0) { - pLine0 = gFrameBuffer[0]; - pLine1 = gFrameBuffer[1]; - Line = 0; - } else { - pLine0 = gFrameBuffer[4]; - pLine1 = gFrameBuffer[5]; - Line = 4; - } - Channel = gEeprom.TX_CHANNEL; bIsSameVfo = !!(Channel == i); @@ -91,7 +81,7 @@ void UI_DisplayMain(void) } else { sprintf(String, ">%s", gDTMF_InputBox); } - UI_PrintString(String, 2, 127, i * 3, 8, false); + UI_PrintString(String, gUI_Theme.Main.VfoState0[i].X0, gUI_Theme.Main.VfoState0[i].X1, gUI_Theme.Main.VfoState0[i].Y, gUI_Theme.Main.VfoState0[i].W, false); memset(String, 0, sizeof(String)); memset(Contact, 0, sizeof(Contact)); @@ -113,16 +103,16 @@ void UI_DisplayMain(void) sprintf(String, ">%s", gDTMF_String); } } - UI_PrintString(String, 2, 127, 2 + (i * 3), 8, false); + UI_PrintString(String, gUI_Theme.Main.VfoState1[i].X0, gUI_Theme.Main.VfoState1[i].X1, gUI_Theme.Main.VfoState1[i].Y, gUI_Theme.Main.VfoState1[i].W, false); continue; } else if (bIsSameVfo) { - memcpy(pLine0 + 2, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); + memcpy(GET_PTR(gUI_Theme.Main.VfoSelect[i]), BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); } } else { if (bIsSameVfo) { - memcpy(pLine0 + 2, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); + memcpy(GET_PTR(gUI_Theme.Main.VfoSelect[i]), BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); } else { - memcpy(pLine0 + 2, BITMAP_VFO_NotDefault, sizeof(BITMAP_VFO_NotDefault)); + memcpy(GET_PTR(gUI_Theme.Main.VfoSelect[i]), BITMAP_VFO_NotDefault, sizeof(BITMAP_VFO_NotDefault)); } } @@ -144,41 +134,41 @@ void UI_DisplayMain(void) } if (Channel == i) { SomeValue = 1; - memcpy(pLine0 + 14, BITMAP_TX, sizeof(BITMAP_TX)); + memcpy(GET_PTR(gUI_Theme.Main.RX_TX[i]), BITMAP_TX, sizeof(BITMAP_TX)); } } } else { SomeValue = 2; if ((gCurrentFunction == FUNCTION_RECEIVE || gCurrentFunction == FUNCTION_MONITOR) && gEeprom.RX_CHANNEL == i) { - memcpy(pLine0 + 14, BITMAP_RX, sizeof(BITMAP_RX)); + memcpy(GET_PTR(gUI_Theme.Main.RX_TX[i]), BITMAP_RX, sizeof(BITMAP_RX)); } } // 0x8F3C if (IS_MR_CHANNEL(gEeprom.ScreenChannel[i])) { - memcpy(pLine1 + 2, BITMAP_M, sizeof(BITMAP_M)); + memcpy(GET_PTR(gUI_Theme.Main.IconM[i]), BITMAP_M, sizeof(BITMAP_M)); if (gInputBoxIndex == 0 || gEeprom.TX_CHANNEL != i) { NUMBER_ToDigits(gEeprom.ScreenChannel[i] + 1, String); } else { memcpy(String + 5, gInputBox, 3); } - UI_DisplaySmallDigits(3, String + 5, 10, Line + 1); + UI_DisplaySmallDigits(gUI_Theme.Main.ChannelMR[i].Count, String + 5, gUI_Theme.Main.ChannelMR[i].X, gUI_Theme.Main.ChannelMR[i].Y); } else if (IS_FREQ_CHANNEL(gEeprom.ScreenChannel[i])) { char c; - memcpy(pLine1 + 14, BITMAP_F, sizeof(BITMAP_F)); + memcpy(GET_PTR(gUI_Theme.Main.IconF[i]), BITMAP_F, sizeof(BITMAP_F)); c = (gEeprom.ScreenChannel[i] - FREQ_CHANNEL_FIRST) + 1; - UI_DisplaySmallDigits(1, &c, 22, Line + 1); + UI_DisplaySmallDigits(gUI_Theme.Main.ChannelFreq[i].Count, &c, gUI_Theme.Main.ChannelFreq[i].X, gUI_Theme.Main.ChannelFreq[i].Y); } else { #if defined(ENABLE_NOAA) - memcpy(pLine1 + 7, BITMAP_NarrowBand, sizeof(BITMAP_NarrowBand)); + memcpy(GET_PTR(gUI_Theme.Main.IconN[i]), BITMAP_NarrowBand, sizeof(BITMAP_NarrowBand)); if (gInputBoxIndex == 0 || gEeprom.TX_CHANNEL != i) { NUMBER_ToDigits((gEeprom.ScreenChannel[i] - NOAA_CHANNEL_FIRST) + 1, String); } else { String[6] = gInputBox[0]; String[7] = gInputBox[1]; } - UI_DisplaySmallDigits(2, String + 6, 15, Line + 1); + UI_DisplaySmallDigits(gUI_Theme.Main.ChannelNOAA[i].Count, String + 6, gUI_Theme.Main.ChannelNOAA[i].X, gUI_Theme.Main.ChannelNOAA[i].Y); #endif } @@ -225,10 +215,10 @@ void UI_DisplayMain(void) Width = 8; break; } - UI_PrintString(String, 31, 111, i * 4, Width, true); + UI_PrintString(String, gUI_Theme.Main.VfoStatus[i].X0, gUI_Theme.Main.VfoStatus[i].X1, gUI_Theme.Main.VfoStatus[i].Y, Width, true); } else { if (gInputBoxIndex && IS_FREQ_CHANNEL(gEeprom.ScreenChannel[i]) && gEeprom.TX_CHANNEL == i) { - UI_DisplayFrequency(gInputBox, 31, i * 4, true, false); + UI_DisplayFrequency(gInputBox, gUI_Theme.Main.Freq[i].X, gUI_Theme.Main.Freq[i].Y, true, false); } else { if (!IS_MR_CHANNEL(gEeprom.ScreenChannel[i]) || gEeprom.CHANNEL_DISPLAY_MODE == MDF_FREQUENCY) { if (gCurrentFunction == FUNCTION_TRANSMIT) { @@ -245,26 +235,26 @@ void UI_DisplayMain(void) } else { NUMBER_ToDigits(gEeprom.VfoInfo[i].pRX->Frequency, String); } - UI_DisplayFrequency(String, 31, i * 4, false, false); + UI_DisplayFrequency(String, gUI_Theme.Main.Freq[i].X, gUI_Theme.Main.Freq[i].Y, false, false); if (IS_MR_CHANNEL(gEeprom.ScreenChannel[i])) { const uint8_t Attributes = gMR_ChannelAttributes[gEeprom.ScreenChannel[i]]; if (Attributes & MR_CH_SCANLIST1) { - memcpy(pLine0 + 113, BITMAP_ScanList, sizeof(BITMAP_ScanList)); + memcpy(GET_PTR(gUI_Theme.Main.IconSL1[i]), BITMAP_ScanList, sizeof(BITMAP_ScanList)); } if (Attributes & MR_CH_SCANLIST2) { - memcpy(pLine0 + 120, BITMAP_ScanList, sizeof(BITMAP_ScanList)); + memcpy(GET_PTR(gUI_Theme.Main.IconSL2[i]), BITMAP_ScanList, sizeof(BITMAP_ScanList)); } } - UI_DisplaySmallDigits(2, String + 6, 112, Line + 1); + UI_DisplaySmallDigits(gUI_Theme.Main.FreqSmall[i].Count, String + 6, gUI_Theme.Main.FreqSmall[i].X, gUI_Theme.Main.FreqSmall[i].Y); } else if (gEeprom.CHANNEL_DISPLAY_MODE == MDF_CHANNEL) { sprintf(String, "CH-%03d", gEeprom.ScreenChannel[i] + 1); - UI_PrintString(String, 31, 112, i * 4, 8, true); + UI_PrintString(String, gUI_Theme.Main.ChannelNum[i].X0, gUI_Theme.Main.ChannelNum[i].X1, gUI_Theme.Main.ChannelNum[i].Y, gUI_Theme.Main.ChannelNum[i].W, true); } else if (gEeprom.CHANNEL_DISPLAY_MODE == MDF_NAME) { if(gEeprom.VfoInfo[i].Name[0] == 0 || gEeprom.VfoInfo[i].Name[0] == 0xFF) { sprintf(String, "CH-%03d", gEeprom.ScreenChannel[i] + 1); - UI_PrintString(String, 31, 112, i * 4, 8, true); + UI_PrintString(String, gUI_Theme.Main.ChannelNum[i].X0, gUI_Theme.Main.ChannelNum[i].X1, gUI_Theme.Main.ChannelNum[i].Y, gUI_Theme.Main.ChannelNum[i].W, true); } else { - UI_PrintString(gEeprom.VfoInfo[i].Name, 31, 112, i * 4, 8, true); + UI_PrintString(gEeprom.VfoInfo[i].Name, gUI_Theme.Main.ChannelName[i].X0, gUI_Theme.Main.ChannelName[i].X1, gUI_Theme.Main.ChannelName[i].Y, gUI_Theme.Main.ChannelName[i].W, true); } } } @@ -289,28 +279,28 @@ void UI_DisplayMain(void) // TODO: not quite how the original does it, but it's quite entangled in Ghidra. if (Level) { - memcpy(pLine1 + 128 + 0, BITMAP_Antenna, sizeof(BITMAP_Antenna)); - memcpy(pLine1 + 128 + 5, BITMAP_AntennaLevel1, sizeof(BITMAP_AntennaLevel1)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Antenna[i][0]), BITMAP_Antenna, sizeof(BITMAP_Antenna)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Antenna[i][1]), BITMAP_AntennaLevel1, sizeof(BITMAP_AntennaLevel1)); if (Level >= 2) { - memcpy(pLine1 + 128 + 8, BITMAP_AntennaLevel2, sizeof(BITMAP_AntennaLevel2)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Antenna[i][2]), BITMAP_AntennaLevel2, sizeof(BITMAP_AntennaLevel2)); } if (Level >= 3) { - memcpy(pLine1 + 128 + 11, BITMAP_AntennaLevel3, sizeof(BITMAP_AntennaLevel3)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Antenna[i][3]), BITMAP_AntennaLevel3, sizeof(BITMAP_AntennaLevel3)); } if (Level >= 4) { - memcpy(pLine1 + 128 + 14, BITMAP_AntennaLevel4, sizeof(BITMAP_AntennaLevel4)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Antenna[i][4]), BITMAP_AntennaLevel4, sizeof(BITMAP_AntennaLevel4)); } if (Level >= 5) { - memcpy(pLine1 + 128 + 17, BITMAP_AntennaLevel5, sizeof(BITMAP_AntennaLevel5)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Antenna[i][5]), BITMAP_AntennaLevel5, sizeof(BITMAP_AntennaLevel5)); } if (Level >= 6) { - memcpy(pLine1 + 128 + 20, BITMAP_AntennaLevel6, sizeof(BITMAP_AntennaLevel6)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Antenna[i][6]), BITMAP_AntennaLevel6, sizeof(BITMAP_AntennaLevel6)); } } // 0x931E if (gEeprom.VfoInfo[i].IsAM) { - memcpy(pLine1 + 128 + 27, BITMAP_AM, sizeof(BITMAP_AM)); + memcpy(GET_PTR(gUI_Theme.Main.BM.AM[i]), BITMAP_AM, sizeof(BITMAP_AM)); } else { const FREQ_Config_t *pConfig; @@ -321,11 +311,11 @@ void UI_DisplayMain(void) } switch (pConfig->CodeType) { case CODE_TYPE_CONTINUOUS_TONE: - memcpy(pLine1 + 128 + 27, BITMAP_CT, sizeof(BITMAP_CT)); + memcpy(GET_PTR(gUI_Theme.Main.BM.CT[i]), BITMAP_CT, sizeof(BITMAP_CT)); break; case CODE_TYPE_DIGITAL: case CODE_TYPE_REVERSE_DIGITAL: - memcpy(pLine1 + 128 + 24, BITMAP_DCS, sizeof(BITMAP_DCS)); + memcpy(GET_PTR(gUI_Theme.Main.BM.DCS[i]), BITMAP_DCS, sizeof(BITMAP_DCS)); break; default: break; @@ -335,37 +325,37 @@ void UI_DisplayMain(void) // 0x936C switch (gEeprom.VfoInfo[i].OUTPUT_POWER) { case OUTPUT_POWER_LOW: - memcpy(pLine1 + 128 + 44, BITMAP_PowerLow, sizeof(BITMAP_PowerLow)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Power[i]), BITMAP_PowerLow, sizeof(BITMAP_PowerLow)); break; case OUTPUT_POWER_MID: - memcpy(pLine1 + 128 + 44, BITMAP_PowerMid, sizeof(BITMAP_PowerMid)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Power[i]), BITMAP_PowerMid, sizeof(BITMAP_PowerMid)); break; case OUTPUT_POWER_HIGH: - memcpy(pLine1 + 128 + 44, BITMAP_PowerHigh, sizeof(BITMAP_PowerHigh)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Power[i]), BITMAP_PowerHigh, sizeof(BITMAP_PowerHigh)); break; } if (gEeprom.VfoInfo[i].ConfigRX.Frequency != gEeprom.VfoInfo[i].ConfigTX.Frequency) { if (gEeprom.VfoInfo[i].FREQUENCY_DEVIATION_SETTING == FREQUENCY_DEVIATION_ADD) { - memcpy(pLine1 + 128 + 54, BITMAP_Add, sizeof(BITMAP_Add)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Offset[i]), BITMAP_Add, sizeof(BITMAP_Add)); } if (gEeprom.VfoInfo[i].FREQUENCY_DEVIATION_SETTING == FREQUENCY_DEVIATION_SUB) { - memcpy(pLine1 + 128 + 54, BITMAP_Sub, sizeof(BITMAP_Sub)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Offset[i]), BITMAP_Sub, sizeof(BITMAP_Sub)); } } if (gEeprom.VfoInfo[i].FrequencyReverse) { - memcpy(pLine1 + 128 + 64, BITMAP_ReverseMode, sizeof(BITMAP_ReverseMode)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Reverse[i]), BITMAP_ReverseMode, sizeof(BITMAP_ReverseMode)); } if (gEeprom.VfoInfo[i].CHANNEL_BANDWIDTH == BANDWIDTH_NARROW) { - memcpy(pLine1 + 128 + 74, BITMAP_NarrowBand, sizeof(BITMAP_NarrowBand)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Narrow[i]), BITMAP_NarrowBand, sizeof(BITMAP_NarrowBand)); } if (gEeprom.VfoInfo[i].DTMF_DECODING_ENABLE || gSetting_KILLED) { - memcpy(pLine1 + 128 + 84, BITMAP_DTMF, sizeof(BITMAP_DTMF)); + memcpy(GET_PTR(gUI_Theme.Main.BM.DTMF[i]), BITMAP_DTMF, sizeof(BITMAP_DTMF)); } if (gEeprom.VfoInfo[i].SCRAMBLING_TYPE && gSetting_ScrambleEnable) { - memcpy(pLine1 + 128 + 110, BITMAP_Scramble, sizeof(BITMAP_Scramble)); + memcpy(GET_PTR(gUI_Theme.Main.BM.Scramble[i]), BITMAP_Scramble, sizeof(BITMAP_Scramble)); } } diff --git a/ui/scanner.c b/ui/scanner.c index e93ca5fb..99336a4c 100644 --- a/ui/scanner.c +++ b/ui/scanner.c @@ -23,6 +23,7 @@ #include "misc.h" #include "ui/helper.h" #include "ui/scanner.h" +#include "ui/theme.h" void UI_DisplayScanner(void) { @@ -38,7 +39,7 @@ void UI_DisplayScanner(void) } else { sprintf(String, "FREQ:**.*****"); } - UI_PrintString(String, 2, 127, 1, 8, 0); + UI_PrintString(String, gUI_Theme.Scanner.Freq.X0, gUI_Theme.Scanner.Freq.X1, gUI_Theme.Scanner.Freq.Y, gUI_Theme.Scanner.Freq.W, 0); memset(String, 0, sizeof(String)); if (gScanCssState < SCAN_CSS_STATE_FOUND || !gScanUseCssResult) { @@ -48,7 +49,7 @@ void UI_DisplayScanner(void) } else { sprintf(String, "DCS:D%03oN", DCS_Options[gScanCssResultCode]); } - UI_PrintString(String, 2, 127, 3, 8, 0); + UI_PrintString(String, gUI_Theme.Scanner.Css.X0, gUI_Theme.Scanner.Css.X1, gUI_Theme.Scanner.Css.Y, gUI_Theme.Scanner.Css.W, 0); memset(String, 0, sizeof(String)); if (gScannerEditState == 2) { @@ -73,7 +74,7 @@ void UI_DisplayScanner(void) bCentered = 0; } - UI_PrintString(String, Start, 127, 5, 8, bCentered); + UI_PrintString(String, gUI_Theme.Scanner.Status.X0 + Start, gUI_Theme.Scanner.Status.X1, gUI_Theme.Scanner.Status.Y, gUI_Theme.Scanner.Status.W, bCentered); ST7565_BlitFullScreen(); } diff --git a/ui/status.c b/ui/status.c index c6b586d2..dee56ecb 100644 --- a/ui/status.c +++ b/ui/status.c @@ -26,60 +26,61 @@ #include "misc.h" #include "settings.h" #include "ui/status.h" +#include "ui/theme.h" void UI_DisplayStatus(void) { memset(gStatusLine, 0, sizeof(gStatusLine)); if (gCurrentFunction == FUNCTION_POWER_SAVE) { - memcpy(gStatusLine, BITMAP_PowerSave, sizeof(BITMAP_PowerSave)); + memcpy(gStatusLine + gUI_Theme.Status.PowerSave, BITMAP_PowerSave, sizeof(BITMAP_PowerSave)); } if (gBatteryDisplayLevel < 2) { if (gLowBatteryBlink == 1) { - memcpy(gStatusLine + 110, BITMAP_BatteryLevel1, sizeof(BITMAP_BatteryLevel1)); + memcpy(gStatusLine + gUI_Theme.Battery.X, BITMAP_BatteryLevel1, sizeof(BITMAP_BatteryLevel1)); } } else { if (gBatteryDisplayLevel == 2) { - memcpy(gStatusLine + 110, BITMAP_BatteryLevel2, sizeof(BITMAP_BatteryLevel2)); + memcpy(gStatusLine + gUI_Theme.Battery.X, BITMAP_BatteryLevel2, sizeof(BITMAP_BatteryLevel2)); } else if (gBatteryDisplayLevel == 3) { - memcpy(gStatusLine + 110, BITMAP_BatteryLevel3, sizeof(BITMAP_BatteryLevel3)); + memcpy(gStatusLine + gUI_Theme.Battery.X, BITMAP_BatteryLevel3, sizeof(BITMAP_BatteryLevel3)); } else if (gBatteryDisplayLevel == 4) { - memcpy(gStatusLine + 110, BITMAP_BatteryLevel4, sizeof(BITMAP_BatteryLevel4)); + memcpy(gStatusLine + gUI_Theme.Battery.X, BITMAP_BatteryLevel4, sizeof(BITMAP_BatteryLevel4)); } else { - memcpy(gStatusLine + 110, BITMAP_BatteryLevel5, sizeof(BITMAP_BatteryLevel5)); + memcpy(gStatusLine + gUI_Theme.Battery.X, BITMAP_BatteryLevel5, sizeof(BITMAP_BatteryLevel5)); } } if (gChargingWithTypeC) { - memcpy(gStatusLine + 100, BITMAP_USB_C, sizeof(BITMAP_USB_C)); + memcpy(gStatusLine + gUI_Theme.Status.Charging, BITMAP_USB_C, sizeof(BITMAP_USB_C)); } if (gEeprom.KEY_LOCK) { - memcpy(gStatusLine + 90, BITMAP_KeyLock, sizeof(BITMAP_KeyLock)); + memcpy(gStatusLine + gUI_Theme.Status.KeyLock, BITMAP_KeyLock, sizeof(BITMAP_KeyLock)); } else if (gWasFKeyPressed) { - memcpy(gStatusLine + 90, BITMAP_F_Key, sizeof(BITMAP_F_Key)); + memcpy(gStatusLine + gUI_Theme.Status.FKey, BITMAP_F_Key, sizeof(BITMAP_F_Key)); } if (gEeprom.VOX_SWITCH) { - memcpy(gStatusLine + 71, BITMAP_VOX, sizeof(BITMAP_VOX)); + memcpy(gStatusLine + gUI_Theme.Status.Vox, BITMAP_VOX, sizeof(BITMAP_VOX)); } if (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) { - memcpy(gStatusLine + 58, BITMAP_WX, sizeof(BITMAP_WX)); + memcpy(gStatusLine + gUI_Theme.Status.CrossBand, BITMAP_WX, sizeof(BITMAP_WX)); } if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF) { - memcpy(gStatusLine + 45, BITMAP_TDR, sizeof(BITMAP_TDR)); + memcpy(gStatusLine + gUI_Theme.Status.DualWatch, BITMAP_TDR, sizeof(BITMAP_TDR)); } if (gEeprom.VOICE_PROMPT != VOICE_PROMPT_OFF) { - memcpy(gStatusLine + 34, BITMAP_VoicePrompt, sizeof(BITMAP_VoicePrompt)); + memcpy(gStatusLine + gUI_Theme.Status.Prompt, BITMAP_VoicePrompt, sizeof(BITMAP_VoicePrompt)); } if (gSetting_KILLED) { - memset(gStatusLine + 21, 0xFF, 10); + memset(gStatusLine + gUI_Theme.Status.Killed, 0xFF, 10); } #if defined(ENABLE_FMRADIO) else if (gFmRadioMode) { - memcpy(gStatusLine + 21, BITMAP_FM, sizeof(BITMAP_FM)); + memcpy(gStatusLine + gUI_Theme.Status.FM, BITMAP_FM, sizeof(BITMAP_FM)); } #endif #if defined(ENABLE_NOAA) if (gIsNoaaMode) { - memcpy(gStatusLine + 7, BITMAP_NOAA, sizeof(BITMAP_NOAA)); + memcpy(gStatusLine + gUI_Theme.Status.NOAA, BITMAP_NOAA, sizeof(BITMAP_NOAA)); } #endif ST7565_BlitStatusLine(); diff --git a/ui/theme.c b/ui/theme.c new file mode 100644 index 00000000..5cdbe37a --- /dev/null +++ b/ui/theme.c @@ -0,0 +1,113 @@ +/* Copyright 2023 Dual Tachyon + * https://github.com/DualTachyon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ui/theme.h" + +UI_Theme_t gUI_Theme; + +#define LINE0 (0 * 128) +#define LINE1 (1 * 128) +#define LINE2 (2 * 128) +#define LINE3 (3 * 128) +#define LINE4 (4 * 128) +#define LINE5 (5 * 128) +#define LINE6 (6 * 128) + +const UI_Theme_t gUI_ThemeDefault = { + .Aircopy = { + .Status = { 2, 0, 127, 8 }, + .Freq = { 16, 2 }, + .Digits = { 97, 3, 2 }, + .Mode = { 2, 4, 127, 8 }, + }, + .Battery = { + .X = 110, + .Y = 0, + .Size = 18, + }, + .FM = { + .Title = { 0, 0, 127, 12 }, + .Status = { 0, 2, 127, 10 }, + .Freq = { 23, 4 }, + .Channel = { 0, 4, 127, 10 }, + }, + .Lock = { + .Title = { 0, 1, 127, 10 }, + .Code = { 0, 3, 127, 12 }, + }, + .Main = { + .Lock0 = { 0, 1, 127, 8 }, + .Lock1 = { 0, 3, 127, 8 }, + + .VfoState0 = { { 2, 0, 127, 8 }, { 2, 3, 127, 8 } }, + .VfoState1 = { { 2, 2, 127, 8 }, { 2, 5, 127, 8 } }, + + .VfoSelect = { LINE0 + 2, LINE4 + 2 }, + .RX_TX = { LINE0 + 14, LINE4 + 14 }, + .IconM = { LINE1 + 2, LINE5 + 2 }, + .IconF = { LINE1 + 14, LINE5 + 14 }, + .IconN = { LINE1 + 7, LINE5 + 7 }, + .IconSL1 = { LINE0 + 113, LINE1 + 113 }, + .IconSL2 = { LINE0 + 120, LINE1 + 120 }, + + .ChannelMR = { { 10, 1, 3 }, { 10, 5, 3 } }, + .ChannelFreq = { { 22, 1, 1 }, { 22, 5, 1 } }, + .ChannelNOAA = { { 15, 1, 2 }, { 15, 5, 2 } }, + .VfoStatus = { { 31, 0, 111, 0 }, { 31, 4, 111, 0 } }, // W is not used + .Freq = { { 31, 0 }, { 31, 4 } }, + .FreqSmall = { { 112, 1, 2 }, { 112, 5, 2 } }, + .ChannelNum = { { 31, 0, 112, 8 }, { 31, 4, 112, 8 } }, + .ChannelName = { { 31, 0, 112, 8 }, { 31, 4, 112, 8 } }, + .BM = { + .Antenna = { + { LINE2 + 0, LINE2 + 5, LINE2 + 8, LINE2 + 11, LINE2 + 14, LINE2 + 17, LINE2 + 20 }, + { LINE6 + 0, LINE6 + 5, LINE6 + 8, LINE6 + 11, LINE6 + 14, LINE6 + 17, LINE6 + 20 }, + }, + .AM = { LINE2 + 27, LINE6 + 27 }, + .CT = { LINE2 + 27, LINE6 + 27 }, + .DCS = { LINE2 + 24, LINE6 + 24 }, + .Power = { LINE2 + 44, LINE6 + 44 }, + .Offset = { LINE2 + 54, LINE6 + 54 }, + .Reverse = { LINE2 + 64, LINE6 + 64 }, + .Narrow = { LINE2 + 74, LINE6 + 74 }, + .DTMF = { LINE2 + 84, LINE6 + 84 }, + .Scramble = { LINE2 + 110, LINE6 + 110 }, + }, + }, + .Scanner = { + .Freq = { 2, 1, 127, 8 }, + .Css = { 2, 3, 127, 8 }, + .Status = { 0, 5, 127, 8 }, + }, + .Status = { + .PowerSave = 0, + .Charging = 100, + .KeyLock = 90, + .FKey = 90, + .Vox = 71, + .CrossBand = 58, + .DualWatch = 45, + .Prompt = 34, + .Killed = 21, + .FM = 21, + .NOAA = 7, + }, + .Welcome = { + .Line0 = { 0, 1, 127, 10 }, + .Line1 = { 0, 3, 127, 10 }, + }, +}; + diff --git a/ui/theme.h b/ui/theme.h new file mode 100644 index 00000000..ad9a770b --- /dev/null +++ b/ui/theme.h @@ -0,0 +1,122 @@ +/* Copyright 2023 Dual Tachyon + * https://github.com/DualTachyon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UI_THEME_H +#define UI_THEME_H + +#include + +typedef struct { + uint8_t X0, Y; + uint8_t X1, W; +} UI_ThemePrint_t; + +typedef struct { + uint8_t X, Y; +} UI_ThemeXY_t; + +typedef struct { + uint8_t X, Y; + uint8_t Count; +} UI_ThemeDigits_t; + +typedef struct { + uint8_t X, Y; + uint16_t Size; +} UI_ThemeLine_t; + +typedef struct { + struct { + UI_ThemePrint_t Status; + UI_ThemeXY_t Freq; + UI_ThemeDigits_t Digits; + UI_ThemePrint_t Mode; + } Aircopy; + UI_ThemeLine_t Battery; + struct { + UI_ThemePrint_t Title; + UI_ThemePrint_t Status; + UI_ThemeXY_t Freq; + UI_ThemePrint_t Channel; + } FM; + struct { + UI_ThemePrint_t Title; + UI_ThemePrint_t Code; + } Lock; + struct { + UI_ThemePrint_t Lock0; + UI_ThemePrint_t Lock1; + uint8_t VfoLine0[2]; + uint8_t VfoLine1[2]; + UI_ThemePrint_t VfoState0[2]; + UI_ThemePrint_t VfoState1[2]; + uint16_t VfoSelect[2]; + uint16_t RX_TX[2]; + uint16_t IconM[2]; + uint16_t IconF[2]; + uint16_t IconN[2]; + uint16_t IconSL1[2]; + uint16_t IconSL2[2]; + UI_ThemeDigits_t ChannelMR[2]; + UI_ThemeDigits_t ChannelFreq[2]; + UI_ThemeDigits_t ChannelNOAA[2]; + UI_ThemePrint_t VfoStatus[2]; + UI_ThemeXY_t Freq[2]; + UI_ThemeDigits_t FreqSmall[2]; + UI_ThemePrint_t ChannelNum[2]; + UI_ThemePrint_t ChannelName[2]; + struct { + uint16_t Antenna[2][7]; + uint16_t AM[2]; + uint16_t CT[2]; + uint16_t DCS[2]; + uint16_t Power[2]; + uint16_t Offset[2]; + uint16_t Reverse[2]; + uint16_t Narrow[2]; + uint16_t DTMF[2]; + uint16_t Scramble[2]; + } BM; + } Main; + struct { + UI_ThemePrint_t Freq; + UI_ThemePrint_t Css; + UI_ThemePrint_t Status; + } Scanner; + struct { + uint8_t PowerSave; + uint8_t Charging; + uint8_t KeyLock; + uint8_t FKey; + uint8_t Vox; + uint8_t CrossBand; + uint8_t DualWatch; + uint8_t Prompt; + uint8_t Killed; + uint8_t FM; + uint8_t NOAA; + } Status; + struct { + UI_ThemePrint_t Line0; + UI_ThemePrint_t Line1; + } Welcome; +} UI_Theme_t; + +extern UI_Theme_t gUI_Theme; +extern const UI_Theme_t gUI_ThemeDefault; + +#endif + diff --git a/ui/welcome.c b/ui/welcome.c index d495cdbb..ef3dcac3 100644 --- a/ui/welcome.c +++ b/ui/welcome.c @@ -21,6 +21,7 @@ #include "helper/battery.h" #include "settings.h" #include "ui/helper.h" +#include "ui/theme.h" #include "ui/welcome.h" #include "version.h" @@ -44,8 +45,8 @@ void UI_DisplayWelcome(void) EEPROM_ReadBuffer(0x0EB0, WelcomeString0, 16); EEPROM_ReadBuffer(0x0EC0, WelcomeString1, 16); } - UI_PrintString(WelcomeString0, 0, 127, 1, 10, true); - UI_PrintString(WelcomeString1, 0, 127, 3, 10, true); + UI_PrintString(WelcomeString0, gUI_Theme.Welcome.Line0.X0, gUI_Theme.Welcome.Line0.X1, gUI_Theme.Welcome.Line0.Y, gUI_Theme.Welcome.Line0.W, true); + UI_PrintString(WelcomeString1, gUI_Theme.Welcome.Line1.X0, gUI_Theme.Welcome.Line1.X1, gUI_Theme.Welcome.Line1.Y, gUI_Theme.Welcome.Line1.W, true); UI_PrintString(Version, 0, 127, 5, 10, true); ST7565_BlitStatusLine(); ST7565_BlitFullScreen();