Added support for using themes with extension '.romfs', which contains '/theme.cfg', optionally '/icon.jpg' for the menu-entry in theme-menu, and any assets. Added 'assets' group to theme config, this is only used with .romfs themes. Added 'backgroundImage' to layout theme config, which requires assets.background_image to be setup. Various improvements.
This commit is contained in:
parent
42a4ad9787
commit
d11585589e
@ -63,7 +63,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lminizip `freetype-config --libs` -lconfig -lturbojpeg
|
||||
LIBS := -lminizip `freetype-config --libs` -lconfig -lturbojpeg -lpng
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
|
@ -14,7 +14,7 @@ test : pc_main/main.cpp pc_main/pc_launch.c pc_main/pc_power.c pc_main/pc_netsta
|
||||
common/menu-entry.c common/menu-list.c common/message-box.c common/text.c \
|
||||
common/ui.c common/assets.c common/math.c common/theme.c \
|
||||
common/netloader.c
|
||||
gcc -Wall -O2 -g -DVERSION=\"v$(APP_VERSION)\" $(EXTRA_CFLAGS) `pkg-config freetype2 --cflags` $^ -lsfml-graphics -lsfml-window -lsfml-system -lstdc++ -lpthread `pkg-config freetype2 --libs` -lm -lminizip -lz -lconfig -lturbojpeg $(EXTRA_LDFLAGS) -I. -iquote $(DEVKITPRO)/libnx/include -Ibuild_pc -g -o $@
|
||||
gcc -Wall -O2 -g -DVERSION=\"v$(APP_VERSION)\" $(EXTRA_CFLAGS) `pkg-config freetype2 --cflags` $^ -lsfml-graphics -lsfml-window -lsfml-system -lstdc++ -lpthread `pkg-config freetype2 --libs` -lm -lminizip -lz -lconfig -lturbojpeg -lpng $(EXTRA_LDFLAGS) -I. -iquote $(DEVKITPRO)/libnx/include -Ibuild_pc -g -o $@
|
||||
|
||||
clean:
|
||||
rm -rf build_pc/ test test.*
|
||||
|
229
common/assets.c
229
common/assets.c
@ -1,32 +1,28 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <minizip/unzip.h>
|
||||
#include <png.h>
|
||||
|
||||
typedef struct {
|
||||
u8 *buffer;
|
||||
size_t size;
|
||||
const char *filename;
|
||||
} assetsDataEntry;
|
||||
|
||||
#define GENASSET(x) {.filename = x}
|
||||
#define GENASSET(_p, _mode, _w, _h) {{.path = _p, .imageMode = _mode, .imageSize = {_w, _h}}, {}}
|
||||
|
||||
static bool g_assetsInitialized = 0;
|
||||
assetsDataEntry g_assetsDataList[AssetId_Max] = {
|
||||
GENASSET("battery_icon.bin"),
|
||||
GENASSET("charging_icon.bin"),
|
||||
GENASSET("folder_icon.bin"),
|
||||
GENASSET("invalid_icon.bin"),
|
||||
GENASSET("hbmenu_logo_dark.bin"),
|
||||
GENASSET("hbmenu_logo_light.bin"),
|
||||
GENASSET("theme_icon_dark.bin"),
|
||||
GENASSET("theme_icon_light.bin"),
|
||||
GENASSET("airplane_icon.bin"),
|
||||
GENASSET("wifi_none_icon.bin"),
|
||||
GENASSET("wifi1_icon.bin"),
|
||||
GENASSET("wifi2_icon.bin"),
|
||||
GENASSET("wifi3_icon.bin"),
|
||||
GENASSET("eth_icon.bin"),
|
||||
GENASSET("eth_none_icon.bin"),
|
||||
assetsDataEntry g_assetsDataList[AssetId_Max][2] = {
|
||||
GENASSET("battery_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("charging_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("folder_icon.bin", IMAGE_MODE_RGB24, 256, 256),
|
||||
GENASSET("invalid_icon.bin", IMAGE_MODE_RGB24, 256, 256),
|
||||
GENASSET("hbmenu_logo_dark.bin", IMAGE_MODE_RGBA32, 140, 60),
|
||||
GENASSET("hbmenu_logo_light.bin", IMAGE_MODE_RGBA32, 140, 60),
|
||||
GENASSET("theme_icon_dark.bin", IMAGE_MODE_RGB24, 256, 256),
|
||||
GENASSET("theme_icon_light.bin", IMAGE_MODE_RGB24, 256, 256),
|
||||
GENASSET("airplane_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("wifi_none_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("wifi1_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("wifi2_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("wifi3_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("eth_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("eth_none_icon.bin", IMAGE_MODE_RGBA32, 24, 24),
|
||||
GENASSET("", IMAGE_MODE_RGB24, 1280, 720),
|
||||
};
|
||||
|
||||
static void assetsClearEntry(assetsDataEntry *entry) {
|
||||
@ -34,6 +30,20 @@ static void assetsClearEntry(assetsDataEntry *entry) {
|
||||
|
||||
entry->size = 0;
|
||||
entry->buffer = NULL;
|
||||
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
}
|
||||
|
||||
static void assetsSetPixelSize(assetsDataEntry *entry) {
|
||||
switch (entry->imageMode) {
|
||||
case IMAGE_MODE_RGB24:
|
||||
entry->pixSize = 3;
|
||||
break;
|
||||
|
||||
case IMAGE_MODE_RGBA32:
|
||||
entry->pixSize = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int assetsLoadFile(unzFile zipf, assetsDataEntry *entry) {
|
||||
@ -42,7 +52,9 @@ static int assetsLoadFile(unzFile zipf, assetsDataEntry *entry) {
|
||||
unz_file_info file_info;
|
||||
u8* buffer = NULL;
|
||||
|
||||
ret = unzLocateFile(zipf, entry->filename, 0);
|
||||
assetsSetPixelSize(entry);
|
||||
|
||||
ret = unzLocateFile(zipf, entry->path, 0);
|
||||
|
||||
if (ret==UNZ_OK) ret = unzOpenCurrentFile(zipf);
|
||||
|
||||
@ -50,7 +62,7 @@ static int assetsLoadFile(unzFile zipf, assetsDataEntry *entry) {
|
||||
ret = unzGetCurrentFileInfo(zipf, &file_info, NULL, 0, NULL, 0, NULL, 0);
|
||||
|
||||
filesize = file_info.uncompressed_size;
|
||||
if (filesize == 0) ret = -10;
|
||||
if (filesize != entry->imageSize[0] * entry->imageSize[1] * entry->pixSize) ret = -10;
|
||||
|
||||
if (ret==UNZ_OK) {
|
||||
buffer = (u8*)malloc(filesize);
|
||||
@ -88,7 +100,7 @@ Result assetsInit(void) {
|
||||
int i, stopi;
|
||||
unzFile zipf;
|
||||
assetsDataEntry *entry = NULL;
|
||||
char tmp_path[PATH_MAX+1];
|
||||
char tmp_path[PATH_MAX];
|
||||
|
||||
if (g_assetsInitialized) return 0;
|
||||
|
||||
@ -116,14 +128,17 @@ Result assetsInit(void) {
|
||||
|
||||
for (i=0; i<AssetId_Max; i++) {
|
||||
stopi = i;
|
||||
entry = &g_assetsDataList[i];
|
||||
ret = assetsLoadFile(zipf, entry);
|
||||
if (ret!=UNZ_OK) break;
|
||||
entry = &g_assetsDataList[i][0];
|
||||
if (entry->path[0]) {
|
||||
ret = assetsLoadFile(zipf, entry);
|
||||
if (ret!=UNZ_OK) break;
|
||||
entry->initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret!=UNZ_OK) {
|
||||
for (i=0; i<stopi; i++) {
|
||||
assetsClearEntry(&g_assetsDataList[i]);
|
||||
assetsClearEntry(&g_assetsDataList[i][0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,31 +154,157 @@ Result assetsInit(void) {
|
||||
}
|
||||
|
||||
void assetsExit(void) {
|
||||
int i;
|
||||
|
||||
if (!g_assetsInitialized) return;
|
||||
g_assetsInitialized = 0;
|
||||
|
||||
for (i=0; i<AssetId_Max; i++) {
|
||||
assetsClearEntry(&g_assetsDataList[i]);
|
||||
for (int i=0; i<AssetId_Max; i++) {
|
||||
assetsClearEntry(&g_assetsDataList[i][0]);
|
||||
}
|
||||
|
||||
assetsClearTheme();
|
||||
}
|
||||
|
||||
void assetsClearTheme(void) {
|
||||
for (int i=0; i<AssetId_Max; i++) {
|
||||
assetsClearEntry(&g_assetsDataList[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
void assetsGetData(AssetId id, u8 **buffer, size_t *size) {
|
||||
if (buffer) *buffer = NULL;
|
||||
if (size) *size = 0;
|
||||
bool assetsLoadJpgFromMemory(u8 *indata, size_t indata_size, u8 *outdata, ImageMode imageMode, size_t width, size_t height) {
|
||||
int w,h,samp;
|
||||
|
||||
tjhandle _jpegDecompressor = tjInitDecompress();
|
||||
|
||||
if (_jpegDecompressor == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tjDecompressHeader2(_jpegDecompressor, indata, indata_size, &w, &h, &samp) == -1) {
|
||||
tjDestroy(_jpegDecompressor);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (w != width || h != height ) {
|
||||
tjDestroy(_jpegDecompressor);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tjDecompress2(_jpegDecompressor, indata, indata_size, outdata, w, 0, h, imageMode == IMAGE_MODE_RGB24 ? TJPF_RGB : TJPF_RGBA, TJFLAG_ACCURATEDCT) == -1) {
|
||||
tjDestroy(_jpegDecompressor);
|
||||
return false;
|
||||
}
|
||||
|
||||
tjDestroy(_jpegDecompressor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool assetsLoadPngFromMemory(u8 *indata, size_t indata_size, u8 *outdata, ImageMode imageMode, size_t width, size_t height) {
|
||||
png_image image;
|
||||
bool ret=true;
|
||||
|
||||
memset(&image, 0, sizeof(image));
|
||||
image.version = PNG_IMAGE_VERSION;
|
||||
|
||||
if (png_image_begin_read_from_memory(&image, indata, indata_size) != 0) {
|
||||
if (image.width != width || image.height != height)
|
||||
ret = false;
|
||||
|
||||
if (ret) image.format = imageMode == IMAGE_MODE_RGB24 ? PNG_FORMAT_RGB : PNG_FORMAT_RGBA;
|
||||
|
||||
if (ret && png_image_finish_read(&image, NULL, outdata, 0, NULL) == 0)
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
|
||||
png_image_free(&image);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool assetsLoadFromTheme(AssetId id, const char *path, int *imageSize) {
|
||||
if (id < 0 || id >= AssetId_Max) return false;
|
||||
|
||||
assetsDataEntry *entry = &g_assetsDataList[id][1];
|
||||
if (entry->initialized) return false;
|
||||
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
|
||||
entry->imageSize[0] = imageSize[0];
|
||||
entry->imageSize[1] = imageSize[1];
|
||||
|
||||
entry->imageMode = g_assetsDataList[id][0].imageMode;
|
||||
assetsSetPixelSize(entry);
|
||||
entry->size = entry->imageSize[0] * entry->imageSize[1] * entry->pixSize;
|
||||
|
||||
strncpy(entry->path, path, sizeof(entry->path)-1);
|
||||
|
||||
const char* ext = getExtension(entry->path);
|
||||
bool ret=true;
|
||||
if (ext==NULL) ret = false;
|
||||
|
||||
u8 *data_buf = NULL;
|
||||
struct stat st;
|
||||
|
||||
if (ret && stat(path, &st)==-1) ret = false;
|
||||
|
||||
if (ret) {
|
||||
entry->buffer = (u8*)malloc(entry->size);
|
||||
if (entry->buffer) memset(entry->buffer, 0, entry->size);
|
||||
else ret = false;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
data_buf = (u8*)malloc(st.st_size);
|
||||
if (data_buf) memset(data_buf, 0, st.st_size);
|
||||
else ret = false;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
FILE *f = fopen(entry->path, "rb");
|
||||
if (f==NULL) ret = false;
|
||||
else {
|
||||
ret = fread(data_buf, st.st_size, 1, f) == 1;
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (strcasecmp(ext, ".bin")==0) {
|
||||
if (st.st_size != entry->size) ret = false;
|
||||
|
||||
if (ret) memcpy(entry->buffer, data_buf, entry->size);
|
||||
}
|
||||
else if (strcasecmp(ext, ".jpg")==0 || strcasecmp(ext, ".jpeg")==0)
|
||||
ret = assetsLoadJpgFromMemory(data_buf, st.st_size, entry->buffer, entry->imageMode, entry->imageSize[0], entry->imageSize[1]);
|
||||
else if (strcasecmp(ext, ".png")==0)
|
||||
ret = assetsLoadPngFromMemory(data_buf, st.st_size, entry->buffer, entry->imageMode, entry->imageSize[0], entry->imageSize[1]);
|
||||
else
|
||||
ret = false; // File extension not recognized.
|
||||
}
|
||||
|
||||
if (ret) entry->initialized = true;
|
||||
else assetsClearEntry(entry);
|
||||
|
||||
free(data_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void assetsGetData(AssetId id, assetsDataEntry **out) {
|
||||
if (out) *out = NULL;
|
||||
if (id < 0 || id >= AssetId_Max) return;
|
||||
|
||||
assetsDataEntry *entry = &g_assetsDataList[id];
|
||||
|
||||
if (buffer) *buffer = entry->buffer;
|
||||
if (size) *size = entry->size;
|
||||
u32 pos = g_assetsDataList[id][1].initialized ? 1 : 0;
|
||||
assetsDataEntry *entry = &g_assetsDataList[id][pos];
|
||||
if (entry->initialized) *out = entry;
|
||||
}
|
||||
|
||||
u8 *assetsGetDataBuffer(AssetId id) {
|
||||
u8 *buffer = NULL;
|
||||
assetsDataEntry *entry = NULL;
|
||||
|
||||
assetsGetData(id, &buffer, NULL);
|
||||
return buffer;
|
||||
assetsGetData(id, &entry);
|
||||
return entry ? entry->buffer : NULL;
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,27 @@ typedef enum {
|
||||
AssetId_wifi3_icon,
|
||||
AssetId_eth_icon,
|
||||
AssetId_eth_none_icon,
|
||||
AssetId_background_image,
|
||||
|
||||
AssetId_Max
|
||||
AssetId_Max,
|
||||
} AssetId;
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
u8 *buffer;
|
||||
size_t size;
|
||||
ImageMode imageMode;
|
||||
size_t pixSize;
|
||||
size_t imageSize[2];
|
||||
char path[PATH_MAX];
|
||||
} assetsDataEntry;
|
||||
|
||||
Result assetsInit(void);
|
||||
void assetsExit(void);
|
||||
void assetsGetData(AssetId id, u8 **buffer, size_t *size);
|
||||
void assetsClearTheme(void);
|
||||
bool assetsLoadFromTheme(AssetId id, const char *path, int *imageSize);
|
||||
void assetsGetData(AssetId id, assetsDataEntry **out);
|
||||
u8 *assetsGetDataBuffer(AssetId id);
|
||||
|
||||
bool assetsLoadJpgFromMemory(u8 *indata, size_t indata_size, u8 *outdata, ImageMode imageMode, size_t width, size_t height);
|
||||
|
||||
|
@ -59,6 +59,7 @@ typedef enum
|
||||
ThemeLayoutId_MenuTypeMsg,
|
||||
ThemeLayoutId_MsgBoxSeparator,
|
||||
ThemeLayoutId_MsgBoxBottomText,
|
||||
ThemeLayoutId_BackgroundImage,
|
||||
ThemeLayoutId_BackWave,
|
||||
ThemeLayoutId_MiddleWave,
|
||||
ThemeLayoutId_FrontWave,
|
||||
|
@ -106,12 +106,15 @@ static bool menuEntryImportIconGfx(menuEntry_s* me, uint8_t* icon_gfx, uint8_t*
|
||||
|
||||
if (icon_gfx == NULL || icon_gfx_small == NULL) return false;
|
||||
|
||||
tmpsize = 256*256*3;
|
||||
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon];
|
||||
ThemeLayoutObject *layoutobj2 = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListIcon];
|
||||
|
||||
tmpsize = layoutobj->imageSize[0]*layoutobj->imageSize[1]*3;
|
||||
me->icon_gfx = (uint8_t*)malloc(tmpsize);
|
||||
if (me->icon_gfx) memcpy(me->icon_gfx, icon_gfx, tmpsize);
|
||||
|
||||
if (me->icon_gfx) {
|
||||
tmpsize = 140*140*3;
|
||||
tmpsize = layoutobj2->imageSize[0]*layoutobj2->imageSize[1]*3;
|
||||
me->icon_gfx_small = (uint8_t*)malloc(tmpsize);
|
||||
if (me->icon_gfx_small) memcpy(me->icon_gfx_small, icon_gfx_small, tmpsize);
|
||||
|
||||
@ -403,8 +406,20 @@ bool menuEntryLoad(menuEntry_s* me, const char* name, bool shortcut, bool check_
|
||||
const char *name,
|
||||
*author = textGetString(StrId_DefaultPublisher),
|
||||
*version = "1.0.0";
|
||||
|
||||
if (config_read_file(&cfg, me->path)) {
|
||||
|
||||
const char* cfg_path = me->path;
|
||||
#ifdef __SWITCH__
|
||||
const char* ext = getExtension(me->path);
|
||||
bool is_romfs = false;
|
||||
if (strcasecmp(ext, ".romfs")==0) {
|
||||
if (R_FAILED(romfsMountFromFsdev(me->path, 0, "themetmp")))
|
||||
return false;
|
||||
is_romfs = true;
|
||||
cfg_path = "themetmp:/theme.cfg";
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config_read_file(&cfg, cfg_path)) {
|
||||
themeInfo = config_lookup(&cfg, "themeInfo");
|
||||
if (themeInfo != NULL) {
|
||||
if(config_setting_lookup_string(themeInfo, "name", &name))
|
||||
@ -417,6 +432,18 @@ bool menuEntryLoad(menuEntry_s* me, const char* name, bool shortcut, bool check_
|
||||
strncpy(me->author, author, sizeof(me->author)-1);
|
||||
strncpy(me->version, version, sizeof(me->version)-1);
|
||||
config_destroy(&cfg);
|
||||
|
||||
#ifdef __SWITCH__
|
||||
if (is_romfs) {
|
||||
bool iconLoaded = false;
|
||||
|
||||
iconLoaded = menuEntryLoadExternalIcon(me, "themetmp:/icon.jpg");
|
||||
|
||||
if (iconLoaded) menuEntryParseIcon(me);
|
||||
}
|
||||
|
||||
if (is_romfs) romfsUnmount("themetmp");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (me->type == ENTRY_TYPE_FILE_OTHER)
|
||||
@ -641,62 +668,24 @@ void menuEntryFileassocLoad(const char* filepath) {
|
||||
void menuEntryParseIcon(menuEntry_s* me) {
|
||||
if (me->icon_size==0 || me->icon==NULL) return;
|
||||
|
||||
int w,h,samp;
|
||||
size_t imagesize = 256*256*3;
|
||||
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon];
|
||||
ThemeLayoutObject *layoutobj2 = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListIcon];
|
||||
|
||||
size_t imagesize = layoutobj->imageSize[0]*layoutobj->imageSize[1]*3;
|
||||
bool ret=true;
|
||||
me->icon_gfx = (uint8_t*)malloc(imagesize);
|
||||
|
||||
if (me->icon_gfx == NULL) {
|
||||
me->icon_size = 0;
|
||||
free(me->icon);
|
||||
me->icon = NULL;
|
||||
return;
|
||||
}
|
||||
if (me->icon_gfx == NULL) ret = false;
|
||||
|
||||
tjhandle _jpegDecompressor = tjInitDecompress();
|
||||
|
||||
if (_jpegDecompressor == NULL) {
|
||||
free(me->icon_gfx);
|
||||
me->icon_gfx = NULL;
|
||||
|
||||
me->icon_size = 0;
|
||||
free(me->icon);
|
||||
me->icon = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tjDecompressHeader2(_jpegDecompressor, me->icon, me->icon_size, &w, &h, &samp) == -1) {
|
||||
free(me->icon_gfx);
|
||||
me->icon_gfx = NULL;
|
||||
|
||||
me->icon_size = 0;
|
||||
free(me->icon);
|
||||
me->icon = NULL;
|
||||
tjDestroy(_jpegDecompressor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (w != 256 || h != 256 ) return;
|
||||
|
||||
if (tjDecompress2(_jpegDecompressor, me->icon, me->icon_size, me->icon_gfx, w, 0, h, TJPF_RGB, TJFLAG_ACCURATEDCT) == -1) {
|
||||
free(me->icon_gfx);
|
||||
me->icon_gfx = NULL;
|
||||
|
||||
me->icon_size = 0;
|
||||
free(me->icon);
|
||||
me->icon = NULL;
|
||||
tjDestroy(_jpegDecompressor);
|
||||
return;
|
||||
}
|
||||
if (ret) ret = assetsLoadJpgFromMemory(me->icon, me->icon_size, me->icon_gfx, IMAGE_MODE_RGB24, layoutobj->imageSize[0], layoutobj->imageSize[1]);
|
||||
|
||||
me->icon_size = 0;
|
||||
free(me->icon);
|
||||
me->icon = NULL;
|
||||
|
||||
tjDestroy(_jpegDecompressor);
|
||||
if (ret) me->icon_gfx_small = downscaleImg(me->icon_gfx, layoutobj->imageSize[0], layoutobj->imageSize[1], layoutobj2->imageSize[0], layoutobj2->imageSize[1], IMAGE_MODE_RGB24);
|
||||
|
||||
me->icon_gfx_small = downscaleImg(me->icon_gfx, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
|
||||
if (me->icon_gfx_small == NULL) {
|
||||
if (!ret || me->icon_gfx_small == NULL) {
|
||||
free(me->icon_gfx);
|
||||
me->icon_gfx = NULL;
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ int themeMenuScan(const char* target) {
|
||||
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)
|
||||
if (strcasecmp(ext, ".cfg")==0 || strcasecmp(ext, ".romfs")==0)
|
||||
me = menuCreateEntry(ENTRY_TYPE_THEME);
|
||||
|
||||
if (!me)
|
||||
|
@ -8,6 +8,11 @@
|
||||
|
||||
char rootPathBase[PATH_MAX];
|
||||
char rootPath[PATH_MAX+8];
|
||||
|
||||
uint8_t *folder_icon_small;
|
||||
uint8_t *invalid_icon_small;
|
||||
uint8_t *theme_icon_small;
|
||||
|
||||
void computeFrontGradient(color_t baseColor, int height);
|
||||
|
||||
char *menuGetRootPath(void) {
|
||||
@ -113,12 +118,37 @@ void menuHandleXButton(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void menuStartupCommon(void) {
|
||||
free(folder_icon_small);
|
||||
free(invalid_icon_small);
|
||||
free(theme_icon_small);
|
||||
|
||||
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon];
|
||||
ThemeLayoutObject *layoutobj2 = &themeCurrent.layoutObjects[ThemeLayoutId_MenuListIcon];
|
||||
assetsDataEntry *data = NULL;
|
||||
|
||||
assetsGetData(AssetId_folder_icon, &data);
|
||||
folder_icon_small = downscaleImg(data->buffer, layoutobj->imageSize[0], layoutobj->imageSize[1], layoutobj2->imageSize[0], layoutobj2->imageSize[1], data->imageMode);
|
||||
assetsGetData(AssetId_invalid_icon, &data);
|
||||
invalid_icon_small = downscaleImg(data->buffer, layoutobj->imageSize[0], layoutobj->imageSize[1], layoutobj2->imageSize[0], layoutobj2->imageSize[1], data->imageMode);
|
||||
if(themeGlobalPreset == THEME_PRESET_DARK) {
|
||||
assetsGetData(AssetId_theme_icon_dark, &data);
|
||||
theme_icon_small = downscaleImg(data->buffer, layoutobj->imageSize[0], layoutobj->imageSize[1], layoutobj2->imageSize[0], layoutobj2->imageSize[1], data->imageMode);
|
||||
}
|
||||
else {
|
||||
assetsGetData(AssetId_theme_icon_light, &data);
|
||||
theme_icon_small = downscaleImg(data->buffer, layoutobj->imageSize[0], layoutobj->imageSize[1], layoutobj2->imageSize[0], layoutobj2->imageSize[1], data->imageMode);
|
||||
}
|
||||
|
||||
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_FrontWave];
|
||||
computeFrontGradient(themeCurrent.frontWaveColor, layoutobj->size[1]);
|
||||
}
|
||||
|
||||
void launchApplyThemeTask(menuEntry_s* arg) {
|
||||
const char* themePath = arg->path;
|
||||
SetThemePathToConfig(themePath);
|
||||
themeStartup(themeGlobalPreset);
|
||||
computeFrontGradient(themeCurrent.frontWaveColor, 280);
|
||||
menuStartupCommon();
|
||||
}
|
||||
|
||||
bool menuIsNetloaderActive(void) {
|
||||
@ -171,10 +201,6 @@ static void drawIcon(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) {
|
||||
ThemeLayoutObject *layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MenuList];
|
||||
int x, y;
|
||||
@ -413,14 +439,7 @@ void menuStartup(void) {
|
||||
|
||||
menuScan(rootPath);
|
||||
|
||||
folder_icon_small = downscaleImg(assetsGetDataBuffer(AssetId_folder_icon), 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
invalid_icon_small = downscaleImg(assetsGetDataBuffer(AssetId_invalid_icon), 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
if(themeGlobalPreset == THEME_PRESET_DARK)
|
||||
theme_icon_small = downscaleImg(assetsGetDataBuffer(AssetId_theme_icon_dark), 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
else
|
||||
theme_icon_small = downscaleImg(assetsGetDataBuffer(AssetId_theme_icon_light), 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||
computeFrontGradient(themeCurrent.frontWaveColor, 280);
|
||||
//menuCreateMsgBox(780, 300, "This is a test");
|
||||
menuStartupCommon();
|
||||
}
|
||||
|
||||
void themeMenuStartup(void) {
|
||||
@ -500,17 +519,22 @@ void drawCharge() {
|
||||
}
|
||||
|
||||
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);
|
||||
assetsDataEntry *data = NULL;
|
||||
assetsGetData(AssetId_battery_icon, &data);
|
||||
if (layoutobj->visible) drawIcon(layoutobj->posStart[0], layoutobj->posStart[1], data->imageSize[0], data->imageSize[1], data->buffer, themeCurrent.textColor);
|
||||
|
||||
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_ChargingIcon];
|
||||
assetsGetData(AssetId_charging_icon, &data);
|
||||
if (isCharging && layoutobj->visible)
|
||||
drawIcon(layoutobj->posStart[0], layoutobj->posStart[1], layoutobj->imageSize[0], layoutobj->imageSize[1], assetsGetDataBuffer(AssetId_charging_icon), themeCurrent.textColor);
|
||||
drawIcon(layoutobj->posStart[0], layoutobj->posStart[1], data->imageSize[0], data->imageSize[1], data->buffer, themeCurrent.textColor);
|
||||
}
|
||||
}
|
||||
|
||||
void drawNetwork(int tmpX, AssetId id) {
|
||||
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);
|
||||
assetsDataEntry *data = NULL;
|
||||
assetsGetData(id, &data);
|
||||
if (layoutobj->visible) drawIcon(layoutobj->posType ? tmpX + layoutobj->posStart[0] : layoutobj->posStart[0], layoutobj->posStart[1], data->imageSize[0], data->imageSize[1], data->buffer, themeCurrent.textColor);
|
||||
}
|
||||
|
||||
u32 drawStatus() {
|
||||
@ -637,6 +661,11 @@ void menuLoop(void) {
|
||||
}
|
||||
}
|
||||
|
||||
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_BackgroundImage];
|
||||
assetsDataEntry *data = NULL;
|
||||
assetsGetData(AssetId_background_image, &data);
|
||||
if (layoutobj->visible && data) drawImage(layoutobj->posStart[0], layoutobj->posStart[1], data->imageSize[0], endy < data->imageSize[1] ? endy : data->imageSize[1], data->buffer, data->imageMode);
|
||||
|
||||
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_BackWave];
|
||||
if (layoutobj->visible) drawWave(0, menuTimer, themeCurrent.backWaveColor, layoutobj->size[1], 0.0, 3.0);
|
||||
layoutobj = &themeCurrent.layoutObjects[ThemeLayoutId_MiddleWave];
|
||||
|
@ -62,6 +62,31 @@ bool layoutObjectFromSetting(config_setting_t *layout_setting, ThemeLayoutObject
|
||||
return true;
|
||||
}
|
||||
|
||||
bool assetObjectFromSetting(config_setting_t *asset_setting, AssetId id, ThemeLayoutObject *layoutobj) {
|
||||
int imageSize[2]={0};
|
||||
const char *path = NULL;
|
||||
char tmp_path[PATH_MAX];
|
||||
if (!asset_setting)
|
||||
return false;
|
||||
|
||||
if (config_setting_lookup_string(asset_setting, "path", &path)==CONFIG_FALSE)
|
||||
return false;
|
||||
|
||||
if (!intElemFromSetting(config_setting_lookup(asset_setting, "imageSize"), imageSize, 2))
|
||||
return false;
|
||||
|
||||
if (imageSize[0] <= 0 || imageSize[1] <= 0 || imageSize[0] > 1280 || imageSize[1] > 720)
|
||||
return false;
|
||||
|
||||
if (layoutobj && (imageSize[0] != layoutobj->imageSize[0] || imageSize[1] != layoutobj->imageSize[1]))
|
||||
return false;
|
||||
|
||||
memset(tmp_path, 0, sizeof(tmp_path));
|
||||
snprintf(tmp_path, sizeof(tmp_path)-1, "theme:/%s", path);
|
||||
|
||||
return assetsLoadFromTheme(id, tmp_path, imageSize);
|
||||
}
|
||||
|
||||
void themeStartup(ThemePreset preset) {
|
||||
themeGlobalPreset = preset;
|
||||
theme_t themeLight = (theme_t) {
|
||||
@ -184,6 +209,8 @@ void themeStartup(ThemePreset preset) {
|
||||
.posStart = {0, -29},
|
||||
},
|
||||
|
||||
// ThemeLayoutId_BackgroundImage is not set with the defaults.
|
||||
|
||||
[ThemeLayoutId_BackWave] = {
|
||||
.visible = true,
|
||||
.posType = true,
|
||||
@ -388,14 +415,31 @@ void themeStartup(ThemePreset preset) {
|
||||
theme_t *themeDefault;
|
||||
config_t cfg = {0};
|
||||
config_init(&cfg);
|
||||
config_setting_t *theme = NULL, *layout = NULL;
|
||||
config_setting_t *theme = NULL, *layout = NULL, *assets = NULL;
|
||||
color_t text, attentionText, frontWave, middleWave, backWave, background, highlight, separator, borderColor, borderTextColor, progressBarColor;
|
||||
int waveBlending;
|
||||
const char *AText, *BText, *XText, *YText, *PText, *MText, *starOnText, *starOffText;
|
||||
bool good_cfg = false;
|
||||
bool is_romfs = false;
|
||||
|
||||
if(themePath[0]!=0)
|
||||
good_cfg = config_read_file(&cfg, themePath);
|
||||
assetsClearTheme();
|
||||
|
||||
if(themePath[0]!=0) {
|
||||
const char* cfg_path = themePath;
|
||||
#ifdef __SWITCH__
|
||||
const char* ext = getExtension(themePath);
|
||||
if (strcasecmp(ext, ".romfs")==0) {
|
||||
if (R_FAILED(romfsMountFromFsdev(themePath, 0, "theme")))
|
||||
cfg_path = NULL;
|
||||
else {
|
||||
is_romfs = true;
|
||||
cfg_path = "theme:/theme.cfg";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cfg_path) good_cfg = config_read_file(&cfg, cfg_path);
|
||||
}
|
||||
|
||||
switch (preset) {
|
||||
case THEME_PRESET_LIGHT:
|
||||
@ -504,6 +548,7 @@ void themeStartup(ThemePreset preset) {
|
||||
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, "backgroundImage"), &themeCurrent.layoutObjects[ThemeLayoutId_BackgroundImage], 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);
|
||||
@ -532,6 +577,24 @@ void themeStartup(ThemePreset preset) {
|
||||
layoutObjectFromSetting(config_setting_lookup(layout, "menuActiveEntryAuthor"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryAuthor], false);
|
||||
layoutObjectFromSetting(config_setting_lookup(layout, "menuActiveEntryVersion"), &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryVersion], false);
|
||||
}
|
||||
|
||||
if (is_romfs) assets = config_lookup(&cfg, "assets");
|
||||
if (is_romfs && assets) {
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "battery_icon"), AssetId_battery_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "charging_icon"), AssetId_charging_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "folder_icon"), AssetId_folder_icon, &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon]);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "invalid_icon"), AssetId_invalid_icon, &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon]);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "theme_icon_dark"), AssetId_theme_icon_dark, &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon]);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "theme_icon_light"), AssetId_theme_icon_light, &themeCurrent.layoutObjects[ThemeLayoutId_MenuActiveEntryIcon]);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "airplane_icon"), AssetId_airplane_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "wifi_none_icon"), AssetId_wifi_none_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "wifi1_icon"), AssetId_wifi1_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "wifi2_icon"), AssetId_wifi2_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "wifi3_icon"), AssetId_wifi3_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "eth_icon"), AssetId_eth_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "eth_none_icon"), AssetId_eth_none_icon, NULL);
|
||||
assetObjectFromSetting(config_setting_lookup(assets, "background_image"), AssetId_background_image, NULL);
|
||||
}
|
||||
} else {
|
||||
themeCurrent = *themeDefault;
|
||||
memcpy(themeCurrent.layoutObjects, themeCommon.layoutObjects, sizeof(themeCommon.layoutObjects));
|
||||
@ -541,6 +604,10 @@ void themeStartup(ThemePreset preset) {
|
||||
if (layoutobj->posEnd[0] < 1) layoutobj->posEnd[0] = 1;
|
||||
|
||||
config_destroy(&cfg);
|
||||
|
||||
#ifdef __SWITCH__
|
||||
if (is_romfs) romfsUnmount("theme");
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetThemePathFromConfig(char* themePath, size_t size) {
|
||||
|
Loading…
Reference in New Issue
Block a user