Implemented a theme switcher feature (#62)
* Implemented Theme Menu. * Minor adjustments. * added two new theming attributes, borderColor, borderTextcolor, allows users to modify the boxes that surrounds the menu entries * added theme info to config file, users can now add theme author, theme name, and theme version to a theme config file. * tested building on mac osx, added to .gitignore and make clean for files generated on osx * The path for the theme is now stored in a config string in settings.cfg, instead of a hard-coded theme.cfg path. * added functions to create/modify settings config for hbmenu theme * added Default theme entry that will always insert itself at the front of the list of themes * added code for + and - button, using - button for theme menu now (button display for this is disabled).
This commit is contained in:
parent
985dc946fe
commit
992c4c482b
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,3 +11,5 @@ build
|
||||
*.pfs0
|
||||
*.nacp
|
||||
*.nro
|
||||
test.*
|
||||
switch
|
||||
|
12
Makefile.pc
12
Makefile.pc
@ -25,6 +25,7 @@ test : pc_main/main.cpp pc_main/pc_launch.c \
|
||||
common/netloader.c \
|
||||
build_pc/invalid_icon.bin.o build_pc/folder_icon.bin.o \
|
||||
build_pc/hbmenu_logo_light.bin.o build_pc/hbmenu_logo_dark.bin.o \
|
||||
build_pc/theme_icon_dark.bin.o build_pc/theme_icon_light.bin.o \
|
||||
#build_pc/tahoma24.o build_pc/tahoma12.o build_pc/interuimedium20.o build_pc/interuimedium30.o build_pc/interuiregular14.o build_pc/interuiregular18.o
|
||||
gcc -Wall -O2 -g -DVERSION=\"v$(APP_VERSION)\" $(EXTRA_CFLAGS) `pkg-config freetype2 --cflags` $^ -lsfml-graphics -lsfml-window -lsfml-system -lstdc++ `pkg-config freetype2 --libs` -lm -lz -lconfig $(EXTRA_LDFLAGS) -I. -iquote $(DEVKITPRO)/libnx/include -Ibuild_pc -g -o $@
|
||||
|
||||
@ -78,7 +79,16 @@ build_pc/hbmenu_logo_dark.bin.o : data/hbmenu_logo_dark.bin
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
build_pc/theme_icon_light.bin.o : data/theme_icon_light.bin
|
||||
mkdir -p $(dir $@)
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
build_pc/theme_icon_dark.bin.o : data/theme_icon_dark.bin
|
||||
mkdir -p $(dir $@)
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf build_pc/ test
|
||||
rm -rf build_pc/ test test.*
|
||||
|
@ -60,6 +60,7 @@ typedef union {
|
||||
#include "message-box.h"
|
||||
|
||||
void menuStartup();
|
||||
void themeMenuStartup();
|
||||
void menuLoop();
|
||||
|
||||
static inline uint8_t BlendColor(uint32_t src, uint32_t dst, uint8_t alpha)
|
||||
@ -152,6 +153,8 @@ 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 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);
|
||||
uint32_t GetTextXCoordinate(u32 font, uint32_t rX, const char* text, const char align);
|
||||
uint32_t GetTextYCoordinate(u32 font, uint32_t rY, const char* text, const char align);
|
||||
|
||||
bool fontInitialize(void);
|
||||
void fontExit();
|
||||
|
@ -376,3 +376,51 @@ void fontExit()
|
||||
if (s_font_libret==0) FT_Done_FreeType(s_font_library);
|
||||
}
|
||||
|
||||
/*Automatically gives you the desired x-coordinate
|
||||
*based on the string length and desired alignment
|
||||
*rY=reference point... where to align around
|
||||
*align='t','b','c' translates to (top,bottom,center)
|
||||
*'t' aligned, top of text aligns with rY,
|
||||
*you get the rest....
|
||||
*/
|
||||
uint32_t GetTextYCoordinate(u32 font, uint32_t rY, const char* text, const char align) {
|
||||
uint32_t height_o,width;
|
||||
GetTextDimensions(font,text,&width,&height_o);
|
||||
uint32_t height = (uint32_t)height_o;
|
||||
uint32_t fC = (rY-height);
|
||||
|
||||
switch(align){
|
||||
case 't':
|
||||
default:
|
||||
return rY;
|
||||
case 'c':
|
||||
return (rY+(height>>1));//>>1 is a bitwise shift for dividing by 2
|
||||
case 'b':
|
||||
if(fC<=0) return 0;
|
||||
else return fC;
|
||||
}
|
||||
}
|
||||
|
||||
/*Automatically gives you the desired x-coordinate
|
||||
*based on the string length and desired alignment
|
||||
*rX=reference point... where to align around
|
||||
*text=string you want to display
|
||||
*align='r','l','c' translates to (right,left,center)
|
||||
*'r' aligned, rX location = end of string, you get the rest...
|
||||
*/
|
||||
uint32_t GetTextXCoordinate(u32 font, uint32_t rX, const char* text, const char align) {
|
||||
uint32_t height,width_o;
|
||||
GetTextDimensions(font,text,&width_o,&height);
|
||||
uint32_t fC = (rX-width_o);
|
||||
|
||||
switch(align){
|
||||
case 'r':
|
||||
if(fC<0) return 0;
|
||||
else return fC;
|
||||
case 'c':
|
||||
return (rX+(width_o>>1));//>>1 is a bitwise shift for dividing by 2
|
||||
case 'l':
|
||||
default:
|
||||
return rX;
|
||||
}
|
||||
}
|
||||
|
@ -310,6 +310,33 @@ const char* const g_strings[StrId_Max][16] =
|
||||
STR_TW("確認"),
|
||||
},
|
||||
|
||||
[StrId_Actions_Apply] =
|
||||
{
|
||||
STR_EN("Apply"),
|
||||
STR_ES("Aplicar"),
|
||||
STR_JP("適用"),
|
||||
STR_KO("대다"),
|
||||
STR_TW("应用"),
|
||||
},
|
||||
|
||||
[StrId_ThemeMenu] =
|
||||
{
|
||||
STR_EN("Theme Menu"),
|
||||
STR_ES("Menú temático"),
|
||||
STR_JP("テーマメニュー"),
|
||||
STR_KO("테마 메뉴"),
|
||||
STR_TW("主题菜单"),
|
||||
},
|
||||
|
||||
[StrId_ThemeNotApplied] =
|
||||
{
|
||||
STR_EN("Theme cannot be applied because an error occurred."),
|
||||
STR_ES("El tema no se pudo aplicar porque se ha producido un error."),
|
||||
STR_JP("エラーが発生したため、テーマを適用できませんでした。"),
|
||||
STR_KO("오류가 발생 했기 때문에 테마를 적용할 수 없습니다."),
|
||||
STR_TW("由于发生错误, 无法应用主题。"),
|
||||
},
|
||||
|
||||
/*[StrId_Reboot] =
|
||||
{
|
||||
STR_EN(
|
||||
|
@ -21,6 +21,7 @@ typedef enum
|
||||
StrId_Actions_Launch,
|
||||
StrId_Actions_Open,
|
||||
StrId_Actions_Back,
|
||||
StrId_Actions_Apply,
|
||||
|
||||
StrId_MsgBox_OK,
|
||||
|
||||
@ -42,6 +43,9 @@ typedef enum
|
||||
StrId_NetLoaderActive,
|
||||
StrId_NetLoaderTransferring,
|
||||
|
||||
StrId_ThemeMenu,
|
||||
StrId_ThemeNotApplied,
|
||||
|
||||
StrId_Max,
|
||||
} StrId;
|
||||
|
||||
|
@ -137,6 +137,7 @@ bool menuEntryLoad(menuEntry_s* me, const char* name, bool shortcut) {
|
||||
|
||||
tempbuf[PATH_MAX] = 0;
|
||||
strcpy(me->name, name);
|
||||
|
||||
if (me->type == ENTRY_TYPE_FOLDER)
|
||||
{
|
||||
//Check for <dirpath>/<dirname>.nro
|
||||
@ -182,7 +183,7 @@ bool menuEntryLoad(menuEntry_s* me, const char* name, bool shortcut) {
|
||||
|
||||
if (me->type == ENTRY_TYPE_FILE)
|
||||
{
|
||||
strcpy(me->name, name);
|
||||
//strcpy(me->name, name);//This is already done before both if statements
|
||||
strcpy(me->author, textGetString(StrId_DefaultPublisher));
|
||||
strcpy(me->version, "1.0.0");
|
||||
|
||||
@ -293,6 +294,29 @@ bool menuEntryLoad(menuEntry_s* me, const char* name, bool shortcut) {
|
||||
/*if (shortcut)
|
||||
shortcutFree(&sc);*/
|
||||
}
|
||||
|
||||
if (me->type == ENTRY_TYPE_THEME) {
|
||||
config_t cfg = {0};
|
||||
config_init(&cfg);
|
||||
config_setting_t *themeInfo;
|
||||
const char *name,
|
||||
*author = textGetString(StrId_DefaultPublisher),
|
||||
*version = "1.0.0";
|
||||
|
||||
if(config_read_file(&cfg, me->path)) {
|
||||
themeInfo = config_lookup(&cfg, "themeInfo");
|
||||
if (themeInfo != NULL) {
|
||||
if(config_setting_lookup_string(themeInfo, "name", &name))
|
||||
strncpy(me->name, name, sizeof(me->name)-1);
|
||||
config_setting_lookup_string(themeInfo, "author", &author);
|
||||
config_setting_lookup_string(themeInfo, "version", &version);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(me->author, author, sizeof(me->author)-1);
|
||||
strncpy(me->version, version, sizeof(me->version)-1);
|
||||
config_destroy(&cfg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -34,6 +34,22 @@ static void menuAddEntry(menuEntry_s* me) {
|
||||
m->nEntries ++;
|
||||
}
|
||||
|
||||
static void menuAddEntryToFront(menuEntry_s* me) {
|
||||
menu_s* m = &s_menu[!s_curMenu];
|
||||
me->menu = m;
|
||||
if (m->lastEntry)
|
||||
{
|
||||
me->next = m->firstEntry;
|
||||
m->firstEntry = me;
|
||||
} else
|
||||
{
|
||||
m->firstEntry = me;
|
||||
m->lastEntry = me;
|
||||
}
|
||||
m->xPos = 0;
|
||||
m->nEntries ++;
|
||||
}
|
||||
|
||||
static void menuClear(void) {
|
||||
menu_s* m = &s_menu[!s_curMenu];
|
||||
menuEntry_s *cur, *next;
|
||||
@ -150,3 +166,54 @@ int menuScan(const char* target) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int themeMenuScan(const char* target) {
|
||||
menuClear();
|
||||
if (chdir(target) < 0) return 1;
|
||||
if (getcwd(s_menu[!s_curMenu].dirname, PATH_MAX+1) == NULL)
|
||||
return 1;
|
||||
DIR* dir;
|
||||
struct dirent* dp;
|
||||
char tmp_path[PATH_MAX+1];
|
||||
dir = opendir(s_menu[!s_curMenu].dirname);
|
||||
if (!dir) return 2;
|
||||
|
||||
while ((dp = readdir(dir)))
|
||||
{
|
||||
menuEntry_s* me = NULL;
|
||||
|
||||
bool shortcut = false;
|
||||
if (dp->d_name[0]=='.')
|
||||
continue;
|
||||
|
||||
memset(tmp_path, 0, sizeof(tmp_path));
|
||||
snprintf(tmp_path, sizeof(tmp_path)-1, "%s/%s", s_menu[!s_curMenu].dirname, dp->d_name);
|
||||
|
||||
const char* ext = getExtension(dp->d_name);
|
||||
if (strcasecmp(ext, ".cfg")==0)
|
||||
me = menuCreateEntry(ENTRY_TYPE_THEME);
|
||||
|
||||
if (!me)
|
||||
continue;
|
||||
|
||||
strncpy(me->path, tmp_path, sizeof(me->path)-1);
|
||||
me->path[sizeof(me->path)-1] = 0;
|
||||
if (menuEntryLoad(me, dp->d_name, shortcut))
|
||||
menuAddEntry(me);
|
||||
else
|
||||
menuDeleteEntry(me);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
menuSort();
|
||||
|
||||
menuEntry_s* me = menuCreateEntry(ENTRY_TYPE_THEME);
|
||||
|
||||
if(me) {
|
||||
if(menuEntryLoad(me, "Default Theme", false));//Create Default theme Menu Entry
|
||||
menuAddEntryToFront(me);
|
||||
}
|
||||
// Swap the menu and clear the previous menu
|
||||
s_curMenu = !s_curMenu;
|
||||
menuClear();
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,19 +4,23 @@
|
||||
|
||||
#include "invalid_icon_bin.h"
|
||||
#include "folder_icon_bin.h"
|
||||
#include "theme_icon_dark_bin.h"
|
||||
#include "theme_icon_light_bin.h"
|
||||
|
||||
char rootPath[PATH_MAX+8];
|
||||
void computeFrontGradient(color_t baseColor, int height);
|
||||
|
||||
char *menuGetRootPath() {
|
||||
return rootPath;
|
||||
}
|
||||
|
||||
void launchMenuEntryTask(menuEntry_s* arg)
|
||||
{
|
||||
void launchMenuEntryTask(menuEntry_s* arg) {
|
||||
menuEntry_s* me = arg;
|
||||
if (me->type == ENTRY_TYPE_FOLDER)
|
||||
menuScan(me->path);
|
||||
//changeDirTask(me->path);
|
||||
else if(me->type == ENTRY_TYPE_THEME)
|
||||
launchApplyThemeTask(me);
|
||||
else
|
||||
launchMenuEntry(me);
|
||||
}
|
||||
@ -27,6 +31,7 @@ static enum
|
||||
HBMENU_NETLOADER_ACTIVE,
|
||||
HBMENU_NETLOADER_ERROR,
|
||||
HBMENU_NETLOADER_SUCCESS,
|
||||
HBMENU_THEME_MENU,
|
||||
} hbmenu_state = HBMENU_DEFAULT;
|
||||
|
||||
void launchMenuNetloaderTask() {
|
||||
@ -34,17 +39,28 @@ void launchMenuNetloaderTask() {
|
||||
if(netloader_activate() == 0) hbmenu_state = HBMENU_NETLOADER_ACTIVE;
|
||||
}
|
||||
|
||||
void launchMenuBackTask()
|
||||
{
|
||||
void launchMenuBackTask() {
|
||||
if(hbmenu_state == HBMENU_NETLOADER_ACTIVE) {
|
||||
netloader_deactivate();
|
||||
hbmenu_state = HBMENU_DEFAULT;
|
||||
} else {
|
||||
}
|
||||
else if(hbmenu_state == HBMENU_THEME_MENU) {
|
||||
hbmenu_state = HBMENU_DEFAULT;
|
||||
menuScan(rootPath);
|
||||
}
|
||||
else {
|
||||
menuScan("..");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void launchApplyThemeTask(menuEntry_s* arg) {
|
||||
const char* themePath = removeDriveFromPath(arg->path);
|
||||
SetThemePathToConfig(themePath);
|
||||
themeStartup(themeGlobalPreset);
|
||||
computeFrontGradient(themeCurrent.frontWaveColor, 280);
|
||||
}
|
||||
|
||||
//Draws an RGB888 or RGBA8888 image.
|
||||
static void drawImage(int x, int y, int width, int height, const uint8_t *image, ImageMode mode) {
|
||||
int tmpx, tmpy;
|
||||
@ -72,6 +88,7 @@ static void drawImage(int x, int y, int width, int height, const uint8_t *image,
|
||||
|
||||
uint8_t *folder_icon_small;
|
||||
uint8_t *invalid_icon_small;
|
||||
uint8_t *theme_icon_small;
|
||||
|
||||
static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
|
||||
int x, y;
|
||||
@ -87,7 +104,7 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
|
||||
|
||||
int border_start_x, border_end_x;
|
||||
int border_start_y, border_end_y;
|
||||
color_t border_color = MakeColor(255, 255, 255, 255);
|
||||
color_t border_color = themeCurrent.borderColor;
|
||||
|
||||
int shadow_start_y, shadow_y;
|
||||
int shadow_inset;
|
||||
@ -166,7 +183,7 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
|
||||
|
||||
for (y=start_y; y<end_y; y++) {
|
||||
for (x=start_x; x<end_x; x+=4) {
|
||||
Draw4PixelsRaw(x, y, MakeColor(255, 255, 255, 255));
|
||||
Draw4PixelsRaw(x, y, themeCurrent.borderColor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,6 +195,12 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
|
||||
smallimg = folder_icon_small;
|
||||
largeimg = folder_icon_bin;
|
||||
}
|
||||
else if (me->type == ENTRY_TYPE_THEME){
|
||||
smallimg = theme_icon_small;
|
||||
if(themeGlobalPreset == THEME_PRESET_DARK)
|
||||
largeimg = theme_icon_dark_bin;
|
||||
else largeimg = theme_icon_light_bin;
|
||||
}
|
||||
else {
|
||||
smallimg = invalid_icon_small;
|
||||
largeimg = invalid_icon_bin;
|
||||
@ -206,7 +229,7 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
|
||||
}
|
||||
}
|
||||
|
||||
DrawTextTruncate(interuiregular14, start_x + 4, start_y + 4 + 18, MakeColor(64, 64, 64, 255), me->name, 140 - 32, "...");
|
||||
DrawTextTruncate(interuiregular14, start_x + 4, start_y + 4 + 18, themeCurrent.borderTextColor, me->name, 140 - 32, "...");
|
||||
|
||||
if (is_active) {
|
||||
start_x = 1280 - 790;
|
||||
@ -267,10 +290,24 @@ void menuStartup() {
|
||||
|
||||
folder_icon_small = downscaleImg(folder_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
invalid_icon_small = downscaleImg(invalid_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
if(themeGlobalPreset == THEME_PRESET_DARK)
|
||||
theme_icon_small = downscaleImg(theme_icon_dark_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
else
|
||||
theme_icon_small = downscaleImg(theme_icon_light_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
computeFrontGradient(themeCurrent.frontWaveColor, 280);
|
||||
//menuCreateMsgBox(780, 300, "This is a test");
|
||||
}
|
||||
|
||||
void themeMenuStartup() {
|
||||
if(hbmenu_state != HBMENU_DEFAULT) return;
|
||||
hbmenu_state = HBMENU_THEME_MENU;
|
||||
char tmp_path[PATH_MAX];
|
||||
|
||||
snprintf(tmp_path, sizeof(tmp_path)-1, "%s%s%s%s%s%s",DIRECTORY_SEPARATOR, "config", DIRECTORY_SEPARATOR, "nx-hbmenu" , DIRECTORY_SEPARATOR, "themes");
|
||||
|
||||
themeMenuScan(tmp_path);
|
||||
}
|
||||
|
||||
color_t waveBlendAdd(color_t a, color_t b, float alpha) {
|
||||
return MakeColor(a.r+(b.r*alpha), a.g+b.g*alpha, a.b + b.b*alpha, 255);
|
||||
}
|
||||
@ -440,14 +477,25 @@ void menuLoop() {
|
||||
drawEntry(me, entry_start_x + menu->xPos, is_active);
|
||||
}
|
||||
|
||||
int getX = GetTextXCoordinate(interuiregular18, 1180, textGetString(StrId_ThemeMenu), 'r');
|
||||
|
||||
if(hbmenu_state == HBMENU_THEME_MENU) {
|
||||
DrawText(interuiregular18, getX, 0 + 47, themeCurrent.textColor, textGetString(StrId_ThemeMenu));
|
||||
} else {
|
||||
//DrawText(interuiregular18, getX, 0 + 47, themeCurrent.textColor, textGetString(StrId_ThemeMenu));
|
||||
//DrawText(fontscale7, getX - 40, 0 + 47, themeCurrent.textColor, themeCurrent.buttonMText);
|
||||
}
|
||||
|
||||
if(active_entry != NULL) {
|
||||
if (active_entry->type != ENTRY_TYPE_FOLDER) {
|
||||
//drawImage(1280 - 126 - 30 - 32, 720 - 48, 32, 32, themeCurrent.buttonAImage, IMAGE_MODE_RGBA32);
|
||||
if (active_entry->type == ENTRY_TYPE_THEME) {
|
||||
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));
|
||||
}
|
||||
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.
|
||||
DrawText(interuiregular18, 1280 - 90 - 30 - 32, 720 - 47 + 24, themeCurrent.textColor, textGetString(StrId_Actions_Launch));
|
||||
}
|
||||
else {
|
||||
//drawImage(1280 - 126 - 30 - 32, 720 - 48, 32, 32, themeCurrent.buttonAImage, IMAGE_MODE_RGBA32);
|
||||
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_Open));
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ typedef enum
|
||||
{
|
||||
ENTRY_TYPE_FILE,
|
||||
ENTRY_TYPE_FOLDER,
|
||||
ENTRY_TYPE_THEME,
|
||||
} MenuEntryType;
|
||||
|
||||
typedef struct menuEntry_s_tag menuEntry_s;
|
||||
@ -84,8 +85,10 @@ void menuEntryParseNacp(menuEntry_s* me);
|
||||
|
||||
menu_s* menuGetCurrent(void);
|
||||
int menuScan(const char* target);
|
||||
int themeMenuScan(const char* target);
|
||||
|
||||
void launchMenuEntryTask(menuEntry_s* arg);
|
||||
void launchApplyThemeTask(menuEntry_s* arg);
|
||||
void launchMenuBackTask();
|
||||
void launchMenuNetloaderTask();
|
||||
char *menuGetRootPath();
|
||||
@ -109,3 +112,9 @@ static inline char* getSlash(const char* str)
|
||||
return (char*)p;
|
||||
}
|
||||
|
||||
static inline char* removeDriveFromPath(const char* str) {
|
||||
const char* p;
|
||||
for (p = str; p <= (str+strlen(str)) && *p != ':'; p++);
|
||||
p++;//iterate one more time past ':'
|
||||
return (char*)p;
|
||||
}
|
123
common/theme.c
123
common/theme.c
@ -6,6 +6,9 @@
|
||||
#include "hbmenu_logo_light_bin.h"
|
||||
#include "hbmenu_logo_dark_bin.h"
|
||||
|
||||
theme_t themeCurrent;
|
||||
ThemePreset themeGlobalPreset;
|
||||
|
||||
bool colorFromSetting(config_setting_t *rgba, color_t *col) {
|
||||
if(rgba == NULL)
|
||||
return false;
|
||||
@ -14,6 +17,7 @@ bool colorFromSetting(config_setting_t *rgba, color_t *col) {
|
||||
}
|
||||
|
||||
void themeStartup(ThemePreset preset) {
|
||||
themeGlobalPreset = preset;
|
||||
theme_t themeLight = (theme_t) {
|
||||
.textColor = MakeColor(0, 0, 0, 255),
|
||||
.frontWaveColor = MakeColor(100, 212, 250, 255),
|
||||
@ -22,11 +26,13 @@ void themeStartup(ThemePreset preset) {
|
||||
.backgroundColor = MakeColor(233, 236, 241, 255),
|
||||
.highlightColor = MakeColor(91, 237, 224, 255),
|
||||
.separatorColor = MakeColor(219, 218, 219, 255),
|
||||
.borderColor = MakeColor(255,255,255,255),
|
||||
.borderTextColor = MakeColor(64,64,64,255),
|
||||
.enableWaveBlending = 0,
|
||||
.buttonAText = "\uE0E0",
|
||||
.buttonBText = "\uE0E1",
|
||||
//.buttonAImage = button_a_light_bin,
|
||||
//.buttonBImage = button_b_light_bin,
|
||||
.buttonPText = "\uE0EF",
|
||||
.buttonMText = "\uE0F0",
|
||||
.hbmenuLogoImage = hbmenu_logo_light_bin
|
||||
};
|
||||
|
||||
@ -38,31 +44,31 @@ void themeStartup(ThemePreset preset) {
|
||||
.backgroundColor = MakeColor(45, 45, 50, 255),
|
||||
.highlightColor = MakeColor(91, 237, 224, 255),
|
||||
.separatorColor = MakeColor(219, 218, 219, 255),
|
||||
.borderColor = MakeColor(255,255,255,255),
|
||||
.borderTextColor = MakeColor(64,64,64,255),
|
||||
.enableWaveBlending = 0,
|
||||
.buttonAText = "\uE0A0",
|
||||
.buttonBText = "\uE0A1",
|
||||
//.buttonAImage = button_a_dark_bin,
|
||||
//.buttonBImage = button_b_dark_bin,
|
||||
.buttonPText = "\uE0B3",
|
||||
.buttonMText = "\uE0B4",
|
||||
.hbmenuLogoImage = hbmenu_logo_dark_bin
|
||||
};
|
||||
|
||||
char tmp_path[PATH_MAX] = {0};
|
||||
|
||||
#ifdef __SWITCH__
|
||||
tmp_path[0] = '/';
|
||||
#endif
|
||||
char themePath[PATH_MAX] = {0};
|
||||
GetThemePathFromConfig(themePath, PATH_MAX);
|
||||
|
||||
strncat(tmp_path, "config/nx-hbmenu/themes/theme.cfg", sizeof(tmp_path)-2);
|
||||
|
||||
theme_t *themeDefault;
|
||||
config_t cfg = {0};
|
||||
config_init(&cfg);
|
||||
config_setting_t *theme;
|
||||
color_t text, frontWave, middleWave, backWave, background, highlight, separator;
|
||||
config_setting_t *theme = NULL;
|
||||
color_t text, frontWave, middleWave, backWave, background, highlight, separator, borderColor, borderTextColor;
|
||||
int waveBlending;
|
||||
const char *AText, *BText;
|
||||
bool good_cfg = config_read_file(&cfg, tmp_path);
|
||||
|
||||
const char *AText, *BText, *PText, *MText;
|
||||
bool good_cfg = false;
|
||||
|
||||
if(themePath[0]!=0)
|
||||
good_cfg = config_read_file(&cfg, themePath);
|
||||
|
||||
switch (preset) {
|
||||
case THEME_PRESET_LIGHT:
|
||||
default:
|
||||
@ -77,7 +83,7 @@ void themeStartup(ThemePreset preset) {
|
||||
theme = config_lookup(&cfg, "darkTheme");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (good_cfg) {
|
||||
if (theme != NULL) {
|
||||
if (!colorFromSetting(config_setting_lookup(theme, "textColor"), &text))
|
||||
@ -94,12 +100,20 @@ void themeStartup(ThemePreset preset) {
|
||||
highlight = themeDefault->highlightColor;
|
||||
if (!colorFromSetting(config_setting_lookup(theme, "separatorColor"), &separator))
|
||||
separator = themeDefault->separatorColor;
|
||||
if (!colorFromSetting(config_setting_lookup(theme, "borderColor"), &borderColor))
|
||||
borderColor = themeDefault->borderColor;
|
||||
if (!colorFromSetting(config_setting_lookup(theme, "borderTextColor"), &borderTextColor))
|
||||
borderTextColor = themeDefault->borderTextColor;
|
||||
if (!config_setting_lookup_int(theme, "enableWaveBlending", &waveBlending))
|
||||
waveBlending = themeDefault->enableWaveBlending;
|
||||
if (!config_setting_lookup_string(theme, "buttonAText", &AText))
|
||||
AText = themeDefault->buttonAText;
|
||||
if (!config_setting_lookup_string(theme, "buttonBText", &BText))
|
||||
BText = themeDefault->buttonBText;
|
||||
if (!config_setting_lookup_string(theme, "buttonPText", &PText))
|
||||
PText = themeDefault->buttonPText;
|
||||
if (!config_setting_lookup_string(theme, "buttonMText", &MText))
|
||||
MText = themeDefault->buttonMText;
|
||||
themeCurrent = (theme_t) {
|
||||
.textColor = text,
|
||||
.frontWaveColor = frontWave,
|
||||
@ -108,13 +122,15 @@ void themeStartup(ThemePreset preset) {
|
||||
.backgroundColor = background,
|
||||
.highlightColor = highlight,
|
||||
.separatorColor = separator,
|
||||
.borderColor = borderColor,
|
||||
.borderTextColor = borderTextColor,
|
||||
.enableWaveBlending = waveBlending,
|
||||
.buttonAText = AText,
|
||||
.buttonBText = BText,
|
||||
//.buttonAImage = button_a_dark_bin,
|
||||
//.buttonBImage = button_b_dark_bin,
|
||||
.hbmenuLogoImage = hbmenu_logo_dark_bin
|
||||
.hbmenuLogoImage = themeDefault->hbmenuLogoImage
|
||||
};
|
||||
strncpy(themeCurrent.buttonAText, AText, sizeof(themeCurrent.buttonAText)-1);
|
||||
strncpy(themeCurrent.buttonBText, BText, sizeof(themeCurrent.buttonBText)-1);
|
||||
strncpy(themeCurrent.buttonPText, PText, sizeof(themeCurrent.buttonPText)-1);
|
||||
strncpy(themeCurrent.buttonMText, MText, sizeof(themeCurrent.buttonMText)-1);
|
||||
} else {
|
||||
themeCurrent = *themeDefault;
|
||||
}
|
||||
@ -123,3 +139,66 @@ void themeStartup(ThemePreset preset) {
|
||||
}
|
||||
config_destroy(&cfg);
|
||||
}
|
||||
|
||||
void GetThemePathFromConfig(char* themePath, size_t size) {
|
||||
const char* tmpThemePath = "";
|
||||
config_t cfg = {0};
|
||||
config_setting_t *settings = NULL;
|
||||
char tmp_path[PATH_MAX] = {0};
|
||||
|
||||
#ifdef __SWITCH__
|
||||
tmp_path[0] = '/';
|
||||
#endif
|
||||
|
||||
strncat(tmp_path, "config/nx-hbmenu/settings.cfg", sizeof(tmp_path)-2);
|
||||
bool good_cfg = config_read_file(&cfg, tmp_path);
|
||||
|
||||
if(good_cfg) {
|
||||
settings = config_lookup(&cfg, "settings");
|
||||
if(settings != NULL) {
|
||||
if(config_setting_lookup_string(settings, "themePath", &tmpThemePath))
|
||||
strncpy(themePath, tmpThemePath, size-1);
|
||||
}
|
||||
}
|
||||
|
||||
config_destroy(&cfg);
|
||||
}
|
||||
|
||||
void SetThemePathToConfig(const char* themePath) {
|
||||
config_t cfg = {0};
|
||||
config_init(&cfg);
|
||||
|
||||
char settingPath[PATH_MAX] = {0};
|
||||
config_setting_t *root = NULL,
|
||||
*group = NULL,
|
||||
*settings = NULL;
|
||||
|
||||
#ifdef __SWITCH__
|
||||
settingPath[0] = '/';
|
||||
#endif
|
||||
|
||||
strncat(settingPath, "config/nx-hbmenu/settings.cfg", sizeof(settingPath)-2);
|
||||
bool good_cfg = config_read_file(&cfg, settingPath);
|
||||
|
||||
if(good_cfg) {
|
||||
group = config_lookup(&cfg, "settings");
|
||||
if(group != NULL)
|
||||
settings = config_setting_lookup(group, "themePath");
|
||||
if(settings != NULL)
|
||||
config_setting_set_string(settings, themePath);
|
||||
} else {
|
||||
root = config_root_setting(&cfg);
|
||||
if(root != NULL)
|
||||
group = config_setting_add(root, "settings", CONFIG_TYPE_GROUP);
|
||||
if(group != NULL)
|
||||
settings = config_setting_add(group, "themePath", CONFIG_TYPE_STRING);
|
||||
if(settings != NULL)
|
||||
config_setting_set_string(settings, themePath);
|
||||
}
|
||||
|
||||
if(!config_write_file(&cfg, settingPath)) {
|
||||
menuCreateMsgBox(780, 300, textGetString(StrId_ThemeNotApplied));
|
||||
}
|
||||
|
||||
config_destroy(&cfg);
|
||||
}
|
@ -12,12 +12,13 @@ typedef struct
|
||||
color_t backgroundColor;
|
||||
color_t highlightColor;
|
||||
color_t separatorColor;
|
||||
color_t activeColor;
|
||||
color_t borderColor;
|
||||
color_t borderTextColor;
|
||||
bool enableWaveBlending;
|
||||
const char *buttonAText;
|
||||
const char *buttonBText;
|
||||
//const uint8_t *buttonAImage;
|
||||
//const uint8_t *buttonBImage;
|
||||
char buttonAText[32];
|
||||
char buttonBText[32];
|
||||
char buttonPText[32];
|
||||
char buttonMText[32];
|
||||
const uint8_t *hbmenuLogoImage;
|
||||
} theme_t;
|
||||
|
||||
@ -28,7 +29,10 @@ typedef enum
|
||||
} ThemePreset;
|
||||
|
||||
bool colorFromSetting(config_setting_t *rgba, color_t *col);
|
||||
|
||||
void themeStartup(ThemePreset preset);
|
||||
void GetThemePathFromConfig(char* themePath, size_t size);
|
||||
void SetThemePathToConfig(const char* themePath);
|
||||
|
||||
theme_t themeCurrent;
|
||||
extern theme_t themeCurrent;
|
||||
|
||||
extern ThemePreset themeGlobalPreset;
|
||||
|
1
data/theme_icon_dark.bin
Normal file
1
data/theme_icon_dark.bin
Normal file
File diff suppressed because one or more lines are too long
1
data/theme_icon_light.bin
Normal file
1
data/theme_icon_light.bin
Normal file
File diff suppressed because one or more lines are too long
@ -135,6 +135,9 @@ bool menuUpdate(void) {
|
||||
{
|
||||
launchMenuBackTask();
|
||||
}
|
||||
else if(down & KEY_MINUS){
|
||||
themeMenuStartup();
|
||||
}
|
||||
else if (down & KEY_PLUS)
|
||||
{
|
||||
exitflag = 1;
|
||||
|
@ -66,6 +66,8 @@ extern "C" bool menuUpdate(void) {
|
||||
int new_return_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Return);
|
||||
static int y_state = 0;
|
||||
int new_y_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Y);
|
||||
static int t_state = 0;
|
||||
int new_t_state = sf::Keyboard::isKeyPressed(sf::Keyboard::T);
|
||||
|
||||
if(!new_y_state && y_state)
|
||||
{
|
||||
@ -77,6 +79,9 @@ extern "C" bool menuUpdate(void) {
|
||||
{
|
||||
launchMenuBackTask();
|
||||
}
|
||||
else if(!new_t_state && t_state){
|
||||
themeMenuStartup();
|
||||
}
|
||||
else if (!new_return_state && return_state)
|
||||
{
|
||||
if (menuIsMsgBoxOpen()) {
|
||||
|
BIN
resources/theme_icon_dark.png
Normal file
BIN
resources/theme_icon_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
resources/theme_icon_light.png
Normal file
BIN
resources/theme_icon_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
Loading…
Reference in New Issue
Block a user