Fixed a crash in touch handling for star-button when the current directory is empty (no menu entries). Implemented layouts which can optionally be loaded from theme config, closes #83.

This commit is contained in:
yellows8 2019-12-26 01:40:54 -05:00
parent 387850d301
commit b40d558458
No known key found for this signature in database
GPG Key ID: 0AF90DA3F1E60E43
8 changed files with 668 additions and 156 deletions

View File

@ -47,6 +47,48 @@ typedef union {
}; };
} color_t; } color_t;
typedef enum
{
ThemeLayoutId_Logo,
ThemeLayoutId_HbmenuVersion,
ThemeLayoutId_LoaderInfo,
ThemeLayoutId_AttentionText,
ThemeLayoutId_LogInfo,
ThemeLayoutId_InfoMsg,
ThemeLayoutId_MenuPath,
ThemeLayoutId_MenuTypeMsg,
ThemeLayoutId_MsgBoxSeparator,
ThemeLayoutId_MsgBoxBottomText,
ThemeLayoutId_BackWave,
ThemeLayoutId_MiddleWave,
ThemeLayoutId_FrontWave,
ThemeLayoutId_ButtonA,
ThemeLayoutId_ButtonAText,
ThemeLayoutId_ButtonB,
ThemeLayoutId_ButtonBText,
ThemeLayoutId_ButtonY,
ThemeLayoutId_ButtonYText,
ThemeLayoutId_ButtonM,
ThemeLayoutId_ButtonMText,
ThemeLayoutId_ButtonX,
ThemeLayoutId_ButtonXText,
ThemeLayoutId_NetworkIcon,
ThemeLayoutId_BatteryCharge,
ThemeLayoutId_BatteryIcon,
ThemeLayoutId_ChargingIcon,
ThemeLayoutId_Status,
ThemeLayoutId_Temperature,
ThemeLayoutId_MenuList,
ThemeLayoutId_MenuListTiles,
ThemeLayoutId_MenuListIcon,
ThemeLayoutId_MenuListName,
ThemeLayoutId_MenuActiveEntryIcon,
ThemeLayoutId_MenuActiveEntryName,
ThemeLayoutId_MenuActiveEntryAuthor,
ThemeLayoutId_MenuActiveEntryVersion,
ThemeLayoutId_Total,
} ThemeLayoutId;
// when building for pc we need to include these separately // when building for pc we need to include these separately
#ifndef __SWITCH__ #ifndef __SWITCH__
#include "switch/nro.h" #include "switch/nro.h"
@ -163,6 +205,8 @@ static inline color_t FetchPixelColor(uint32_t x, uint32_t y)
void DrawPixel(uint32_t x, uint32_t y, color_t clr); void DrawPixel(uint32_t x, uint32_t y, color_t clr);
void DrawText(u32 font, uint32_t x, uint32_t y, color_t clr, const char* text); void DrawText(u32 font, uint32_t x, uint32_t y, color_t clr, const char* text);
void DrawTextFromLayout(ThemeLayoutId id, color_t clr, const char* text);
void DrawTextFromLayoutRelative(ThemeLayoutId id, int base_x, int base_y, int *inPos, int *outPos, color_t clr, const char* text, const char align);
void DrawTextTruncate(u32 font, uint32_t x, uint32_t y, color_t clr, const char* text, uint32_t max_width, const char* end_text); void DrawTextTruncate(u32 font, uint32_t x, uint32_t y, color_t clr, const char* text, uint32_t max_width, const char* end_text);
void GetTextDimensions(u32 font, const char* text, uint32_t* width_out, uint32_t* height_out); void GetTextDimensions(u32 font, const char* text, uint32_t* width_out, uint32_t* height_out);
uint32_t GetTextXCoordinate(u32 font, uint32_t rX, const char* text, const char align); uint32_t GetTextXCoordinate(u32 font, uint32_t rX, const char* text, const char align);

View File

