Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions workspace/all/common/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void CFG_defaults(NextUISettings *cfg)

NextUISettings defaults = {
.fontFile = CFG_DEFAULT_FONT_FILE,
.themeFolder = CFG_DEFAULT_THEME_FOLDER,
.fontStyle = CFG_DEFAULT_FONT_STYLE,
.color1_255 = CFG_DEFAULT_COLOR1,
.color2_255 = CFG_DEFAULT_COLOR2,
Expand Down Expand Up @@ -134,6 +135,13 @@ void CFG_init(FontLoad_callback_t cb, ColorSet_callback_t ccb)
fontLoaded = true;
continue;
}
if (strncmp(line, "theme=", 6) == 0)
{
char *value = line + 6;
value[strcspn(value, "\n")] = 0;
CFG_setThemeFolder(value);
continue;
}
if (sscanf(line, "color1=%x", &temp_color) == 1)
{
char hexColor[7];
Expand Down Expand Up @@ -467,6 +475,23 @@ void CFG_setFontFile(const char* filename)
settings.onFontChange(fontPath);
}

const char* CFG_getThemeFolder(void)
{
return settings.themeFolder;
}

// empty folder means theme off
void CFG_setThemeFolder(const char* folder)
{
if (!folder || !folder[0] || strchr(folder, '/')) {
strncpy(settings.themeFolder, CFG_DEFAULT_THEME_FOLDER, sizeof(settings.themeFolder) - 1);
settings.themeFolder[sizeof(settings.themeFolder) - 1] = '\0';
} else {
strncpy(settings.themeFolder, folder, sizeof(settings.themeFolder) - 1);
settings.themeFolder[sizeof(settings.themeFolder) - 1] = '\0';
}
}

