WiiFlow_Lite/source/menu/menu.cpp
2023-03-19 18:18:06 -05:00

2976 lines
108 KiB
C++

#include <fstream>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>
#include <wchar.h>
#include <network.h>
#include <errno.h>
#include "menu.hpp"
#include "types.h"
#include "fonts.h"
#include "banner/BannerWindow.hpp"
#include "channel/nand.hpp"
#include "channel/nand_save.hpp"
#include "gc/gc.hpp"
#include "hw/Gekko.h"
#include "gui/WiiMovie.hpp"
#include "loader/alt_ios.h"
#include "loader/cios.h"
#include "loader/fs.h"
#include "loader/nk.h"
#include "loader/playlog.h"
#include "loader/wbfs.h"
#include "music/SoundHandler.hpp"
#include "network/gcard.h"
#include "unzip/U8Archive.h"
#include "network/proxysettings.h"
// Sounds
extern const u8 click_wav[];
extern const u32 click_wav_size;
extern const u8 hover_wav[];
extern const u32 hover_wav_size;
extern const u8 camera_wav[];
extern const u32 camera_wav_size;
CMenu mainMenu;
//u8 CMenu::downloadStack[8192] ATTRIBUTE_ALIGN(32);
//const u32 CMenu::downloadStackSize = 8192;
CMenu::CMenu()
{
m_aa = 0;
m_thrdWorking = false;
m_thrdStop = false;
m_thrdProgress = 0.f;
m_locked = false;
m_favorites = false;
m_thrdNetwork = false;
m_mutex = 0;
m_showtimer = 0;
m_gameSoundThread = LWP_THREAD_NULL;
m_soundThrdBusy = false;
m_numCFVersions = 0;
m_bgCrossFade = 0;
m_bnrSndVol = 0;
m_directLaunch = false;
m_exit = false;
m_reload = false;
m_gamesound_changed = false;
m_video_playing = false;
m_base_font = NULL;
m_base_font_size = 0;
m_wbf1_font = NULL;
m_wbf2_font = NULL;
m_current_view = COVERFLOW_WII;
m_prevBg = NULL;
m_nextBg = NULL;
m_lqBg = NULL;
m_use_sd_logging = false;
m_use_wifi_gecko = false;
//m_init_network = false;
m_use_source = true;
m_sourceflow = false;
m_clearCats = false;
m_getFavs = true;
m_catStartPage = 1;
cacheCovers = false;
SF_cacheCovers = true;
m_snapshot_loaded = false;
curCustBg = 1;
/* Explorer stuff */
m_txt_view = false;
m_txt_path = NULL;
/* download stuff */
m_file = NULL;
m_buffer = NULL;
m_filesize = 0;
/* thread stuff */
m_thrdPtr = LWP_THREAD_NULL;
m_thrdInstalling = false;
m_thrdUpdated = false;
m_thrdDone = false;
m_thrdWritten = 0;
m_thrdTotal = 0;
/* screensaver */
no_input_time = 0;
/* Autoboot stuff */
m_source_autoboot = false;
}
bool CMenu::init(bool usb_mounted)
{
/* Clear Playlog to prevent wiiflow from being added to it */
Playlog_Delete();
/* Find the first partition with apps/wiiflow folder */
const char *drive = NULL;
struct stat dummy;
for(int i = SD; i <= USB8; i++)
{
if(DeviceHandle.IsInserted(i) && DeviceHandle.GetFSType(i) != PART_FS_WBFS && stat(fmt("%s:/%s", DeviceName[i], APPS_DIR), &dummy) == 0)
{
drive = DeviceName[i];
break;
}
}
if(drive == NULL) // Could not find apps/wiiflow so we can't go on
return false;
m_appDir = fmt("%s:/%s", drive, APPS_DIR);
gprintf("Wiiflow boot.dol Location: %s\n", m_appDir.c_str());
m_imgsDir = fmt("%s/imgs", m_appDir.c_str());
m_binsDir = fmt("%s/bins", m_appDir.c_str());
/* Set data folder on same device as the apps/wiiflow folder */
m_dataDir = fmt("%s:/%s", drive, APP_DATA_DIR);
gprintf("Data Directory: %s\n", m_dataDir.c_str());
/* Load/Create wiiflow.ini so we can get settings to start Gecko and Network */
m_cfg.load(fmt("%s/" CFG_FILENAME, m_appDir.c_str()));
/* ------------------------------------------------------*/
/* setup debugging stuff after loading wiiflow.ini */
show_mem = m_cfg.getBool("DEBUG", "show_mem", false);
/* Check if we want WiFi Gecko */
m_use_wifi_gecko = m_cfg.getBool("DEBUG", "wifi_gecko", false);
WiFiDebugger.SetBuffer(m_use_wifi_gecko);
if(m_use_wifi_gecko || m_cfg.getBool("GENERAL", "async_network", false))
_initAsyncNetwork();
/* Check if we want SD Gecko */
m_use_sd_logging = m_cfg.getBool("DEBUG", "sd_write_log", false);
LogToSD_SetBuffer(m_use_sd_logging);
/* ------------------------------------------------------*/
/* Init gamer tags now in case we need to init network on boot */
m_cfg.setString("GAMERCARD", "gamercards", "wiinnertag");
m_cfg.getString("GAMERCARD", "wiinnertag_url", WIINNERTAG_URL);
m_cfg.getString("GAMERCARD", "wiinnertag_key", "");
if(m_cfg.getBool("GAMERCARD", "gamercards_enable", false))
{
vector<string> gamercards = stringToVector(m_cfg.getString("GAMERCARD", "gamercards"), '|');
if (gamercards.size() == 0)
{
gamercards.push_back("wiinnertag");
}
for (vector<string>::iterator itr = gamercards.begin(); itr != gamercards.end(); itr++)
{
gprintf("Found gamercard provider: %s\n",(*itr).c_str());
register_card_provider(
m_cfg.getString("GAMERCARD", fmt("%s_url", (*itr).c_str())).c_str(),
m_cfg.getString("GAMERCARD", fmt("%s_key", (*itr).c_str())).c_str()
);
}
}
/* Init Network if wanted for gamercard if it isn't already inited */
if(has_enabled_providers())
_initAsyncNetwork();
/* Set the proxy settings */
proxyUseSystem = m_cfg.getBool("PROXY", "proxy_use_system", true);
memset(proxyAddress, 0, sizeof(proxyAddress));
strncpy(proxyAddress, m_cfg.getString("PROXY", "proxy_address", "").c_str(), sizeof(proxyAddress) - 1);
proxyPort = m_cfg.getInt("PROXY", "proxy_port", 0);
memset(proxyUsername, 0, sizeof(proxyUsername));
strncpy(proxyUsername, m_cfg.getString("PROXY", "proxy_username", "").c_str(), sizeof(proxyUsername) - 1);
memset(proxyPassword, 0, sizeof(proxyPassword));
strncpy(proxyPassword, m_cfg.getString("PROXY", "proxy_password", "").c_str(), sizeof(proxyPassword) - 1);
getProxyInfo();
/* set default homebrew partition for first boot */
m_cfg.getInt(HOMEBREW_DOMAIN, "partition", strcmp(drive, "sd") == 0 ? 0 : 1);// drive is device where wiiflow is.
/* Set SD only to off if any usb device is attached */
bool cfg_sdonly = m_cfg.getBool("GENERAL", "sd_only", usb_mounted ? false : true);// will only set it if this doesn't already exist - very first boot up
if(cfg_sdonly != sdOnly)// done for backwards compatibility with older wiiflow lite's
InternalSave.SaveSDOnly(cfg_sdonly);
/* set default wii games partition in case this is the first boot */
int wp = m_cfg.getInt(WII_DOMAIN, "partition", -1);
if(wp < 0)
{
if(!m_cfg.getBool("GENERAL", "sd_only"))
{
for(int i = SD; i <= USB8; i++) // Find first wbfs folder or a partition of wbfs file system
{
if(DeviceHandle.IsInserted(i) && (DeviceHandle.GetFSType(i) == PART_FS_WBFS || stat(fmt(GAMES_DIR, DeviceName[i]), &dummy) == 0))
{
wp = i;
break;
}
}
}
if(wp < 0)// not found
{
if(DeviceHandle.IsInserted(SD))// set to sd if inserted otherwise USB1
wp = 0;
else
wp = 1;
}
m_cfg.setInt(WII_DOMAIN, "partition", wp);
}
/* preferred partition setting - negative 1 means not set by user so skip this */
int pp = m_cfg.getInt(WII_DOMAIN, "preferred_partition", -1);
if(pp >= 0)
{
if(usb_mounted && pp > 0)
m_cfg.setInt(WII_DOMAIN, "partition", pp);
else
m_cfg.setInt(WII_DOMAIN, "partition", SD);
}
pp = m_cfg.getInt(GC_DOMAIN, "preferred_partition", -1);
if(pp >= 0)
{
if(usb_mounted && pp > 0)
m_cfg.setInt(GC_DOMAIN, "partition", USB1);
else
m_cfg.setInt(GC_DOMAIN, "partition", SD);
}
/* Our Wii games dir */
u8 partition = m_cfg.getInt(WII_DOMAIN, "partition");
gprintf("Setting Wii games partition to: %i\n", partition);
memset(wii_games_dir, 0, 64);
strncpy(wii_games_dir, m_cfg.getString(WII_DOMAIN, "wii_games_dir", GAMES_DIR).c_str(), 63);
if(strncmp(wii_games_dir, "%s:/", 4) != 0)
strcpy(wii_games_dir, GAMES_DIR);
gprintf("Wii Games Directory: %s\n", wii_games_dir);
/* GameCube stuff */
memset(gc_games_dir, 0, 64);
strncpy(gc_games_dir, m_cfg.getString(GC_DOMAIN, "gc_games_dir", DF_GC_GAMES_DIR).c_str(), 63);
if(strncmp(gc_games_dir, "%s:/", 4) != 0)
strcpy(gc_games_dir, DF_GC_GAMES_DIR);
gprintf("GameCube Games Directory: %s\n", gc_games_dir);
m_devo_installed = DEVO_Installed(m_dataDir.c_str());
m_nintendont_installed = Nintendont_Installed();
m_gc_play_banner_sound = m_cfg.getBool(GC_DOMAIN, "play_banner_sound", true);
m_gc_play_default_sound = m_cfg.getBool(GC_DOMAIN, "play_default_sound", true);
/* init directories */
m_cacheDir = m_cfg.getString("GENERAL", "dir_cache", fmt("%s/cache", m_dataDir.c_str()));
m_listCacheDir = m_cfg.getString("GENERAL", "dir_list_cache", fmt("%s/lists", m_cacheDir.c_str()));
m_bnrCacheDir = m_cfg.getString("GENERAL", "dir_banner_cache", fmt("%s/banners", m_cacheDir.c_str()));
m_customBnrDir = m_cfg.getString("GENERAL", "dir_custom_banners", fmt("%s/custom_banners", m_dataDir.c_str()));
m_txtCheatDir = m_cfg.getString("GENERAL", "dir_txtcheat", fmt("%s/codes", m_dataDir.c_str()));
m_cheatDir = m_cfg.getString("GENERAL", "dir_cheat", fmt("%s/gct", m_txtCheatDir.c_str()));
m_wipDir = m_cfg.getString("GENERAL", "dir_wip", fmt("%s/wip", m_txtCheatDir.c_str()));
m_settingsDir = m_cfg.getString("GENERAL", "dir_settings", fmt("%s/settings", m_dataDir.c_str()));
m_languagesDir = m_cfg.getString("GENERAL", "dir_languages", fmt("%s/languages", m_dataDir.c_str()));
m_helpDir = m_cfg.getString("GENERAL", "dir_help", fmt("%s/help", m_dataDir.c_str()));
m_screenshotDir = m_cfg.getString("GENERAL", "dir_screenshot", fmt("%s/screenshots", m_dataDir.c_str()));
m_wiiTDBDir = m_cfg.getString("GENERAL", "dir_wiitdb", fmt("%s",m_settingsDir.c_str()));
m_boxPicDir = m_cfg.getString("GENERAL", "dir_box_covers", fmt("%s/boxcovers", m_dataDir.c_str()));
m_picDir = m_cfg.getString("GENERAL", "dir_flat_covers", fmt("%s/covers", m_dataDir.c_str()));
m_themeDir = m_cfg.getString("GENERAL", "dir_themes_lite", fmt("%s/themes_lite", m_dataDir.c_str()));
m_coverflowsDir = m_cfg.getString("GENERAL", "dir_coverflows", fmt("%s/coverflows", m_themeDir.c_str()));
m_musicDir = m_cfg.getString("GENERAL", "dir_music", fmt("%s/music", m_dataDir.c_str()));
m_videoDir = m_cfg.getString("GENERAL", "dir_trailers", fmt("%s/trailers", m_dataDir.c_str()));
m_fanartDir = m_cfg.getString("GENERAL", "dir_fanart", fmt("%s/fanart", m_dataDir.c_str()));
m_bckgrndsDir = m_cfg.getString("GENERAL", "dir_backgrounds", fmt("%s/backgrounds", m_dataDir.c_str()));
m_sourceDir = m_cfg.getString("GENERAL", "dir_Source", fmt("%s/source_menu", m_dataDir.c_str()));
m_pluginsDir = m_cfg.getString("GENERAL", "dir_plugins", fmt("%s/plugins", m_dataDir.c_str()));
m_pluginDataDir = m_cfg.getString("GENERAL", "dir_plugins_data", fmt("%s/plugins_data", m_dataDir.c_str()));
m_cartDir = m_cfg.getString("GENERAL", "dir_cart", fmt("%s/cart_disk", m_dataDir.c_str()));
m_snapDir = m_cfg.getString("GENERAL", "dir_snap", fmt("%s/snapshots", m_dataDir.c_str()));
/* Create our Folder Structure */
fsop_MakeFolder(m_dataDir.c_str()); //D'OH!
fsop_MakeFolder(m_cacheDir.c_str());
fsop_MakeFolder(m_listCacheDir.c_str());
fsop_MakeFolder(m_bnrCacheDir.c_str());
fsop_MakeFolder(m_customBnrDir.c_str());
fsop_MakeFolder(m_txtCheatDir.c_str());
fsop_MakeFolder(m_cheatDir.c_str());
fsop_MakeFolder(m_wipDir.c_str());
fsop_MakeFolder(m_settingsDir.c_str());
fsop_MakeFolder(m_languagesDir.c_str());
fsop_MakeFolder(m_screenshotDir.c_str());
fsop_MakeFolder(m_helpDir.c_str());
fsop_MakeFolder(m_boxPicDir.c_str());
fsop_MakeFolder(m_picDir.c_str());
fsop_MakeFolder(m_themeDir.c_str());
fsop_MakeFolder(m_coverflowsDir.c_str());
fsop_MakeFolder(m_musicDir.c_str());
fsop_MakeFolder(m_videoDir.c_str());
fsop_MakeFolder(m_fanartDir.c_str());
fsop_MakeFolder(m_bckgrndsDir.c_str());
fsop_MakeFolder(m_sourceDir.c_str());
fsop_MakeFolder(m_pluginsDir.c_str());
fsop_MakeFolder(m_pluginDataDir.c_str());
fsop_MakeFolder(m_cartDir.c_str());
fsop_MakeFolder(m_snapDir.c_str());
if(!isWiiVC)
{
/* Emu nands init even if not being used */
memset(emu_nands_dir, 0, sizeof(emu_nands_dir));
bool vwiinands = IsOnWiiU() && m_cfg.getBool(CHANNEL_DOMAIN, "use_vwiinands", true);
strncpy(emu_nands_dir, vwiinands ? "vwiinands" : "nands", sizeof(emu_nands_dir) - 1);
int dev = DeviceHandle.PartitionUsableForNandEmu(SD) ? 0 : 1;
string emuNand = m_cfg.getString(CHANNEL_DOMAIN, "current_emunand", "default");// just to set to default on first boot
int emuPart = m_cfg.getInt(CHANNEL_DOMAIN, "partition", dev);
string savesNand = m_cfg.getString(WII_DOMAIN, "current_save_emunand", "default");
int savesPart = m_cfg.getInt(WII_DOMAIN, "savepartition", dev);
gprintf("emunand = %s:/%s/%s\n", DeviceName[emuPart], emu_nands_dir, emuNand.c_str());
gprintf("savesnand = %s:/%s/%s\n", DeviceName[savesPart], emu_nands_dir, savesNand.c_str());
m_cfg.getInt(CHANNEL_DOMAIN, "emulation", 0);// partial by default
m_cfg.getInt(WII_DOMAIN, "save_emulation", 0);// off by default
}
/* misc. setup */
SoundHandle.Init();
m_gameSound.SetVoice(1);
_loadDefaultFont();// load default font
LWP_MutexInit(&m_mutex, 0);
/* Load cIOS Map */
_installed_cios.clear();
_load_installed_cioses();
/* Check if wiiflow is parental locked */
m_locked = m_cfg.getString("GENERAL", "parent_code", "").size() >= 4;
/* Switch WFLA to DWFA in case they were using old wiiflow lite */
if(m_cfg.getString("GENERAL", "returnto") == "WFLA")
m_cfg.setString("GENERAL", "returnto", "DWFA");
/* set WIIFLOW_DEF exit to option */
/* 0 thru 2 of exit to enum (EXIT_TO_MENU, EXIT_TO_HBC, EXIT_TO_WIIU) in sys.h */
int exit_to = min(max(0, m_cfg.getInt("GENERAL", "exit_to", 0)), (int)ARRAY_SIZE(CMenu::_exitTo) - 1);
Sys_ExitTo(exit_to);
/* load misc config files */
m_cat.load(fmt("%s/" CAT_FILENAME, m_settingsDir.c_str()));
m_gcfg1.load(fmt("%s/" GAME_SETTINGS1_FILENAME, m_settingsDir.c_str()));
m_platform.load(fmt("%s/platform.ini", m_pluginDataDir.c_str()));
/* Init plugins */
m_plugin.init(m_pluginsDir);
vector<string> magics = m_cfg.getStrings(PLUGIN_DOMAIN, "enabled_plugins", ',');
if(magics.size() > 0)
{
enabledPluginsCount = 0;
string enabledMagics;
for(u8 i = 0; i < magics.size(); i++)
{
u8 pos = m_plugin.GetPluginPosition(strtoul(magics[i].c_str(), NULL, 16));
if(pos < 255)
{
enabledPluginsCount++;
m_plugin.SetEnablePlugin(pos, 2);
if(enabledPluginsCount == 1)
enabledMagics = magics[i];
else
enabledMagics.append(',' + magics[i]);
}
}
m_cfg.setString(PLUGIN_DOMAIN, "enabled_plugins", enabledMagics);
magics.clear();
}
/* Set wiiflow language */
const char *defLang = "Default";
switch (CONF_GetLanguage())
{
case CONF_LANG_JAPANESE:
defLang = "japanese";
break;
case CONF_LANG_GERMAN:
defLang = "german";
break;
case CONF_LANG_FRENCH:
defLang = "french";
break;
case CONF_LANG_SPANISH:
defLang = "spanish";
break;
case CONF_LANG_ITALIAN:
defLang = "italian";
break;
case CONF_LANG_DUTCH:
defLang = "dutch";
break;
case CONF_LANG_SIMP_CHINESE:
defLang = "chinese_s";
break;
case CONF_LANG_TRAD_CHINESE:
defLang = "chinese_t";
break;
case CONF_LANG_KOREAN:
defLang = "korean";
break;
case CONF_LANG_ENGLISH:
defLang = "english";
break;
}
if(CONF_GetArea() == CONF_AREA_BRA)
defLang = "brazilian";
m_curLanguage = m_cfg.getString("GENERAL", "language", defLang);
if(!m_loc.load(fmt("%s/%s.ini", m_languagesDir.c_str(), m_curLanguage.c_str())))
{
m_curLanguage = "Default";
m_cfg.setString("GENERAL", "language", m_curLanguage.c_str());
m_loc.unload();
}
/* Init gametdb and custom titles for game list making */
m_cacheList.Init(m_settingsDir.c_str(), m_loc.getString(m_curLanguage, "gametdb_code", "EN").c_str(), m_pluginDataDir.c_str(),
m_cfg.getString(CONFIG_FILENAME_SKIP_DOMAIN, CONFIG_FILENAME_SKIP_KEY, CONFIG_FILENAME_SKIP_DEFAULT));
/* Coverflow init */
CoverFlow.init(m_base_font, m_base_font_size, m_vid.vid_50hz());
/* Load theme and coverflow files */
m_themeName = m_cfg.getString("GENERAL", "theme", "default");
m_themeDataDir = fmt("%s/%s", m_themeDir.c_str(), m_themeName.c_str());
m_theme.load(fmt("%s.ini", m_themeDataDir.c_str()));
m_coverflow.load(fmt("%s/%s.ini", m_coverflowsDir.c_str(), m_themeName.c_str()));
if(!m_coverflow.loaded())
m_coverflow.load(fmt("%s/default.ini", m_coverflowsDir.c_str()));
/* Init the onscreen pointer */
m_aa = 3;
CColor pShadowColor = m_theme.getColor("GENERAL", "pointer_shadow_color", CColor(0x3F000000));
float pShadowX = m_theme.getFloat("GENERAL", "pointer_shadow_x", 3.f);
float pShadowY = m_theme.getFloat("GENERAL", "pointer_shadow_y", 3.f);
bool pShadowBlur = m_theme.getBool("GENERAL", "pointer_shadow_blur", false);
for(int chan = WPAD_MAX_WIIMOTES-1; chan >= 0; chan--)
{
m_cursor[chan].init(fmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString("GENERAL", fmt("pointer%i", chan+1)).c_str()),
m_vid.wide(), pShadowColor, pShadowX, pShadowY, pShadowBlur, chan);
WPAD_SetVRes(chan, m_vid.width() + m_cursor[chan].width(), m_vid.height() + m_cursor[chan].height());
}
/* Init background Music Player and song info */
MusicPlayer.Init(m_cfg, m_musicDir, fmt("%s/music", m_themeDataDir.c_str()));
m_music_info = m_cfg.getBool("GENERAL", "display_music_info", false);
MusicPlayer.SetResampleSetting(m_cfg.getBool("general", "resample_to_48khz", false));
/* set sound volumes */
CoverFlow.setSoundVolume(m_cfg.getInt("GENERAL", "sound_volume_coverflow", 255));
m_bnrSndVol = m_cfg.getInt("GENERAL", "sound_volume_bnr", 255);
m_bnr_settings = m_cfg.getBool("GENERAL", "banner_in_settings", true);
/* Init Button Manager and build the menus */
_buildMenus();
return true;
}
bool cleaned_up = false;
void CMenu::cleanup()
{
if(cleaned_up)
return;
//gprintf("MEM1_freesize(): %i\nMEM2_freesize(): %i\n", MEM1_freesize(), MEM2_freesize());
m_btnMgr.hide(m_mainLblCurMusic);
_stopSounds();
MusicPlayer.Cleanup();
_cleanupDefaultFont();
CoverFlow.shutdown(); /* possibly plugin flow crash so cleanup early */
m_banner.DeleteBanner();
m_plugin.Cleanup();
m_source.save(true);
m_platform.unload();
m_loc.unload();
_Theme_Cleanup();
for(int chan = WPAD_MAX_WIIMOTES-1; chan >= 0; chan--)
m_cursor[chan].cleanup();
m_gameSound.FreeMemory();
SoundHandle.Cleanup();
soundDeinit();
m_vid.cleanup();
wiiLightOff();
LWP_MutexDestroy(m_mutex);
m_mutex = 0;
cleaned_up = true;
//gprintf(" \nMemory cleaned up\n");
gprintf("MEM1_freesize(): %i\nMEM2_freesize(): %i\n", MEM1_freesize(), MEM2_freesize());
}
void CMenu::_Theme_Cleanup(void)
{
/* Backgrounds */
TexHandle.Cleanup(theme.bg);
m_prevBg = NULL;
m_nextBg = NULL;
TexHandle.Cleanup(m_curBg);
m_lqBg = NULL;
TexHandle.Cleanup(m_mainCustomBg[0]);
TexHandle.Cleanup(m_mainCustomBg[1]);
/* Buttons */
TexHandle.Cleanup(theme.btnTexL);
TexHandle.Cleanup(theme.btnTexR);
TexHandle.Cleanup(theme.btnTexC);
TexHandle.Cleanup(theme.btnTexLS);
TexHandle.Cleanup(theme.btnTexRS);
TexHandle.Cleanup(theme.btnTexCS);
TexHandle.Cleanup(theme.btnAUOn);
TexHandle.Cleanup(theme.btnAUOns);
TexHandle.Cleanup(theme.btnAUOff);
TexHandle.Cleanup(theme.btnAUOffs);
TexHandle.Cleanup(theme.btnENOn);
TexHandle.Cleanup(theme.btnENOns);
TexHandle.Cleanup(theme.btnENOff);
TexHandle.Cleanup(theme.btnENOffs);
TexHandle.Cleanup(theme.btnJAOn);
TexHandle.Cleanup(theme.btnJAOns);
TexHandle.Cleanup(theme.btnJAOff);
TexHandle.Cleanup(theme.btnJAOffs);
TexHandle.Cleanup(theme.btnFROn);
TexHandle.Cleanup(theme.btnFROns);
TexHandle.Cleanup(theme.btnFROff);
TexHandle.Cleanup(theme.btnFROffs);
TexHandle.Cleanup(theme.btnDEOn);
TexHandle.Cleanup(theme.btnDEOns);
TexHandle.Cleanup(theme.btnDEOff);
TexHandle.Cleanup(theme.btnDEOffs);
TexHandle.Cleanup(theme.btnESOn);
TexHandle.Cleanup(theme.btnESOns);
TexHandle.Cleanup(theme.btnESOff);
TexHandle.Cleanup(theme.btnESOffs);
TexHandle.Cleanup(theme.btnITOn);
TexHandle.Cleanup(theme.btnITOns);
TexHandle.Cleanup(theme.btnITOff);
TexHandle.Cleanup(theme.btnITOffs);
TexHandle.Cleanup(theme.btnNLOn);
TexHandle.Cleanup(theme.btnNLOns);
TexHandle.Cleanup(theme.btnNLOff);
TexHandle.Cleanup(theme.btnNLOffs);
TexHandle.Cleanup(theme.btnPTOn);
TexHandle.Cleanup(theme.btnPTOns);
TexHandle.Cleanup(theme.btnPTOff);
TexHandle.Cleanup(theme.btnPTOffs);
TexHandle.Cleanup(theme.btnRUOn);
TexHandle.Cleanup(theme.btnRUOns);
TexHandle.Cleanup(theme.btnRUOff);
TexHandle.Cleanup(theme.btnRUOffs);
TexHandle.Cleanup(theme.btnKOOn);
TexHandle.Cleanup(theme.btnKOOns);
TexHandle.Cleanup(theme.btnKOOff);
TexHandle.Cleanup(theme.btnKOOffs);
TexHandle.Cleanup(theme.btnZHCNOn);
TexHandle.Cleanup(theme.btnZHCNOns);
TexHandle.Cleanup(theme.btnZHCNOff);
TexHandle.Cleanup(theme.btnZHCNOffs);
TexHandle.Cleanup(theme.btnTexPlus);
TexHandle.Cleanup(theme.btnTexPlusS);
TexHandle.Cleanup(theme.btnTexMinus);
TexHandle.Cleanup(theme.btnTexMinusS);
/* Checkboxes */
TexHandle.Cleanup(theme.checkboxoff);
TexHandle.Cleanup(theme.checkboxoffs);
TexHandle.Cleanup(theme.checkboxon);
TexHandle.Cleanup(theme.checkboxons);
TexHandle.Cleanup(theme.checkboxHid);
TexHandle.Cleanup(theme.checkboxHids);
TexHandle.Cleanup(theme.checkboxReq);
TexHandle.Cleanup(theme.checkboxReqs);
/* Progress Bars */
TexHandle.Cleanup(theme.pbarTexL);
TexHandle.Cleanup(theme.pbarTexR);
TexHandle.Cleanup(theme.pbarTexC);
TexHandle.Cleanup(theme.pbarTexLS);
TexHandle.Cleanup(theme.pbarTexRS);
TexHandle.Cleanup(theme.pbarTexCS);
/* plugin game snapshot and overlay */
TexHandle.Cleanup(m_game_snap);
TexHandle.Cleanup(m_game_overlay);
/* Other Theme Stuff */
for(TexSet::iterator texture = theme.texSet.begin(); texture != theme.texSet.end(); ++texture)
TexHandle.Cleanup(texture->second);
for(vector<SFont>::iterator font = theme.fontSet.begin(); font != theme.fontSet.end(); ++font)
font->ClearData();
for(SoundSet::iterator sound = theme.soundSet.begin(); sound != theme.soundSet.end(); ++sound)
sound->second->FreeMemory();
theme.texSet.clear();
theme.fontSet.clear();
theme.soundSet.clear();
m_theme.unload();
m_coverflow.unload();
}
void CMenu::_setAA(int aa)
{
switch (aa)
{
case 2:
case 3:
case 4:
case 5:
case 6:
case 8:
m_aa = aa;
break;
case 7:
m_aa = 6;
break;
default:
m_aa = 0;
}
}
void CMenu::_loadCFCfg()
{
const char *domain = "_COVERFLOW";
//gprintf("Preparing to load sounds from %s\n", m_themeDataDir.c_str());
CoverFlow.setCachePath(m_cacheDir.c_str());
CoverFlow.setBufferSize(m_cfg.getInt("GENERAL", "cover_buffer", 20));
// Coverflow Sounds
CoverFlow.setSounds(
new GuiSound(fmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "sound_flip").c_str())),
_sound(theme.soundSet, m_theme.getString(domain, "sound_hover", "").c_str(), hover_wav, hover_wav_size, "default_btn_hover", false),
_sound(theme.soundSet, m_theme.getString(domain, "sound_select", "").c_str(), click_wav, click_wav_size, "default_btn_click", false),
new GuiSound(fmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "sound_cancel").c_str()))
);
// Textures
string texLoading = fmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "loading_cover_box").c_str());
string texNoCover = fmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "missing_cover_box").c_str());
string texLoadingFlat = fmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "loading_cover_flat").c_str());
string texNoCoverFlat = fmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "missing_cover_flat").c_str());
CoverFlow.setTextures(texLoading, texLoadingFlat, texNoCover, texNoCoverFlat);
// Font
CoverFlow.setFont(_font(domain, "font", theme.titleFont), m_theme.getColor(domain, "font_color", CColor(0xFFFFFFFF)));
}
Vector3D CMenu::_getCFV3D(const string &domain, const string &key, const Vector3D &def, bool otherScrnFmt)
{
string key169(key);
string key43(key);
key43 += "_4_3";
if (m_vid.wide() == otherScrnFmt)
swap(key169, key43);
if (m_coverflow.has(domain, key169))
{
Vector3D v(m_coverflow.getVector3D(domain, key169));
m_coverflow.getVector3D(domain, key43, v);
return v;
}
return m_coverflow.getVector3D(domain, key169, m_coverflow.getVector3D(domain, key43, def));
}
int CMenu::_getCFInt(const string &domain, const string &key, int def, bool otherScrnFmt)
{
string key169(key);
string key43(key);
key43 += "_4_3";
if (m_vid.wide() == otherScrnFmt)
swap(key169, key43);
if (m_coverflow.has(domain, key169))
{
int v = m_coverflow.getInt(domain, key169);
m_coverflow.getInt(domain, key43, v);
return v;
}
return m_coverflow.getInt(domain, key169, m_coverflow.getInt(domain, key43, def));
}
float CMenu::_getCFFloat(const string &domain, const string &key, float def, bool otherScrnFmt)
{
string key169(key);
string key43(key);
key43 += "_4_3";
if (m_vid.wide() == otherScrnFmt)
swap(key169, key43);
if (m_coverflow.has(domain, key169))
{
float v = m_coverflow.getFloat(domain, key169);
m_coverflow.getFloat(domain, key43, v);
return v;
}
return m_coverflow.getFloat(domain, key169, m_coverflow.getFloat(domain, key43, def));
}
void CMenu::_loadCFLayout(int version, bool forceAA, bool otherScrnFmt)
{
string domain = fmt("%s_%i", cf_domain, version);
string domainSel = fmt("%s_%i_S", cf_domain, version);
bool smallflow = strcasecmp(cf_domain, "_SMALLFLOW") == 0;
bool sf = otherScrnFmt;
int max_fsaa = m_coverflow.getInt(domain, "max_fsaa", 3);
_setAA(forceAA ? max_fsaa : min(max_fsaa, m_cfg.getInt("GENERAL", "max_fsaa", 3)));
CoverFlow.setTextureQuality(m_coverflow.getFloat(domain, "tex_lod_bias", -3.f),
m_coverflow.getInt(domain, "tex_aniso", 2),
m_coverflow.getBool(domain, "tex_edge_lod", true));
CoverFlow.setRange(_getCFInt(domain, "rows", (smallflow ? 5 : 1), sf), _getCFInt(domain, "columns", 11, sf));
CoverFlow.setCameraPos(false,
_getCFV3D(domain, "camera_pos", Vector3D(0.f, 0.f, 5.f), sf),
_getCFV3D(domain, "camera_aim", Vector3D(0.f, 0.f, 0.f), sf));
CoverFlow.setCameraPos(true,
_getCFV3D(domainSel, "camera_pos", Vector3D(0.f, 0.f, 5.f), sf),
_getCFV3D(domainSel, "camera_aim", Vector3D(0.f, 0.f, 0.f), sf));
CoverFlow.setCameraOsc(false,
_getCFV3D(domain, "camera_osc_speed", Vector3D(2.f, 0.f, 0.f), sf),
_getCFV3D(domain, "camera_osc_amp", Vector3D(0.1f, 0.f, 0.f), sf));
CoverFlow.setCameraOsc(true,
_getCFV3D(domainSel, "camera_osc_speed", Vector3D(), sf),
_getCFV3D(domainSel, "camera_osc_amp", Vector3D(), sf));
float def_cvr_posX = smallflow ? 1.f : 1.6f;
float def_cvr_posY = smallflow ? -0.8f : -1.f;
CoverFlow.setCoverPos(false,
_getCFV3D(domain, "left_pos", Vector3D(-def_cvr_posX, def_cvr_posY, 0.f), sf),
_getCFV3D(domain, "right_pos", Vector3D(def_cvr_posX, def_cvr_posY, 0.f), sf),
_getCFV3D(domain, "center_pos", Vector3D(0.f, def_cvr_posY, 1.f), sf),
_getCFV3D(domain, "row_center_pos", Vector3D(0.f, def_cvr_posY, 0.f), sf));
if(smallflow)
CoverFlow.setCoverPos(true,
_getCFV3D(domainSel, "left_pos", Vector3D(-4.05f, -0.6f, -1.f), sf),
_getCFV3D(domainSel, "right_pos", Vector3D(3.35f, -0.6f, -1.f), sf),
_getCFV3D(domainSel, "center_pos", Vector3D(-0.5f, -0.8f, 2.6f), sf),
_getCFV3D(domainSel, "row_center_pos", Vector3D(-3.05f, -0.6f, -1.f), sf));
else
CoverFlow.setCoverPos(true,
_getCFV3D(domainSel, "left_pos", Vector3D(-4.7f, -1.f, 0.f), sf),
_getCFV3D(domainSel, "right_pos", Vector3D(4.7f, -1.f, 0.f), sf),
_getCFV3D(domainSel, "center_pos", Vector3D(-0.6f, -1.f, 2.6f), sf),
_getCFV3D(domainSel, "row_center_pos", Vector3D(0.f, 0.f, 0.f), sf));
CoverFlow.setCoverAngleOsc(false,
m_coverflow.getVector3D(domain, "cover_osc_speed", Vector3D(2.f, 2.f, 0.f)),
m_coverflow.getVector3D(domain, "cover_osc_amp", Vector3D(5.f, 10.f, 0.f)));
CoverFlow.setCoverAngleOsc(true,
m_coverflow.getVector3D(domainSel, "cover_osc_speed", Vector3D(2.1f, 2.1f, 0.f)),
m_coverflow.getVector3D(domainSel, "cover_osc_amp", Vector3D(2.f, 5.f, 0.f)));
CoverFlow.setCoverPosOsc(false,
m_coverflow.getVector3D(domain, "cover_pos_osc_speed"),
m_coverflow.getVector3D(domain, "cover_pos_osc_amp"));
CoverFlow.setCoverPosOsc(true,
m_coverflow.getVector3D(domainSel, "cover_pos_osc_speed"),
m_coverflow.getVector3D(domainSel, "cover_pos_osc_amp"));
float spacerX = smallflow ? 1.f : 0.35f;
CoverFlow.setSpacers(false,
m_coverflow.getVector3D(domain, "left_spacer", Vector3D(-spacerX, 0.f, 0.f)),
m_coverflow.getVector3D(domain, "right_spacer", Vector3D(spacerX, 0.f, 0.f)));
CoverFlow.setSpacers(true,
m_coverflow.getVector3D(domainSel, "left_spacer", Vector3D(-spacerX, 0.f, 0.f)),
m_coverflow.getVector3D(domainSel, "right_spacer", Vector3D(spacerX, 0.f, 0.f)));
CoverFlow.setDeltaAngles(false,
m_coverflow.getVector3D(domain, "left_delta_angle"),
m_coverflow.getVector3D(domain, "right_delta_angle"));
CoverFlow.setDeltaAngles(true,
m_coverflow.getVector3D(domainSel, "left_delta_angle"),
m_coverflow.getVector3D(domainSel, "right_delta_angle"));
float angleY = smallflow ? 0.f : 70.f;
CoverFlow.setAngles(false,
m_coverflow.getVector3D(domain, "left_angle", Vector3D(0.f, angleY, 0.f)),
m_coverflow.getVector3D(domain, "right_angle", Vector3D(0.f, -angleY, 0.f)),
m_coverflow.getVector3D(domain, "center_angle", Vector3D(0.f, 0.f, 0.f)),
m_coverflow.getVector3D(domain, "row_center_angle"));
angleY = smallflow ? 0.f : 90.f;
float angleY1 = smallflow ? 0.f : 360.f;
float angleX = smallflow ? 0.f : -45.f;
CoverFlow.setAngles(true,
m_coverflow.getVector3D(domainSel, "left_angle", Vector3D(angleX, angleY, 0.f)),
m_coverflow.getVector3D(domainSel, "right_angle", Vector3D(angleX, -angleY, 0.f)),
m_coverflow.getVector3D(domainSel, "center_angle", Vector3D(0.f, angleY1, 0.f)),
m_coverflow.getVector3D(domainSel, "row_center_angle"));
angleX = smallflow ? 0.f : 20.f;
CoverFlow.setTitleAngles(false,
_getCFFloat(domain, "text_left_angle", -angleX, sf),
_getCFFloat(domain, "text_right_angle", angleX, sf),
_getCFFloat(domain, "text_center_angle", 0.f, sf));
CoverFlow.setTitleAngles(true,
_getCFFloat(domainSel, "text_left_angle", -angleX, sf),
_getCFFloat(domainSel, "text_right_angle", angleX, sf),
_getCFFloat(domainSel, "text_center_angle", 0.f, sf));
def_cvr_posX = smallflow ? 2.f : 1.f;
CoverFlow.setTitlePos(false,
_getCFV3D(domain, "text_left_pos", Vector3D(-def_cvr_posX, 0.8f, 2.6f), sf),
_getCFV3D(domain, "text_right_pos", Vector3D(def_cvr_posX, 0.8f, 2.6f), sf),
_getCFV3D(domain, "text_center_pos", Vector3D(0.f, 0.8f, 2.6f), sf));
def_cvr_posX = smallflow ? .6f : 2.1f;
CoverFlow.setTitlePos(true,
_getCFV3D(domainSel, "text_left_pos", Vector3D(-4.f, 0.f, 1.3f), sf),
_getCFV3D(domainSel, "text_right_pos", Vector3D(4.f, 0.f, 1.3f), sf),
_getCFV3D(domainSel, "text_center_pos", Vector3D(def_cvr_posX, 1.f, 1.6f), sf));
CoverFlow.setTitleWidth(false,
_getCFFloat(domain, "text_side_wrap_width", 500.f, sf),
_getCFFloat(domain, "text_center_wrap_width", 500.f, sf));
CoverFlow.setTitleWidth(true,
_getCFFloat(domainSel, "text_side_wrap_width", 500.f, sf),
_getCFFloat(domainSel, "text_center_wrap_width", 390.f, sf));
CoverFlow.setTitleStyle(false,
_textStyle(domain.c_str(), "text_side_style", FTGX_ALIGN_MIDDLE | FTGX_JUSTIFY_CENTER, true),
_textStyle(domain.c_str(), "text_center_style", FTGX_ALIGN_MIDDLE | FTGX_JUSTIFY_CENTER, true));
CoverFlow.setTitleStyle(true,
_textStyle(domainSel.c_str(), "text_side_style", FTGX_ALIGN_MIDDLE | FTGX_JUSTIFY_CENTER, true),
_textStyle(domainSel.c_str(), "text_center_style", FTGX_ALIGN_TOP | FTGX_JUSTIFY_RIGHT, true));
CoverFlow.setColors(false,
m_coverflow.getColor(domain, "color_beg", 0xCFFFFFFF),
m_coverflow.getColor(domain, "color_end", 0x3FFFFFFF),
m_coverflow.getColor(domain, "color_off", 0x7FFFFFFF));
CoverFlow.setColors(true,
m_coverflow.getColor(domainSel, "color_beg", 0x7FFFFFFF),
m_coverflow.getColor(domainSel, "color_end", 0x1FFFFFFF),
m_coverflow.getColor(domain, "color_off", 0x7FFFFFFF)); // Mouse not used once a selection has been made
CoverFlow.setMirrorAlpha(m_coverflow.getFloat(domain, "mirror_alpha", 0.15f), m_coverflow.getFloat(domain, "title_mirror_alpha", 0.03f)); // Doesn't depend on selection
CoverFlow.setMirrorBlur(m_coverflow.getBool(domain, "mirror_blur", true)); // Doesn't depend on selection
CoverFlow.setShadowColors(false,
m_coverflow.getColor(domain, "color_shadow_center", 0x00000000),
m_coverflow.getColor(domain, "color_shadow_beg", 0x00000000),
m_coverflow.getColor(domain, "color_shadow_end", 0x00000000),
m_coverflow.getColor(domain, "color_shadow_off", 0x00000000));
CoverFlow.setShadowColors(true,
m_coverflow.getColor(domainSel, "color_shadow_center", 0x0000007F),
m_coverflow.getColor(domainSel, "color_shadow_beg", 0x0000007F),
m_coverflow.getColor(domainSel, "color_shadow_end", 0x0000007F),
m_coverflow.getColor(domainSel, "color_shadow_off", 0x0000007F));
CoverFlow.setShadowPos(m_coverflow.getFloat(domain, "shadow_scale", 1.1f),
m_coverflow.getFloat(domain, "shadow_x"),
m_coverflow.getFloat(domain, "shadow_y"));
float spacerY = smallflow ? 0.60f : 2.f;
CoverFlow.setRowSpacers(false,
m_coverflow.getVector3D(domain, "top_spacer", Vector3D(0.f, spacerY, 0.f)),
m_coverflow.getVector3D(domain, "bottom_spacer", Vector3D(0.f, -spacerY, 0.f)));
CoverFlow.setRowSpacers(true,
m_coverflow.getVector3D(domainSel, "top_spacer", Vector3D(0.f, spacerY, 0.f)),
m_coverflow.getVector3D(domainSel, "bottom_spacer", Vector3D(0.f, -spacerY, 0.f)));
CoverFlow.setRowDeltaAngles(false,
m_coverflow.getVector3D(domain, "top_delta_angle"),
m_coverflow.getVector3D(domain, "bottom_delta_angle"));
CoverFlow.setRowDeltaAngles(true,
m_coverflow.getVector3D(domainSel, "top_delta_angle"),
m_coverflow.getVector3D(domainSel, "bottom_delta_angle"));
CoverFlow.setRowAngles(false,
m_coverflow.getVector3D(domain, "top_angle"),
m_coverflow.getVector3D(domain, "bottom_angle"));
CoverFlow.setRowAngles(true,
m_coverflow.getVector3D(domainSel, "top_angle"),
m_coverflow.getVector3D(domainSel, "bottom_angle"));
Vector3D def_cvr_scale = smallflow ? Vector3D(0.66f, 0.25f, 1.f) : Vector3D(1.f, 1.f, 1.f);
CoverFlow.setCoverScale(false,
m_coverflow.getVector3D(domain, "left_scale", def_cvr_scale),
m_coverflow.getVector3D(domain, "right_scale", def_cvr_scale),
m_coverflow.getVector3D(domain, "center_scale", def_cvr_scale),
m_coverflow.getVector3D(domain, "row_center_scale", def_cvr_scale));
CoverFlow.setCoverScale(true,
m_coverflow.getVector3D(domainSel, "left_scale", def_cvr_scale),
m_coverflow.getVector3D(domainSel, "right_scale", def_cvr_scale),
m_coverflow.getVector3D(domainSel, "center_scale", def_cvr_scale),
m_coverflow.getVector3D(domainSel, "row_center_scale", def_cvr_scale));
float flipX = smallflow ? 360.f : 180.f;
CoverFlow.setCoverFlipping(
_getCFV3D(domainSel, "flip_pos", Vector3D(), sf),
_getCFV3D(domainSel, "flip_angle", Vector3D(0.f, flipX, 0.f), sf),
_getCFV3D(domainSel, "flip_scale", Vector3D(1.f, 1.f, 1.f), sf));
CoverFlow.setBlur(
m_coverflow.getInt(domain, "blur_resolution", 1),
m_coverflow.getInt(domain, "blur_radius", 2),
m_coverflow.getFloat(domain, "blur_factor", 1.f));
}
void CMenu::_buildMenus(void)
{
m_btnMgr.init();
m_btnMgr.setSoundVolume(m_cfg.getInt("GENERAL", "sound_volume_gui", 255));
m_btnMgr.setRumble(m_cfg.getBool("GENERAL", "rumble", true));
// Default fonts
theme.btnFont = _dfltFont(BUTTONFONT);
theme.btnFontColor = m_theme.getColor("GENERAL", "button_font_color", 0xD0BFDFFF);
theme.lblFont = _dfltFont(LABELFONT);
theme.lblFontColor = m_theme.getColor("GENERAL", "label_font_color", 0xD0BFDFFF);
theme.titleFont = _dfltFont(TITLEFONT);
theme.titleFontColor = m_theme.getColor("GENERAL", "title_font_color", 0xFFFFFFFF);
theme.txtFont = _dfltFont(TEXTFONT);
theme.txtFontColor = m_theme.getColor("GENERAL", "text_font_color", 0xFFFFFFFF);
// Default Sounds
theme.clickSound = _sound(theme.soundSet, m_theme.getString("GENERAL", "click_sound", "").c_str(), click_wav, click_wav_size, "default_btn_click", false);
theme.hoverSound = _sound(theme.soundSet, m_theme.getString("GENERAL", "hover_sound", "").c_str(), hover_wav, hover_wav_size, "default_btn_hover", false);
theme.cameraSound = _sound(theme.soundSet, m_theme.getString("GENERAL", "camera_sound", "").c_str(), camera_wav, camera_wav_size, "default_camera", false);
// Default textures
TexHandle.fromImageFile(theme.btnTexL, fmt("%s/butleft.png", m_imgsDir.c_str()));
theme.btnTexL = _texture("GENERAL", "button_texture_left", theme.btnTexL);
TexHandle.fromImageFile(theme.btnTexR, fmt("%s/butright.png", m_imgsDir.c_str()));
theme.btnTexR = _texture("GENERAL", "button_texture_right", theme.btnTexR);
TexHandle.fromImageFile(theme.btnTexC, fmt("%s/butcenter.png", m_imgsDir.c_str()));
theme.btnTexC = _texture("GENERAL", "button_texture_center", theme.btnTexC);
TexHandle.fromImageFile(theme.btnTexLS, fmt("%s/butsleft.png", m_imgsDir.c_str()));
theme.btnTexLS = _texture("GENERAL", "button_texture_left_selected", theme.btnTexLS);
TexHandle.fromImageFile(theme.btnTexRS, fmt("%s/butsright.png", m_imgsDir.c_str()));
theme.btnTexRS = _texture("GENERAL", "button_texture_right_selected", theme.btnTexRS);
TexHandle.fromImageFile(theme.btnTexCS, fmt("%s/butscenter.png", m_imgsDir.c_str()));
theme.btnTexCS = _texture("GENERAL", "button_texture_center_selected", theme.btnTexCS);
/* Language Buttons */
u32 img_buf_size = 0;
u8 *img_buf = fsop_ReadFile(fmt("%s/butauon.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnAUOn, img_buf);
TexHandle.fromPNG(theme.btnAUOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnAUOn = _texture("GENERAL", "button_au_on", theme.btnAUOn);
theme.btnAUOff = _texture("GENERAL", "button_au_off", theme.btnAUOff);
img_buf = fsop_ReadFile(fmt("%s/butauons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnAUOns, img_buf);
TexHandle.fromPNG(theme.btnAUOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnAUOns = _texture("GENERAL", "button_au_on_selected", theme.btnAUOns);
theme.btnAUOffs = _texture("GENERAL", "button_au_off_selected", theme.btnAUOffs);
img_buf = fsop_ReadFile(fmt("%s/butenon.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnENOn, img_buf);
TexHandle.fromPNG(theme.btnENOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnENOn = _texture("GENERAL", "button_en_on", theme.btnENOn);
theme.btnENOff = _texture("GENERAL", "button_en_off", theme.btnENOff);
img_buf = fsop_ReadFile(fmt("%s/butenons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnENOns, img_buf);
TexHandle.fromPNG(theme.btnENOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnENOns = _texture("GENERAL", "button_en_on_selected", theme.btnENOns);
theme.btnENOffs = _texture("GENERAL", "button_en_off_selected", theme.btnENOffs);
img_buf = fsop_ReadFile(fmt("%s/butjaon.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnJAOn, img_buf);
TexHandle.fromPNG(theme.btnJAOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnJAOn = _texture("GENERAL", "button_ja_on", theme.btnJAOn);
theme.btnJAOff = _texture("GENERAL", "button_ja_off", theme.btnJAOff);
img_buf = fsop_ReadFile(fmt("%s/butjaons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnJAOns, img_buf);
TexHandle.fromPNG(theme.btnJAOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnJAOns = _texture("GENERAL", "button_ja_on_selected", theme.btnJAOns);
theme.btnJAOffs = _texture("GENERAL", "button_ja_off_selected", theme.btnJAOffs);
img_buf = fsop_ReadFile(fmt("%s/butfron.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnFROn, img_buf);
TexHandle.fromPNG(theme.btnFROff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnFROn = _texture("GENERAL", "button_fr_on", theme.btnFROn);
theme.btnFROff = _texture("GENERAL", "button_fr_off", theme.btnFROff);
img_buf = fsop_ReadFile(fmt("%s/butfrons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnFROns, img_buf);
TexHandle.fromPNG(theme.btnFROffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnFROns = _texture("GENERAL", "button_fr_on_selected", theme.btnFROns);
theme.btnFROffs = _texture("GENERAL", "button_fr_off_selected", theme.btnFROffs);
img_buf = fsop_ReadFile(fmt("%s/butdeon.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnDEOn, img_buf);
TexHandle.fromPNG(theme.btnDEOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnDEOn = _texture("GENERAL", "button_de_on", theme.btnDEOn);
theme.btnDEOff = _texture("GENERAL", "button_de_off", theme.btnDEOff);
img_buf = fsop_ReadFile(fmt("%s/butdeons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnDEOns, img_buf);
TexHandle.fromPNG(theme.btnDEOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnDEOns = _texture("GENERAL", "button_de_on_selected", theme.btnDEOns);
theme.btnDEOffs = _texture("GENERAL", "button_de_off_selected", theme.btnDEOffs);
img_buf = fsop_ReadFile(fmt("%s/buteson.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnESOn, img_buf);
TexHandle.fromPNG(theme.btnESOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnESOn = _texture("GENERAL", "button_es_on", theme.btnESOn);
theme.btnESOff = _texture("GENERAL", "button_es_off", theme.btnESOff);
img_buf = fsop_ReadFile(fmt("%s/butesons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnESOns, img_buf);
TexHandle.fromPNG(theme.btnESOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnESOns = _texture("GENERAL", "button_es_on_selected", theme.btnESOns);
theme.btnESOffs = _texture("GENERAL", "button_es_off_selected", theme.btnESOffs);
img_buf = fsop_ReadFile(fmt("%s/butiton.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnITOn, img_buf);
TexHandle.fromPNG(theme.btnITOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnITOn = _texture("GENERAL", "button_it_on", theme.btnITOn);
theme.btnITOff = _texture("GENERAL", "button_it_off", theme.btnITOff);
img_buf = fsop_ReadFile(fmt("%s/butitons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnITOns, img_buf);
TexHandle.fromPNG(theme.btnITOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnITOns = _texture("GENERAL", "button_it_on_selected", theme.btnITOns);
theme.btnITOffs = _texture("GENERAL", "button_it_off_selected", theme.btnITOffs);
img_buf = fsop_ReadFile(fmt("%s/butnlon.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnNLOn, img_buf);
TexHandle.fromPNG(theme.btnNLOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnNLOn = _texture("GENERAL", "button_nl_on", theme.btnNLOn);
theme.btnNLOff = _texture("GENERAL", "button_nl_off", theme.btnNLOff);
img_buf = fsop_ReadFile(fmt("%s/butnlons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnNLOns, img_buf);
TexHandle.fromPNG(theme.btnNLOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnNLOns = _texture("GENERAL", "button_nl_on_selected", theme.btnNLOns);
theme.btnNLOffs = _texture("GENERAL", "button_nl_off_selected", theme.btnNLOffs);
img_buf = fsop_ReadFile(fmt("%s/butpton.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnPTOn, img_buf);
TexHandle.fromPNG(theme.btnPTOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnPTOn = _texture("GENERAL", "button_pt_on", theme.btnPTOn);
theme.btnPTOff = _texture("GENERAL", "button_pt_off", theme.btnPTOff);
img_buf = fsop_ReadFile(fmt("%s/butptons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnPTOns, img_buf);
TexHandle.fromPNG(theme.btnPTOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnPTOns = _texture("GENERAL", "button_pt_on_selected", theme.btnPTOns);
theme.btnPTOffs = _texture("GENERAL", "button_pt_off_selected", theme.btnPTOffs);
img_buf = fsop_ReadFile(fmt("%s/butruon.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnRUOn, img_buf);
TexHandle.fromPNG(theme.btnRUOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnRUOn = _texture("GENERAL", "button_ru_on", theme.btnRUOn);
theme.btnRUOff = _texture("GENERAL", "button_ru_off", theme.btnRUOff);
img_buf = fsop_ReadFile(fmt("%s/butruons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnRUOns, img_buf);
TexHandle.fromPNG(theme.btnRUOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnRUOns = _texture("GENERAL", "button_ru_on_selected", theme.btnRUOns);
theme.btnRUOffs = _texture("GENERAL", "button_ru_off_selected", theme.btnRUOffs);
img_buf = fsop_ReadFile(fmt("%s/butkoon.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnKOOn, img_buf);
TexHandle.fromPNG(theme.btnKOOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnKOOn = _texture("GENERAL", "button_ko_on", theme.btnKOOn);
theme.btnKOOff = _texture("GENERAL", "button_ko_off", theme.btnKOOff);
img_buf = fsop_ReadFile(fmt("%s/butkoons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnKOOns, img_buf);
TexHandle.fromPNG(theme.btnKOOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnKOOns = _texture("GENERAL", "button_ko_on_selected", theme.btnKOOns);
theme.btnKOOffs = _texture("GENERAL", "button_ko_off_selected", theme.btnKOOffs);
img_buf = fsop_ReadFile(fmt("%s/butzhcnon.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnZHCNOn, img_buf);
TexHandle.fromPNG(theme.btnZHCNOff, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnZHCNOn = _texture("GENERAL", "button_zhcn_on", theme.btnZHCNOn);
theme.btnZHCNOff = _texture("GENERAL", "button_zhcn_off", theme.btnZHCNOff);
img_buf = fsop_ReadFile(fmt("%s/butzhcnons.png", m_imgsDir.c_str()), &img_buf_size);
if(img_buf != NULL)
{
TexHandle.fromPNG(theme.btnZHCNOns, img_buf);
TexHandle.fromPNG(theme.btnZHCNOffs, img_buf, GX_TF_RGBA8, 0, 0, true);
MEM2_free(img_buf);
}
theme.btnZHCNOns = _texture("GENERAL", "button_zhcn_on_selected", theme.btnZHCNOns);
theme.btnZHCNOffs = _texture("GENERAL", "button_zhcn_off_selected", theme.btnZHCNOffs);
/* Default textures */
TexHandle.fromImageFile(theme.checkboxoff, fmt("%s/checkboxoff.png", m_imgsDir.c_str()));
theme.checkboxoff = _texture("GENERAL", "checkbox_off", theme.checkboxoff);
TexHandle.fromImageFile(theme.checkboxoffs, fmt("%s/checkboxoffs.png", m_imgsDir.c_str()));
theme.checkboxoffs = _texture("GENERAL", "checkbox_off_selected", theme.checkboxoffs);
TexHandle.fromImageFile(theme.checkboxon, fmt("%s/checkboxon.png", m_imgsDir.c_str()));
theme.checkboxon = _texture("GENERAL", "checkbox_on", theme.checkboxon);
TexHandle.fromImageFile(theme.checkboxons, fmt("%s/checkboxons.png", m_imgsDir.c_str()));
theme.checkboxons = _texture("GENERAL", "checkbox_on_selected", theme.checkboxons);
TexHandle.fromImageFile(theme.checkboxHid, fmt("%s/checkboxhid.png", m_imgsDir.c_str()));
theme.checkboxHid = _texture("GENERAL", "checkbox_Hid", theme.checkboxHid);
TexHandle.fromImageFile(theme.checkboxHids, fmt("%s/checkboxhids.png", m_imgsDir.c_str()));
theme.checkboxHids = _texture("GENERAL", "checkbox_Hid_selected", theme.checkboxHids);
TexHandle.fromImageFile(theme.checkboxReq, fmt("%s/checkboxreq.png", m_imgsDir.c_str()));
theme.checkboxReq = _texture("GENERAL", "checkbox_Req", theme.checkboxReq);
TexHandle.fromImageFile(theme.checkboxReqs, fmt("%s/checkboxreqs.png", m_imgsDir.c_str()));
theme.checkboxReqs = _texture("GENERAL", "checkbox_Req_selected", theme.checkboxReqs);
TexHandle.fromImageFile(theme.pbarTexL, fmt("%s/pbarleft.png", m_imgsDir.c_str()));
theme.pbarTexL = _texture("GENERAL", "progressbar_texture_left", theme.pbarTexL);
TexHandle.fromImageFile(theme.pbarTexR, fmt("%s/pbarright.png", m_imgsDir.c_str()));
theme.pbarTexR = _texture("GENERAL", "progressbar_texture_right", theme.pbarTexR);
TexHandle.fromImageFile(theme.pbarTexC, fmt("%s/pbarcenter.png", m_imgsDir.c_str()));
theme.pbarTexC = _texture("GENERAL", "progressbar_texture_center", theme.pbarTexC);
TexHandle.fromImageFile(theme.pbarTexLS, fmt("%s/pbarlefts.png", m_imgsDir.c_str()));
theme.pbarTexLS = _texture("GENERAL", "progressbar_texture_left_selected", theme.pbarTexLS);
TexHandle.fromImageFile(theme.pbarTexRS, fmt("%s/pbarrights.png", m_imgsDir.c_str()));
theme.pbarTexRS = _texture("GENERAL", "progressbar_texture_right_selected", theme.pbarTexRS);
TexHandle.fromImageFile(theme.pbarTexCS, fmt("%s/pbarcenters.png", m_imgsDir.c_str()));
theme.pbarTexCS = _texture("GENERAL", "progressbar_texture_center_selected", theme.pbarTexCS);
TexHandle.fromImageFile(theme.btnTexPlus, fmt("%s/btnplus.png", m_imgsDir.c_str()));
theme.btnTexPlus = _texture("GENERAL", "plus_button_texture", theme.btnTexPlus);
TexHandle.fromImageFile(theme.btnTexPlusS, fmt("%s/btnpluss.png", m_imgsDir.c_str()));
theme.btnTexPlusS = _texture("GENERAL", "plus_button_texture_selected", theme.btnTexPlusS);
TexHandle.fromImageFile(theme.btnTexMinus, fmt("%s/btnminus.png", m_imgsDir.c_str()));
theme.btnTexMinus = _texture("GENERAL", "minus_button_texture", theme.btnTexMinus);
TexHandle.fromImageFile(theme.btnTexMinusS, fmt("%s/btnminuss.png", m_imgsDir.c_str()));
theme.btnTexMinusS = _texture("GENERAL", "minus_button_texture_selected", theme.btnTexMinusS);
// Default background
TexHandle.fromImageFile(theme.bg, fmt("%s/background.png", m_imgsDir.c_str()));
TexHandle.fromImageFile(m_mainBgLQ, fmt("%s/background.png", m_imgsDir.c_str()), GX_TF_CMPR, 64, 64);
m_gameBgLQ = m_mainBgLQ;
// Build menus
_initMainMenu();
_initErrorMenu();
_initConfigMenu();
_initConfigGCMenu();
_initConfigSrc();
_initConfigHB();
_initBoot();
_initNandEmuMenu();
_initPartitionsCfgMenu();
_initPathsMenu();
_initDownloadMenu();
_initCodeMenu();
_initCFThemeMenu();
_initGameMenu();
_initGameInfoMenu();
_initConfigGameMenu();
_initCheatSettingsMenu();
_initCoverBanner();
_initWBFSMenu();
_initCategorySettingsMenu();
_initHomeAndExitToMenu();
_initAboutMenu();
_initExplorer();
_initWad();
_initSourceMenu();
_initPluginSettingsMenu();
_initCheckboxesMenu();
_loadCFCfg();
}
void CMenu::_updateText(void)
{
_textConfig();
_textConfigGC();
_textConfigSrc();
_textConfigHB();
_textBoot();
_textNandEmu();
_textPartitionsCfg();
_textPaths();
_textDownload();
_textCode();
_textGame();
_textConfigGame();
_textCheatSettings();
_textCoverBanner();
_textWBFS();
_textCategorySettings();
_textHome();
_textExitTo();
_textShutdown();
_textExplorer();
_textWad();
if(m_use_source)
_textSource();
_textPluginSettings();
_textCheckboxesMenu();
}
typedef struct
{
string ext;
u32 min;
u32 max;
u32 def;
u32 res;
} FontHolder;
SFont CMenu::_dfltFont(u32 fontSize, u32 lineSpacing, u32 weight, u32 index, const char *genKey)
{
/* get font info from theme.ini or use the default values */
string filename;
FontHolder fonts[3] = {{ "_size", 6u, 300u, fontSize, 0 }, { "_line_height", 6u, 300u, lineSpacing, 0 }, { "_weight", 1u, 32u, weight, 0 }};
filename = m_theme.getString("GENERAL", genKey, genKey);
bool useDefault = filename == genKey;
/* get the resources - fontSize, lineSpacing, and weight */
for(u32 i = 0; i < 3; i++)
{
string defValue = genKey;
defValue += fonts[i].ext;// _size, _line_height, _weight
fonts[i].res = (u32)m_theme.getInt("GENERAL", defValue);
fonts[i].res = min(max(fonts[i].min, fonts[i].res <= 0 ? fonts[i].def : fonts[i].res), fonts[i].max);
}
/* check if font is already in memory */
/* and the filename, size, spacing, and weight are the same */
/* if so return this font */
std::vector<SFont>::iterator font_itr;
for(font_itr = theme.fontSet.begin(); font_itr != theme.fontSet.end(); ++font_itr)
{
if(strncmp(filename.c_str(), font_itr->name, 127) == 0 && font_itr->fSize == fonts[0].res &&
font_itr->lineSpacing == fonts[1].res && font_itr->weight && fonts[2].res)
break;
}
if (font_itr != theme.fontSet.end()) return *font_itr;
/* font not found in memory, load it to create a new font */
/* unless useDefault font is specified */
SFont retFont;
if(!useDefault && retFont.fromFile(fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str()), fonts[0].res, fonts[1].res, fonts[2].res, index, filename.c_str()))
{
// Theme Font
theme.fontSet.push_back(retFont);
return retFont;
}
/* try default font in imgs folder */
if(retFont.fromFile(fmt("%s/font.ttf", m_imgsDir.c_str()), fonts[0].res, fonts[1].res, fonts[2].res, index, filename.c_str()))
{
// Default font
theme.fontSet.push_back(retFont);
return retFont;
}
/* Fallback to default font */
/* default font is the wii's system font */
if(retFont.fromBuffer(m_base_font, m_base_font_size, fonts[0].res, fonts[1].res, fonts[2].res, index, filename.c_str()))
{
// Default font
theme.fontSet.push_back(retFont);
return retFont;
}
return retFont;
}
SFont CMenu::_font(const char *domain, const char *key, SFont def_font)
{
string filename;
FontHolder fonts[3] = {{ "_size", 6u, 300u, 0, 0 }, { "_line_height", 6u, 300u, 0, 0 }, { "_weight", 1u, 32u, 0, 0 }};
filename = m_theme.getString(domain, key);
if(filename.empty())
filename = def_font.name;
/* get the resources - fontSize, lineSpacing, and weight */
for(u32 i = 0; i < 3; i++)
{
string value = key;
value += fonts[i].ext;// _size, _line_height, _weight
fonts[i].res = (u32)m_theme.getInt(domain, value);
if(fonts[i].res <= 0 && i == 0)
fonts[i].res = def_font.fSize;
else if(fonts[i].res <= 0 && i == 1)
fonts[i].res = def_font.lineSpacing;
else if(fonts[i].res <= 0 && i == 2)
fonts[i].res = def_font.weight;
fonts[i].res = min(max(fonts[i].min, fonts[i].res), fonts[i].max);
}
/* check if font is already in memory */
/* and the filename, size, spacing, and weight are the same */
/* if so return this font */
std::vector<SFont>::iterator font_itr;
for(font_itr = theme.fontSet.begin(); font_itr != theme.fontSet.end(); ++font_itr)
{
if(strncmp(filename.c_str(), font_itr->name, 127) == 0 && font_itr->fSize == fonts[0].res &&
font_itr->lineSpacing == fonts[1].res && font_itr->weight && fonts[2].res)
break;
}
if(font_itr != theme.fontSet.end()) return *font_itr;
/* font not found in memory, load it to create a new font */
/* unless useDefault font is specified */
SFont retFont;
if(retFont.fromFile(fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str()), fonts[0].res, fonts[1].res, fonts[2].res, 1, filename.c_str()))
{
// Theme Font
theme.fontSet.push_back(retFont);
return retFont;
}
return def_font;
}
vector<TexData> CMenu::_textures(const char *domain, const char *key)
{
vector<TexData> textures;
if (m_theme.loaded())
{
vector<string> filenames = m_theme.getStrings(domain, key);
if (filenames.size() > 0)
{
for (vector<string>::iterator itr = filenames.begin(); itr != filenames.end(); itr++)
{
const string &filename = *itr;
TexSet::iterator i = theme.texSet.find(filename);
if (i != theme.texSet.end())
textures.push_back(i->second);
TexData themetex;
if(TexHandle.fromImageFile(themetex, fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str())) == TE_OK)
{
theme.texSet[filename] = themetex;
textures.push_back(themetex);
}
}
}
}
return textures;
}
TexData CMenu::_texture(const char *domain, const char *key, TexData &def, bool freeDef)
{
string filename;
if(m_theme.loaded())
{
/* Load from theme */
filename = m_theme.getString(domain, key);
if(!filename.empty())
{
TexSet::iterator i = theme.texSet.find(filename);
if(i != theme.texSet.end())
return i->second;
/* Load from image file */
TexData themetex;
if(TexHandle.fromImageFile(themetex, fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str())) == TE_OK)
{
if(freeDef && def.data != NULL)
{
MEM2_free(def.data);
def.data = NULL;
}
theme.texSet[filename] = themetex;
return themetex;
}
}
}
/* Fallback to default */
return def;
}
// Only for loading defaults and GENERAL domains!!
GuiSound *CMenu::_sound(CMenu::SoundSet &soundSet, const char *filename, const u8 * snd, u32 len, const char *name, bool isAllocated)
{
if(filename == NULL || filename[0] == '\0')
filename = name;
CMenu::SoundSet::iterator i = soundSet.find(upperCase(name));
if(i == soundSet.end())
{
if(filename != name && fsop_FileExist(fmt("%s/%s", m_themeDataDir.c_str(), filename)))
{
u32 size = 0;
u8 *mem = fsop_ReadFile(fmt("%s/%s", m_themeDataDir.c_str(), filename), &size);
soundSet[upperCase(filename)] = new GuiSound(mem, size, filename, true);
}
else
soundSet[upperCase(filename)] = new GuiSound(snd, len, filename, isAllocated);
return soundSet[upperCase(filename)];
}
return i->second;
}
//For buttons and labels only!!
GuiSound *CMenu::_sound(CMenu::SoundSet &soundSet, const char *domain, const char *key, const char *name)
{
const char *filename = m_theme.getString(domain, key).c_str();
if(filename == NULL || filename[0] == '\0')
{
if(strrchr(name, '/') != NULL)
name = strrchr(name, '/') + 1;
return soundSet[upperCase(name)]; // General/Default are already cached!
}
SoundSet::iterator i = soundSet.find(upperCase(filename));
if(i == soundSet.end())
{
if(fsop_FileExist(fmt("%s/%s", m_themeDataDir.c_str(), filename)))
{
u32 size = 0;
u8 *mem = fsop_ReadFile(fmt("%s/%s", m_themeDataDir.c_str(), filename), &size);
soundSet[upperCase(filename)] = new GuiSound(mem, size, filename, true);
}
else
soundSet[upperCase(filename)] = new GuiSound();
return soundSet[upperCase(filename)];
}
return i->second;
}
u16 CMenu::_textStyle(const char *domain, const char *key, u16 def, bool coverflow)
{
u16 textStyle = 0;
string style;
if(coverflow)
style = m_coverflow.getString(domain, key);
else
style = m_theme.getString(domain, key);
if (style.empty()) return def;
if (style.find_first_of("Cc") != string::npos)
textStyle |= FTGX_JUSTIFY_CENTER;
else if (style.find_first_of("Rr") != string::npos)
textStyle |= FTGX_JUSTIFY_RIGHT;
else
textStyle |= FTGX_JUSTIFY_LEFT;
if (style.find_first_of("Mm") != string::npos)
textStyle |= FTGX_ALIGN_MIDDLE;
else if (style.find_first_of("Bb") != string::npos)
textStyle |= FTGX_ALIGN_BOTTOM;
else
textStyle |= FTGX_ALIGN_TOP;
return textStyle;
}
s16 CMenu::_addButton(const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color)
{
SButtonTextureSet btnTexSet;
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
btnTexSet.left = _texture(domain, "texture_left", theme.btnTexL, false);
btnTexSet.right = _texture(domain, "texture_right", theme.btnTexR, false);
btnTexSet.center = _texture(domain, "texture_center", theme.btnTexC, false);
btnTexSet.leftSel = _texture(domain, "texture_left_selected", theme.btnTexLS, false);
btnTexSet.rightSel = _texture(domain, "texture_right_selected", theme.btnTexRS, false);
btnTexSet.centerSel = _texture(domain, "texture_center_selected", theme.btnTexCS, false);
font = _font(domain, "font", font);
GuiSound *clickSound = _sound(theme.soundSet, domain, "click_sound", theme.clickSound->GetName());
GuiSound *hoverSound = _sound(theme.soundSet, domain, "hover_sound", theme.hoverSound->GetName());
return m_btnMgr.addButton(font, text, x, y, width, height, c, btnTexSet, clickSound, hoverSound);
}
s16 CMenu::_addPicButton(const char *domain, TexData &texNormal, TexData &texSelected, int x, int y, u32 width, u32 height)
{
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
TexData tex1 = _texture(domain, "texture_normal", texNormal, false);
TexData tex2 = _texture(domain, "texture_selected", texSelected, false);
GuiSound *clickSound = _sound(theme.soundSet, domain, "click_sound", theme.clickSound->GetName());
GuiSound *hoverSound = _sound(theme.soundSet, domain, "hover_sound", theme.hoverSound->GetName());
return m_btnMgr.addPicButton(tex1, tex2, x, y, width, height, clickSound, hoverSound);
}
s16 CMenu::_addLabel(const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color, s16 style)
{
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
font = _font(domain, "font", font);
style = _textStyle(domain, "style", style);
return m_btnMgr.addLabel(font, text, x, y, width, height, c, style);
}
s16 CMenu::_addLabel(const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color, s16 style, TexData &bg)
{
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
font = _font(domain, "font", font);
TexData texBg = _texture(domain, "background_texture", bg, false);
style = _textStyle(domain, "style", style);
return m_btnMgr.addLabel(font, text, x, y, width, height, c, style, texBg);
}
s16 CMenu::_addProgressBar(const char *domain, int x, int y, u32 width, u32 height)
{
SButtonTextureSet btnTexSet;
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
btnTexSet.left = _texture(domain, "texture_left", theme.pbarTexL, false);
btnTexSet.right = _texture(domain, "texture_right", theme.pbarTexR, false);
btnTexSet.center = _texture(domain, "texture_center", theme.pbarTexC, false);
btnTexSet.leftSel = _texture(domain, "texture_left_selected", theme.pbarTexLS, false);
btnTexSet.rightSel = _texture(domain, "texture_right_selected", theme.pbarTexRS, false);
btnTexSet.centerSel = _texture(domain, "texture_center_selected", theme.pbarTexCS, false);
return m_btnMgr.addProgressBar(x, y, width, height, btnTexSet);
}
void CMenu::_setHideAnim(s16 id, const char *domain, int dx, int dy, float scaleX, float scaleY)
{
dx = m_theme.getInt(domain, "effect_x", dx);
dy = m_theme.getInt(domain, "effect_y", dy);
scaleX = m_theme.getFloat(domain, "effect_scale_x", scaleX);
scaleY = m_theme.getFloat(domain, "effect_scale_y", scaleY);
m_btnMgr.hide(id, dx, dy, scaleX, scaleY, true);
}
void CMenu::_addUserLabels(s16 *ids, u32 size, const char *domain)
{
_addUserLabels(ids, 0, size, domain);
}
void CMenu::_addUserLabels(s16 *ids, u32 start, u32 size, const char *domain)
{
for(u32 i = start; i < start + size; ++i)
{
string dom(fmt("%s/USER%i", domain, i + 1));
if (m_theme.hasDomain(dom))
{
TexData emptyTex;
ids[i] = _addLabel(dom.c_str(), theme.lblFont, L"", 40, 200, 64, 64, CColor(0xFFFFFFFF), 0, emptyTex);
_setHideAnim(ids[i], dom.c_str(), -50, 0, 0.f, 0.f);
}
else
ids[i] = -1;
}
}
bool musicPaused = false;
void CMenu::_mainLoopCommon(bool withCF, bool adjusting)
{
if(m_thrdWorking)
{
musicPaused = true;
MusicPlayer.Pause();//note - bg music is paused but sound thread is still running. so banner gamesound still plays
m_btnMgr.tick();
m_vid.prepare();
m_vid.setup2DProjection(false, true);// false = prepare() already set view port, true = no scaling - draw at 640x480
_updateBg();
if(CoverFlow.getRenderTex())
CoverFlow.RenderTex();
m_vid.setup2DProjection();// this time set the view port and allow scaling
_drawBg();
m_btnMgr.draw();
m_vid.render();
return;
}
if(musicPaused && !m_thrdWorking)
{
musicPaused = false;
MusicPlayer.Resume();
}
/* ticks - for moving and scaling covers and gui buttons and text */
if(withCF)
CoverFlow.tick();
m_btnMgr.tick();
m_fa.tick();
/* video setup */
m_vid.prepare();
m_vid.setup2DProjection(false, true);
/* background and coverflow drawing */
_updateBg();
if(CoverFlow.getRenderTex())
CoverFlow.RenderTex();
if(withCF && m_lqBg != NULL)
CoverFlow.makeEffectTexture(m_lqBg);
if(withCF && m_aa > 0)
{
m_vid.setAA(m_aa, true);
for(int i = 0; i < m_aa; ++i)
{
m_vid.prepareAAPass(i);
m_vid.setup2DProjection(false, true);
_drawBg();
CoverFlow.draw();
m_vid.setup2DProjection(false, true);
CoverFlow.drawEffect();
if(!m_soundThrdBusy && !m_banner.GetSelectedGame() && !m_snapshot_loaded)
CoverFlow.drawText(adjusting);
m_vid.renderAAPass(i);
}
m_vid.setup2DProjection();
m_vid.drawAAScene();
}
else
{
m_vid.setup2DProjection();
_drawBg();
if(withCF)
{
CoverFlow.draw();
m_vid.setup2DProjection();
CoverFlow.drawEffect();
if(!m_soundThrdBusy && !m_banner.GetSelectedGame() && !m_snapshot_loaded)
CoverFlow.drawText(adjusting);
}
}
/* game video or banner drawing */
if(m_gameSelected)
{
if(m_fa.isLoaded())
m_fa.draw();
else if(m_video_playing)
{
if(movie.Frame != NULL)
{
DrawTexturePos(movie.Frame);
movie.Frame->thread = false;
}
}
else if(m_banner.GetSelectedGame() && (!m_banner.GetInGameSettings() || (m_banner.GetInGameSettings() && m_bnr_settings)))
{
if(!m_soundThrdBusy)// banner loaded
m_banner.Draw();
else if(m_banner.GetZoomSetting())// banner not loaded but in full zoom mode
DrawRectangle(0.0f, 0.0f, m_vid.width(), m_vid.height(), (GXColor) {0, 0, 0, 0xFF});// to prevent coverflow from showing
}
}
/* gui buttons and text drawing */
m_btnMgr.draw();
/* reading controller inputs and drawing cursor pointers*/
ScanInput();
/* check if we want screensaver and if its idle long enuff, if so draw full screen black square with mild alpha */
if(!m_cfg.getBool("GENERAL", "screensaver_disabled", true))
m_vid.screensaver(NoInputTime(), m_cfg.getInt("GENERAL", "screensaver_idle_seconds", 60));
/* render everything on screen */
m_vid.render();
// check if power button is pressed and exit wiiflow
if(Sys_Exiting())
{
if(m_cfg.getBool("GENERAL", "idle_standby", false))
exitHandler(SHUTDOWN_IDLE);
else
exitHandler(SHUTDOWN_STANDBY);
}
// check if we need to start playing the game/banner sound
// m_gameSelected means we are on the game selected menu
// m_gamesound_changed means a new game sound is loaded and ready to play
// the previous game sound needs to stop before playing new sound
// and the bg music volume needs to be 0 before playing game sound
if(!m_soundThrdBusy && withCF && m_gameSelected && m_gamesound_changed && !m_gameSound.IsPlaying() && MusicPlayer.GetVolume() == 0)
{
_stopGameSoundThread();// stop game sound loading thread
m_gameSound.Play(m_bnrSndVol);// play game sound
m_gamesound_changed = false;
}
// stop game/banner sound from playing if we exited game selected menu or if we move to new game
else if((!m_soundThrdBusy && withCF && m_gameSelected && m_gamesound_changed && m_gameSound.IsPlaying()) || (!m_gameSelected && m_gameSound.IsPlaying()))
m_gameSound.Stop();
/* decrease music volume to zero if any of these are true:
trailer video playing or||
game/banner sound is being loaded because we are switching to a new game or||
game/banner sound is loaded and ready to play or||
gamesound hasn't finished - when finishes music volume back to normal - some gamesounds don't loop continuously
also this switches to next song if current song is done */
MusicPlayer.Tick((withCF && (m_video_playing || (m_gameSelected && m_soundThrdBusy) ||
(m_gameSelected && m_gamesound_changed))) || m_gameSound.IsPlaying());
// set song title and display it if music info is allowed
if(MusicPlayer.SongChanged() && m_music_info)
{
m_btnMgr.setText(m_mainLblCurMusic, MusicPlayer.GetFileName());
m_btnMgr.show(m_mainLblCurMusic);
MusicPlayer.DisplayTime = time(NULL);
}
// hide song title if it's displaying and been >3 seconds
else if(MusicPlayer.DisplayTime > 0 && time(NULL) - MusicPlayer.DisplayTime > 3)
{
MusicPlayer.DisplayTime = 0;
m_btnMgr.hide(m_mainLblCurMusic);
if(MusicPlayer.OneSong) m_music_info = false;
}
//Take Screenshot
if(WBTN_Z_PRESSED || GBTN_Z_PRESSED)
{
time_t rawtime;
struct tm *timeinfo;
char buffer[80];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer,80,"%b-%d-20%y-%Hh%Mm%Ss.png",timeinfo);
gprintf("Screenshot taken and saved to: %s/%s\n", m_screenshotDir.c_str(), buffer);
m_vid.TakeScreenshot(fmt("%s/%s", m_screenshotDir.c_str(), buffer));
if(theme.cameraSound != NULL)
theme.cameraSound->Play(255);
}
if(show_mem)
{
m_btnMgr.setText(m_mem1FreeSize, wfmt(L"Mem1 lo Free:%u, Mem1 Free:%u", MEM1_lo_freesize(), MEM1_freesize()), true);// true = dont wrap text
m_btnMgr.setText(m_mem2FreeSize, wfmt(L"Mem2 Free:%u", MEM2_freesize()), true);// true = dont wrap text
}
#ifdef SHOWMEMGECKO
mem1 = MEM1_freesize();
mem2 = MEM2_freesize();
if(mem1 != mem1old)
{
mem1old = mem1;
gprintf("Mem1 Free: %u\n", mem1);
}
if(mem2 != mem2old)
{
mem2old = mem2;
gprintf("Mem2 Free: %u\n", mem2);
}
#endif
}
void CMenu::_setBg(const TexData &bgTex, const TexData &bglqTex)
{
/* Not setting same bg again */
if(m_nextBg == &bgTex)
return;
m_lqBg = &bglqTex;
/* before setting new next bg set previous */
if(m_nextBg != NULL)
m_prevBg = m_nextBg;
m_nextBg = &bgTex;
m_bgCrossFade = 0xFF;
}
void CMenu::_updateBg(void)
{
if(m_bgCrossFade == 0)
return;
m_bgCrossFade = max(0, (int)m_bgCrossFade - 14);
Mtx modelViewMtx;
GXTexObj texObj;
GXTexObj texObj2;
/* last pass so remove previous bg */
if(m_bgCrossFade == 0)
m_prevBg = NULL;
GX_ClearVtxDesc();
GX_SetNumTevStages(m_prevBg == NULL ? 1 : 2);
GX_SetNumChans(0);
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GX_SetNumTexGens(m_prevBg == NULL ? 1 : 2);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTevKColor(GX_KCOLOR0, CColor(m_bgCrossFade, 0xFF - m_bgCrossFade, 0, 0));
GX_SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0_R);
GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_TEXC, GX_CC_ZERO, GX_CC_KONST, GX_CC_ZERO);
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
GX_SetTevKColorSel(GX_TEVSTAGE1, GX_TEV_KCSEL_K0_G);
GX_SetTevColorIn(GX_TEVSTAGE1, GX_CC_TEXC, GX_CC_ZERO, GX_CC_KONST, GX_CC_CPREV);
GX_SetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GX_SetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLORNULL);
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaUpdate(GX_FALSE);
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
if(m_nextBg != NULL && m_nextBg->data != NULL)
{
GX_InitTexObj(&texObj, m_nextBg->data, m_nextBg->width, m_nextBg->height, m_nextBg->format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
}
if(m_prevBg != NULL && m_prevBg->data != NULL)
{
GX_InitTexObj(&texObj2, m_prevBg->data, m_prevBg->width, m_prevBg->height, m_prevBg->format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj2, GX_TEXMAP1);
}
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position3f32(0.f, 0.f, 0.f);
GX_TexCoord2f32(0.f, 0.f);
GX_Position3f32(640.f, 0.f, 0.f);
GX_TexCoord2f32(1.f, 0.f);
GX_Position3f32(640.f, 480.f, 0.f);
GX_TexCoord2f32(1.f, 1.f);
GX_Position3f32(0.f, 480.f, 0.f);
GX_TexCoord2f32(0.f, 1.f);
GX_End();
GX_SetNumTevStages(1);
m_curBg.width = 640;
m_curBg.height = 480;
m_curBg.format = GX_TF_RGBA8;
m_curBg.maxLOD = 0;
m_vid.renderToTexture(m_curBg, true);
}
void CMenu::_drawBg(void)
{
Mtx modelViewMtx;
GXTexObj texObj;
GX_ClearVtxDesc();
GX_SetNumTevStages(1);
GX_SetNumChans(0);
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GX_SetNumTexGens(1);
GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaUpdate(GX_FALSE);
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_InitTexObj(&texObj, m_curBg.data, m_curBg.width, m_curBg.height, m_curBg.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position3f32(0.f, 0.f, 0.f);
GX_TexCoord2f32(0.f, 0.f);
GX_Position3f32(640.f, 0.f, 0.f);
GX_TexCoord2f32(1.f, 0.f);
GX_Position3f32(640.f, 480.f, 0.f);
GX_TexCoord2f32(1.f, 1.f);
GX_Position3f32(0.f, 480.f, 0.f);
GX_TexCoord2f32(0.f, 1.f);
GX_End();
}
const wstringEx CMenu::_fmt(const char *key, const wchar_t *def)
{
wstringEx ws = m_loc.getWString(m_curLanguage, key, def);
if (checkFmt(def, ws)) return ws;
return def;
}
void CMenu::_initCF(void)
{
Config dump;
bool dumpGameLst = m_cfg.getBool("GENERAL", "dump_list", true);
if(dumpGameLst) dump.load(fmt("%s/" TITLES_DUMP_FILENAME, m_settingsDir.c_str()));
CoverFlow.clear();
CoverFlow.reserve(m_gameList.size());
char cfgKey1[74];
char cfgKey2[74];
char catKey1[64];
char catKey2[64];
// filter list based on categories, favorites, and adult only
for(vector<dir_discHdr>::iterator hdr = m_gameList.begin(); hdr != m_gameList.end(); ++hdr)
{
if(m_sourceflow)
{
if(!m_source.getBool(sfmt("button_%i", hdr->settings[0]), "hidden", false))
CoverFlow.addItem(&(*hdr), 0, 0);// no filtering for sourceflow
continue;
}
string favDomain = "FAVORITES";
string adultDomain = "ADULTONLY";
string playcntDomain = "PLAYCOUNT";
string lastplayDomain = "LASTPLAYED";
if(hdr->type == TYPE_PLUGIN)
{
favDomain = "FAVORITES_PLUGINS";
adultDomain = "ADULTONLY_PLUGINS";
string playcntDomain = "PLAYCOUNT_PLUGINS";
string lastplayDomain = "LASTPLAYED_PLUGINS";
}
// 1 is the one used. 2 is a temp copied to 1.
string catDomain1 = "";
string catDomain2 = "";
memset(catKey1, 0, 64);
memset(catKey2, 0, 64);
memset(cfgKey1, 0, 74);
memset(cfgKey2, 0, 74);
if(hdr->type == TYPE_HOMEBREW)
wcstombs(cfgKey1, hdr->title, 63);// uses title which is the folder name in apps.
else if(hdr->type == TYPE_PLUGIN)
{
strncpy(m_plugin.PluginMagicWord, fmt("%08x", hdr->settings[0]), 8);
// old pre 5.4.4 method which uses plugin magic/title of game
if(strrchr(hdr->path, '/') != NULL)
wcstombs(catKey1, hdr->title, 63);
else
memcpy(catKey1, hdr->path, 63);// scummvm
strcpy(cfgKey1, fmt("%s/%s", m_plugin.PluginMagicWord, catKey1));
// if game has an id from the plugin database we use the new method which uses platform name/id
if(strcmp(hdr->id, "PLUGIN") != 0 && !m_platform.getString("PLUGINS", m_plugin.PluginMagicWord, "").empty())
{
strcpy(cfgKey2, fmt("%s/%s", m_platform.getString("PLUGINS", m_plugin.PluginMagicWord).c_str(), hdr->id));
if(m_gcfg1.has(favDomain, cfgKey1) && !m_gcfg1.has(favDomain, cfgKey2))// convert old [DOMAIN] key= to new [DOMAIN] key=
{
m_gcfg1.setString(favDomain, cfgKey2, m_gcfg1.getString(favDomain, cfgKey1));
m_gcfg1.remove(favDomain, cfgKey1);// remove old method from cfg1
}
if(m_gcfg1.has(adultDomain, cfgKey1) && !m_gcfg1.has(adultDomain, cfgKey2))// convert old [DOMAIN] key= to new [DOMAIN] key=
{
m_gcfg1.setString(adultDomain, cfgKey2, m_gcfg1.getString(adultDomain, cfgKey1));
m_gcfg1.remove(adultDomain, cfgKey1);// remove old method from cfg1
}
strcpy(cfgKey1, cfgKey2);// copy 2 temp to 1 to use.
}
}
else // wii, gc, channels
{
strcpy(cfgKey1, hdr->id);
strcpy(catKey1, hdr->id);
}
if((!m_favorites || m_gcfg1.getBool(favDomain, cfgKey1, false))
&& (!m_locked || !m_gcfg1.getBool(adultDomain, cfgKey1, false)))
{
string requiredCats = m_cat.getString("GENERAL", "required_categories", "");
string selectedCats = m_cat.getString("GENERAL", "selected_categories", "");
string hiddenCats = m_cat.getString("GENERAL", "hidden_categories", "");
if(hdr->type == TYPE_PLUGIN && m_cat.hasDomain("PLUGINS"))// if using the optional PLUGINS domain for categories_lite.ini
{
requiredCats = m_cat.getString("PLUGINS", "required_categories", "");
selectedCats = m_cat.getString("PLUGINS", "selected_categories", "");
hiddenCats = m_cat.getString("PLUGINS", "hidden_categories", "");
}
u8 numReqCats = requiredCats.length();
u8 numSelCats = selectedCats.length();
u8 numHidCats = hiddenCats.length();
if(hdr->type == TYPE_CHANNEL)
catDomain1 = "NAND";
else if(hdr->type == TYPE_EMUCHANNEL)
catDomain1 = "CHANNELS";
else if(hdr->type == TYPE_GC_GAME)
catDomain1 = "GAMECUBE";
else if(hdr->type == TYPE_WII_GAME)
catDomain1 = "WII";
else if(hdr->type == TYPE_HOMEBREW)
catDomain1 = "HOMEBREW";
else //hdr->type == TYPE_PLUGIN
{
// old categories method use [MAGIC] and game title as the key.
catDomain1 = m_plugin.PluginMagicWord;
// catKey1 already set above
// if game has an id from the plugin database we use the new method which uses [platform name] and id as the key
if(strcmp(hdr->id, "PLUGIN") != 0 && !m_platform.getString("PLUGINS", m_plugin.PluginMagicWord, "").empty())
{
catDomain2 = m_platform.getString("PLUGINS", m_plugin.PluginMagicWord);
strcpy(catKey2, hdr->id);
if(m_cat.has(catDomain1, catKey1) && !m_cat.has(catDomain2, catKey2))// convert old [DOMAIN] key= to new [DOMAIN] key=
{
m_cat.setString(catDomain2, catKey2, m_cat.getString(catDomain1, catKey1));
m_cat.remove(catDomain1, catKey1);// remove old method from categories cfg
}
strcpy(catKey1, catKey2);// copy 2 temp to 1 to use.
catDomain1 = catDomain2;
}
}
if(numReqCats != 0 || numSelCats != 0 || numHidCats != 0) // if all 0 skip checking cats and show all games
{
string idCats= m_cat.getString(catDomain1, catKey1, "");
u8 numIdCats = idCats.length();
if(numIdCats == 0)
m_cat.remove(catDomain1, catKey1);
bool inaCat = false;
bool inHiddenCat = false;
int reqMatch = 0;
if(numIdCats != 0)
{
for(u8 j = 0; j < numIdCats; ++j)
{
int k = (static_cast<int>(idCats[j])) - 32;
if(k <= 0)
continue;
bool match = false;
if(numReqCats != 0)
{
for(u8 l = 0; l < numReqCats; ++l)
{
if(k == (static_cast<int>(requiredCats[l]) - 32))
{
match = true;
reqMatch++;
inaCat = true;
}
}
}
if(match)
continue;
if(numSelCats != 0)
{
for(u8 l = 0; l < numSelCats; ++l)
{
if(k == (static_cast<int>(selectedCats[l]) - 32))
{
match = true;
inaCat = true;
}
}
}
if(match)
continue;
if(numHidCats != 0)
{
for(u8 l = 0; l < numHidCats; ++l)
{
if(k == (static_cast<int>(hiddenCats[l]) - 32))
inHiddenCat = true;
}
}
}
}
//continue; means don't add game to list (don't show)
if(inHiddenCat)
continue;
if(numReqCats != reqMatch)
continue;
if(!inaCat)
{
if(numHidCats == 0)
continue;
else if(numSelCats > 0)
continue;
}
}
if(dumpGameLst && hdr->type != TYPE_HOMEBREW && strcmp(hdr->id, "PLUGIN") != 0)
dump.setWString(catDomain1, catKey1, hdr->title);
if(hdr->type != TYPE_HOMEBREW && strcmp(hdr->id, "PLUGIN") != 0)
{
int playcount = m_gcfg1.getInt(playcntDomain, cfgKey1, 0);
if(playcount == 0)
m_gcfg1.remove(playcntDomain, cfgKey1);
unsigned int lastPlayed = m_gcfg1.getUInt(lastplayDomain, cfgKey1, 0);
if(lastPlayed == 0)
m_gcfg1.remove("lastplayDomain", cfgKey1);
CoverFlow.addItem(&(*hdr), playcount, lastPlayed);
}
else
CoverFlow.addItem(&(*hdr), 0, 0);
}
/* remove them if false to keep file short */
if(!m_gcfg1.getBool(favDomain, cfgKey1))
m_gcfg1.remove(favDomain, cfgKey1);
if(!m_gcfg1.getBool(adultDomain, cfgKey1))
m_gcfg1.remove(adultDomain, cfgKey1);
}
if(CoverFlow.empty())
{
dump.unload();
return;
}
if(dumpGameLst)
{
dump.save(true);
//m_cfg.setBool("GENERAL", "dump_list", false);
}
/*********************** sort coverflow list ***********************/
CoverFlow.setSorting((Sorting)m_cfg.getInt(_domainFromView(), "sort", 0));
/*********************** set box mode and small box mode **************************/
if(!m_sourceflow)
{
if(m_current_view == COVERFLOW_HOMEBREW)
{
CoverFlow.setBoxMode(m_cfg.getBool(HOMEBREW_DOMAIN, "box_mode", true));
CoverFlow.setSmallBoxMode(m_cfg.getBool(HOMEBREW_DOMAIN, "smallbox", false));
}
else if(m_current_view == COVERFLOW_PLUGIN)
{
if(enabledPluginsCount == 1)// only one plugin enabled
{
if(m_plugin.GetEnabledStatus(HB_PMAGIC))// homebrew plugin
{
CoverFlow.setBoxMode(m_cfg.getBool(HOMEBREW_DOMAIN, "box_mode", true));
CoverFlow.setSmallBoxMode(m_cfg.getBool(HOMEBREW_DOMAIN, "smallbox", false));
}
else
{
s8 bm = -1;
for(u8 i = 0; m_plugin.PluginExist(i); ++i)
{
if(m_plugin.GetEnabledStatus(i))
{
bm = m_plugin.GetBoxMode(i);
break;
}
}
if(bm < 0)// if negative then use default setting
CoverFlow.setBoxMode(m_cfg.getBool("GENERAL", "box_mode", true));
else
CoverFlow.setBoxMode(bm == 0 ? false : true);
CoverFlow.setSmallBoxMode(false);
}
}
else // more than 1 plugin enabled
{
s8 bm1 = -1;
s8 bm2 = -1;
bool all_same = true;
for(u8 i = 0; m_plugin.PluginExist(i); ++i)
{
if(m_plugin.GetEnabledStatus(i))
{
if(bm1 == -1)
{
bm1 = m_plugin.GetBoxMode(i);
if(bm1 < 0)
bm1 = m_cfg.getBool("GENERAL", "box_mode", true) ? 1 : 0;
}
else
{
bm2 = m_plugin.GetBoxMode(i);
if(bm2 < 0)
bm2 = m_cfg.getBool("GENERAL", "box_mode", true) ? 1 : 0;
if(bm2 != bm1)
{
all_same = false;
break;
}
}
}
}
if(!all_same)
CoverFlow.setBoxMode(m_cfg.getBool("GENERAL", "box_mode", true));
else
CoverFlow.setBoxMode(bm1 == 0 ? false : true);
CoverFlow.setSmallBoxMode(false);
}
}
else
{
CoverFlow.setBoxMode(m_cfg.getBool("GENERAL", "box_mode", true));
CoverFlow.setSmallBoxMode(false);
}
}
else // sourceflow
{
CoverFlow.setBoxMode(m_cfg.getBool(SOURCEFLOW_DOMAIN, "box_mode", true));
CoverFlow.setSmallBoxMode(m_cfg.getBool(SOURCEFLOW_DOMAIN, "smallbox", false));
}
/*********************** Setup coverflow covers settings ***********************/
CoverFlow.setBufferSize(m_cfg.getInt("GENERAL", "cover_buffer", 20));
CoverFlow.setHQcover(m_cfg.getBool("GENERAL", "cover_use_hq", false));
CoverFlow.start(m_imgsDir);
/*********************** Get and set game list current item to center cover **************************/
if(!CoverFlow.empty())
{
/* get ID or filename or source number of center cover */
string ID = "", filename = "";
u32 sourceNumber = 0;
if(m_current_view == COVERFLOW_PLUGIN && !m_sourceflow)
{
if(!m_plugin.GetEnabledStatus(m_cfg.getString(PLUGIN_DOMAIN, "cur_magic", "00000000").c_str()))
{
for(u8 i = 0; m_plugin.PluginExist(i); ++i)
{
if(m_plugin.GetEnabledStatus(i))
{
m_cfg.setString(PLUGIN_DOMAIN, "cur_magic", sfmt("%08x", m_plugin.GetPluginMagic(i)));
break;
}
}
}
strncpy(m_plugin.PluginMagicWord, m_cfg.getString(PLUGIN_DOMAIN, "cur_magic").c_str(), 8);
if(strncasecmp(m_plugin.PluginMagicWord, GC_PMAGIC, 8) == 0)//NGCM
ID = m_cfg.getString("plugin_item", m_plugin.PluginMagicWord, "");
else if(strncasecmp(m_plugin.PluginMagicWord, WII_PMAGIC, 8) == 0)//NWII
ID = m_cfg.getString("plugin_item", m_plugin.PluginMagicWord, "");
else if(strncasecmp(m_plugin.PluginMagicWord, NAND_PMAGIC, 8) == 0)//NAND
ID = m_cfg.getString("plugin_item", m_plugin.PluginMagicWord, "");
else if(strncasecmp(m_plugin.PluginMagicWord, ENAND_PMAGIC, 8) == 0)//EMUNAND
ID = m_cfg.getString("plugin_item", m_plugin.PluginMagicWord, "");
else
filename = m_cfg.getString("plugin_item", m_plugin.PluginMagicWord, "");// homebrew and plugins
}
else if(m_sourceflow && sm_numbers.size() > 0)
sourceNumber = stoi(sm_numbers[sm_numbers.size() - 1]);
else if(m_current_view == COVERFLOW_HOMEBREW)
filename = m_cfg.getString(HOMEBREW_DOMAIN, "current_item", "");
else
ID = m_cfg.getString(_domainFromView(), "current_item", "");
/* set center cover as coverflow current position */
if(!CoverFlow._setCurPosToCurItem(ID.c_str(), filename.c_str(), sourceNumber, true))
CoverFlow._setCurPos(0);// if not found set first cover as coverflow current position
/************************** create and start the cover loader thread *************************/
CoverFlow.startCoverLoader();
}
}
bool CMenu::_loadList(void)
{
CoverFlow.clear();// clears filtered list (m_items), cover list (m_covers), and cover textures and stops coverloader
m_gameList.clear();
vector<dir_discHdr>().swap(m_gameList);
NANDemuView = false;
if(m_sourceflow)
{
m_cacheList.createSFList(m_max_source_btn, m_source, m_sourceDir);
for(vector<dir_discHdr>::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++)
m_gameList.push_back(*tmp_itr);
m_cacheList.Clear();
if(SF_cacheCovers)
{
SF_cacheCovers = false;
cacheCovers = true;
}
return true;
}
gprintf("Creating Gamelist\n");
if(m_current_view & COVERFLOW_PLUGIN)
_loadPluginList();
if(m_current_view & COVERFLOW_WII)
_loadWiiList();
if(m_current_view & COVERFLOW_CHANNEL)
_loadChannelList();
if(m_current_view & COVERFLOW_GAMECUBE)
_loadGamecubeList();
if(m_current_view & COVERFLOW_HOMEBREW)
_loadHomebrewList(HOMEBREW_DIR);
m_cacheList.Clear();
gprintf("Games found: %i\n", m_gameList.size());
return m_gameList.size() > 0 ? true : false;
}
bool CMenu::_loadWiiList(void)
{
gprintf("Adding wii list\n");
bool updateCache = m_cfg.getBool(WII_DOMAIN, "update_cache");
if(updateCache)
cacheCovers = true;
m_cfg.remove(WII_DOMAIN, "update_cache");
for(u8 i = 0; i < 2; ++i)
{
currentPartition = m_cfg.getInt(WII_DOMAIN, "partition", USB1);
if(currentPartition == 8)
currentPartition = i;
else if(i == 1)
continue;
if(!DeviceHandle.IsInserted(currentPartition))
continue;
DeviceHandle.OpenWBFS(currentPartition);
string gameDir(fmt(wii_games_dir, DeviceName[currentPartition]));
string cacheDir(fmt("%s/%s_wii.db", m_listCacheDir.c_str(), DeviceName[currentPartition]));
bool preCachedList = fsop_FileExist(cacheDir.c_str());
m_cacheList.CreateList(COVERFLOW_WII, gameDir, stringToVector(".wbfs|.iso", '|'), cacheDir, updateCache);
WBFS_Close();
for(vector<dir_discHdr>::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++)
m_gameList.push_back(*tmp_itr);
if(!preCachedList && fsop_FileExist(cacheDir.c_str()))
cacheCovers = true;
}
return true;
}
bool CMenu::_loadHomebrewList(const char *HB_Dir)
{
currentPartition = m_cfg.getInt(HOMEBREW_DOMAIN, "partition", SD);
if(!DeviceHandle.IsInserted(currentPartition))
return false;
gprintf("Adding homebrew list\n");
string gameDir(fmt("%s:/%s", DeviceName[currentPartition], HB_Dir));
string cacheDir(fmt("%s/%s_%s.db", m_listCacheDir.c_str(), DeviceName[currentPartition], HB_Dir));
bool updateCache = m_cfg.getBool(HOMEBREW_DOMAIN, "update_cache");
bool preCachedList = fsop_FileExist(cacheDir.c_str());
m_cacheList.CreateList(COVERFLOW_HOMEBREW, gameDir, stringToVector(".dol|.elf", '|'), cacheDir, updateCache);
m_cfg.remove(HOMEBREW_DOMAIN, "update_cache");
for(vector<dir_discHdr>::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++)
m_gameList.push_back(*tmp_itr);
if(updateCache || (!preCachedList && fsop_FileExist(cacheDir.c_str())))
cacheCovers = true;
return true;
}
bool CMenu::_loadGamecubeList()
{
gprintf("Adding gamecube list\n");
bool updateCache = m_cfg.getBool(GC_DOMAIN, "update_cache");
if(updateCache)
cacheCovers = true;
m_cfg.remove(GC_DOMAIN, "update_cache");
for(u8 i = 0; i < 2; ++i)
{
currentPartition = m_cfg.getInt(GC_DOMAIN, "partition", USB1);
if(currentPartition == 8)
currentPartition = i;
else if(i == 1)
continue;
if(!DeviceHandle.IsInserted(currentPartition))
continue;
string gameDir(fmt(gc_games_dir, DeviceName[currentPartition]));
string cacheDir(fmt("%s/%s_gamecube.db", m_listCacheDir.c_str(), DeviceName[currentPartition]));
bool preCachedList = fsop_FileExist(cacheDir.c_str());
m_cacheList.CreateList(COVERFLOW_GAMECUBE, gameDir, stringToVector(".iso|.gcm|.ciso|root", '|'), cacheDir, updateCache);
for(vector<dir_discHdr>::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++)
{
if(tmp_itr->settings[0] == 1) /* disc 2 */
continue;// skip gc disc 2 if its still part of the cached list
m_gameList.push_back(*tmp_itr);
}
if(!preCachedList && fsop_FileExist(cacheDir.c_str()))
cacheCovers = true;
}
return true;
}
bool CMenu::_loadChannelList(void)
{
u8 chantypes = m_cfg.getUInt(CHANNEL_DOMAIN, "channels_type", CHANNELS_REAL);
if(chantypes < CHANNELS_REAL || chantypes > CHANNELS_BOTH)
{
m_cfg.setUInt(CHANNEL_DOMAIN, "channels_type", CHANNELS_REAL);
chantypes = CHANNELS_REAL;
}
bool updateCache = m_cfg.getBool(CHANNEL_DOMAIN, "update_cache");
m_cfg.remove(CHANNEL_DOMAIN, "update_cache");
vector<string> NullVector;
if(chantypes & CHANNELS_REAL)
{
gprintf("Adding real nand list\n");
NANDemuView = false;
if(updateCache)
cacheCovers = true;// real nand channels list is not cached but covers may still need to be updated
m_cacheList.CreateList(COVERFLOW_CHANNEL, std::string(), NullVector, std::string(), false);
for(vector<dir_discHdr>::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++)
m_gameList.push_back(*tmp_itr);
}
if(chantypes & CHANNELS_EMU)
{
NANDemuView = true;
int emuPartition = _FindEmuPart(EMU_NAND, false);// check if emunand folder exist and on FAT
if(emuPartition >= 0)
{
gprintf("Adding emu nand list\n");
currentPartition = emuPartition;
string cacheDir = fmt("%s/%s_channels.db", m_listCacheDir.c_str(), DeviceName[currentPartition]);
bool preCachedList = fsop_FileExist(cacheDir.c_str());
m_cacheList.CreateList(COVERFLOW_CHANNEL, std::string(), NullVector, cacheDir, updateCache);
for(vector<dir_discHdr>::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++)
m_gameList.push_back(*tmp_itr);
if(updateCache || (!preCachedList && fsop_FileExist(cacheDir.c_str())))
cacheCovers = true;
}
}
return true;
}
bool CMenu::_loadPluginList()
{
bool updateCache = m_cfg.getBool(PLUGIN_DOMAIN, "update_cache");
int channels_type = min(max(1, m_cfg.getInt(CHANNEL_DOMAIN, "channels_type", CHANNELS_REAL)), (int)ARRAY_SIZE(CMenu::_ChannelsType));
gprintf("Adding plugins list\n");
for(u8 i = 0; m_plugin.PluginExist(i); ++i)
{
if(!m_plugin.GetEnabledStatus(i))
continue;
int romsPartition = m_plugin.GetRomPartition(i);
if(romsPartition < 0)
romsPartition = m_cfg.getInt(PLUGIN_DOMAIN, "partition", 0);
currentPartition = romsPartition;
if(!DeviceHandle.IsInserted(currentPartition))
continue;
strncpy(m_plugin.PluginMagicWord, fmt("%08x", m_plugin.GetPluginMagic(i)), 8);
const char *romDir = m_plugin.GetRomDir(i);
if(strstr(romDir, "scummvm.ini") == NULL)
{
if(strncasecmp(m_plugin.PluginMagicWord, HB_PMAGIC, 6) == 0)//HBRW
{
if(updateCache)
m_cfg.setBool(HOMEBREW_DOMAIN, "update_cache", true);
_loadHomebrewList(romDir);
}
else if(strncasecmp(m_plugin.PluginMagicWord, GC_PMAGIC, 8) == 0)//NGCM
{
if(updateCache)
m_cfg.setBool(GC_DOMAIN, "update_cache", true);
_loadGamecubeList();
}
else if(strncasecmp(m_plugin.PluginMagicWord, WII_PMAGIC, 8) == 0)//NWII
{
if(updateCache)
m_cfg.setBool(WII_DOMAIN, "update_cache", true);
_loadWiiList();
}
else if(strncasecmp(m_plugin.PluginMagicWord, NAND_PMAGIC, 8) == 0)//NAND
{
if(updateCache)
m_cfg.setBool(CHANNEL_DOMAIN, "update_cache", true);
m_cfg.setInt(CHANNEL_DOMAIN, "channels_type", CHANNELS_REAL);
_loadChannelList();
}
else if(strncasecmp(m_plugin.PluginMagicWord, ENAND_PMAGIC, 8) == 0)//ENAN
{
if(updateCache)
m_cfg.setBool(CHANNEL_DOMAIN, "update_cache", true);
m_cfg.setInt(CHANNEL_DOMAIN, "channels_type", CHANNELS_EMU);
_loadChannelList();
}
else
{
string cachedListFile(fmt("%s/%s_%s.db", m_listCacheDir.c_str(), DeviceName[currentPartition], m_plugin.PluginMagicWord));
bool preCachedList = fsop_FileExist(cachedListFile.c_str());
string romsDir(fmt("%s:/%s", DeviceName[currentPartition], romDir));
vector<string> FileTypes = stringToVector(m_plugin.GetFileTypes(i), '|');
m_cacheList.Color = m_plugin.GetCaseColor(i);
m_cacheList.Magic = m_plugin.GetPluginMagic(i);
m_cacheList.usePluginDBTitles = m_cfg.getBool(PLUGIN_DOMAIN, "database_titles", true);
string platformName = m_platform.getString("PLUGINS", m_plugin.PluginMagicWord, "");
if(!platformName.empty())
{
/* check COMBINED for platform names that mean the same system just different region */
/* some platforms have different names per country (ex. Genesis/Megadrive) */
/* but we use only one platform name for both */
string newName = m_platform.getString("COMBINED", platformName, "");
if(newName.empty())
m_platform.remove("COMBINED", platformName);
else
platformName = newName;
}
m_cacheList.CreateRomList(platformName.c_str(), romsDir, FileTypes, cachedListFile, updateCache);
for(vector<dir_discHdr>::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++)
m_gameList.push_back(*tmp_itr);
if(updateCache || (!preCachedList && fsop_FileExist(cachedListFile.c_str())))
cacheCovers = true;
}
}
else
{
string cachedListFile(fmt("%s/%s_%s.db", m_listCacheDir.c_str(), DeviceName[currentPartition], m_plugin.PluginMagicWord));
bool preCachedList = fsop_FileExist(cachedListFile.c_str());
Config scummvm;
if(strchr(romDir, ':') == NULL || !fsop_FileExist(romDir))
scummvm.load(fmt("%s/%s", m_pluginsDir.c_str(), romDir));
else
scummvm.load(romDir);
// should add error msg if loading scummvm fails or is not found
string platformName = "";
if(m_platform.loaded())/* convert plugin magic to platform name */
platformName = m_platform.getString("PLUGINS", m_plugin.PluginMagicWord);
m_cacheList.Color = m_plugin.GetCaseColor(i);
m_cacheList.Magic = m_plugin.GetPluginMagic(i);
m_cacheList.usePluginDBTitles = m_cfg.getBool(PLUGIN_DOMAIN, "database_titles", true);
m_cacheList.ParseScummvmINI(scummvm, DeviceName[currentPartition], m_pluginDataDir.c_str(), platformName.c_str(), cachedListFile, updateCache);
for(vector<dir_discHdr>::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++)
m_gameList.push_back(*tmp_itr);
if(updateCache || (!preCachedList && fsop_FileExist(cachedListFile.c_str())))
cacheCovers = true;
scummvm.unload();
}
}
m_cfg.remove(PLUGIN_DOMAIN, "update_cache");
m_cfg.setInt(CHANNEL_DOMAIN, "channels_type", channels_type);
return true;
}
void CMenu::_stopSounds(void)
{
// Fade out sounds
int fade_rate = 20;
if(!MusicPlayer.IsStopped())
{
while(MusicPlayer.GetVolume() > 0 || m_gameSound.GetVolume() > 0)
{
MusicPlayer.Tick(true);
if(m_gameSound.GetVolume() > 0)
m_gameSound.SetVolume(m_gameSound.GetVolume() < fade_rate ? 0 : m_gameSound.GetVolume() - fade_rate);
VIDEO_WaitVSync();
}
}
m_btnMgr.stopSounds();
CoverFlow.stopSound();
m_gameSound.Stop();
}
/* wiiflow creates a map<u8 slot, u8 base > _installed_cios list for slots 200 to 253 and slot 0
the first u8 is the slot and the second u8 is the base if its a d2x cios otherwise the slot number again.
slot 0 is set to 1 - first = 0 and second = 1
game config only shows the first (slot) or auto if first = 0 */
void CMenu::_load_installed_cioses()
{
if(isWiiVC)
return;
gprintf("Loading cIOS map\n");
_installed_cios[0] = 1;
for(u8 slot = 200; slot < 254; slot++)
{
u8 base = 1;
if(IOS_D2X(slot, &base))
{
gprintf("Found d2x base %u in slot %u\n", base, slot);
_installed_cios[slot] = base;
_cios_base[base] = slot;// these are sorted low to high. no duplicates. higher slot will replace lower slot if same base.
}
else if(CustomIOS(IOS_GetType(slot)))
{
gprintf("Found cIOS in slot %u\n", slot);
_installed_cios[slot] = slot;// we don't add the base for non d2x cios. only keep this if a user wants to try a hermies cios for example.
}
}
}
void CMenu::_hideWaitMessage()
{
m_vid.hideWaitMessage();
}
void CMenu::_showWaitMessage()
{
m_vid.waitMessage(0.15f);
}
typedef struct map_entry
{
char filename[8];
u8 sha1[20];
} ATTRIBUTE_PACKED map_entry_t;
void CMenu::_loadDefaultFont(void)
{
if(m_base_font != NULL)
return;
u32 size = 0;
bool retry = false;
bool korean = (CONF_GetLanguage() == CONF_LANG_KOREAN);
char ISFS_Filename[32] ATTRIBUTE_ALIGN(32);
// Read content.map from ISFS
strcpy(ISFS_Filename, "/shared1/content.map");
u8 *content = ISFS_GetFile(ISFS_Filename, &size, -1);
if(content == NULL)
return;
u32 items = size / sizeof(map_entry_t);
//gprintf("Open content.map, size %d, items %d\n", size, items);
map_entry_t *cm = (map_entry_t *)content;
retry:
bool kor_font = (korean && !retry) || (!korean && retry);
for(u32 i = 0; i < items; i++)
{
if(m_base_font != NULL && m_wbf1_font != NULL && m_wbf2_font != NULL)
break;
if(memcmp(cm[i].sha1, kor_font ? WIIFONT_HASH_KOR : WIIFONT_HASH, 20) == 0 && m_base_font == NULL)
{
sprintf(ISFS_Filename, "/shared1/%.8s.app", cm[i].filename); //who cares about the few ticks more?
u8 *u8_font_archive = ISFS_GetFile(ISFS_Filename, &size, -1);
if(u8_font_archive != NULL)
{
const u8 *font_file = u8_get_file_by_index(u8_font_archive, 1, &size); // There is only one file in that app
//gprintf("Extracted font: %d\n", size);
m_base_font = (u8*)MEM1_lo_alloc(size);
memcpy(m_base_font, font_file, size);
DCFlushRange(m_base_font, size);
m_base_font_size = size;
MEM2_free(u8_font_archive);
}
}
else if(memcmp(cm[i].sha1, WFB_HASH, 20) == 0 && m_wbf1_font == NULL && m_wbf2_font == NULL)
{
sprintf(ISFS_Filename, "/shared1/%.8s.app", cm[i].filename); //who cares about the few ticks more?
u8 *u8_font_archive = ISFS_GetFile(ISFS_Filename, &size, -1);
if(u8_font_archive != NULL)
{
const u8 *font_file1 = u8_get_file(u8_font_archive, "wbf1.brfna", &size);
m_wbf1_font = (u8*)MEM1_lo_alloc(size);
memcpy(m_wbf1_font, font_file1, size);
DCFlushRange(m_wbf1_font, size);
const u8 *font_file2 = u8_get_file(u8_font_archive, "wbf2.brfna", &size);
m_wbf2_font = (u8*)MEM1_lo_alloc(size);
memcpy(m_wbf2_font, font_file2, size);
DCFlushRange(m_wbf2_font, size);
MEM2_free(u8_font_archive);
}
}
}
if(!retry && m_base_font == NULL)
{
retry = true;
goto retry;
}
MEM2_free(content);
}
void CMenu::_cleanupDefaultFont()
{
MEM1_lo_free(m_base_font);
m_base_font = NULL;
m_base_font_size = 0;
MEM1_lo_free(m_wbf1_font);
m_wbf1_font = NULL;
MEM1_lo_free(m_wbf2_font);
m_wbf2_font = NULL;
}
const char *CMenu::_domainFromView()
{
if(m_sourceflow)
return SOURCEFLOW_DOMAIN;
switch(m_current_view)
{
case COVERFLOW_CHANNEL:
return CHANNEL_DOMAIN;
case COVERFLOW_HOMEBREW:
return HOMEBREW_DOMAIN;
case COVERFLOW_GAMECUBE:
return GC_DOMAIN;
case COVERFLOW_PLUGIN:
return PLUGIN_DOMAIN;
default:
return WII_DOMAIN;
}
return "NULL";
}
void CMenu::RemoveCover(const char *id)
{
const char *CoverPath = NULL;
if(id == NULL)
return;
CoverPath = fmt("%s/%s.png", m_boxPicDir.c_str(), id);
fsop_deleteFile(CoverPath);
CoverPath = fmt("%s/%s.png", m_picDir.c_str(), id);
fsop_deleteFile(CoverPath);
CoverPath = fmt("%s/%s.wfc", m_cacheDir.c_str(), id);
fsop_deleteFile(CoverPath);
}
/* if wiiflow using IOS58 this switches to cIOS for certain functions and back to IOS58 when done. */
/* if wiiflow using cIOS no need to temp switch */
void CMenu::TempLoadIOS(int IOS)
{
/* Only temp reload in IOS58 mode */
if(useMainIOS)
return;
if(IOS == IOS_TYPE_NORMAL_IOS)
IOS = 58;
else if(IOS == 0)
IOS = mainIOS;
if(CurrentIOS.Version != IOS)
{
loadIOS(IOS, true);// switch to new IOS
Sys_Init();
Open_Inputs();
for(int chan = WPAD_MAX_WIIMOTES-1; chan >= 0; chan--)
WPAD_SetVRes(chan, m_vid.width() + m_cursor[chan].width(), m_vid.height() + m_cursor[chan].height());
if(has_enabled_providers() || m_use_wifi_gecko)
_initAsyncNetwork();
}
}
static char blankCoverPath[MAX_FAT_PATH];
const char *CMenu::getBlankCoverPath(const dir_discHdr *element)
{
string blankCoverTitle = "wii";
if(m_platform.loaded())
{
switch(element->type)
{
case TYPE_CHANNEL:
strncpy(m_plugin.PluginMagicWord, NAND_PMAGIC, 9);
break;
case TYPE_EMUCHANNEL:
strncpy(m_plugin.PluginMagicWord, ENAND_PMAGIC, 9);
break;
case TYPE_HOMEBREW:
strncpy(m_plugin.PluginMagicWord, HB_PMAGIC, 9);
break;
case TYPE_GC_GAME:
strncpy(m_plugin.PluginMagicWord, GC_PMAGIC, 9);
break;
case TYPE_PLUGIN:
strncpy(m_plugin.PluginMagicWord, fmt("%08x", element->settings[0]), 8);
break;
default:// wii
strncpy(m_plugin.PluginMagicWord, WII_PMAGIC, 9);
}
blankCoverTitle = m_platform.getString("PLUGINS", m_plugin.PluginMagicWord, "wii");
}
snprintf(blankCoverPath, sizeof(blankCoverPath), "%s/blank_covers/%s.png", m_boxPicDir.c_str(), blankCoverTitle.c_str());
if(!fsop_FileExist(blankCoverPath))
snprintf(blankCoverPath, sizeof(blankCoverPath), "%s/blank_covers/%s.jpg", m_boxPicDir.c_str(), blankCoverTitle.c_str());
return blankCoverPath;
}
const char *CMenu::getBoxPath(const dir_discHdr *element)
{
if(element->type == TYPE_PLUGIN)
{
const char *filename = fmt("%s", element->path);
if(strchr(filename, '/') != NULL)
{
filename = fmt("%s", strrchr(element->path, '/') + 1);
}
const char *coverFolder = m_plugin.GetCoverFolderName(element->settings[0]);
return fmt("%s/%s/%s.png", m_boxPicDir.c_str(), coverFolder, filename);
}
else if(element->type == TYPE_HOMEBREW)// use folder name for the png name
return fmt("%s/homebrew/%s.png", m_boxPicDir.c_str(), strrchr(element->path, '/') + 1);
else if(element->type == TYPE_SOURCE)//sourceflow
{
const char *coverImg = strrchr(element->path, '/') + 1;
if(coverImg == NULL)
return NULL;
return fmt("%s/full_covers/%s", m_sourceDir.c_str(), coverImg);
}
return fmt("%s/%s.png", m_boxPicDir.c_str(), element->id);
}
const char *CMenu::getFrontPath(const dir_discHdr *element)
{
if(element->type == TYPE_PLUGIN)
{
const char *tempname = element->path;
if(strchr(element->path, '/') != NULL)
tempname = strrchr(element->path, '/') + 1;
const char *coverFolder = m_plugin.GetCoverFolderName(element->settings[0]);
if(strlen(coverFolder) > 0)
return fmt("%s/%s/%s.png", m_picDir.c_str(), coverFolder, tempname);
else
return fmt("%s/%s.png", m_picDir.c_str(), tempname);
}
else if(element->type == TYPE_HOMEBREW)
{
if(m_cfg.getBool(HOMEBREW_DOMAIN, "smallbox"))
{
const char *coverPath = fmt("%s/homebrew_small/%s.png", m_picDir.c_str(), strrchr(element->path, '/') + 1);
if(!fsop_FileExist(coverPath))
return fmt("%s/icon.png", element->path);
else
return coverPath;
}
else
return fmt("%s/homebrew/%s.png", m_picDir.c_str(), strrchr(element->path, '/') + 1);
}
else if(element->type == TYPE_SOURCE)//sourceflow
{
const char *coverImg = strrchr(element->path, '/') + 1;
if(coverImg == NULL)
return NULL;
const char *coverPath = fmt("%s/front_covers/%s", m_sourceDir.c_str(), coverImg);
if(m_cfg.getBool(SOURCEFLOW_DOMAIN, "smallbox") || !fsop_FileExist(coverPath))
{
string themeName = m_cfg.getString("GENERAL", "theme", "default");
coverPath = fmt("%s/small_covers/%s/%s", m_sourceDir.c_str(), themeName.c_str(), coverImg);
if(!fsop_FileExist(coverPath))
{
coverPath = fmt("%s/small_covers/%s", m_sourceDir.c_str(), coverImg);
if(!fsop_FileExist(coverPath))
return element->path;
}
}
return coverPath;
}
return fmt("%s/%s.png", m_picDir.c_str(), element->id);
}