@ -276,6 +276,38 @@ void DrawText(u32 font, uint32_t x, uint32_t y, color_t clr, const char* text)
DrawText_(font, x, y, clr, text, 0, NULL); DrawText_(font, x, y, clr, text, 0, NULL);
} }
void DrawTextFromLayout(ThemeLayoutId id, color_t clr, const char* text)
{
ThemeLayoutObject *obj = &themeCurrent.layoutObjects[id];
if (!obj->visible) return;
DrawText(obj->font, obj->posStart[0], obj->posStart[1], clr, text);
}
void DrawTextFromLayoutRelative(ThemeLayoutId id, int base_x, int base_y, int *inPos, int *outPos, color_t clr, const char* text, const char align)
{
ThemeLayoutObject *obj = &themeCurrent.layoutObjects[id];
base_x = obj->posType ? base_x + inPos[0] : inPos[0];
base_y = obj->posType ? base_y + inPos[1] : inPos[1];
base_x = GetTextXCoordinate(obj->font, base_x, text, align);
if (outPos) {
outPos[0] = base_x;
outPos[1] = base_y;
}
obj->posFinal[0] = base_x;
obj->posFinal[1] = base_y;
if (!obj->visible) return;
GetTextDimensions(obj->font, text, &obj->textSize[0], &obj->textSize[1]);
DrawText(obj->font, base_x, base_y, clr, text);
}
void DrawTextTruncate(u32 font, uint32_t x, uint32_t y, color_t clr, const char* text, uint32_t max_width, const char* end_text) void DrawTextTruncate(u32 font, uint32_t x, uint32_t y, color_t clr, const char* text, uint32_t max_width, const char* end_text)
{ {
DrawText_(font, x, y, clr, text, max_width, end_text); DrawText_(font, x, y, clr, text, max_width, end_text);

View File

@ -150,6 +150,12 @@ static void drawImage(int x, int y, int width, int height, const uint8_t *image,
} }
} }
static void drawImageFromLayout(ThemeLayoutId id, const uint8_t *image, ImageMode mode) {
ThemeLayoutObject *obj = &themeCurrent.layoutObjects[id];
if (!obj->visible) return;
drawImage(obj->posStart[0], obj->posStart[1], obj->imageSize[0], obj->imageSize[1], image, mode);
}
//Draws an RGBA8888 image masked by the passed color. //Draws an RGBA8888 image masked by the passed color.
static void drawIcon(int x, int y, int width, int height, const uint8_t *image, color_t color) { static void drawIcon(int x, int y, int width, int height, const uint8_t *image, color_t color) {
int tmpx, tmpy; int tmpx, tmpy;
@ -170,11 +176,12 @@ uint8_t *invalid_icon_small;
uint8_t *theme_icon_small; uint8_t *theme_icon_small;
static void drawEntry(menuEntry_s* me, int off_x, int is_active) { static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuList];
int x, y; int x, y;
int start_y = 720 - 100 - 145;//*(n % 2); int start_y = layoutobj->posStart[1];//*(n % 2);
int end_y = start_y + 140 + 32; int end_y = start_y + layoutobj->size[1];
int start_x = off_x;//(n / 2); int start_x = off_x;//(n / 2);
int end_x = start_x + 140; int end_x = start_x + layoutobj->size[0];
int j; int j;
const uint8_t *smallimg = NULL; const uint8_t *smallimg = NULL;
@ -287,15 +294,17 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
} }
if (smallimg) { if (smallimg) {
drawImage(start_x, start_y + 32, 140, 140, smallimg, IMAGE_MODE_RGB24); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListIcon];
drawImage(start_x + layoutobj->posStart[0], start_y + layoutobj->posStart[1], layoutobj->imageSize[0], layoutobj->imageSize[1], smallimg, IMAGE_MODE_RGB24);
} }
if (is_active && largeimg) { layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon];
drawImage(117, 100+10, 256, 256, largeimg, IMAGE_MODE_RGB24); if (is_active && largeimg && layoutobj->visible) {
drawImage(layoutobj->posStart[0], layoutobj->posStart[1], layoutobj->imageSize[0], layoutobj->imageSize[1], largeimg, IMAGE_MODE_RGB24);
shadow_start_y = 100+10+256; shadow_start_y = layoutobj->posStart[1]+layoutobj->imageSize[1];
border_start_x = 117; border_start_x = layoutobj->posStart[0];
border_end_x = 117+256; border_end_x = layoutobj->posStart[0]+layoutobj->imageSize[0];
for (shadow_y=shadow_start_y; shadow_y <shadow_start_y+shadow_size; shadow_y++) { for (shadow_y=shadow_start_y; shadow_y <shadow_start_y+shadow_size; shadow_y++) {
for (x=border_start_x; x<border_end_x; x++) { for (x=border_start_x; x<border_end_x; x++) {
@ -317,21 +326,23 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
memset(tmpstr, 0, sizeof(tmpstr)); memset(tmpstr, 0, sizeof(tmpstr));
snprintf(tmpstr, sizeof(tmpstr)-1, "%s%s", strptr, me->name); snprintf(tmpstr, sizeof(tmpstr)-1, "%s%s", strptr, me->name);
DrawTextTruncate(interuiregular14, start_x + 4, start_y + 4 + 18, themeCurrent.borderTextColor, tmpstr, 140 - 32, "..."); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListName];
DrawTextTruncate(layoutobj->font, start_x + layoutobj->posStart[0], start_y + layoutobj->posStart[1], themeCurrent.borderTextColor, tmpstr, layoutobj->size[0], "...");
if (is_active) { if (is_active) {
start_x = 1280 - 790; layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryName];
start_y = 135+10; if (layoutobj->visible) DrawTextTruncate(layoutobj->font, layoutobj->posStart[0], layoutobj->posStart[1], themeCurrent.textColor, tmpstr, layoutobj->size[0], "...");
DrawTextTruncate(interuimedium30, start_x, start_y + 39, themeCurrent.textColor, tmpstr, 1280 - start_x - 120 ,"...");
if (me->type != ENTRY_TYPE_FOLDER) { if (me->type != ENTRY_TYPE_FOLDER) {
memset(tmpstr, 0, sizeof(tmpstr)); memset(tmpstr, 0, sizeof(tmpstr));
snprintf(tmpstr, sizeof(tmpstr)-1, "%s: %s", textGetString(StrId_AppInfo_Author), me->author); snprintf(tmpstr, sizeof(tmpstr)-1, "%s: %s", textGetString(StrId_AppInfo_Author), me->author);
DrawText(interuiregular14, start_x, start_y + 28 + 30 + 18, themeCurrent.textColor, tmpstr); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryAuthor];
if (layoutobj->visible) DrawText(layoutobj->font, layoutobj->posStart[0], layoutobj->posStart[1], themeCurrent.textColor, tmpstr);
memset(tmpstr, 0, sizeof(tmpstr)); memset(tmpstr, 0, sizeof(tmpstr));
snprintf(tmpstr, sizeof(tmpstr)-1, "%s: %s", textGetString(StrId_AppInfo_Version), me->version); snprintf(tmpstr, sizeof(tmpstr)-1, "%s: %s", textGetString(StrId_AppInfo_Version), me->version);
DrawText(interuiregular14, start_x, start_y + 28 + 30 + 18 + 6 + 18, themeCurrent.textColor, tmpstr); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryVersion];
if (layoutobj->visible) DrawText(layoutobj->font, layoutobj->posStart[0], layoutobj->posStart[1], themeCurrent.textColor, tmpstr);
} }
} }
} }
@ -344,6 +355,8 @@ void computeFrontGradient(color_t baseColor, int height) {
float dark_mult, dark_sub = 75; float dark_mult, dark_sub = 75;
color_t color; color_t color;
if (height < 0 || height > 720) return;
for (y=0; y<720; y++) { for (y=0; y<720; y++) {
alpha = y - (720 - height); alpha = y - (720 - height);
@ -429,6 +442,7 @@ void drawWave(int id, float timer, color_t color, int height, float phase, float
float wave_top_y, alpha, one_minus_alpha; float wave_top_y, alpha, one_minus_alpha;
color_t existing_color, new_color; color_t existing_color, new_color;
if (height < 0 || height > 720) return;
height = 720 - height; height = 720 - height;
for (x=0; x<1280; x++) { for (x=0; x<1280; x++) {
@ -478,17 +492,25 @@ void drawCharge() {
sprintf(chargeString, "%d%%", batteryCharge); sprintf(chargeString, "%d%%", batteryCharge);
int tmpX = GetTextXCoordinate(interuiregular14, 1180 - 10, chargeString, 'r'); ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_BatteryCharge];
DrawText(interuiregular14, tmpX - 24 - 8, 0 + 47 + 10 + 21 + 4, themeCurrent.textColor, chargeString); if (layoutobj->visible) {
drawIcon(1180 - 8 - 24 - 8, 0 + 47 + 10 + 6, 24, 24, assetsGetDataBuffer(AssetId_battery_icon), themeCurrent.textColor); int tmpX = GetTextXCoordinate(layoutobj->font, layoutobj->posStart[0], chargeString, 'r');
if (isCharging) DrawText(layoutobj->font, tmpX, layoutobj->posStart[1], themeCurrent.textColor, chargeString);
drawIcon(1180 - 20, 0 + 47 + 10 + 6, 24, 24, assetsGetDataBuffer(AssetId_charging_icon), themeCurrent.textColor); }
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_BatteryIcon];
if (layoutobj->visible) drawIcon(layoutobj->posStart[0], layoutobj->posStart[1], layoutobj->imageSize[0], layoutobj->imageSize[1], assetsGetDataBuffer(AssetId_battery_icon), themeCurrent.textColor);
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ChargingIcon];
if (isCharging && layoutobj->visible)
drawIcon(layoutobj->posStart[0], layoutobj->posStart[1], layoutobj->imageSize[0], layoutobj->imageSize[1], assetsGetDataBuffer(AssetId_charging_icon), themeCurrent.textColor);
} }
} }
void drawNetwork(int tmpX, AssetId id) { void drawNetwork(int tmpX, AssetId id) {
drawIcon(tmpX, 0 + 47 + 10 + 3, 24, 24, assetsGetDataBuffer(id), themeCurrent.textColor); ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_NetworkIcon];
if (layoutobj->visible) drawIcon(layoutobj->posType ? tmpX + layoutobj->posStart[0] : layoutobj->posStart[0], layoutobj->posStart[1], layoutobj->imageSize[0], layoutobj->imageSize[1], assetsGetDataBuffer(id), themeCurrent.textColor);
} }
u32 drawStatus() { u32 drawStatus() {
@ -508,9 +530,11 @@ u32 drawStatus() {
snprintf(tmpstr, sizeof(tmpstr)-1, "%02d:%02d:%02d", hours, minutes, seconds); snprintf(tmpstr, sizeof(tmpstr)-1, "%02d:%02d:%02d", hours, minutes, seconds);
u32 tmpX = GetTextXCoordinate(interuimedium20, 1180, tmpstr, 'r'); ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_Status];
DrawText(interuimedium20, tmpX, 0 + 47 + 10, themeCurrent.textColor, tmpstr); u32 tmpX = GetTextXCoordinate(layoutobj->font, layoutobj->posStart[0], tmpstr, 'r');
if (layoutobj->visible) DrawText(layoutobj->font, tmpX, layoutobj->posStart[1], themeCurrent.textColor, tmpstr);
drawCharge(); drawCharge();
@ -518,21 +542,19 @@ u32 drawStatus() {
if (netstatusFlag) drawNetwork(tmpX, id); if (netstatusFlag) drawNetwork(tmpX, id);
if (temperatureFlag) { if (temperatureFlag) {
snprintf(tmpstr, sizeof(tmpstr)-1, "%.1f°C", ((float)temperature) / 1000); snprintf(tmpstr, sizeof(tmpstr)-1, "%.1f°C", ((float)temperature) / 1000);
DrawText(interuiregular14, 1180 + 4, 0 + 47 + 10 + + 21 + 6, themeCurrent.textColor, tmpstr); DrawTextFromLayout(ThemeLayoutId_Temperature, themeCurrent.textColor, tmpstr);
} }
} }
return tmpX; return tmpX;
} }
void drawButtons(menu_s* menu, bool emptyDir, int *x_image_out) { void drawButtons(menu_s* menu, bool emptyDir, int *out_basePos) {
int x_image = 1280 - 252 - 30 - 32; ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonA];
int x_text = 1280 - 216 - 30 - 32; int basePos[2]={0};
if(emptyDir) { basePos[0] = layoutobj->posStart[0];
x_image = 1280 - 126 - 30 - 32; basePos[1] = layoutobj->posStart[1];
x_text = 1280 - 90 - 30 - 32;
}
#ifdef __SWITCH__ #ifdef __SWITCH__
if (strcmp( menu->dirname, "sdmc:/") != 0) if (strcmp( menu->dirname, "sdmc:/") != 0)
@ -540,27 +562,26 @@ void drawButtons(menu_s* menu, bool emptyDir, int *x_image_out) {
if (strcmp( menu->dirname, "/") != 0) if (strcmp( menu->dirname, "/") != 0)
#endif #endif
{ {
//drawImage(x_image, 720 - 48, 32, 32, themeCurrent.buttonBImage, IMAGE_MODE_RGBA32); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonBText];
DrawText(fontscale7, x_image, 720 - 47 + 24, themeCurrent.textColor, themeCurrent.buttonBText);//Display the 'B' button from SharedFont. DrawTextFromLayoutRelative(ThemeLayoutId_ButtonBText, basePos[0], basePos[1], !emptyDir ? layoutobj->posStart : layoutobj->posEnd, basePos, themeCurrent.textColor, textGetString(StrId_Actions_Back), 'l');
DrawText(interuiregular18, x_text, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_Actions_Back)); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonB];
DrawTextFromLayoutRelative(ThemeLayoutId_ButtonB, basePos[0], basePos[1], layoutobj->posStart, basePos, themeCurrent.textColor, themeCurrent.buttonBText, 'l');
} }
if(hbmenu_state == HBMENU_DEFAULT) if(hbmenu_state == HBMENU_DEFAULT)
{ {
x_text = GetTextXCoordinate(interuiregular18, x_image - 32, textGetString(StrId_NetLoader), 'r'); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonYText];
x_image = x_text - 36; DrawTextFromLayoutRelative(ThemeLayoutId_ButtonYText, basePos[0], basePos[1], layoutobj->posStart, basePos, themeCurrent.textColor, textGetString(StrId_NetLoader), 'r');
*x_image_out = x_image - 40; layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonY];
DrawTextFromLayoutRelative(ThemeLayoutId_ButtonY, basePos[0], basePos[1], layoutobj->posStart, basePos, themeCurrent.textColor, themeCurrent.buttonYText, 'l');
DrawText(fontscale7, x_image, 720 - 47 + 24, themeCurrent.textColor, themeCurrent.buttonYText); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonMText];
DrawText(interuiregular18, x_text, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_NetLoader)); DrawTextFromLayoutRelative(ThemeLayoutId_ButtonMText, basePos[0], basePos[1], layoutobj->posStart, basePos, themeCurrent.textColor, textGetString(StrId_ThemeMenu), 'r');
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonM];
x_text = GetTextXCoordinate(interuiregular18, x_image - 32, textGetString(StrId_ThemeMenu), 'r'); DrawTextFromLayoutRelative(ThemeLayoutId_ButtonM, basePos[0], basePos[1], layoutobj->posStart, basePos, themeCurrent.textColor, themeCurrent.buttonMText, 'l');
x_image = x_text - 36;
*x_image_out = x_image - 40;
DrawText(fontscale7, x_image, 720 - 47 + 24, themeCurrent.textColor, themeCurrent.buttonMText);
DrawText(interuiregular18, x_text, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_ThemeMenu));
} }
out_basePos[0] = basePos[0];
out_basePos[1] = basePos[1];
} }
void menuUpdateNetloader(netloaderState *netloader_state) { void menuUpdateNetloader(netloaderState *netloader_state) {
@ -595,44 +616,60 @@ void menuLoop(void) {
menuEntry_s* me; menuEntry_s* me;
menu_s* menu = NULL; menu_s* menu = NULL;
int i; int i;
int x, y; int x, y, endy = 720;
int menupath_x_endpos = 918 + 40; int curPos[2]={0};
netloaderState netloader_state; netloaderState netloader_state;
ThemeLayoutObject *layoutobj = NULL;
for (y=0; y<450; y++) { for (i=0; i<3; i++) {
if (i==2) layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_BackWave];
if (i==1) layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MiddleWave];
if (i==0) layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_FrontWave];
if (layoutobj->visible && layoutobj->size[1] >= 0 && layoutobj->size[1] <= 720-10) {
endy = 720 - layoutobj->size[1] + 10;
break;
}
}
for (y=0; y<endy; y++) {
for (x=0; x<1280; x+=4) {// don't draw bottom pixels as they are covered by the waves for (x=0; x<1280; x+=4) {// don't draw bottom pixels as they are covered by the waves
Draw4PixelsRaw(x, y, themeCurrent.backgroundColor); Draw4PixelsRaw(x, y, themeCurrent.backgroundColor);
} }
} }
drawWave(0, menuTimer, themeCurrent.backWaveColor, 295, 0.0, 3.0); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_BackWave];
drawWave(1, menuTimer, themeCurrent.middleWaveColor, 290, 2.0, 3.5); if (layoutobj->visible) drawWave(0, menuTimer, themeCurrent.backWaveColor, layoutobj->size[1], 0.0, 3.0);
drawWave(2, menuTimer, themeCurrent.frontWaveColor, 280, 4.0, -2.5); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MiddleWave];
if (layoutobj->visible) drawWave(1, menuTimer, themeCurrent.middleWaveColor, layoutobj->size[1], 2.0, 3.5);
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_FrontWave];
if (layoutobj->visible) drawWave(2, menuTimer, themeCurrent.frontWaveColor, layoutobj->size[1], 4.0, -2.5);
menuTimer += 0.05; menuTimer += 0.05;
drawImage(40, 20, 140, 60, themeCurrent.hbmenuLogoImage, IMAGE_MODE_RGBA32); drawImageFromLayout(ThemeLayoutId_Logo, themeCurrent.hbmenuLogoImage, IMAGE_MODE_RGBA32);
DrawText(interuiregular14, 184, 46 + 18, themeCurrent.textColor, VERSION); DrawTextFromLayout(ThemeLayoutId_HbmenuVersion, themeCurrent.textColor, VERSION);
u32 statusXPos = drawStatus(); u32 statusXPos = drawStatus();
#ifdef __SWITCH__ #ifdef __SWITCH__
AppletType at = appletGetAppletType(); AppletType at = appletGetAppletType();
if (at != AppletType_Application && at != AppletType_SystemApplication) { layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_AttentionText];
if (at != AppletType_Application && at != AppletType_SystemApplication && layoutobj->visible) {
const char* appletMode = textGetString(StrId_AppletMode); const char* appletMode = textGetString(StrId_AppletMode);
u32 x_pos = GetTextXCoordinate(interuimedium30, statusXPos, appletMode, 'r'); u32 x_pos = GetTextXCoordinate(layoutobj->font, statusXPos, appletMode, 'r');
DrawText(interuimedium30, x_pos - 32, 46 + 18, themeCurrent.attentionTextColor, appletMode); DrawText(layoutobj->font, layoutobj->posType ? x_pos + layoutobj->posStart[0] : layoutobj->posStart[0], layoutobj->posStart[1], themeCurrent.attentionTextColor, appletMode);
} }
const char* loaderInfo = envGetLoaderInfo(); const char* loaderInfo = envGetLoaderInfo();
if (loaderInfo) { layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_LoaderInfo];
u32 x_pos = 43; if (loaderInfo && layoutobj->visible) {
u32 x_pos = layoutobj->posStart[0];
char* spacePos = strchr(loaderInfo, ' '); char* spacePos = strchr(loaderInfo, ' ');
if (spacePos) { if (spacePos) {
char tempbuf[64] = {0}; char tempbuf[64] = {0};
size_t tempsize = spacePos - loaderInfo + 1; size_t tempsize = spacePos - loaderInfo + 1;
if (tempsize > sizeof(tempbuf)-1) tempsize = sizeof(tempbuf)-1; if (tempsize > sizeof(tempbuf)-1) tempsize = sizeof(tempbuf)-1;
memcpy(tempbuf, loaderInfo, tempsize); memcpy(tempbuf, loaderInfo, tempsize);
x_pos = GetTextXCoordinate(interuiregular14, 184, tempbuf, 'r'); x_pos = GetTextXCoordinate(layoutobj->font, layoutobj->posEnd[0], tempbuf, 'r');
} }
DrawText(interuiregular14, x_pos, 46 + 18 + 20, themeCurrent.textColor, loaderInfo); DrawText(layoutobj->font, x_pos, layoutobj->posStart[1], themeCurrent.textColor, loaderInfo);
} }
#endif #endif
@ -642,7 +679,7 @@ void menuLoop(void) {
char tmpstr[64]; char tmpstr[64];
snprintf(tmpstr, sizeof(tmpstr)-1, "%lu", g_tickdiff_frame); snprintf(tmpstr, sizeof(tmpstr)-1, "%lu", g_tickdiff_frame);
DrawText(interuiregular14, 180 + 256, 46 + 16 + 18, themeCurrent.textColor, tmpstr); DrawTextFromLayout(ThemeLayoutId_LogInfo, themeCurrent.textColor, tmpstr);
#endif #endif
memset(&netloader_state, 0, sizeof(netloader_state)); memset(&netloader_state, 0, sizeof(netloader_state));
@ -680,16 +717,19 @@ void menuLoop(void) {
launchMenuEntryTask(netloader_state.me); launchMenuEntryTask(netloader_state.me);
} }
} else { } else {
DrawText(interuiregular14, 64, 128 + 18, themeCurrent.textColor, textGetString(StrId_NoAppsFound_Msg)); DrawTextFromLayout(ThemeLayoutId_InfoMsg, themeCurrent.textColor, textGetString(StrId_NoAppsFound_Msg));
} }
drawButtons(menu, true, &menupath_x_endpos); drawButtons(menu, true, curPos);
} }
else else
{ {
static int v = 0; static int v = 0;
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListTiles];
int entries_count = layoutobj->posEnd[0];
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuList];
if (menu->nEntries > 7) { if (menu->nEntries > entries_count) {
int wanted_x = clamp(-menu->curEntry * (140 + 30), -(menu->nEntries - 7) * (140 + 30), 0); int wanted_x = clamp(-menu->curEntry * layoutobj->posEnd[0], -(menu->nEntries - entries_count) * layoutobj->posEnd[0], 0);
menu->xPos += v; menu->xPos += v;
v += (wanted_x - menu->xPos) / 3; v += (wanted_x - menu->xPos) / 3;
v /= 2; v /= 2;
@ -702,7 +742,7 @@ void menuLoop(void) {
// Draw menu entries // Draw menu entries
for (me = menu->firstEntry, i = 0; me; me = me->next, i ++) { for (me = menu->firstEntry, i = 0; me; me = me->next, i ++) {
int entry_start_x = 29 + i * (140 + 30); int entry_start_x = layoutobj->posStart[0] + i * layoutobj->posEnd[0];
int entry_draw_x = entry_start_x + menu->xPos; int entry_draw_x = entry_start_x + menu->xPos;
int screen_width = 1280; int screen_width = 1280;
@ -714,54 +754,61 @@ void menuLoop(void) {
if (is_active) if (is_active)
active_entry = me; active_entry = me;
if (!is_active && entry_draw_x < -(29 + 140 + 30)) if (!is_active && entry_draw_x < -(layoutobj->posStart[0] + layoutobj->posEnd[0]))
continue; continue;
drawEntry(me, entry_draw_x, is_active); drawEntry(me, entry_draw_x, is_active);
} }
int getX = GetTextXCoordinate(interuiregular18, 1180, textGetString(StrId_ThemeMenu), 'r'); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuTypeMsg];
int getX=0;
if (layoutobj->visible) {
getX = GetTextXCoordinate(layoutobj->font, layoutobj->posStart[0], textGetString(StrId_ThemeMenu), 'r');
if(hbmenu_state == HBMENU_THEME_MENU) { if(hbmenu_state == HBMENU_THEME_MENU) {
DrawText(interuiregular18, getX, 30 + 26 + 32 + 20, themeCurrent.textColor, textGetString(StrId_ThemeMenu)); DrawText(layoutobj->font, getX, layoutobj->posStart[1], themeCurrent.textColor, textGetString(StrId_ThemeMenu));
} else { } else {
//DrawText(interuiregular18, getX, 30 + 26 + 32 + 10, themeCurrent.textColor, textGetString(StrId_ThemeMenu)); //DrawText(interuiregular18, getX, 30 + 26 + 32 + 10, themeCurrent.textColor, textGetString(StrId_ThemeMenu));
//DrawText(fontscale7, getX - 40, 30 + 26 + 32 + 10, themeCurrent.textColor, themeCurrent.buttonMText); //DrawText(fontscale7, getX - 40, 30 + 26 + 32 + 10, themeCurrent.textColor, themeCurrent.buttonMText);
} }
}
if(active_entry != NULL) { if(active_entry != NULL) {
if (active_entry->type == ENTRY_TYPE_THEME) { const char *buttonstr = "";
DrawText(fontscale7, 1280 - 126 - 30 - 32, 720 - 47 + 24, themeCurrent.textColor, themeCurrent.buttonAText);
DrawText(interuiregular18, 1280 - 90 - 30 - 32, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_Actions_Apply)); if (active_entry->type == ENTRY_TYPE_THEME)
} buttonstr = textGetString(StrId_Actions_Apply);
else if (active_entry->type != ENTRY_TYPE_FOLDER) { else if (active_entry->type != ENTRY_TYPE_FOLDER)
DrawText(fontscale7, 1280 - 126 - 30 - 32, 720 - 47 + 24, themeCurrent.textColor, themeCurrent.buttonAText);//Display the 'A' button from SharedFont. buttonstr = textGetString(StrId_Actions_Launch);
DrawText(interuiregular18, 1280 - 90 - 30 - 32, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_Actions_Launch)); else
} buttonstr = textGetString(StrId_Actions_Open);
else {
DrawText(fontscale7, 1280 - 126 - 30 - 32, 720 - 47 + 24, themeCurrent.textColor, themeCurrent.buttonAText); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonAText];
DrawText(interuiregular18, 1280 - 90 - 30 - 32, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_Actions_Open)); DrawTextFromLayoutRelative(ThemeLayoutId_ButtonAText, curPos[0], curPos[1], layoutobj->posStart, curPos, themeCurrent.textColor, buttonstr, 'l');
} layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonA];
DrawTextFromLayoutRelative(ThemeLayoutId_ButtonA, curPos[0], curPos[1], layoutobj->posStart, curPos, themeCurrent.textColor, themeCurrent.buttonAText, 'l');
} }
drawButtons(menu, false, &menupath_x_endpos); drawButtons(menu, false, curPos);
if (active_entry && active_entry->type != ENTRY_TYPE_THEME) { if (active_entry && active_entry->type != ENTRY_TYPE_THEME) {
if (active_entry->starred) { const char *buttonstr = "";
getX = GetTextXCoordinate(interuiregular18, menupath_x_endpos + 8, textGetString(StrId_Actions_Unstar), 'r'); if (active_entry->starred)
DrawText(fontscale7, getX - 36, 720 - 47 + 24, themeCurrent.textColor, themeCurrent.buttonXText); buttonstr = textGetString(StrId_Actions_Unstar);
DrawText(interuiregular18, getX, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_Actions_Unstar)); else
} else { buttonstr = textGetString(StrId_Actions_Star);
getX = GetTextXCoordinate(interuiregular18, menupath_x_endpos + 8, textGetString(StrId_Actions_Star), 'r');
DrawText(fontscale7, getX - 36, 720 - 47 + 24, themeCurrent.textColor, themeCurrent.buttonXText); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonXText];
DrawText(interuiregular18, getX, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_Actions_Star)); DrawTextFromLayoutRelative(ThemeLayoutId_ButtonXText, curPos[0], curPos[1], layoutobj->posStart, curPos, themeCurrent.textColor, buttonstr, 'r');
} layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ButtonX];
menupath_x_endpos = getX - 36 - 40; DrawTextFromLayoutRelative(ThemeLayoutId_ButtonX, curPos[0], curPos[1], layoutobj->posStart, curPos, themeCurrent.textColor, themeCurrent.buttonXText, 'l');
} }
} }
DrawTextTruncate(interuiregular18, 40, 720 - 47 + 24, themeCurrent.textColor, menu->dirname, menupath_x_endpos - 40, "..."); layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuPath];
if (layoutobj->visible) DrawTextTruncate(layoutobj->font, layoutobj->posStart[0], layoutobj->posStart[1], themeCurrent.textColor, menu->dirname, layoutobj->size[0], "...");
menuDrawMsgBox(); menuDrawMsgBox();
} }

