WiiFlow_Lite/source/menu/menu.cpp
Fledge68 6f6b3ec2d8 external_booter.bin fixes that i missed when i changed the booter in v5.5.0 beta 12 commit 9f7da43
- added missing *BI2 = 0x817E5480; to  Disc_SetLowMem() for wii games.
- added missing memcpy((void*)0x80001800, (void*)Disc_ID, 8); needed for debugger and ocarina cheats engine.

- fixed default setting for savegame emulation back to OFF (0). v5.5.0 and v5.5.1 new clean install's would set it to FULL (2) which caused wii games to crash on boot up. if you have this issue you can simply go to main settings>nand emulation settings and set it to OFF.
- changes to STexture::fromPNG() to hopefully clear up the out of mem issue when downloading and converting the cover png to a wfc cache file.
- v5.5.2
2022-02-07 07:19:27 -06:00

2957 lines
105 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_thrdStep = 0.f;
m_thrdStepLen = 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)
_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 SD only to off if any usb device is attached */
m_cfg.getBool("GENERAL", "sd_only", usb_mounted ? false : true);// will only set it if this doesn't already exist - very first boot up
/* 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_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));
strncpy(emu_nands_dir, IsOnWiiU() ? "vwiinands" : "nands", sizeof(emu_nands_dir) - 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", -1);
string savesNand = m_cfg.getString(WII_DOMAIN, "current_save_emunand", "default");
int savesPart = m_cfg.getInt(WII_DOMAIN, "savepartition", -1);
if(emuPart < 0)
{
u8 i;
for(i = SD; i < MAXDEVICES; i++)// find first usable partition
{
if(DeviceHandle.PartitionUsableForNandEmu(i))
{
emuPart = i;
break;
}
}
if(i == MAXDEVICES)// if no usable partitions found set to SD for now
emuPart = SD;// cfgne8=No valid FAT partition found for NAND Emulation!
m_cfg.setInt(CHANNEL_DOMAIN, "partition", emuPart);
}
gprintf("emunand = %s:/%s/%s\n", DeviceName[emuPart], emu_nands_dir, emuNand.c_str());
if(savesPart < 0)
{
u8 i;
for(i = SD; i < MAXDEVICES; i++)
{
if(DeviceHandle.PartitionUsableForNandEmu(i))
{
savesPart = i;
break;
}
}
if(i == MAXDEVICES)
savesPart = SD;
m_cfg.setInt(WII_DOMAIN, "savepartition", savesPart);
}
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_btnMgr.setSoundVolume(m_cfg.getInt("GENERAL", "sound_volume_gui", 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.unload();
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.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();
_initWad();
_initWBFSMenu();
_initConfigAdvMenu();
_initConfigSndMenu();
_initConfig4Menu();
_initConfigScreenMenu();
_initConfig3Menu();
_initConfigMenu();
_initConfigGCMenu();
_initConfig7Menu();
_initPartitionsCfgMenu();
_initGameMenu();
_initDownloadMenu();
_initCodeMenu();
_initAboutMenu();
_initCFThemeMenu();
_initGameSettingsMenu();
_initCheatSettingsMenu();
_initSourceMenu();
_initCfgSrc();
_initCfgHB();
_initPluginSettingsMenu();
_initCategorySettingsMenu();
_initGameInfoMenu();
_initNandEmuMenu();
_initHomeAndExitToMenu();
_initCoverBanner();
_initExplorer();
_initBoot();
_initPathsMenu();
_initCheckboxesMenu();
_loadCFCfg();
}
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(), false);// false for word wrap
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);
m_btnMgr.setText(m_mem2FreeSize, wfmt(L"Mem2 Free:%u", MEM2_freesize()), true);
}
#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();
}
void CMenu::_updateText(void)
{
if(m_use_source)
_textSource();
_textPluginSettings();
_textCategorySettings();
_textCheatSettings();
_textConfig();
_textConfig3();
_textConfigScreen();
_textConfig4();
_textConfigAdv();
_textConfigSnd();
_textConfigGC();
_textPartitionsCfg();
_textCfgHB();
_textGame();
_textDownload();
_textCode();
_textWBFS();
_textGameSettings();
_textNandEmu();
_textHome();
_textExitTo();
_textShutdown();
_textBoot();
_textCoverBanner();
_textExplorer();
_textWad();
_textCheckboxesMenu();
}
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());
string requiredCats;
string selectedCats;
string hiddenCats;
char id[74];
char catID[64];
// filter list based on categories and favorites
for(vector<dir_discHdr>::iterator hdr = m_gameList.begin(); hdr != m_gameList.end(); ++hdr)
{
requiredCats = m_cat.getString("GENERAL", "required_categories", "");
selectedCats = m_cat.getString("GENERAL", "selected_categories", "");
hiddenCats = m_cat.getString("GENERAL", "hidden_categories", "");
const char *favDomain = "FAVORITES";
const char *adultDomain = "ADULTONLY";
memset(id, 0, 74);
memset(catID, 0, 64);
if(m_sourceflow)
{
if(m_source.getBool(sfmt("button_%i", hdr->settings[0]), "hidden", false) == false)
CoverFlow.addItem(&(*hdr), 0, 0);
continue;
}
else if(hdr->type == TYPE_HOMEBREW)
{
wcstombs(id, hdr->title, 63);
strcpy(catID, id);
}
else if(hdr->type == TYPE_PLUGIN)
{
if(m_cat.hasDomain("PLUGINS"))// if using new style categories_lite.ini
{
requiredCats = m_cat.getString("PLUGINS", "required_categories", "");
selectedCats = m_cat.getString("PLUGINS", "selected_categories", "");
hiddenCats = m_cat.getString("PLUGINS", "hidden_categories", "");
}
strncpy(m_plugin.PluginMagicWord, fmt("%08x", hdr->settings[0]), 8);
if(strrchr(hdr->path, '/') != NULL)
wcstombs(catID, hdr->title, 63);
else
strncpy(catID, hdr->path, 63);// scummvm
strcpy(id, m_plugin.PluginMagicWord);
strcat(id, fmt("/%s", catID));
favDomain = "FAVORITES_PLUGINS";
adultDomain = "ADULTONLY_PLUGINS";
}
else // wii, gc, channels
{
strcpy(id, hdr->id);
strcpy(catID, id);
}
u8 numReqCats = requiredCats.length();
u8 numSelCats = selectedCats.length();
u8 numHidCats = hiddenCats.length();
if((!m_favorites || m_gcfg1.getBool(favDomain, id, false))
&& (!m_locked || !m_gcfg1.getBool(adultDomain, id, false)))
{
string catDomain = "";
if(hdr->type == TYPE_CHANNEL)
catDomain = "NAND";
else if(hdr->type == TYPE_EMUCHANNEL)
catDomain = "CHANNELS";
else if(hdr->type == TYPE_GC_GAME)
catDomain = "GAMECUBE";
else if(hdr->type == TYPE_WII_GAME)
catDomain = "WII";
else if(hdr->type == TYPE_HOMEBREW)
catDomain = "HOMEBREW";
else
catDomain = m_plugin.PluginMagicWord;
if(numReqCats != 0 || numSelCats != 0 || numHidCats != 0) // if all 0 skip checking cats and show all games
{
string idCats= m_cat.getString(catDomain, catID, "");
u8 numIdCats = idCats.length();
if(numIdCats == 0)
m_cat.remove(catDomain, catID);
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 && !NoGameID(hdr->type))
{
const char *domain = NULL;
switch(hdr->type)
{
case TYPE_CHANNEL:
domain = "NAND";
break;
case TYPE_EMUCHANNEL:
domain = "CHANNELS";
break;
case TYPE_GC_GAME:
domain = "GAMECUBE";
break;
default:
domain = "WII";
break;
}
dump.setWString(domain, id, hdr->title);
}
if(hdr->type == TYPE_PLUGIN && m_plugin.GetEnabledStatus(m_plugin.GetPluginPosition(hdr->settings[0])))
CoverFlow.addItem(&(*hdr), 0, 0);
else
{
int playcount = m_gcfg1.getInt("PLAYCOUNT", id, 0);
unsigned int lastPlayed = m_gcfg1.getUInt("LASTPLAYED", id, 0);
CoverFlow.addItem(&(*hdr), playcount, lastPlayed);
}
}
/* remove them if false to keep file short */
if(!m_gcfg1.getBool(favDomain, id))
m_gcfg1.remove(favDomain, id);
if(!m_gcfg1.getBool(adultDomain, id))
m_gcfg1.remove(adultDomain, id);
}
if(CoverFlow.empty())
{
dump.unload();
return;
}
if(dumpGameLst)
{
dump.save(true);
m_cfg.setBool("GENERAL", "dump_list", false);
}
/*********************** sort coverflow list ***********************/
CoverFlow.setSorting(m_source_cnt > 1 ? (Sorting)0 : (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(m_plugin.GetPluginPosition(strtoul("48425257", NULL, 16))))// 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_plugin.GetPluginPosition(strtoul(m_cfg.getString(PLUGIN_DOMAIN, "cur_magic", "00000000").c_str(), NULL, 16))))
{
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, "4E47434D", 8) == 0)//NGCM
ID = m_cfg.getString("plugin_item", m_plugin.PluginMagicWord, "");
else if(strncasecmp(m_plugin.PluginMagicWord, "4E574949", 8) == 0)//NWII
ID = m_cfg.getString("plugin_item", m_plugin.PluginMagicWord, "");
else if(strncasecmp(m_plugin.PluginMagicWord, "4E414E44", 8) == 0)//NAND
ID = m_cfg.getString("plugin_item", m_plugin.PluginMagicWord, "");
else if(strncasecmp(m_plugin.PluginMagicWord, "454E414E", 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 || (m_source_cnt > 1 && NoGameID(m_cfg.getInt("MULTI", "current_item_type", TYPE_PLUGIN))))
filename = m_cfg.getString(_domainFromView(), "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)
{
currentPartition = m_cfg.getInt(WII_DOMAIN, "partition", USB1);
if(!DeviceHandle.IsInserted(currentPartition))
return false;
gprintf("Adding wii list\n");
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 updateCache = m_cfg.getBool(WII_DOMAIN, "update_cache");
bool preCachedList = fsop_FileExist(cacheDir.c_str());
m_cacheList.CreateList(COVERFLOW_WII, gameDir, stringToVector(".wbfs|.iso", '|'), cacheDir, updateCache);
WBFS_Close();
m_cfg.remove(WII_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::_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()
{
currentPartition = m_cfg.getInt(GC_DOMAIN, "partition", USB1);
if(!DeviceHandle.IsInserted(currentPartition))
return false;
gprintf("Adding gamecube list\n");
string gameDir(fmt(gc_games_dir, DeviceName[currentPartition]));
string cacheDir(fmt("%s/%s_gamecube.db", m_listCacheDir.c_str(), DeviceName[currentPartition]));
bool updateCache = m_cfg.getBool(GC_DOMAIN, "update_cache");
bool preCachedList = fsop_FileExist(cacheDir.c_str());
m_cacheList.CreateList(COVERFLOW_GAMECUBE, gameDir, stringToVector(".iso|.gcm|.ciso|root", '|'), cacheDir, updateCache);
m_cfg.remove(GC_DOMAIN, "update_cache");
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(updateCache || (!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;
}
vector<string> NullVector;
if(chantypes & CHANNELS_REAL)
{
gprintf("Adding real nand list\n");
NANDemuView = false;
bool updateCache = m_cfg.getBool(CHANNEL_DOMAIN, "update_cache");
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);
m_cfg.remove(CHANNEL_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(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 updateCache = m_cfg.getBool(CHANNEL_DOMAIN, "update_cache");
bool preCachedList = fsop_FileExist(cacheDir.c_str());
m_cacheList.CreateList(COVERFLOW_CHANNEL, std::string(), NullVector, cacheDir, updateCache);
m_cfg.remove(CHANNEL_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::_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, "484252", 6) == 0)//HBRW
{
if(updateCache)
m_cfg.setBool(HOMEBREW_DOMAIN, "update_cache", true);
_loadHomebrewList(romDir);
}
else if(strncasecmp(m_plugin.PluginMagicWord, "4E47434D", 8) == 0)//NGCM
{
if(updateCache)
m_cfg.setBool(GC_DOMAIN, "update_cache", true);
_loadGamecubeList();
}
else if(strncasecmp(m_plugin.PluginMagicWord, "4E574949", 8) == 0)//NWII
{
if(updateCache)
m_cfg.setBool(WII_DOMAIN, "update_cache", true);
_loadWiiList();
}
else if(strncasecmp(m_plugin.PluginMagicWord, "4E414E44", 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, "454E414E", 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 romsDir(fmt("%s:/%s", DeviceName[currentPartition], romDir));
string cachedListFile(fmt("%s/%s_%s.db", m_listCacheDir.c_str(), DeviceName[currentPartition], m_plugin.PluginMagicWord));
bool preCachedList = fsop_FileExist(cachedListFile.c_str());
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);
m_cacheList.CreateRomList(m_platform, 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.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();
}
bool CMenu::_loadFile(u8 * &buffer, u32 &size, const char *path, const char *file)
{
u32 fileSize = 0;
u8 *fileBuf = fsop_ReadFile(file == NULL ? path : fmt("%s/%s", path, file), &fileSize);
if(fileBuf == NULL)
return false;
if(buffer != NULL)
MEM2_free(buffer);
buffer = fileBuf;
size = fileSize;
return true;
}
/* wiiflow creates a map<u8, u8> _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;
}
else if(CustomIOS(IOS_GetType(slot)))
{
gprintf("Found cIOS in slot %u\n", slot);
_installed_cios[slot] = slot;
}
}
}
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;
if(m_source_cnt > 1)
return "MULTI";
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, "4E414E44", 9);
break;
case TYPE_EMUCHANNEL:
strncpy(m_plugin.PluginMagicWord, "454E414E", 9);
break;
case TYPE_HOMEBREW:
strncpy(m_plugin.PluginMagicWord, "48425257", 9);
break;
case TYPE_GC_GAME:
strncpy(m_plugin.PluginMagicWord, "4E47434D", 9);
break;
case TYPE_PLUGIN:
strncpy(m_plugin.PluginMagicWord, fmt("%08x", element->settings[0]), 8);
break;
default:// wii
strncpy(m_plugin.PluginMagicWord, "4E574949", 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);
}