uint32_t CFG_getColor(int color_id)
{
switch (color_id)
Expand Down Expand Up @@ -1328,6 +1353,10 @@ void CFG_get(const char *key, char *value)
{
sprintf(value, "%i", CFG_getFontStyle());
}
else if (strcmp(key, "theme") == 0)
{
sprintf(value, "%s", CFG_getThemeFolder());
}

// meta, not a real setting
else if (strcmp(key, "fontpath") == 0)
Expand Down Expand Up @@ -1367,6 +1396,9 @@ void CFG_sync(void)
fprintf(file, "font=0\n");
else
fprintf(file, "font=%s\n", settings.fontFile);
// off stays out of the file so old installs stay the same
if (settings.themeFolder[0])
fprintf(file, "theme=%s\n", settings.themeFolder);
fprintf(file, "color1=0x%06X\n", settings.color1_255);
fprintf(file, "color2=0x%06X\n", settings.color2_255);
fprintf(file, "color3=0x%06X\n", settings.color3_255);
Expand Down Expand Up @@ -1434,6 +1466,7 @@ void CFG_print(void)
printf("\t\"font\": 0,\n");
else
printf("\t\"font\": 1,\n");
printf("\t\"theme\": \"%s\",\n", settings.themeFolder);
printf("\t\"color1\": \"0x%06X\",\n", settings.color1_255);
printf("\t\"color2\": \"0x%06X\",\n", settings.color2_255);
printf("\t\"color3\": \"0x%06X\",\n", settings.color3_255);
Expand Down
4 changes: 4 additions & 0 deletions workspace/all/common/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ typedef struct
{
// Theme
char fontFile[256];
char themeFolder[256]; // empty means off
int fontStyle; // 0x00 = TTF_STYLE_NORMAL, 0x01 = TTF_STYLE_BOLD, etc.
uint32_t color1_255; // not screen mapped
uint32_t color2_255; // not screen mapped
Expand Down Expand Up @@ -172,6 +173,7 @@ typedef struct
#define TRANSITION_COMFY 2

#define CFG_DEFAULT_FONT_FILE "font1.ttf" // Next
#define CFG_DEFAULT_THEME_FOLDER ""
#define CFG_DEFAULT_FONT_STYLE 0x01 // TTF_STYLE_BOLD (MinUI default)
#define CFG_DEFAULT_COLOR1 0xffffffU
#define CFG_DEFAULT_COLOR2 0x9b2257U
Expand Down Expand Up @@ -254,6 +256,8 @@ void CFG_get(const char *key, char * value);
// Custom fonts go in RES_PATH alongside built-in fonts.
const char* CFG_getFontFile(void);
void CFG_setFontFile(const char* filename);
const char* CFG_getThemeFolder(void);
void CFG_setThemeFolder(const char* folder);
// The font style to use for the UI font.
int CFG_getFontStyle(void);
void CFG_setFontStyle(int style);
Expand Down
77 changes: 70 additions & 7 deletions workspace/all/nextui/nextui.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,74 @@ typedef struct Entry {
int alpha; // index in parent Directory's alphas Array, which points to the index of an Entry in its entries Array :sweat_smile:
} Entry;

// theme bg.png replaces root bg.png when selected
static void getDefaultBackgroundPath(char* out_path, size_t out_size) {
const char* theme = CFG_getThemeFolder();
if (theme && theme[0]) {
char theme_path[MAX_PATH];
snprintf(theme_path, sizeof(theme_path), SDCARD_PATH "/Themes/%s/bg.png", theme);
if (exists(theme_path)) {
snprintf(out_path, out_size, "%s", theme_path);
return;
}
}
snprintf(out_path, out_size, SDCARD_PATH "/bg.png");
}

// these menu folders use plain theme names
static int getSpecialBackgroundName(char* folder_path, char* out_name) {
if (exactMatch(folder_path, COLLECTIONS_PATH))
strcpy(out_name, "Collections");
else if (exactMatch(folder_path, FAUX_RECENT_PATH))
strcpy(out_name, "Recently Played");
else if (exactMatch(folder_path, TOOLS_PATH))
strcpy(out_name, "Tools");
else
return 0;
return 1;
}

// pick a background without breaking old .media folders
static int getBackgroundPath(char* out_path, size_t out_size, char* folder_path, int type, char* default_path) {
if (type == ENTRY_DIR)
snprintf(out_path, out_size, "%s/.media/bg.png", folder_path);
else if (type == ENTRY_ROM)
snprintf(out_path, out_size, "%s/.media/bglist.png", folder_path);
else {
snprintf(out_path, out_size, "%s", default_path);
return 0;
}

// old media backgrounds stay first for compatibility and per-folder overrides
if (exists(out_path)) return 1;

const char* theme = CFG_getThemeFolder();
if (theme && theme[0]) {
char theme_name[MAX_PATH];
char theme_path[MAX_PATH];
theme_name[0] = '\0';

if (!exactMatch(folder_path, ROMS_PATH) && prefixMatch(ROMS_PATH, folder_path))
getEmuName(folder_path, theme_name);
else
getSpecialBackgroundName(folder_path, theme_name);

if (theme_name[0]) {
if (type == ENTRY_DIR)
snprintf(theme_path, sizeof(theme_path), SDCARD_PATH "/Themes/%s/%s.png", theme, theme_name);
else
snprintf(theme_path, sizeof(theme_path), SDCARD_PATH "/Themes/%s/%s-list.png", theme, theme_name);
if (exists(theme_path)) {
snprintf(out_path, out_size, "%s", theme_path);
return 1;
}
}
}

snprintf(out_path, out_size, "%s", default_path);
return 0;
}

static Entry* Entry_new(char* path, int type) {
char display_name[256];
getDisplayName(path, display_name);
Expand Down Expand Up @@ -2950,22 +3018,17 @@ int main (int argc, char *argv[]) {

// load folder background
char defaultBgPath[512];
snprintf(defaultBgPath, sizeof(defaultBgPath), SDCARD_PATH "/bg.png");
getDefaultBackgroundPath(defaultBgPath, sizeof(defaultBgPath));

if(((entry->type == ENTRY_DIR || entry->type == ENTRY_ROM) && CFG_getRomsUseFolderBackground())) {
char *newBg = entry->type == ENTRY_DIR ? entry->path:rompath;
if((strcmp(newBg, folderBgPath) != 0 || lastType != entry->type) && sizeof(folderBgPath) != 1) {
lastType = entry->type;
char tmppath[512];
strncpy(folderBgPath, newBg, sizeof(folderBgPath) - 1);
if (entry->type == ENTRY_DIR)
snprintf(tmppath, sizeof(tmppath), "%s/.media/bg.png", folderBgPath);
else if (entry->type == ENTRY_ROM)
snprintf(tmppath, sizeof(tmppath), "%s/.media/bglist.png", folderBgPath);
if(!exists(tmppath)) {
if(!getBackgroundPath(tmppath, sizeof(tmppath), folderBgPath, entry->type, defaultBgPath)) {
// Safeguard: If no background is available, still render the text to leave the user a way out
list_show_entry_names = true;
snprintf(tmppath, sizeof(tmppath), defaultBgPath, folderBgPath);
}
startLoadFolderBackground(tmppath, onBackgroundLoaded, NULL);
}
Expand Down
54 changes: 53 additions & 1 deletion workspace/all/settings/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ struct FontEntry {
std::string label;
};

struct ThemeEntry {
std::string folder;
std::string label;
};

static std::vector<FontEntry> enumerateFonts() {
std::vector<FontEntry> fonts;
fonts.push_back({"font1.ttf", "Next"});
Expand Down Expand Up @@ -125,6 +130,32 @@ static std::vector<FontEntry> enumerateFonts() {
return fonts;
}

static std::vector<ThemeEntry> enumerateThemes() {
std::vector<ThemeEntry> themes;
themes.push_back({"", "Off"});

// theme folders live at the sd root
DIR *dir = opendir(SDCARD_PATH "/Themes");
if (dir) {
struct dirent *ent;
while ((ent = readdir(dir)) != NULL) {
if (ent->d_name[0] == '.') continue;

char theme_path[MAX_PATH];
snprintf(theme_path, sizeof(theme_path), SDCARD_PATH "/Themes/%s", ent->d_name);
DIR *theme_dir = opendir(theme_path);
if (!theme_dir)
continue;
closedir(theme_dir);

themes.push_back({std::string(ent->d_name), std::string(ent->d_name)});
}
closedir(dir);
}

return themes;
}

static const std::vector<std::any> screen_timeout_secs = {0U, 5U, 10U, 15U, 30U, 45U, 60U, 90U, 120U, 240U, 360U, 600U};
static const std::vector<std::string> screen_timeout_labels = {"Never", "5s", "10s", "15s", "30s", "45s", "60s", "90s", "2m", "4m", "6m", "10m"};

Expand Down Expand Up @@ -403,6 +434,17 @@ int main(int argc, char *argv[])
[]() -> std::any { return std::string(CFG_getFontFile()); },
[](const std::any &value) { CFG_setFontFile(std::any_cast<std::string>(value).c_str()); },
[]() { CFG_setFontFile(CFG_DEFAULT_FONT_FILE); }});
auto themes = enumerateThemes();
std::vector<std::any> theme_values;
std::vector<std::string> theme_labels;
for (const auto &t : themes) {
theme_values.push_back(t.folder);
theme_labels.push_back(t.label);
}
appearanceItems.push_back(new MenuItem{ListItemType::Generic, "Theme", "Theme folder for menu backgrounds.", theme_values, theme_labels,
[]() -> std::any { return std::string(CFG_getThemeFolder()); },
[](const std::any &value) { CFG_setThemeFolder(std::any_cast<std::string>(value).c_str()); },
[]() { CFG_setThemeFolder(CFG_DEFAULT_THEME_FOLDER); }});
appearanceItems.push_back(new MenuItem{ListItemType::Generic, "Font style", "The style to render the UI font (e.g. bold)", std::vector<std::any>{0, 1}, std::vector<std::string>{"Normal", "Bold"},
[]() -> std::any { return CFG_getFontStyle(); },
[](const std::any &value) { CFG_setFontStyle(std::any_cast<int>(value)); },
Expand Down Expand Up @@ -1012,7 +1054,17 @@ int main(int argc, char *argv[])

ctx.menu = new MenuList(MenuItemType::List, "Main", mainItems);

SDL_Surface* bgbmp = IMG_Load(SDCARD_PATH "/bg.png");
char bg_path[MAX_PATH];
snprintf(bg_path, sizeof(bg_path), SDCARD_PATH "/bg.png");
const char* theme = CFG_getThemeFolder();
if (theme && theme[0]) {
char theme_bg_path[MAX_PATH];
snprintf(theme_bg_path, sizeof(theme_bg_path), SDCARD_PATH "/Themes/%s/bg.png", theme);
if (exists(theme_bg_path)) {
snprintf(bg_path, sizeof(bg_path), "%s", theme_bg_path);
}
}
SDL_Surface* bgbmp = IMG_Load(bg_path);
SDL_Surface* convertedbg = SDL_ConvertSurfaceFormat(bgbmp, SDL_PIXELFORMAT_RGB565, 0);
if (convertedbg) {
SDL_FreeSurface(bgbmp);
Expand Down
Loading