View File

@ -16,6 +16,7 @@ void drawMsgBoxBgToBuff(color_t *buff, int width, int height) {
float rad, alpha; float rad, alpha;
color_t base_color = themeCurrent.backgroundColor; color_t base_color = themeCurrent.backgroundColor;
color_t color; color_t color;
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MsgBoxSeparator];
for (y=0; y<height; y++) { for (y=0; y<height; y++) {
for (x=0; x<width; x++) { for (x=0; x<width; x++) {
@ -62,7 +63,7 @@ void drawMsgBoxBgToBuff(color_t *buff, int width, int height) {
else else
color = base_color; color = base_color;
if (y == height - 80) { if (y == height + layoutobj->posStart[1]) {
color = themeCurrent.separatorColor; color = themeCurrent.separatorColor;
} }
@ -76,6 +77,7 @@ void menuDrawMsgBox() {
if (!menuIsMsgBoxOpen()) if (!menuIsMsgBoxOpen())
return; return;
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MsgBoxSeparator];
int off; int off;
int x, y; int x, y;
int start_x = 1280 / 2 - currMsgBox.width / 2; int start_x = 1280 / 2 - currMsgBox.width / 2;
@ -85,7 +87,7 @@ void menuDrawMsgBox() {
color_t curr_color; color_t curr_color;
color_t border_color; color_t border_color;
int sep_start_y = currMsgBox.height - 80; int sep_start_y = currMsgBox.height + layoutobj->posStart[1];
int border_thickness = 6; int border_thickness = 6;
int shadow_start_y, shadow_y; int shadow_start_y, shadow_y;
@ -121,7 +123,7 @@ void menuDrawMsgBox() {
curr_color = border_color; curr_color = border_color;
} }
} }
else if (msgboxNetloaderProgressEnabled && y > currMsgBox.height - 80 && x < progress_width) { else if (msgboxNetloaderProgressEnabled && y > sep_start_y && x < progress_width) {
curr_color = themeCurrent.progressBarColor; curr_color = themeCurrent.progressBarColor;
} }
@ -135,10 +137,11 @@ void menuDrawMsgBox() {
x = GetTextXCoordinate(interuiregular18, start_x + (currMsgBox.width / 2), textptr, 'c'); x = GetTextXCoordinate(interuiregular18, start_x + (currMsgBox.width / 2), textptr, 'c');
if (text_width < currMsgBox.width && text_height < sep_start_y) { if (text_width < currMsgBox.width && text_height < sep_start_y) {
DrawText(interuiregular18, x, start_y + (currMsgBox.height - text_height - 80) / 2, themeCurrent.textColor, textptr); DrawText(interuiregular18, x, start_y + (sep_start_y - text_height) / 2, themeCurrent.textColor, textptr);
} }
y = start_y + 245 + 26; layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MsgBoxBottomText];
y = start_y + currMsgBox.height + layoutobj->posStart[1];
if (!msgboxNetloaderEnabled) { if (!msgboxNetloaderEnabled) {
x = GetTextXCoordinate(interuimedium20, start_x + (currMsgBox.width / 2), textGetString(StrId_MsgBox_OK), 'c'); x = GetTextXCoordinate(interuimedium20, start_x + (currMsgBox.width / 2), textGetString(StrId_MsgBox_OK), 'c');

View File

@ -10,6 +10,58 @@ bool colorFromSetting(config_setting_t *rgba, color_t *col) {
return true; return true;
} }
bool intElemFromSetting(config_setting_t *setting, int *out, size_t count) {
if (!setting || config_setting_length(setting) < count)
return false;
for (size_t i=0; i<count; i++) {
out[i] = config_setting_get_int_elem(setting, i);
}
return true;
}
bool layoutObjectFromSetting(config_setting_t *layout_setting, ThemeLayoutObject *obj, bool ignore_cfg_visible) {
int tmp=0;
ThemeLayoutObject tmpobj={0};
if (!layout_setting)
return false;
memcpy(tmpobj.posStart, obj->posStart, sizeof(obj->posStart));
memcpy(tmpobj.posEnd, obj->posEnd, sizeof(obj->posEnd));
memcpy(tmpobj.size, obj->size, sizeof(obj->size));
if (config_setting_lookup_bool(layout_setting, "visible", &tmp)==CONFIG_TRUE)
tmpobj.visible = tmp;
else
tmpobj.visible = obj->visible;
if (config_setting_lookup_bool(layout_setting, "posType", &tmp)==CONFIG_TRUE)
tmpobj.posType = tmp;
else
tmpobj.posType = obj->posType;
intElemFromSetting(config_setting_lookup(layout_setting, "posStart"), tmpobj.posStart, 2);
intElemFromSetting(config_setting_lookup(layout_setting, "posEnd"), tmpobj.posEnd, 2);
intElemFromSetting(config_setting_lookup(layout_setting, "size"), tmpobj.size, 2);
if (!tmpobj.posType && (tmpobj.posStart[0] < 0 || tmpobj.posStart[1] < 0 || tmpobj.posEnd[0] < 0 || tmpobj.posEnd[1] < 0))
return false;
if (tmpobj.size[0] < 0 || tmpobj.size[1] < 0)
return false;
obj->posStart[0] = tmpobj.posStart[0];
obj->posStart[1] = tmpobj.posStart[1];
obj->posEnd[0] = tmpobj.posEnd[0];
obj->posEnd[1] = tmpobj.posEnd[1];
if (!ignore_cfg_visible) obj->visible = tmpobj.visible;
obj->posType = tmpobj.posType;
obj->size[0] = tmpobj.size[0];
obj->size[1] = tmpobj.size[1];
return true;
}
void themeStartup(ThemePreset preset) { void themeStartup(ThemePreset preset) {
themeGlobalPreset = preset; themeGlobalPreset = preset;
theme_t themeLight = (theme_t) { theme_t themeLight = (theme_t) {
@ -60,13 +112,283 @@ void themeStartup(ThemePreset preset) {
.hbmenuLogoImage = assetsGetDataBuffer(AssetId_hbmenu_logo_dark), .hbmenuLogoImage = assetsGetDataBuffer(AssetId_hbmenu_logo_dark),
}; };
theme_t themeCommon = {
.layoutObjects = {
[ThemeLayoutId_Logo] = {
.visible = true,
.posType = false,
.posStart = {40, 20},
.imageSize = {140, 60},
},
[ThemeLayoutId_HbmenuVersion] = {
.visible = true,
.posType = false,
.posStart = {184, 46 + 18},
.font = interuiregular14,
},
[ThemeLayoutId_LoaderInfo] = {
.visible = true,
.posType = true,
.posStart = {43, 46 + 18 + 20},
.posEnd = {184},
.font = interuiregular14,
},
[ThemeLayoutId_AttentionText] = {
.visible = true,
.posType = true,
.posStart = {-32, 46 + 18},
.font = interuimedium30,
},
[ThemeLayoutId_LogInfo] = {
.visible = true,
.posType = false,
.posStart = {180 + 256, 46 + 16 + 18},
.font = interuiregular14,
},
[ThemeLayoutId_InfoMsg] = {
.visible = true,
.posType = false,
.posStart = {64, 128 + 18},
.font = interuiregular14,
},
[ThemeLayoutId_MenuPath] = {
.visible = true,
.posType = false,
.posStart = {40, 720 - 47 + 24},
.size = {380},
.font = interuiregular18,
},
[ThemeLayoutId_MenuTypeMsg] = {
.visible = true,
.posType = false,
.posStart = {1180, 30 + 26 + 32 + 20},
.font = interuiregular18,
},
[ThemeLayoutId_MsgBoxSeparator] = {
.visible = true,
.posType = true,
.posStart = {0, -80},
},
[ThemeLayoutId_MsgBoxBottomText] = {
.visible = true,
.posType = true,
.posStart = {0, -29},
},
[ThemeLayoutId_BackWave] = {
.visible = true,
.posType = true,
.size = {0, 295},
},
[ThemeLayoutId_MiddleWave] = {
.visible = true,
.posType = true,
.size = {0, 290},
},
[ThemeLayoutId_FrontWave] = {
.visible = true,
.posType = true,
.size = {0, 280},
},
[ThemeLayoutId_ButtonA] = {
.visible = true,
.posType = false,
.posStart = {1280 - 126 - 30 - 32, 720 - 47 + 24},
.touchSize = {36, 25},
.font = fontscale7,
},
[ThemeLayoutId_ButtonAText] = {
.visible = true,
.posType = false,
.posStart = {1280 - 90 - 30 - 32, 720 - 47 + 24},
.touchSize = {0, 25},
.font = interuiregular18,
},
[ThemeLayoutId_ButtonB] = {
.visible = true,
.posType = true,
.posStart = {-36, 0},
.posEnd = {0},
.touchSize = {36, 25},
.font = fontscale7,
},
[ThemeLayoutId_ButtonBText] = {
.visible = true,
.posType = true,
.posStart = {-90, 0},
.touchSize = {0, 32},
.font = interuiregular18,
},
[ThemeLayoutId_ButtonY] = {
.visible = true,
.posType = true,
.posStart = {-36, 0},
.font = fontscale7,
},
[ThemeLayoutId_ButtonYText] = {
.visible = true,
.posType = true,
.posStart = {-32, 0},
.font = interuiregular18,
},
[ThemeLayoutId_ButtonM] = {
.visible = true,
.posType = true,
.posStart = {-36, 0},
.font = fontscale7,
},
[ThemeLayoutId_ButtonMText] = {
.visible = true,
.posType = true,
.posStart = {-32, 0},
.font = interuiregular18,
},
[ThemeLayoutId_ButtonX] = {
.visible = true,
.posType = true,
.posStart = {-36, 0},
.touchSize = {36, 25},
.font = fontscale7,
},
[ThemeLayoutId_ButtonXText] = {
.visible = true,
.posType = true,
.posStart = {-40 + 8, 0},
.touchSize = {0, 25},
.font = interuiregular18,
},
[ThemeLayoutId_NetworkIcon] = {
.visible = true,
.posType = true,
.posStart = {0, 0 + 47 + 10 + 3},
.imageSize = {24, 24},
},
[ThemeLayoutId_BatteryCharge] = {
.visible = true,
.posType = false,
.posStart = {1180 - 10 - 24 - 8, 0 + 47 + 10 + 21 + 4},
.font = interuiregular14,
},
[ThemeLayoutId_BatteryIcon] = {
.visible = true,
.posType = false,
.posStart = {1180 - 8 - 24 - 8, 0 + 47 + 10 + 6},
.imageSize = {24, 24},
},
[ThemeLayoutId_ChargingIcon] = {
.visible = true,
.posType = false,
.posStart = {1180 - 20, 0 + 47 + 10 + 6},
.imageSize = {24, 24},
},
[ThemeLayoutId_Status] = {
.visible = true,
.posType = false,
.posStart = {1180, 0 + 47 + 10},
.font = interuimedium20,
},
[ThemeLayoutId_Temperature] = {
.visible = true,
.posType = false,
.posStart = {1180 + 4, 0 + 47 + 10 + + 21 + 6},
.font = interuiregular14,
},
[ThemeLayoutId_MenuList] = {
.visible = true,
.posType = false,
.posStart = {29, 720 - 100 - 145},
.posEnd = {140 + 30, 0},
.size = {140, 140 + 32},
},
[ThemeLayoutId_MenuListTiles] = {
.visible = true,
.posType = true,
.posEnd = {7, 0},
.size = {0, 0},
},
[ThemeLayoutId_MenuListIcon] = {
.visible = true,
.posType = true,
.posStart = {0, 32},
.imageSize = {140, 140},
},
[ThemeLayoutId_MenuListName] = {
.visible = true,
.posType = true,
.posStart = {4, 4 + 18},
.size = {140 - 32, 0},
.font = interuiregular14,
},
[ThemeLayoutId_MenuActiveEntryIcon] = {
.visible = true,
.posType = false,
.posStart = {117, 100+10},
.imageSize = {256, 256},
},
[ThemeLayoutId_MenuActiveEntryName] = {
.visible = true,
.posType = false,
.posStart = {1280 - 790, 135+10 + 39},
.size = {790 - 120, 0},
.font = interuimedium30,
},
[ThemeLayoutId_MenuActiveEntryAuthor] = {
.visible = true,
.posType = false,
.posStart = {1280 - 790, 135+10 + 28 + 30 + 18},
.font = interuiregular14,
},
[ThemeLayoutId_MenuActiveEntryVersion] = {
.visible = true,
.posType = false,
.posStart = {1280 - 790, 135+10 + 28 + 30 + 18 + 6 + 18},
.font = interuiregular14,
},
},
};
char themePath[PATH_MAX] = {0}; char themePath[PATH_MAX] = {0};
GetThemePathFromConfig(themePath, PATH_MAX); GetThemePathFromConfig(themePath, PATH_MAX);
theme_t *themeDefault; theme_t *themeDefault;
config_t cfg = {0}; config_t cfg = {0};
config_init(&cfg); config_init(&cfg);
config_setting_t *theme = NULL; config_setting_t *theme = NULL, *layout = NULL;
color_t text, attentionText, frontWave, middleWave, backWave, background, highlight, separator, borderColor, borderTextColor, progressBarColor; color_t text, attentionText, frontWave, middleWave, backWave, background, highlight, separator, borderColor, borderTextColor, progressBarColor;
int waveBlending; int waveBlending;
const char *AText, *BText, *XText, *YText, *PText, *MText, *starOnText, *starOffText; const char *AText, *BText, *XText, *YText, *PText, *MText, *starOnText, *starOffText;
@ -166,9 +488,58 @@ void themeStartup(ThemePreset preset) {
} else { } else {
themeCurrent = *themeDefault; themeCurrent = *themeDefault;
} }
memcpy(themeCurrent.layoutObjects, themeCommon.layoutObjects, sizeof(themeCommon.layoutObjects));
layout = config_lookup(&cfg, "layout");
if (layout != NULL) {
layoutObjectFromSetting(config_setting_lookup(layout, "logo"), &themeCurrent.layoutObjects[ThemeLayoutId_Logo], true);
layoutObjectFromSetting(config_setting_lookup(layout, "hbmenuVersion"), &themeCurrent.layoutObjects[ThemeLayoutId_HbmenuVersion], true);
layoutObjectFromSetting(config_setting_lookup(layout, "loaderInfo"), &themeCurrent.layoutObjects[ThemeLayoutId_LoaderInfo], true);
layoutObjectFromSetting(config_setting_lookup(layout, "attentionText"), &themeCurrent.layoutObjects[ThemeLayoutId_AttentionText], true);
layoutObjectFromSetting(config_setting_lookup(layout, "logInfo"), &themeCurrent.layoutObjects[ThemeLayoutId_LogInfo], true);
layoutObjectFromSetting(config_setting_lookup(layout, "infoMsg"), &themeCurrent.layoutObjects[ThemeLayoutId_InfoMsg], true);
layoutObjectFromSetting(config_setting_lookup(layout, "menuPath"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuPath], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuTypeMsg"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuTypeMsg], false);
layoutObjectFromSetting(config_setting_lookup(layout, "msgBoxSeparator"), &themeCurrent.layoutObjects[ThemeLayoutId_MsgBoxSeparator], false);
layoutObjectFromSetting(config_setting_lookup(layout, "msgBoxBottomText"), &themeCurrent.layoutObjects[ThemeLayoutId_MsgBoxBottomText], false);
layoutObjectFromSetting(config_setting_lookup(layout, "backWave"), &themeCurrent.layoutObjects[ThemeLayoutId_BackWave], false);
layoutObjectFromSetting(config_setting_lookup(layout, "middleWave"), &themeCurrent.layoutObjects[ThemeLayoutId_MiddleWave], false);
layoutObjectFromSetting(config_setting_lookup(layout, "frontWave"), &themeCurrent.layoutObjects[ThemeLayoutId_FrontWave], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonA"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonA], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonAText"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonAText], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonB"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonB], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonBText"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonBText], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonY"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonY], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonYText"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonYText], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonM"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonM], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonMText"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonMText], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonX"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonX], false);
layoutObjectFromSetting(config_setting_lookup(layout, "buttonXText"), &themeCurrent.layoutObjects[ThemeLayoutId_ButtonXText], false);
layoutObjectFromSetting(config_setting_lookup(layout, "networkIcon"), &themeCurrent.layoutObjects[ThemeLayoutId_NetworkIcon], false);
layoutObjectFromSetting(config_setting_lookup(layout, "batteryCharge"), &themeCurrent.layoutObjects[ThemeLayoutId_BatteryCharge], false);
layoutObjectFromSetting(config_setting_lookup(layout, "batteryIcon"), &themeCurrent.layoutObjects[ThemeLayoutId_BatteryIcon], false);
layoutObjectFromSetting(config_setting_lookup(layout, "chargingIcon"), &themeCurrent.layoutObjects[ThemeLayoutId_ChargingIcon], false);
layoutObjectFromSetting(config_setting_lookup(layout, "status"), &themeCurrent.layoutObjects[ThemeLayoutId_Status], false);
layoutObjectFromSetting(config_setting_lookup(layout, "temperature"), &themeCurrent.layoutObjects[ThemeLayoutId_Temperature], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuList"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuList], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuListTiles"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuListTiles], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuListIcon"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuListIcon], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuListName"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuListName], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuActiveEntryIcon"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuActiveEntryName"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryName], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuActiveEntryAuthor"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryAuthor], false);
layoutObjectFromSetting(config_setting_lookup(layout, "menuActiveEntryVersion"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryVersion], false);
}
} else { } else {
themeCurrent = *themeDefault; themeCurrent = *themeDefault;
memcpy(themeCurrent.layoutObjects, themeCommon.layoutObjects, sizeof(themeCommon.layoutObjects));
} }
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListTiles];
if (layoutobj->posEnd[0] < 1) layoutobj->posEnd[0] = 1;
config_destroy(&cfg); config_destroy(&cfg);
} }

View File

@ -3,6 +3,26 @@
#include "common.h" #include "common.h"
#include <libconfig.h> #include <libconfig.h>
typedef enum
{
THEME_PRESET_LIGHT,
THEME_PRESET_DARK,
} ThemePreset;
typedef struct
{
bool visible;
bool posType; // false = absolute, true = relative
int posStart[2];
int posEnd[2];
int size[2]; // width/height
int imageSize[2]; // width/height for the actual image data
int touchSize[2];
int posFinal[2];
uint32_t textSize[2];
u32 font;
} ThemeLayoutObject;
typedef struct typedef struct
{ {
color_t textColor; color_t textColor;
@ -26,13 +46,9 @@ typedef struct
char labelStarOnText[32]; char labelStarOnText[32];
char labelStarOffText[32]; char labelStarOffText[32];
const uint8_t *hbmenuLogoImage; const uint8_t *hbmenuLogoImage;
} theme_t;
typedef enum ThemeLayoutObject layoutObjects[ThemeLayoutId_Total];
{ } theme_t;
THEME_PRESET_LIGHT,
THEME_PRESET_DARK,
} ThemePreset;
bool colorFromSetting(config_setting_t *rgba, color_t *col); bool colorFromSetting(config_setting_t *rgba, color_t *col);
void themeStartup(ThemePreset preset); void themeStartup(ThemePreset preset);

View File

@ -209,6 +209,8 @@ bool menuUpdate(void) {
bool exitflag = 0; bool exitflag = 0;
menu_s* menu = menuGetCurrent(); menu_s* menu = menuGetCurrent();
u64 down = menuGetKeysDown(); u64 down = menuGetKeysDown();
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListTiles];
int entries_count = layoutobj->posEnd[0];
handleTouch(menu); handleTouch(menu);
@ -241,8 +243,8 @@ bool menuUpdate(void) {
if (down & KEY_LEFT) move--; if (down & KEY_LEFT) move--;
if (down & KEY_RIGHT) move++; if (down & KEY_RIGHT) move++;
if (down & KEY_DOWN) move-=7; if (down & KEY_DOWN) move-=entries_count;
if (down & KEY_UP) move+=7; if (down & KEY_UP) move+=entries_count;
int newEntry = menu->curEntry + move; int newEntry = menu->curEntry + move;
if (newEntry < 0) newEntry = 0; if (newEntry < 0) newEntry = 0;

View File

@ -5,19 +5,6 @@
#define VERTICAL_SWIPE_MINIMUM_DISTANCE 300 #define VERTICAL_SWIPE_MINIMUM_DISTANCE 300
#define HORIZONTAL_SWIPE_VERTICAL_PLAY 250 #define HORIZONTAL_SWIPE_VERTICAL_PLAY 250
#define HORIZONTAL_SWIPE_MINIMUM_DISTANCE 300 #define HORIZONTAL_SWIPE_MINIMUM_DISTANCE 300
#define LISTING_START_Y 475
#define LISTING_END_Y 647
#define BUTTON_START_Y 672
#define BUTTON_END_Y 704
#define BACK_BUTTON_START_X 966
#define BACK_BUTTON_END_X 1048
#define LAUNCH_BUTTON_START_X 1092
#define LAUNCH_BUTTON_END_X 1200
#define STAR_BUTTON_START_X 426
#define STAR_BUTTON_END_X 490
#define STAR_BUTTON_START_Y 100
#define STAR_BUTTON_END_Y 161
#define distance(x1, y1, x2, y2) (int) sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) #define distance(x1, y1, x2, y2) (int) sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)))
@ -33,15 +20,16 @@ void touchInit() {
void handleTappingOnApp(menu_s* menu, int px) { void handleTappingOnApp(menu_s* menu, int px) {
int i = 0; int i = 0;
menuEntry_s *me = NULL; menuEntry_s *me = NULL;
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuList];
for (me = menu->firstEntry, i = 0; me; me = me->next, i ++) { for (me = menu->firstEntry, i = 0; me; me = me->next, i ++) {
int entry_start_x = 29 + i * (140 + 30); int entry_start_x = layoutobj->posStart[0] + i * layoutobj->posEnd[0];
int screen_width = 1280; int screen_width = 1280;
if (entry_start_x >= (screen_width - menu->xPos)) if (entry_start_x >= (screen_width - menu->xPos))
break; break;
if (px >= (entry_start_x + menu->xPos) && px <= (entry_start_x + menu->xPos) + 140 ) { if (px >= (entry_start_x + menu->xPos) && px <= (entry_start_x + menu->xPos) + layoutobj->size[0]) {
launchMenuEntryTask(me); launchMenuEntryTask(me);
break; break;
} }
@ -58,10 +46,22 @@ void handleTappingOnOpenLaunch(menu_s* menu) {
} }
} }
static inline bool checkInsideTextLayoutObject(ThemeLayoutId id, int x, int y) {
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[id];
if (!layoutobj->visible) return false;
return x > layoutobj->posFinal[0] && x < layoutobj->posFinal[0]+(layoutobj->touchSize[0] ? layoutobj->touchSize[0] : layoutobj->textSize[0]) && y > layoutobj->posFinal[1]-layoutobj->touchSize[1] && y < layoutobj->posFinal[1];
}
void handleTouch(menu_s* menu) { void handleTouch(menu_s* menu) {
ThemeLayoutObject *layoutobj = NULL;
touchPosition currentTouch; touchPosition currentTouch;
u32 touches = hidTouchCount(); u32 touches = hidTouchCount();
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListTiles];
int entries_count = layoutobj->posEnd[0];
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuList];
// On touch start. // On touch start.
if (touches == 1 && !touchInfo.gestureInProgress) { if (touches == 1 && !touchInfo.gestureInProgress) {
hidTouchRead(&currentTouch, 0); hidTouchRead(&currentTouch, 0);
@ -82,15 +82,15 @@ void handleTouch(menu_s* menu) {
if (touchInfo.isTap && (abs(touchInfo.firstTouch.px - currentTouch.px) > TAP_MOVEMENT_GAP || abs(touchInfo.firstTouch.py - currentTouch.py) > TAP_MOVEMENT_GAP)) { if (touchInfo.isTap && (abs(touchInfo.firstTouch.px - currentTouch.px) > TAP_MOVEMENT_GAP || abs(touchInfo.firstTouch.py - currentTouch.py) > TAP_MOVEMENT_GAP)) {
touchInfo.isTap = false; touchInfo.isTap = false;
} }
if (!menuIsMsgBoxOpen() && touchInfo.firstTouch.py > LISTING_START_Y && touchInfo.firstTouch.py < LISTING_END_Y && !touchInfo.isTap && menu->nEntries > 7) { if (!menuIsMsgBoxOpen() && touchInfo.firstTouch.py > layoutobj->posStart[1] && touchInfo.firstTouch.py < layoutobj->posStart[1]+layoutobj->size[1] && !touchInfo.isTap && menu->nEntries > entries_count) {
menu->xPos = touchInfo.initMenuXPos + (currentTouch.px - touchInfo.firstTouch.px); menu->xPos = touchInfo.initMenuXPos + (currentTouch.px - touchInfo.firstTouch.px);
menu->curEntry = touchInfo.initMenuIndex + ((int) (touchInfo.firstTouch.px - currentTouch.px) / 170); menu->curEntry = touchInfo.initMenuIndex + ((int) (touchInfo.firstTouch.px - currentTouch.px) / layoutobj->posEnd[0]);
if (menu->curEntry < 0) if (menu->curEntry < 0)
menu->curEntry = 0; menu->curEntry = 0;
if (menu->curEntry >= menu->nEntries - 6) if (menu->curEntry >= menu->nEntries - entries_count - 1)
menu->curEntry = menu->nEntries - 7; menu->curEntry = menu->nEntries - entries_count;
} }
} }
// On touch end. // On touch end.
@ -103,46 +103,43 @@ void handleTouch(menu_s* menu) {
bool netloader_active = menuIsNetloaderActive(); bool netloader_active = menuIsNetloaderActive();
if (menuIsMsgBoxOpen() && !netloader_active) { if (menuIsMsgBoxOpen() && !netloader_active) {
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MsgBoxSeparator];
MessageBox currMsgBox = menuGetCurrentMsgBox(); MessageBox currMsgBox = menuGetCurrentMsgBox();
int start_x = 1280 / 2 - currMsgBox.width / 2; int start_x = 1280 / 2 - currMsgBox.width / 2;
int start_y = (720 / 2 - currMsgBox.height / 2) + (currMsgBox.height - 80); int start_y = (720 / 2 - currMsgBox.height / 2) + currMsgBox.height;
int end_x = start_x + currMsgBox.width; int end_x = start_x + currMsgBox.width;
int end_y = start_y + 80; int end_y = start_y;
start_y+= layoutobj->posStart[1];
if (x1 > start_x && x1 < end_x && y1 > start_y && y1 < end_y && touchInfo.isTap) { if (x1 > start_x && x1 < end_x && y1 > start_y && y1 < end_y && touchInfo.isTap) {
menuCloseMsgBox(); menuCloseMsgBox();
} }
} else if (touchInfo.isTap && !netloader_active) { } else if (touchInfo.isTap && !netloader_active) {
// App Icons // App Icons
if (y1 > LISTING_START_Y && y1 < LISTING_END_Y) { if (y1 > layoutobj->posStart[1] && y1 < layoutobj->posStart[1]+layoutobj->size[1]) {
handleTappingOnApp(menu, touchInfo.prevTouch.px); handleTappingOnApp(menu, touchInfo.prevTouch.px);
} }
// Bottom Buttons // Bottom Buttons
else if (y1 > BUTTON_START_Y && y1 < BUTTON_END_Y) { else {
// Back Button for non-empty directory // Back Button
if (menu->nEntries != 0 && x1 > BACK_BUTTON_START_X && x1 < BACK_BUTTON_END_X) { if (checkInsideTextLayoutObject(ThemeLayoutId_ButtonB, x1, y1) || checkInsideTextLayoutObject(ThemeLayoutId_ButtonBText, x1, y1)) {
launchMenuBackTask(); launchMenuBackTask();
} }
// Open/Launch Button / Back Button for empty directories // Open/Launch Button
else if (x1 > LAUNCH_BUTTON_START_X && x1 < LAUNCH_BUTTON_END_X) { else if (menu->nEntries != 0 && (checkInsideTextLayoutObject(ThemeLayoutId_ButtonA, x1, y1) || checkInsideTextLayoutObject(ThemeLayoutId_ButtonAText, x1, y1))) {
if (menu->nEntries == 0) {
launchMenuBackTask();
} else {
handleTappingOnOpenLaunch(menu); handleTappingOnOpenLaunch(menu);
} }
} // Star Button
} else if (menu->nEntries != 0) {
// Star
else {
int i; int i;
menuEntry_s* me; menuEntry_s* me;
for (i = 0, me = menu->firstEntry; i != menu->curEntry; i ++, me = me->next); for (i = 0, me = menu->firstEntry; i != menu->curEntry; i ++, me = me->next);
if (me->type != ENTRY_TYPE_THEME && x1 > STAR_BUTTON_START_X && x1 < STAR_BUTTON_END_X if (me->type != ENTRY_TYPE_THEME && (checkInsideTextLayoutObject(ThemeLayoutId_ButtonX, x1, y1) || checkInsideTextLayoutObject(ThemeLayoutId_ButtonXText, x1, y1))) {
&& y1 > STAR_BUTTON_START_Y && y1 < STAR_BUTTON_END_Y) {
menuHandleXButton(); menuHandleXButton();
} }
} }
} }
}
// Vertical Swipe // Vertical Swipe
else if (abs(x1 - x2) < VERTICAL_SWIPE_HORIZONTAL_PLAY && distance(x1, y1, x2, y2) > VERTICAL_SWIPE_MINIMUM_DISTANCE) { else if (abs(x1 - x2) < VERTICAL_SWIPE_HORIZONTAL_PLAY && distance(x1, y1, x2, y2) > VERTICAL_SWIPE_MINIMUM_DISTANCE) {
// Swipe up to go back // Swipe up to go back
@ -155,7 +152,7 @@ void handleTouch(menu_s* menu) {
} }
} }
// Horizontal Swipe // Horizontal Swipe
else if (y1 < LISTING_START_Y && y2 < LISTING_START_Y) { else if (y1 < layoutobj->posStart[1] && y2 < layoutobj->posStart[1]) {
if (abs(y1 - y2) < HORIZONTAL_SWIPE_VERTICAL_PLAY && distance(x1, y1, x2, y2) > HORIZONTAL_SWIPE_MINIMUM_DISTANCE) { if (abs(y1 - y2) < HORIZONTAL_SWIPE_VERTICAL_PLAY && distance(x1, y1, x2, y2) > HORIZONTAL_SWIPE_MINIMUM_DISTANCE) {
// Swipe left to go into theme-menu // Swipe left to go into theme-menu
if (x1 - x2 > 0) { if (x1 - x2 > 0) {