Redesign config and default theme, many more changes and fixes

This commit is contained in:
XorTroll 2021-07-11 03:40:01 +02:00
parent f0641556a3
commit 30c6ff8ff3
40 changed files with 637 additions and 384 deletions

View file

@ -1,21 +0,0 @@
# Changelog
## uLaunch
- Updated with last libnx and Atmosphere.
- Now, instead of always overriding certain applets (if you had uLaunch on your SD), uLaunch makes use of ECS to launch its processes over a certain applet, so that the applet can be used normally when the process isn't launched.
- The internal comunication system between uLaunch's processes has changed internally and made more fast and efficient.
## USB support
- USB support is back (it was temporarily removed in 0.2.1 due to weird technical issues)
- USB now supports an alternative system, which is available under certain circumstances (having patches enabling it being on >10.0.0)
## uMenu
- When launching homebrew as applications, uMenu won't make use of the internal flog system application it used to use (which might have been risky for potential bans). Instead, making use of ECS (mentioned above), after a donor title has been selected by pressing up, homebrew can easily be launched over that application like normal Atmosphere does. Note that you won't be able to launch homebrew over an application unless you select that application as the donor application.
- HOME menu pressing is properly supported on the different menus. For instance, pressing the HOME button inside the settings menu will make it return to the main menu.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View file

@ -1,6 +1,6 @@
<img width="200" src="LibraryAppletDaemon/RomFs/LogoLarge.png"> <img width="200" src="uMenu/RomFs/LogoLarge.png">
> Custom, open-source replacement/reimplementation for Nintendo Switch's HOME menu (qlaunch), extending it with amazing, homebrew-oriented functionality! > uLaunch is a custom, open-source replacement/reimplementation for the Nintendo Switch's HOME menu (qlaunch), extending it with amazing, homebrew-oriented features!
<img src="Screenshots/s1.png" alt="drawing" width="400"/> <img src="Screenshots/s2.png" alt="drawing" width="400"/> <img src="Screenshots/s1.png" alt="drawing" width="400"/> <img src="Screenshots/s2.png" alt="drawing" width="400"/>
@ -8,11 +8,9 @@
<img src="Screenshots/s5.png" alt="drawing" width="400"/> <img src="Screenshots/s6.png" alt="drawing" width="400"/> <img src="Screenshots/s5.png" alt="drawing" width="400"/> <img src="Screenshots/s6.png" alt="drawing" width="400"/>
uLaunch is a very ambitious project, consisting on two custom library applets, a custom system application and a custom system applet, in order to replace the console's **HOME menu** with a custom, homebrew-oriented one. uLaunch is a project which aims to replace the console's **HOME menu** with a custom, homebrew-oriented one.
- This isn't any kind of HOME menu extension, injection, patch, etc. uLaunch is a **complete** reimplementation, 100% open-source, which also takes over eShop and Parental control applets and flog system title (all of them are pretty much useless with this reimpl) for its extended functionality. - This isn't some kind of HOME menu extension, injection, patch, etc. uLaunch is a **complete** reimplementation, 100% open-source, which also takes over eShop and Parental control applets (all of them pretty much useless with this reimpl) for its extended functionality.
- The project is licensed as **GPLv2**.
- For those who are interested in how the UI was done, this project is, like [Goldleaf](https://github.com/XorTroll/Goldleaf), a good example of how powerful [Plutonium libraries](https://github.com/XorTroll/Plutonium) can be in order to make beautiful UIs. - For those who are interested in how the UI was done, this project is, like [Goldleaf](https://github.com/XorTroll/Goldleaf), a good example of how powerful [Plutonium libraries](https://github.com/XorTroll/Plutonium) can be in order to make beautiful UIs.
@ -20,15 +18,15 @@ uLaunch is a very ambitious project, consisting on two custom library applets, a
### Want to create **custom forwarders** (eg. RetroArch ones)? check **uViewer** tool in [latest releases](https://github.com/XorTroll/uLaunch/releases/latest)! ### Want to create **custom forwarders** (eg. RetroArch ones)? check **uViewer** tool in [latest releases](https://github.com/XorTroll/uLaunch/releases/latest)!
### Want to find **themes** for uLaunch? Check [r/uLaunchThemes subreddit](https://www.reddit.com/r/uLaunchThemes/)! ### Want to find **themes** for uLaunch? Check the [r/uLaunchThemes subreddit](https://www.reddit.com/r/uLaunchThemes/)!
### For more detailed **information** about the whole project (*themeing* too), check its [wiki](https://github.com/XorTroll/uLaunch/wiki)! ### For more detailed **information** about the whole project (and *themeing* too), check its [wiki](https://github.com/XorTroll/uLaunch/wiki)!
## Features ## Features
**List of HOME menu features uLaunch has**: **List of HOME menu features uLaunch has**:
- Proper launching and foreground management: launch, suspend and close titles and applets - Proper launching and foreground management: launch, suspend and close applications and applets
- Proper general channel handling (some of it might be not implemented): sleep, shutdown, reboot, HOME menu press detection... - Proper general channel handling (some of it might be not implemented): sleep, shutdown, reboot, HOME menu press detection...
@ -52,7 +50,7 @@ uLaunch is a very ambitious project, consisting on two custom library applets, a
- Launching as applets (no need of **Album**!) - Launching as applets (no need of **Album**!)
- Launching as **applications** (no need of **any titles** to do so!) - Launching as **applications** (using a **donor title**!)
- Custom basic homebrew menu - Custom basic homebrew menu
@ -82,17 +80,25 @@ uLaunch is a very ambitious project, consisting on two custom library applets, a
## Disclaimer ## Disclaimer
### Homebrew-as-application 'flog' takeover ### Ban risks
uLaunch allows you to launch homebrew as an application, taking advantage of the system's '**flog**' built-in application title, which was stubbed but not removed, thus it's content can be overriden via LayeredFS and launched. While no bans have been reported related to using uLaunch, replacing the retail HOME menu's functionality is never a completely safe idea, so always use it at your own risk.
Since launching this title should be impossible, it might involve ban risk. uLaunch has this option **disabled by default**, so enable and use it **use it at your own risk**. Always make youre you're safe from bans (by using tools like 90DNS) before using uLaunch to avoid any possible risks. ## TODO list
- Improve Daemons's IPC with two services, one only for Daemon and the other one for any process to interact with uLaunch:
- Easy way to detect whether uLaunch is present
- Get whether a title/homebrew is opened
- (check suggestions and bugs in issues for user-submitted TODOs)
## Compiling ## Compiling
You will need devkitPro, devkitA64, libnx and all SDL2 libraries for switch development. You will need devkitPro, devkitA64, libnx and all SDL2 libraries for switch development.
Clone (**recursively!**) this repo (uses Atmosphere-libs and Plutonium submodules) and hit `make` in root. It should build everything and generate a `titles` folder ready for use inside `SdOut`. Clone (**recursively!**) this repo (since it uses Atmosphere-libs and Plutonium submodules) and just enter `make` in the command line. It should build everything and generate a `SdOut` folder whose contents sould directly be copied to the root of a console SD card.
In order to only build a certain subproject, you can run `make` plus the subproject's name (`make daemon`, `make hbtarget` or `make menu`). In order to only build a certain subproject, you can run `make` plus the subproject's name (`make daemon`, `make hbtarget` or `make menu`).
@ -100,7 +106,7 @@ In order to only build a certain subproject, you can run `make` plus the subproj
- SciresM for [Atmosphere-libs](https://github.com/Atmosphere-NX/Atmosphere-libs). - SciresM for [Atmosphere-libs](https://github.com/Atmosphere-NX/Atmosphere-libs).
- Switchbrew team for libnx and [nx-hbloader](https://github.com/switchbrew/nx-hbloader), the base of *QHbTarget processes (they're just simple wrappers of hbloader in the end) - Switchbrew team for [libnx](https://github.com/switchbrew/libnx) and [nx-hbloader](https://github.com/switchbrew/nx-hbloader), the base of the uHbTarget processes (they're essentially wrappers of nx-hbloader). This project also makes use of hx-hbmenu's icon.
- C4Phoenix for the amazing design of this project's logo. - C4Phoenix for the amazing design of this project's logo.
@ -108,4 +114,4 @@ In order to only build a certain subproject, you can run `make` plus the subproj
- Several scene developers for their help with small issues or features. - Several scene developers for their help with small issues or features.
- Everyone from Discord or other places whose suggestions made this project a little bit better :) - Everyone from Discord or other places whose suggestions made this project a little bit better ;)

View file

@ -1,9 +0,0 @@
# uLaunch's TODO list
- Improve Daemons's IPC with two services, one only for Daemon and the other one for any process to interact with uLaunch:
- Easy way to detect whether uLaunch is present
- Get whether a title/homebrew is opened
- (check suggestions and bugs in issues for user-submitted TODOs)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

View file

@ -135,7 +135,9 @@ namespace {
} }
inline Result LaunchMenu(dmi::MenuStartMode st_mode, dmi::DaemonStatus status) { inline Result LaunchMenu(dmi::MenuStartMode st_mode, dmi::DaemonStatus status) {
return ecs::RegisterLaunchAsApplet(g_Config.menu_program_id, static_cast<u32>(st_mode), "/ulaunch/bin/uMenu", &status, sizeof(status)); u64 menu_program_id;
UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::MenuTakeoverProgramId, menu_program_id));
return ecs::RegisterLaunchAsApplet(menu_program_id, static_cast<u32>(st_mode), "/ulaunch/bin/uMenu", &status, sizeof(status));
} }
void HandleHomeButton() { void HandleHomeButton() {
@ -445,8 +447,10 @@ namespace {
} }
if(strlen(g_HbTargetLaunchFlag.nro_path)) { if(strlen(g_HbTargetLaunchFlag.nro_path)) {
if(!am::LibraryAppletIsActive()) { if(!am::LibraryAppletIsActive()) {
auto params = hb::HbTargetParams::Create(g_HbTargetLaunchFlag.nro_path, g_HbTargetLaunchFlag.nro_argv, true); auto params = hb::HbTargetParams::Create(g_HbTargetLaunchFlag.nro_path, g_HbTargetLaunchFlag.nro_argv, false);
UL_ASSERT(ecs::RegisterLaunchAsApplet(g_Config.homebrew_applet_program_id, 0, "/ulaunch/bin/uHbTarget/applet", &params, sizeof(params))); u64 homebrew_applet_program_id;
UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::HomebrewAppletTakeoverProgramId, homebrew_applet_program_id));
UL_ASSERT(ecs::RegisterLaunchAsApplet(homebrew_applet_program_id, 0, "/ulaunch/bin/uHbTarget/applet", &params, sizeof(params)));
sth_done = true; sth_done = true;
g_HbTargetLaunchFlag.nro_path[0] = '\0'; g_HbTargetLaunchFlag.nro_path[0] = '\0';
@ -454,7 +458,9 @@ namespace {
} }
if(!am::LibraryAppletIsActive()) { if(!am::LibraryAppletIsActive()) {
auto cur_id = am::LibraryAppletGetId(); auto cur_id = am::LibraryAppletGetId();
if((cur_id == AppletId_LibraryAppletWeb) || (cur_id == AppletId_LibraryAppletPhotoViewer) || (cur_id == g_Config.homebrew_applet_program_id)) { u64 homebrew_applet_program_id;
UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::HomebrewAppletTakeoverProgramId, homebrew_applet_program_id));
if((cur_id == AppletId_LibraryAppletWeb) || (cur_id == AppletId_LibraryAppletPhotoViewer) || (cur_id == homebrew_applet_program_id)) {
auto status = CreateStatus(); auto status = CreateStatus();
UL_ASSERT(LaunchMenu(dmi::MenuStartMode::Menu, status)); UL_ASSERT(LaunchMenu(dmi::MenuStartMode::Menu, status));
@ -462,9 +468,9 @@ namespace {
} }
} }
const auto applet_active_old = g_AppletActive; const auto prev_applet_active = g_AppletActive;
g_AppletActive = am::LibraryAppletIsActive(); g_AppletActive = am::LibraryAppletIsActive();
if(!sth_done && !applet_active_old) { if(!sth_done && !prev_applet_active) {
// If nothing was done, but nothing is active... An application or applet might have crashed, terminated, failed to launch... // If nothing was done, but nothing is active... An application or applet might have crashed, terminated, failed to launch...
// No matter what is it, we reopen Menu in launch-error mode. // No matter what is it, we reopen Menu in launch-error mode.
if(!am::ApplicationIsActive() && !am::LibraryAppletIsActive()) { if(!am::ApplicationIsActive() && !am::LibraryAppletIsActive()) {
@ -520,10 +526,14 @@ namespace {
fs::CreateDirectory(UL_BASE_SD_DIR "/nro"); fs::CreateDirectory(UL_BASE_SD_DIR "/nro");
fs::CreateDirectory(UL_BASE_SD_DIR "/lang"); fs::CreateDirectory(UL_BASE_SD_DIR "/lang");
g_Config = cfg::EnsureConfig(); g_Config = cfg::LoadConfig();
am::LibraryAppletSetMenuAppletId(am::LibraryAppletGetAppletIdForProgramId(g_Config.menu_program_id)); u64 menu_program_id;
UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::MenuTakeoverProgramId, menu_program_id));
am::LibraryAppletSetMenuAppletId(am::LibraryAppletGetAppletIdForProgramId(menu_program_id));
if(g_Config.viewer_usb_enabled) { bool viewer_usb_enabled;
UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::ViewerUsbEnabled, viewer_usb_enabled));
if(viewer_usb_enabled) {
UL_ASSERT(usbCommsInitialize()); UL_ASSERT(usbCommsInitialize());
UL_ASSERT(capsscInitialize()); UL_ASSERT(capsscInitialize());
@ -535,7 +545,9 @@ namespace {
} }
void Exit() { void Exit() {
if(g_Config.viewer_usb_enabled) { bool viewer_usb_enabled;
UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::ViewerUsbEnabled, viewer_usb_enabled));
if(viewer_usb_enabled) {
usbCommsExit(); usbCommsExit();
if(g_UsbViewerMode == UsbMode::JPEG) { if(g_UsbViewerMode == UsbMode::JPEG) {
capsscExit(); capsscExit();

View file

@ -63,32 +63,236 @@ namespace cfg {
std::string icon_path; std::string icon_path;
}; };
// Take over eShop by default enum class ConfigEntryId : u8 {
static constexpr u64 DefaultMenuProgramId = 0x010000000000100B; MenuTakeoverProgramId,
HomebrewAppletTakeoverProgramId,
HomebrewApplicationTakeoverApplicationId,
ViewerUsbEnabled,
ActiveThemeName
};
// Take over parental controls applet by default enum class ConfigEntryType : u8 {
static constexpr u64 DefaultHomebrewAppletProgramId = 0x0100000000001001; Bool,
U64,
String
};
struct ConfigEntryHeader {
ConfigEntryId id;
ConfigEntryType type;
u8 size;
u8 pad;
};
struct ConfigEntry {
ConfigEntryHeader header;
bool bool_value;
u64 u64_value;
std::string str_value;
template<typename T>
bool Get(T &out_t) const {
switch(this->header.type) {
case ConfigEntryType::Bool: {
if constexpr(std::is_same_v<T, bool>) {
out_t = this->bool_value;
return true;
}
else {
return false;
}
}
case ConfigEntryType::U64: {
if constexpr(std::is_same_v<T, u64>) {
out_t = this->u64_value;
return true;
}
else {
return false;
}
}
case ConfigEntryType::String: {
if constexpr(std::is_same_v<T, std::string>) {
out_t = this->str_value;
return true;
}
else {
return false;
}
}
}
return false;
}
template<typename T>
bool Set(const T &t) {
switch(this->header.type) {
case ConfigEntryType::Bool: {
if constexpr(std::is_same_v<T, bool>) {
this->bool_value = t;
return true;
}
else {
return false;
}
}
case ConfigEntryType::U64: {
if constexpr(std::is_same_v<T, u64>) {
this->u64_value = t;
return true;
}
else {
return false;
}
}
case ConfigEntryType::String: {
if constexpr(std::is_same_v<T, std::string>) {
this->str_value = t;
this->header.size = this->str_value.length();
return true;
}
else {
return false;
}
}
}
return false;
}
};
struct ConfigHeader {
u32 magic;
u32 entry_count;
static constexpr u32 Magic = 0x47464355; // "UCFG"
};
struct Config { struct Config {
std::string theme_name; std::vector<ConfigEntry> entries;
bool system_title_override_enabled;
bool viewer_usb_enabled;
u64 menu_program_id;
u64 homebrew_applet_program_id;
u64 homebrew_title_application_id;
JSON main_lang;
JSON default_lang;
Config() : system_title_override_enabled(false), viewer_usb_enabled(false), menu_program_id(DefaultMenuProgramId), homebrew_applet_program_id(DefaultHomebrewAppletProgramId), homebrew_title_application_id(0) {}
template<typename T>
bool SetEntry(const ConfigEntryId id, const T &t) {
for(auto &entry : this->entries) {
if(entry.header.id == id) {
return entry.Set(t);
}
}
// Create new entry
ConfigEntry new_entry = {
.header = {
.id = id
}
};
switch(id) {
case ConfigEntryId::MenuTakeoverProgramId:
case ConfigEntryId::HomebrewAppletTakeoverProgramId:
case ConfigEntryId::HomebrewApplicationTakeoverApplicationId: {
if constexpr(std::is_same_v<T, u64>) {
new_entry.header.type = ConfigEntryType::U64;
new_entry.header.size = sizeof(t);
new_entry.u64_value = t;
break;
}
else {
return false;
}
}
case ConfigEntryId::ViewerUsbEnabled: {
if constexpr(std::is_same_v<T, bool>) {
new_entry.header.type = ConfigEntryType::Bool;
new_entry.header.size = sizeof(t);
new_entry.bool_value = t;
break;
}
else {
return false;
}
}
case ConfigEntryId::ActiveThemeName: {
if constexpr(std::is_same_v<T, std::string>) {
new_entry.header.type = ConfigEntryType::String;
new_entry.header.size = t.length();
new_entry.str_value = t;
break;
}
else {
return false;
}
}
}
this->entries.push_back(std::move(new_entry));
return true;
}
template<typename T>
bool GetEntry(const ConfigEntryId id, T &out_t) const {
for(const auto &entry : this->entries) {
if(entry.header.id == id) {
return entry.Get(out_t);
}
}
// Default values
switch(id) {
case ConfigEntryId::MenuTakeoverProgramId: {
if constexpr(std::is_same_v<T, u64>) {
// Take over eShop by default
out_t = 0x010000000000100B;
return true;
}
else {
return false;
}
}
case ConfigEntryId::HomebrewAppletTakeoverProgramId: {
if constexpr(std::is_same_v<T, u64>) {
// Take over parental control applet by default
out_t = 0x0100000000001001;
return true;
}
else {
return false;
}
}
case ConfigEntryId::HomebrewApplicationTakeoverApplicationId: {
if constexpr(std::is_same_v<T, u64>) {
// No donor title by default
out_t = 0;
return true;
}
else {
return false;
}
}
case ConfigEntryId::ViewerUsbEnabled: {
if constexpr(std::is_same_v<T, bool>) {
// Disabled by default, it might interfer with other homebrews
out_t = false;
return true;
}
else {
return false;
}
}
case ConfigEntryId::ActiveThemeName: {
if constexpr(std::is_same_v<T, std::string>) {
// Empty by default
out_t = "";
return true;
}
else {
return false;
}
}
}
return false;
}
}; };
static constexpr u32 CurrentThemeFormatVersion = 1; static constexpr u32 CurrentThemeFormatVersion = 1;
#define CFG_THEME_DEFAULT "romfs:/default" #define CFG_THEME_DEFAULT "romfs:/default"
#define CFG_LANG_DEFAULT "romfs:/LangDefault.json" #define CFG_LANG_DEFAULT "romfs:/LangDefault.json"
#define CFG_CONFIG_JSON UL_BASE_SD_DIR "/config.json" #define CFG_CONFIG_FILE UL_BASE_SD_DIR "/config.cfg"
TitleList LoadTitleList(); TitleList LoadTitleList();
std::vector<TitleRecord> QueryAllHomebrew(const std::string &base = "sdmc:/switch"); std::vector<TitleRecord> QueryAllHomebrew(const std::string &base = "sdmc:/switch");
@ -112,15 +316,6 @@ namespace cfg {
Config CreateNewAndLoadConfig(); Config CreateNewAndLoadConfig();
Config LoadConfig(); Config LoadConfig();
inline Config EnsureConfig() {
if(fs::ExistsFile(CFG_CONFIG_JSON)) {
return LoadConfig();
}
else {
return CreateNewAndLoadConfig();
}
}
void SaveConfig(const Config &cfg); void SaveConfig(const Config &cfg);

View file

@ -45,7 +45,7 @@ namespace fs {
remove(path.c_str()); remove(path.c_str());
} }
inline bool WriteFile(const std::string &path, void *data, size_t size, bool overwrite) { inline bool WriteFile(const std::string &path, const void *data, size_t size, bool overwrite) {
auto f = fopen(path.c_str(), overwrite ? "wb" : "ab+"); auto f = fopen(path.c_str(), overwrite ? "wb" : "ab+");
if(f) { if(f) {
fwrite(data, 1, size, f); fwrite(data, 1, size, f);

View file

@ -22,6 +22,8 @@ namespace os {
} \ } \
}) })
constexpr u32 MaxTitleCount = 64000;
std::vector<cfg::TitleRecord> QueryInstalledTitles(); std::vector<cfg::TitleRecord> QueryInstalledTitles();
} }

View file

@ -29,7 +29,7 @@ using JSON = nlohmann::json;
#define UL_THEMES_PATH UL_BASE_SD_DIR "/themes" #define UL_THEMES_PATH UL_BASE_SD_DIR "/themes"
#ifndef UL_VERSION #ifndef UL_VERSION
#error uLaunch's release version isn't defined. #error uLaunch's build version isn't defined
#endif #endif
#include <ul_Scope.hpp> #include <ul_Scope.hpp>
@ -47,20 +47,19 @@ static constexpr size_t RawRGBAScreenBufferSize = 1280 * 720 * 4;
#endif #endif
#define STL_FIND_IF(stl_item, var_name, cond) std::find_if(stl_item.begin(), stl_item.end(), [&](const auto &var_name){ return (cond); }); #define STL_FIND_IF(stl_item, var_name, cond) std::find_if(stl_item.begin(), stl_item.end(), [&](const auto &var_name){ return (cond); })
#define STL_FOUND(stl_item, find_ret) (find_ret != stl_item.end()) #define STL_FOUND(stl_item, find_ret) (find_ret != stl_item.end())
#define STL_UNWRAP(find_ret) (*find_ret) #define STL_UNWRAP(find_ret) (*find_ret)
#define STL_REMOVE_IF(stl_item, var_name, cond) stl_item.erase(std::remove_if(stl_item.begin(), stl_item.end(), [&](const auto &var_name){ return (cond); }), stl_item.end()); #define STL_REMOVE_IF(stl_item, var_name, cond) stl_item.erase(std::remove_if(stl_item.begin(), stl_item.end(), [&](const auto &var_name){ return (cond); }), stl_item.end())
static constexpr Result ResultSuccess = 0; constexpr Result ResultSuccess = 0;
constexpr Mutex EmptyMutex = {};
static constexpr Mutex EmptyMutex = (Mutex)0;
#include <ul_Results.hpp> #include <ul_Results.hpp>
#define UL_ASSERTION_LOG_FILE UL_BASE_SD_DIR "/err.log" #define UL_ASSERTION_LOG_FILE UL_BASE_SD_DIR "/err.log"
inline __attribute__((noreturn)) void OnAssertionFailed(const char *log_buf, size_t log_buf_len, const Result rc) { inline void NORETURN OnAssertionFailed(const char *log_buf, size_t log_buf_len, const Result rc) {
auto log_f = fopen(UL_ASSERTION_LOG_FILE, "wb"); \ auto log_f = fopen(UL_ASSERTION_LOG_FILE, "wb"); \
if(log_f) { if(log_f) {
fwrite(log_buf, 1, log_buf_len, log_f); fwrite(log_buf, 1, log_buf_len, log_f);
@ -70,15 +69,23 @@ inline __attribute__((noreturn)) void OnAssertionFailed(const char *log_buf, siz
fatalThrow(rc); fatalThrow(rc);
} }
// TODO: Is this a good size?
#define UL_ASSERT_LOG_LEN 0x400 #define UL_ASSERT_LOG_LEN 0x400
#define UL_ASSERT(expr) ({ \ #define UL_ASSERT(expr) ({ \
const auto _tmp_rc = (expr); \ const auto _tmp_rc = (expr); \
if(R_FAILED(_tmp_rc)) { \ if(R_FAILED(_tmp_rc)) { \
char log_buf[UL_ASSERT_LOG_LEN] = {}; \
const auto log_buf_len = std::sprintf(log_buf, "%s asserted 0x%X...", #expr, _tmp_rc); \
OnAssertionFailed(log_buf, log_buf_len, _tmp_rc); \
} \
})
#define UL_ASSERT_TRUE(expr) ({ \
const auto _tmp_expr = (expr); \
if(!_tmp_expr) { \
char logbuf[UL_ASSERT_LOG_LEN] = {}; \ char logbuf[UL_ASSERT_LOG_LEN] = {}; \
sprintf(logbuf, "%s asserted 0x%X...", #expr, _tmp_rc); \ const auto log_buf_len = sprintf(logbuf, "%s failed...", #expr); \
OnAssertionFailed(logbuf, UL_ASSERT_LOG_LEN, _tmp_rc); \ OnAssertionFailed(logbuf, log_buf_len, 0xDEAD); \
} \ } \
}) })

View file

@ -6,70 +6,77 @@
namespace cfg { namespace cfg {
static void CacheHomebrew(const std::string &nro_path) { namespace {
auto nroimg = GetNROCacheIconPath(nro_path);
auto f = fopen(nro_path.c_str(), "rb"); void CacheHomebrew(const std::string &nro_path) {
if(f) { auto nroimg = GetNROCacheIconPath(nro_path);
fseek(f, sizeof(NroStart), SEEK_SET); auto f = fopen(nro_path.c_str(), "rb");
NroHeader hdr = {}; if(f) {
if(fread(&hdr, sizeof(NroHeader), 1, f) == 1) { fseek(f, sizeof(NroStart), SEEK_SET);
fseek(f, hdr.size, SEEK_SET); NroHeader hdr = {};
NroAssetHeader ahdr = {}; if(fread(&hdr, sizeof(hdr), 1, f) == 1) {
if(fread(&ahdr, sizeof(NroAssetHeader), 1, f) == 1) { fseek(f, hdr.size, SEEK_SET);
if(ahdr.magic == NROASSETHEADER_MAGIC) { NroAssetHeader ahdr = {};
if((ahdr.icon.offset > 0) && (ahdr.icon.size > 0)) { if(fread(&ahdr, sizeof(ahdr), 1, f) == 1) {
auto iconbuf = new u8[ahdr.icon.size](); if(ahdr.magic == NROASSETHEADER_MAGIC) {
fseek(f, hdr.size + ahdr.icon.offset, SEEK_SET); if((ahdr.icon.offset > 0) && (ahdr.icon.size > 0)) {
fread(iconbuf, ahdr.icon.size, 1, f); auto iconbuf = new u8[ahdr.icon.size]();
fs::WriteFile(nroimg, iconbuf, ahdr.icon.size, true); fseek(f, hdr.size + ahdr.icon.offset, SEEK_SET);
delete[] iconbuf; fread(iconbuf, ahdr.icon.size, 1, f);
fs::WriteFile(nroimg, iconbuf, ahdr.icon.size, true);
delete[] iconbuf;
}
} }
} }
} }
fclose(f);
} }
fclose(f);
} }
}
static void CacheInstalledTitles() { void CacheInstalledTitles() {
UL_OS_FOR_EACH_APP_RECORD(rec, { UL_OS_FOR_EACH_APP_RECORD(rec, {
NsApplicationControlData control = {};
rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, rec.application_id, &control, sizeof(control), nullptr);
if(R_SUCCEEDED(rc)) {
auto fname = cfg::GetTitleCacheIconPath(rec.application_id); auto fname = cfg::GetTitleCacheIconPath(rec.application_id);
fs::WriteFile(fname, control.icon, sizeof(control.icon), true); if(!fs::ExistsFile(fname)) {
} NsApplicationControlData control = {};
}); rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, rec.application_id, &control, sizeof(control), nullptr);
} if(R_SUCCEEDED(rc)) {
auto fname = cfg::GetTitleCacheIconPath(rec.application_id);
static void CacheAllHomebrew(const std::string &hb_base_path) { fs::WriteFile(fname, control.icon, sizeof(control.icon), true);
UL_FS_FOR(hb_base_path, name, path, { }
if(dt->d_type & DT_DIR) {
CacheAllHomebrew(path);
}
else if(util::StringEndsWith(name, ".nro")) {
CacheHomebrew(path);
}
});
}
static void ProcessStringsFromNACP(RecordStrings &strs, NacpStruct *nacp) {
NacpLanguageEntry *lent = nullptr;
nacpGetLanguageEntry(nacp, &lent);
if(lent == nullptr) {
for(u32 i = 0; i < 16; i++) {
lent = &nacp->lang[i];
if((strlen(lent->name) > 0) && (strlen(lent->author) > 0)) {
break;
} }
lent = nullptr; });
}
void CacheAllHomebrew(const std::string &hb_base_path) {
UL_FS_FOR(hb_base_path, name, path, {
if(dt->d_type & DT_DIR) {
CacheAllHomebrew(path);
}
else if(util::StringEndsWith(name, ".nro")) {
CacheHomebrew(path);
}
});
}
void ProcessStringsFromNACP(RecordStrings &strs, NacpStruct *nacp) {
NacpLanguageEntry *lent = nullptr;
nacpGetLanguageEntry(nacp, &lent);
if(lent == nullptr) {
for(u32 i = 0; i < 16; i++) {
lent = &nacp->lang[i];
if((strlen(lent->name) > 0) && (strlen(lent->author) > 0)) {
break;
}
lent = nullptr;
}
}
if(lent != nullptr) {
strs.name = lent->name;
strs.author = lent->author;
strs.version = nacp->display_version;
} }
} }
if(lent != nullptr) {
strs.name = lent->name;
strs.author = lent->author;
strs.version = nacp->display_version;
}
} }
std::vector<TitleRecord> QueryAllHomebrew(const std::string &base) { std::vector<TitleRecord> QueryAllHomebrew(const std::string &base) {
@ -210,55 +217,94 @@ namespace cfg {
} }
Config CreateNewAndLoadConfig() { Config CreateNewAndLoadConfig() {
// Default constructor sets everything const Config empty_cfg = {};
Config cfg = {}; SaveConfig(empty_cfg);
SaveConfig(cfg); return empty_cfg;
return cfg;
} }
Config LoadConfig() { Config LoadConfig() {
// Default constructor sets everything
Config cfg = {}; Config cfg = {};
JSON cfgjson; const auto cfg_file_size = fs::GetFileSize(CFG_CONFIG_FILE);
auto rc = util::LoadJSONFromFile(cfgjson, CFG_CONFIG_JSON); auto cfg_file_buf = new u8[cfg_file_size]();
if(R_SUCCEEDED(rc)) { if(fs::ReadFile(CFG_CONFIG_FILE, cfg_file_buf, cfg_file_size)) {
cfg.theme_name = cfgjson.value("theme_name", ""); size_t cur_offset = 0;
cfg.system_title_override_enabled = cfgjson.value("system_title_override_enabled", false); const auto cfg_header = *reinterpret_cast<ConfigHeader*>(cfg_file_buf);
cfg.viewer_usb_enabled = cfgjson.value("viewer_usb_enabled", false); if(cfg_header.magic == ConfigHeader::Magic) {
auto menu_id_str = cfgjson.value("menu_program_id", ""); cur_offset += sizeof(ConfigHeader);
if(!menu_id_str.empty()) { if(cur_offset <= cfg_file_size) {
cfg.menu_program_id = util::Get64FromString(menu_id_str); cfg.entries.reserve(cfg_header.entry_count);
for(u32 i = 0; i < cfg_header.entry_count; i++) {
ConfigEntry ent = {};
ent.header = *reinterpret_cast<ConfigEntryHeader*>(cfg_file_buf + cur_offset);
cur_offset += sizeof(ConfigEntryHeader);
if(cur_offset > cfg_file_size) {
break;
}
switch(ent.header.type) {
case ConfigEntryType::Bool: {
if(ent.header.size != sizeof(bool)) {
return CreateNewAndLoadConfig();
}
ent.bool_value = *reinterpret_cast<bool*>(cfg_file_buf + cur_offset);
break;
}
case ConfigEntryType::U64: {
if(ent.header.size != sizeof(u64)) {
return CreateNewAndLoadConfig();
}
ent.u64_value = *reinterpret_cast<u64*>(cfg_file_buf + cur_offset);
break;
}
case ConfigEntryType::String: {
if(ent.header.size == 0) {
ent.str_value = "";
}
else {
ent.str_value = std::string(reinterpret_cast<char*>(cfg_file_buf + cur_offset), ent.header.size);
}
break;
}
}
cur_offset += ent.header.size;
if(cur_offset > cfg_file_size) {
break;
}
cfg.entries.push_back(std::move(ent));
}
if(cur_offset <= cfg_file_size) {
return cfg;
}
}
} }
auto hb_applet_id_str = cfgjson.value("homebrew_applet_program_id", "");
if(!hb_applet_id_str.empty()) {
cfg.homebrew_applet_program_id = util::Get64FromString(hb_applet_id_str);
}
auto hb_title_id_str = cfgjson.value("homebrew_title_application_id", "");
if(!hb_title_id_str.empty()) {
cfg.homebrew_title_application_id = util::Get64FromString(hb_title_id_str);
}
// Doing this saves any fields not set previously
SaveConfig(cfg);
return cfg;
} }
fs::DeleteFile(CFG_CONFIG_JSON); std::string fail = "Bad load 4";
OnAssertionFailed(fail.c_str(), fail.length(), 0xbabe);
return CreateNewAndLoadConfig(); return CreateNewAndLoadConfig();
} }
void SaveConfig(const Config &cfg) { void SaveConfig(const Config &cfg) {
fs::DeleteFile(CFG_CONFIG_JSON); const ConfigHeader cfg_header = {
.magic = ConfigHeader::Magic,
auto json = JSON::object(); .entry_count = static_cast<u32>(cfg.entries.size())
json["theme_name"] = cfg.theme_name; };
json["viewer_usb_enabled"] = cfg.viewer_usb_enabled; fs::WriteFile(CFG_CONFIG_FILE, &cfg_header, sizeof(cfg_header), true);
json["system_title_override_enabled"] = cfg.system_title_override_enabled; for(const auto &entry : cfg.entries) {
json["menu_program_id"] = util::FormatApplicationId(cfg.menu_program_id); fs::WriteFile(CFG_CONFIG_FILE, &entry.header, sizeof(entry.header), false);
json["homebrew_applet_program_id"] = util::FormatApplicationId(cfg.homebrew_applet_program_id); switch(entry.header.type) {
json["homebrew_title_application_id"] = util::FormatApplicationId(cfg.homebrew_title_application_id); case ConfigEntryType::Bool: {
fs::WriteFile(CFG_CONFIG_FILE, &entry.bool_value, sizeof(entry.bool_value), false);
std::ofstream ofs(CFG_CONFIG_JSON); break;
ofs << std::setw(4) << json; }
ofs.close(); case ConfigEntryType::U64: {
fs::WriteFile(CFG_CONFIG_FILE, &entry.u64_value, sizeof(entry.u64_value), false);
break;
}
case ConfigEntryType::String: {
fs::WriteFile(CFG_CONFIG_FILE, entry.str_value.c_str(), entry.str_value.length(), false);
break;
}
}
}
} }
void SaveRecord(TitleRecord &record) { void SaveRecord(TitleRecord &record) {

View file

@ -4,15 +4,21 @@ namespace os {
std::vector<cfg::TitleRecord> QueryInstalledTitles() { std::vector<cfg::TitleRecord> QueryInstalledTitles() {
std::vector<cfg::TitleRecord> titles; std::vector<cfg::TitleRecord> titles;
UL_OS_FOR_EACH_APP_RECORD(record, { auto records_buf = new NsApplicationRecord[MaxTitleCount]();
cfg::TitleRecord rec = {}; s32 record_count;
rec.app_id = record.application_id; UL_ASSERT(nsListApplicationRecord(records_buf, MaxTitleCount, 0, &record_count));
if(rec.app_id == 0) { for(s32 i = 0; i < record_count; i++) {
const auto &record = records_buf[i];
if(record.application_id == 0) {
continue; continue;
} }
rec.title_type = static_cast<u32>(cfg::TitleType::Installed); const cfg::TitleRecord rec = {
titles.push_back(rec); .title_type = static_cast<u32>(cfg::TitleType::Installed),
}); .app_id = record.application_id,
};
titles.push_back(std::move(rec));
}
delete[] records_buf;
return titles; return titles;
} }

View file

@ -9,6 +9,8 @@
namespace ui { namespace ui {
std::string GetLanguageString(const std::string &name);
enum class MenuType { enum class MenuType {
Startup, Startup,
Main, Main,

View file

@ -35,6 +35,7 @@ namespace ui {
pu::ui::elm::TextBlock::Ref itemAuthor; pu::ui::elm::TextBlock::Ref itemAuthor;
pu::ui::elm::TextBlock::Ref itemVersion; pu::ui::elm::TextBlock::Ref itemVersion;
pu::ui::elm::Image::Ref bannerImage; pu::ui::elm::Image::Ref bannerImage;
pu::ui::elm::Image::Ref guideButtons;
ClickableImage::Ref menuToggle; ClickableImage::Ref menuToggle;
QuickMenu::Ref quickMenu; QuickMenu::Ref quickMenu;
std::string curfolder; std::string curfolder;

View file

@ -3,7 +3,6 @@
"no": "No", "no": "No",
"ok": "Ok", "ok": "Ok",
"cancel": "Cancel", "cancel": "Cancel",
"menu_quick_info": "Tip: to open the quick menu, hold a stick (L or R-stick) and release it after selecting an option by moving it (while being held)",
"menu_multiselect": "Multiselect", "menu_multiselect": "Multiselect",
"menu_multiselect_cancel": "Multiselect was cancelled.", "menu_multiselect_cancel": "Multiselect was cancelled.",
"menu_rename_folder": "Rename folder", "menu_rename_folder": "Rename folder",
@ -102,7 +101,6 @@
"set_viewer_info": "You must enable this if you want to use the PC screen viewer (uViewer). It is not necessary otherwise.", "set_viewer_info": "You must enable this if you want to use the PC screen viewer (uViewer). It is not necessary otherwise.",
"set_flog_info": "This must be enabled to be able to launch homebrew directly as applications. Note that this might involve BAN RISK.", "set_flog_info": "This must be enabled to be able to launch homebrew directly as applications. Note that this might involve BAN RISK.",
"startup_welcome_info": "Welcome! Please select an account to use.", "startup_welcome_info": "Welcome! Please select an account to use.",
"startup_control_info": "Hold the L / R-stick or Z / R / ZL / ZR in order to open menus easily from main menu.",
"startup_login_error": "Invalid password. Please try again.", "startup_login_error": "Invalid password. Please try again.",
"startup_password": "(password)", "startup_password": "(password)",
"startup_new_user": "Create new user", "startup_new_user": "Create new user",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 858 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 951 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -1,7 +1,7 @@
{ {
"suspended_final_alpha": 80, "suspended_final_alpha": 80,
"menu_focus_color": "#5ebcffff", "menu_focus_color": "#864ea0ff",
"menu_bg_color": "#0094ffff", "menu_bg_color": "#57007fff",
"menu_folder_text_x": 30, "menu_folder_text_x": 30,
"menu_folder_text_y": 200, "menu_folder_text_y": 200,
"menu_folder_text_size": 25 "menu_folder_text_size": 25

View file

@ -3,7 +3,6 @@
"no": "いいえ", "no": "いいえ",
"ok": "Ok", "ok": "Ok",
"cancel": "キャンセル", "cancel": "キャンセル",
"menu_quick_info": "ヒントクイックメニューを開くには、スティックLスティックまたはRスティックを押したまま、オプションを選択した後、押しながら動かして離します",
"menu_multiselect": "複数選択", "menu_multiselect": "複数選択",
"menu_multiselect_cancel": "選択を解除しました。", "menu_multiselect_cancel": "選択を解除しました。",
"menu_rename_folder": "フォルダ-の名前を変更する", "menu_rename_folder": "フォルダ-の名前を変更する",
@ -97,7 +96,6 @@
"set_viewer_info": "画面をQForegroundViewerPcTOOLにストリーミングするには、このオプションを有効にする必要があります。\n使用しない場合は無効のままにしてください。", "set_viewer_info": "画面をQForegroundViewerPcTOOLにストリーミングするには、このオプションを有効にする必要があります。\n使用しない場合は無効のままにしてください。",
"set_flog_info": "uLaunchは自作ソフトをアプリとして起動することができるようになります。\nこのオプションはBANのリスクがあるため、デフォルトでは無効化されています。", "set_flog_info": "uLaunchは自作ソフトをアプリとして起動することができるようになります。\nこのオプションはBANのリスクがあるため、デフォルトでは無効化されています。",
"startup_welcome_info": "ようこそ!使用するアカウントを選択してください。", "startup_welcome_info": "ようこそ!使用するアカウントを選択してください。",
"startup_control_info": "メインメニューからメニューを簡単に開くには、LまたはRスティックを押したままにします。",
"startup_login_error": "パスワードが違います。もう一度入力してください。", "startup_login_error": "パスワードが違います。もう一度入力してください。",
"startup_password": "(パスワード)", "startup_password": "(パスワード)",
"startup_new_user": "新しいアカウントを作成", "startup_new_user": "新しいアカウントを作成",

View file

@ -28,11 +28,16 @@ extern "C" {
#define UL_MENU_ROMFS_BIN UL_BASE_SD_DIR "/bin/uMenu/romfs.bin" #define UL_MENU_ROMFS_BIN UL_BASE_SD_DIR "/bin/uMenu/romfs.bin"
ui::MenuApplication::Ref g_MenuApplication; ui::MenuApplication::Ref g_MenuApplication;
u8 *g_ScreenCaptureBuffer;
cfg::TitleList g_EntryList; cfg::TitleList g_EntryList;
std::vector<cfg::TitleRecord> g_HomebrewRecordList; std::vector<cfg::TitleRecord> g_HomebrewRecordList;
cfg::Config g_Config; cfg::Config g_Config;
cfg::Theme g_Theme; cfg::Theme g_Theme;
u8 *g_ScreenCaptureBuffer;
JSON g_DefaultLanguage;
JSON g_MainLanguage;
namespace { namespace {
@ -48,8 +53,10 @@ namespace {
UL_ASSERT(am::InitializeDaemonMessageHandler()); UL_ASSERT(am::InitializeDaemonMessageHandler());
// Load menu config and theme // Load menu config and theme
g_Config = cfg::EnsureConfig(); g_Config = cfg::LoadConfig();
g_Theme = cfg::LoadTheme(g_Config.theme_name); std::string theme_name;
UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::ActiveThemeName, theme_name));
g_Theme = cfg::LoadTheme(theme_name);
} }
void Exit() { void Exit() {
@ -67,74 +74,72 @@ namespace {
// uMenu procedure: read sent storages, initialize RomFs (in a special way), load config and other stuff, finally create the renderer and start the UI // uMenu procedure: read sent storages, initialize RomFs (in a special way), load config and other stuff, finally create the renderer and start the UI
int main() { int main() {
auto smode = dmi::MenuStartMode::Invalid; auto start_mode = dmi::MenuStartMode::Invalid;
UL_ASSERT(am::ReadStartMode(smode)); UL_ASSERT(am::ReadStartMode(start_mode));
UL_ASSERT_TRUE(start_mode != dmi::MenuStartMode::Invalid);
// Information sent as an extra storage to uMenu // Information sent as an extra storage to uMenu
dmi::DaemonStatus status = {}; dmi::DaemonStatus status = {};
UL_ASSERT(am::ReadDataFromStorage(&status, sizeof(status))); UL_ASSERT(am::ReadDataFromStorage(&status, sizeof(status)));
// TODO: better way to handle an invalid mode? maybe directly call UL_ASSERT? // Check if our RomFs data exists...
if(smode != dmi::MenuStartMode::Invalid) { if(!fs::ExistsFile(UL_MENU_ROMFS_BIN)) {
// Check if our RomFs data exists... UL_ASSERT(RES_VALUE(Menu, RomfsBinNotFound));
if(!fs::ExistsFile(UL_MENU_ROMFS_BIN)) {
UL_ASSERT(RES_VALUE(Menu, RomfsBinNotFound));
}
// Try to mount it
UL_ASSERT(romfsMountFromFsdev(UL_MENU_ROMFS_BIN, 0, "romfs"));
// After initializing RomFs, start initializing the rest of stuff here
g_ScreenCaptureBuffer = new u8[RawRGBAScreenBufferSize]();
Initialize();
// Cache title and homebrew icons
cfg::CacheEverything();
g_EntryList = cfg::LoadTitleList();
// Get system language and load translations (default one if not present)
u64 lcode = 0;
setGetLanguageCode(&lcode);
std::string syslang = reinterpret_cast<char*>(&lcode);
auto lpath = cfg::GetLanguageJSONPath(syslang);
UL_ASSERT(util::LoadJSONFromFile(g_Config.default_lang, CFG_LANG_DEFAULT));
g_Config.main_lang = g_Config.default_lang;
if(fs::ExistsFile(lpath)) {
auto ljson = JSON::object();
UL_ASSERT(util::LoadJSONFromFile(ljson, lpath));
g_Config.main_lang = ljson;
}
// Get the text sizes to initialize default fonts
auto uijson = JSON::object();
UL_ASSERT(util::LoadJSONFromFile(uijson, cfg::GetAssetByTheme(g_Theme, "ui/UI.json")));
auto menu_folder_txt_sz = uijson.value<u32>("menu_folder_text_size", 25);
auto renderer = pu::ui::render::Renderer::New(pu::ui::render::RendererInitOptions(SDL_INIT_EVERYTHING, pu::ui::render::RendererHardwareFlags).WithIMG(pu::ui::render::IMGAllFlags).WithMixer(pu::ui::render::MixerAllFlags).WithTTF().WithDefaultFontSize(menu_folder_txt_sz));
g_MenuApplication = ui::MenuApplication::New(renderer);
g_MenuApplication->SetInformation(smode, status, uijson);
g_MenuApplication->Prepare();
// Register handlers for HOME button press detection
am::RegisterLibAppletHomeButtonDetection();
ui::MenuApplication::RegisterHomeButtonDetection();
ui::QuickMenu::RegisterHomeButtonDetection();
if(smode == dmi::MenuStartMode::MenuApplicationSuspended) {
g_MenuApplication->Show();
}
else {
g_MenuApplication->ShowWithFadeIn();
}
// Exit RomFs manually, since we also initialized it manually
romfsExit();
delete[] g_ScreenCaptureBuffer;
Exit();
} }
// Try to mount it
UL_ASSERT(romfsMountFromFsdev(UL_MENU_ROMFS_BIN, 0, "romfs"));
// After initializing RomFs, start initializing the rest of stuff here
g_ScreenCaptureBuffer = new u8[RawRGBAScreenBufferSize]();
Initialize();
// Cache title and homebrew icons
cfg::CacheEverything();
g_EntryList = cfg::LoadTitleList();
// Get system language and load translations (default one if not present)
u64 lang_code = 0;
UL_ASSERT(setGetLanguageCode(&lang_code));
std::string sys_lang = reinterpret_cast<char*>(&lang_code);
auto lang_path = cfg::GetLanguageJSONPath(sys_lang);
UL_ASSERT(util::LoadJSONFromFile(g_DefaultLanguage, CFG_LANG_DEFAULT));
g_MainLanguage = g_DefaultLanguage;
if(fs::ExistsFile(lang_path)) {
auto lang_json = JSON::object();
UL_ASSERT(util::LoadJSONFromFile(lang_json, lang_path));
g_MainLanguage = lang_json;
}
// Get the text sizes to initialize default fonts
auto uijson = JSON::object();
UL_ASSERT(util::LoadJSONFromFile(uijson, cfg::GetAssetByTheme(g_Theme, "ui/UI.json")));
const auto menu_folder_txt_sz = uijson.value<u32>("menu_folder_text_size", 25);
const auto default_font_path = cfg::GetAssetByTheme(g_Theme, "ui/Font.ttf");
auto renderer = pu::ui::render::Renderer::New(pu::ui::render::RendererInitOptions(SDL_INIT_EVERYTHING, pu::ui::render::RendererHardwareFlags).WithIMG(pu::ui::render::IMGAllFlags).WithMixer(pu::ui::render::MixerAllFlags).WithTTF(default_font_path).WithDefaultFontSize(menu_folder_txt_sz));
g_MenuApplication = ui::MenuApplication::New(renderer);
g_MenuApplication->SetInformation(start_mode, status, uijson);
g_MenuApplication->Prepare();
// Register handlers for HOME button press detection
am::RegisterLibAppletHomeButtonDetection();
ui::MenuApplication::RegisterHomeButtonDetection();
ui::QuickMenu::RegisterHomeButtonDetection();
if(start_mode == dmi::MenuStartMode::MenuApplicationSuspended) {
g_MenuApplication->Show();
}
else {
g_MenuApplication->ShowWithFadeIn();
}
// Exit RomFs manually, since we also initialized it manually
romfsExit();
delete[] g_ScreenCaptureBuffer;
Exit();
return 0; return 0;
} }

View file

@ -13,12 +13,13 @@
#include <net/net_Service.hpp> #include <net/net_Service.hpp>
extern ui::MenuApplication::Ref g_MenuApplication; extern ui::MenuApplication::Ref g_MenuApplication;
extern cfg::Config g_Config; extern cfg::Config g_Config;
namespace ui::actions { namespace ui::actions {
void ShowAboutDialog() { void ShowAboutDialog() {
g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "ulaunch_about"), "uLaunch v" + std::string(UL_VERSION) + "\n\n" + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "ulaunch_desc") + ":\nhttps://github.com/XorTroll/uLaunch", { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "ok") }, true, "romfs:/LogoLarge.png"); g_MenuApplication->CreateShowDialog(GetLanguageString("ulaunch_about"), "uLaunch v" + std::string(UL_VERSION) + "\n\n" + GetLanguageString("ulaunch_desc") + ":\nhttps://github.com/XorTroll/uLaunch", { GetLanguageString("ok") }, true, "romfs:/LogoLarge.png");
} }
void ShowSettingsMenu() { void ShowSettingsMenu() {
@ -37,14 +38,14 @@ namespace ui::actions {
auto uid = g_MenuApplication->GetSelectedUser(); auto uid = g_MenuApplication->GetSelectedUser();
std::string name; std::string name;
os::GetAccountName(name, uid); os::GetAccountName(name, uid);
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "user_settings"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "user_selected") + ": " + name + "\n" + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "user_option"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "user_view_page"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "user_logoff"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true, os::GetIconCacheImagePath(uid)); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("user_settings"), GetLanguageString("user_selected") + ": " + name + "\n" + GetLanguageString("user_option"), { GetLanguageString("user_view_page"), GetLanguageString("user_logoff"), GetLanguageString("cancel") }, true, os::GetIconCacheImagePath(uid));
if(sopt == 0) { if(sopt == 0) {
friendsLaShowMyProfileForHomeMenu(uid); friendsLaShowMyProfileForHomeMenu(uid);
} }
else if(sopt == 1) { else if(sopt == 1) {
u32 logoff = 0; u32 logoff = 0;
if(g_MenuApplication->IsSuspended()) { if(g_MenuApplication->IsSuspended()) {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "suspended_app"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "user_logoff_app_suspended"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("suspended_app"), GetLanguageString("user_logoff_app_suspended"), { GetLanguageString("yes"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
logoff = 2; logoff = 2;
} }
@ -82,7 +83,7 @@ namespace ui::actions {
swkbdClose(&swkbd); swkbdClose(&swkbd);
}); });
swkbdConfigSetGuideText(&swkbd, cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "swkbd_webpage_guide").c_str()); swkbdConfigSetGuideText(&swkbd, GetLanguageString("swkbd_webpage_guide").c_str());
char url[500] = {0}; char url[500] = {0};
swkbdShow(&swkbd, url, 500); swkbdShow(&swkbd, url, 500);
@ -102,15 +103,15 @@ namespace ui::actions {
void ShowHelpDialog() { void ShowHelpDialog() {
std::string msg; std::string msg;
msg += " - " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "help_launch") + "\n"; msg += " - " + GetLanguageString("help_launch") + "\n";
msg += " - " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "help_close") + "\n"; msg += " - " + GetLanguageString("help_close") + "\n";
msg += " - " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "help_quick") + "\n"; msg += " - " + GetLanguageString("help_quick") + "\n";
msg += " - " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "help_multiselect") + "\n"; msg += " - " + GetLanguageString("help_multiselect") + "\n";
msg += " - " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "help_back") + "\n"; msg += " - " + GetLanguageString("help_back") + "\n";
msg += " - " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "help_minus") + "\n"; msg += " - " + GetLanguageString("help_minus") + "\n";
msg += " - " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "help_plus") + "\n"; msg += " - " + GetLanguageString("help_plus") + "\n";
g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "help_title"), msg, { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "ok") }, true); g_MenuApplication->CreateShowDialog(GetLanguageString("help_title"), msg, { GetLanguageString("ok") }, true);
} }
void ShowAlbumApplet() { void ShowAlbumApplet() {
@ -130,7 +131,7 @@ namespace ui::actions {
void ShowPowerDialog() { void ShowPowerDialog() {
auto msg = os::GeneralChannelMessage::Invalid; auto msg = os::GeneralChannelMessage::Invalid;
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "power_dialog"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "power_dialog_info"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "power_sleep"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "power_power_off"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "power_reboot"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("power_dialog"), GetLanguageString("power_dialog_info"), { GetLanguageString("power_sleep"), GetLanguageString("power_power_off"), GetLanguageString("power_reboot"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
msg = os::GeneralChannelMessage::Sleep; msg = os::GeneralChannelMessage::Sleep;
} }

View file

@ -21,7 +21,7 @@ namespace ui {
pu::ui::Color menufocusclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_focus_color", "#5ebcffff")); pu::ui::Color menufocusclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_focus_color", "#5ebcffff"));
pu::ui::Color menubgclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_bg_color", "#0094ffff")); pu::ui::Color menubgclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_bg_color", "#0094ffff"));
this->infoText = pu::ui::elm::TextBlock::New(0, 100, cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "lang_info_text")); this->infoText = pu::ui::elm::TextBlock::New(0, 100, GetLanguageString("lang_info_text"));
this->infoText->SetColor(textclr); this->infoText->SetColor(textclr);
this->infoText->SetHorizontalAlign(pu::ui::elm::HorizontalAlign::Center); this->infoText->SetHorizontalAlign(pu::ui::elm::HorizontalAlign::Center);
g_MenuApplication->ApplyConfigForElement("languages_menu", "info_text", this->infoText); g_MenuApplication->ApplyConfigForElement("languages_menu", "info_text", this->infoText);
@ -61,7 +61,7 @@ namespace ui {
for(auto &lang: os::GetLanguageNameList()) { for(auto &lang: os::GetLanguageNameList()) {
auto name = lang; auto name = lang;
if(static_cast<u32>(ilang) == idx) { if(static_cast<u32>(ilang) == idx) {
name += " " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "lang_selected"); name += " " + GetLanguageString("lang_selected");
} }
auto litm = pu::ui::elm::MenuItem::New(name); auto litm = pu::ui::elm::MenuItem::New(name);
litm->SetColor(textclr); litm->SetColor(textclr);
@ -78,10 +78,10 @@ namespace ui {
setMakeLanguage(lcode, &ilang); setMakeLanguage(lcode, &ilang);
if(static_cast<u32>(ilang) == idx) { if(static_cast<u32>(ilang) == idx) {
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "lang_active_this")); g_MenuApplication->ShowNotification(GetLanguageString("lang_active_this"));
} }
else { else {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "lang_set"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "lang_set_conf"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "no") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("lang_set"), GetLanguageString("lang_set_conf"), { GetLanguageString("yes"), GetLanguageString("no") }, true);
if(sopt == 0) { if(sopt == 0) {
u64 codes[16] = {0}; u64 codes[16] = {0};
s32 tmp; s32 tmp;
@ -89,7 +89,7 @@ namespace ui {
auto code = codes[this->langsMenu->GetSelectedIndex()]; auto code = codes[this->langsMenu->GetSelectedIndex()];
auto rc = setsysSetLanguageCode(code); auto rc = setsysSetLanguageCode(code);
g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "lang_set"), R_SUCCEEDED(rc) ? cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "lang_set_ok") : cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "lang_set_error") + ": " + util::FormatResult(rc), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "ok") }, true); g_MenuApplication->CreateShowDialog(GetLanguageString("lang_set"), R_SUCCEEDED(rc) ? GetLanguageString("lang_set_ok") : GetLanguageString("lang_set_error") + ": " + util::FormatResult(rc), { GetLanguageString("ok") }, true);
if(R_SUCCEEDED(rc)) { if(R_SUCCEEDED(rc)) {
g_MenuApplication->FadeOut(); g_MenuApplication->FadeOut();

View file

@ -1,12 +1,20 @@
#include <ui/ui_MenuApplication.hpp> #include <ui/ui_MenuApplication.hpp>
#include <util/util_Misc.hpp> #include <util/util_Misc.hpp>
extern u8 *g_ScreenCaptureBuffer;
extern cfg::Theme g_Theme;
extern ui::MenuApplication::Ref g_MenuApplication; extern ui::MenuApplication::Ref g_MenuApplication;
extern u8 *g_ScreenCaptureBuffer;
extern cfg::Theme g_Theme;
extern JSON g_DefaultLanguage;
extern JSON g_MainLanguage;
namespace ui { namespace ui {
std::string GetLanguageString(const std::string &name) {
return cfg::GetLanguageString(g_MainLanguage, g_DefaultLanguage, name);
}
void UiOnHomeButtonDetection() { void UiOnHomeButtonDetection() {
switch(g_MenuApplication->GetCurrentLoadedMenu()) { switch(g_MenuApplication->GetCurrentLoadedMenu()) {
case MenuType::Startup: { case MenuType::Startup: {

View file

@ -59,13 +59,14 @@ namespace ui {
this->Add(this->controller); this->Add(this->controller);
auto curtime = os::GetCurrentTime(); auto curtime = os::GetCurrentTime();
this->timeText = pu::ui::elm::TextBlock::New(515, 68, curtime); this->timeText = pu::ui::elm::TextBlock::New(515, 65, curtime);
this->timeText->SetColor(textclr); this->timeText->SetColor(textclr);
g_MenuApplication->ApplyConfigForElement("main_menu", "time_text", this->timeText); g_MenuApplication->ApplyConfigForElement("main_menu", "time_text", this->timeText);
this->Add(this->timeText); this->Add(this->timeText);
auto lvl = os::GetBatteryLevel(); auto lvl = os::GetBatteryLevel();
auto lvlstr = std::to_string(lvl) + "%"; auto lvlstr = std::to_string(lvl) + "%";
this->batteryText = pu::ui::elm::TextBlock::New(700, 55, lvlstr); this->batteryText = pu::ui::elm::TextBlock::New(700, 55, lvlstr);
this->batteryText->SetFont("DefaultFont@20");
this->batteryText->SetColor(textclr); this->batteryText->SetColor(textclr);
g_MenuApplication->ApplyConfigForElement("main_menu", "battery_text", this->batteryText); g_MenuApplication->ApplyConfigForElement("main_menu", "battery_text", this->batteryText);
this->Add(this->batteryText); this->Add(this->batteryText);
@ -82,11 +83,15 @@ namespace ui {
g_MenuApplication->ApplyConfigForElement("main_menu", "themes_icon", this->themes); g_MenuApplication->ApplyConfigForElement("main_menu", "themes_icon", this->themes);
this->Add(this->themes); this->Add(this->themes);
this->fwText = pu::ui::elm::TextBlock::New(1140, 68, os::GetFirmwareVersion()); this->fwText = pu::ui::elm::TextBlock::New(1120, 65, os::GetFirmwareVersion());
this->fwText->SetColor(textclr); this->fwText->SetColor(textclr);
g_MenuApplication->ApplyConfigForElement("main_menu", "firmware_text", this->fwText); g_MenuApplication->ApplyConfigForElement("main_menu", "firmware_text", this->fwText);
this->Add(this->fwText); this->Add(this->fwText);
this->guideButtons = pu::ui::elm::Image::New(540, 120, cfg::GetAssetByTheme(g_Theme, "ui/GuideButtons.png"));
g_MenuApplication->ApplyConfigForElement("main_menu", "guide_buttons", this->guideButtons);
this->Add(this->guideButtons);
this->menuToggle = ClickableImage::New(520, 200, cfg::GetAssetByTheme(g_Theme, "ui/ToggleClick.png")); this->menuToggle = ClickableImage::New(520, 200, cfg::GetAssetByTheme(g_Theme, "ui/ToggleClick.png"));
this->menuToggle->SetOnClick(std::bind(&MenuLayout::menuToggle_Click, this)); this->menuToggle->SetOnClick(std::bind(&MenuLayout::menuToggle_Click, this));
g_MenuApplication->ApplyConfigForElement("main_menu", "menu_toggle_button", this->menuToggle); g_MenuApplication->ApplyConfigForElement("main_menu", "menu_toggle_button", this->menuToggle);
@ -171,7 +176,7 @@ namespace ui {
auto ctp = std::chrono::steady_clock::now(); auto ctp = std::chrono::steady_clock::now();
if(std::chrono::duration_cast<std::chrono::milliseconds>(ctp - this->tp).count() >= 500) { if(std::chrono::duration_cast<std::chrono::milliseconds>(ctp - this->tp).count() >= 500) {
if(g_MenuApplication->LaunchFailed() && !this->warnshown) { if(g_MenuApplication->LaunchFailed() && !this->warnshown) {
g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_launch"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_unexpected_error"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "ok") }, true); g_MenuApplication->CreateShowDialog(GetLanguageString("app_launch"), GetLanguageString("app_unexpected_error"), { GetLanguageString("ok") }, true);
this->warnshown = true; this->warnshown = true;
} }
} }
@ -259,7 +264,7 @@ namespace ui {
if((!this->homebrew_mode) && this->curfolder.empty()) { if((!this->homebrew_mode) && this->curfolder.empty()) {
if(index < g_EntryList.folders.size()) { if(index < g_EntryList.folders.size()) {
auto &folder = g_EntryList.folders[index]; auto &folder = g_EntryList.folders[index];
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_multiselect"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_move_existing_folder_conf"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "no"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("menu_multiselect"), GetLanguageString("menu_move_existing_folder_conf"), { GetLanguageString("yes"), GetLanguageString("no"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
this->HandleMultiselectMoveToFolder(folder.name); this->HandleMultiselectMoveToFolder(folder.name);
} }
@ -271,12 +276,12 @@ namespace ui {
} }
else if(down & HidNpadButton_B) { else if(down & HidNpadButton_B) {
this->select_dir = false; this->select_dir = false;
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_move_select_folder_cancel")); g_MenuApplication->ShowNotification(GetLanguageString("menu_move_select_folder_cancel"));
} }
} }
else { else {
if(down & HidNpadButton_B) { if(down & HidNpadButton_B) {
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_multiselect_cancel")); g_MenuApplication->ShowNotification(GetLanguageString("menu_multiselect_cancel"));
this->StopMultiselect(); this->StopMultiselect();
} }
else if(down & HidNpadButton_Y) { else if(down & HidNpadButton_Y) {
@ -298,7 +303,7 @@ namespace ui {
} }
else if(down & HidNpadButton_A) { else if(down & HidNpadButton_A) {
if(this->homebrew_mode) { if(this->homebrew_mode) {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_multiselect"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "hb_mode_entries_add"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "no"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("menu_multiselect"), GetLanguageString("hb_mode_entries_add"), { GetLanguageString("yes"), GetLanguageString("no"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
// Get the idx of the last g_HomebrewRecordList element. // Get the idx of the last g_HomebrewRecordList element.
s32 hbidx = 0; s32 hbidx = 0;
@ -325,7 +330,7 @@ namespace ui {
} }
} }
if(any) { if(any) {
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "hb_mode_entries_added")); g_MenuApplication->ShowNotification(GetLanguageString("hb_mode_entries_added"));
} }
this->StopMultiselect(); this->StopMultiselect();
} }
@ -334,12 +339,12 @@ namespace ui {
} }
} }
else if(this->curfolder.empty()) { else if(this->curfolder.empty()) {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_multiselect"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_move_to_folder"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_move_new_folder"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_move_existing_folder"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "no"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("menu_multiselect"), GetLanguageString("menu_move_to_folder"), { GetLanguageString("menu_move_new_folder"), GetLanguageString("menu_move_existing_folder"), GetLanguageString("no"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
SwkbdConfig swkbd; SwkbdConfig swkbd;
swkbdCreate(&swkbd, 0); swkbdCreate(&swkbd, 0);
swkbdConfigSetGuideText(&swkbd, cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "swkbd_new_folder_guide").c_str()); swkbdConfigSetGuideText(&swkbd, GetLanguageString("swkbd_new_folder_guide").c_str());
char dir[500] = {0}; char dir[500] = {};
auto rc = swkbdShow(&swkbd, dir, 500); auto rc = swkbdShow(&swkbd, dir, 500);
swkbdClose(&swkbd); swkbdClose(&swkbd);
if(R_SUCCEEDED(rc)) { if(R_SUCCEEDED(rc)) {
@ -348,14 +353,14 @@ namespace ui {
} }
else if(sopt == 1) { else if(sopt == 1) {
this->select_dir = true; this->select_dir = true;
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_move_select_folder")); g_MenuApplication->ShowNotification(GetLanguageString("menu_move_select_folder"));
} }
else if(sopt == 2) { else if(sopt == 2) {
this->StopMultiselect(); this->StopMultiselect();
} }
} }
else { else {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_multiselect"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_move_from_folder"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "no"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("menu_multiselect"), GetLanguageString("menu_move_from_folder"), { GetLanguageString("yes"), GetLanguageString("no"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
u32 rmvd = 0; u32 rmvd = 0;
auto &folder = cfg::FindFolderByName(g_EntryList, this->curfolder); auto &folder = cfg::FindFolderByName(g_EntryList, this->curfolder);
@ -451,11 +456,11 @@ namespace ui {
this->MoveFolder(foldr.name, true); this->MoveFolder(foldr.name, true);
} }
else if(down & HidNpadButton_Y) { else if(down & HidNpadButton_Y) {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_rename_folder"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_rename_folder_conf"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "no") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("menu_rename_folder"), GetLanguageString("menu_rename_folder_conf"), { GetLanguageString("yes"), GetLanguageString("no") }, true);
if(sopt == 0) { if(sopt == 0) {
SwkbdConfig swkbd; SwkbdConfig swkbd;
swkbdCreate(&swkbd, 0); swkbdCreate(&swkbd, 0);
swkbdConfigSetGuideText(&swkbd, cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "swkbd_rename_folder_guide").c_str()); swkbdConfigSetGuideText(&swkbd, GetLanguageString("swkbd_rename_folder_guide").c_str());
char dir[500] = {0}; char dir[500] = {0};
auto rc = swkbdShow(&swkbd, dir, 500); auto rc = swkbdShow(&swkbd, dir, 500);
swkbdClose(&swkbd); swkbdClose(&swkbd);
@ -522,7 +527,7 @@ namespace ui {
return; return;
} }
else { else {
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_launch_error") + ": " + util::FormatResult(rc)); g_MenuApplication->ShowNotification(GetLanguageString("app_launch_error") + ": " + util::FormatResult(rc));
} }
} }
} }
@ -543,7 +548,7 @@ namespace ui {
} }
else if(down & HidNpadButton_Y) { else if(down & HidNpadButton_Y) {
if(type == cfg::TitleType::Homebrew) { if(type == cfg::TitleType::Homebrew) {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "entry_options"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "entry_action"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "entry_move"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "entry_remove"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("entry_options"), GetLanguageString("entry_action"), { GetLanguageString("entry_move"), GetLanguageString("entry_remove"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
if(!this->select_on) { if(!this->select_on) {
this->select_on = true; this->select_on = true;
@ -551,11 +556,11 @@ namespace ui {
this->itemsMenu->SetItemMultiselected(this->itemsMenu->GetSelectedItem(), true); this->itemsMenu->SetItemMultiselected(this->itemsMenu->GetSelectedItem(), true);
} }
else if(sopt == 1) { else if(sopt == 1) {
auto sopt2 = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "entry_remove"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "entry_remove_conf"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "no") }, true); auto sopt2 = g_MenuApplication->CreateShowDialog(GetLanguageString("entry_remove"), GetLanguageString("entry_remove_conf"), { GetLanguageString("yes"), GetLanguageString("no") }, true);
if(sopt2 == 0) { if(sopt2 == 0) {
cfg::RemoveRecord(title); cfg::RemoveRecord(title);
folder.titles.erase(folder.titles.begin() + titleidx); folder.titles.erase(folder.titles.begin() + titleidx);
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "entry_remove_ok")); g_MenuApplication->ShowNotification(GetLanguageString("entry_remove_ok"));
this->MoveFolder(this->curfolder, true); this->MoveFolder(this->curfolder, true);
} }
} }
@ -567,11 +572,11 @@ namespace ui {
} }
else if(down & HidNpadButton_AnyUp) { else if(down & HidNpadButton_AnyUp) {
if(type == cfg::TitleType::Installed) { if(type == cfg::TitleType::Installed) {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_launch"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_take_over_select") + "\n" + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_take_over_selected"), { "Yes", "Cancel" }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("app_launch"), GetLanguageString("app_take_over_select") + "\n" + GetLanguageString("app_take_over_selected"), { "Yes", "Cancel" }, true);
if(sopt == 0) { if(sopt == 0) {
g_Config.homebrew_title_application_id = title.app_id; UL_ASSERT_TRUE(g_Config.SetEntry(cfg::ConfigEntryId::HomebrewApplicationTakeoverApplicationId, title.app_id));
cfg::SaveConfig(g_Config); cfg::SaveConfig(g_Config);
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_take_over_done")); g_MenuApplication->ShowNotification(GetLanguageString("app_take_over_done"));
} }
} }
} }
@ -590,7 +595,7 @@ namespace ui {
this->itemAuthor->SetVisible(false); this->itemAuthor->SetVisible(false);
this->itemVersion->SetVisible(false); this->itemVersion->SetVisible(false);
this->bannerImage->SetImage(cfg::GetAssetByTheme(g_Theme, "ui/BannerHomebrew.png")); this->bannerImage->SetImage(cfg::GetAssetByTheme(g_Theme, "ui/BannerHomebrew.png"));
this->itemName->SetText(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "hbmenu_launch")); this->itemName->SetText(GetLanguageString("hbmenu_launch"));
} }
else { else {
realidx--; realidx--;
@ -598,14 +603,14 @@ namespace ui {
auto info = cfg::GetRecordInformation(hb); auto info = cfg::GetRecordInformation(hb);
if(info.strings.name.empty()) { if(info.strings.name.empty()) {
this->itemName->SetText(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "unknown")); this->itemName->SetText(GetLanguageString("unknown"));
} }
else { else {
this->itemName->SetText(info.strings.name); this->itemName->SetText(info.strings.name);
} }
if(info.strings.author.empty()) { if(info.strings.author.empty()) {
this->itemAuthor->SetText(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "unknown")); this->itemAuthor->SetText(GetLanguageString("unknown"));
} }
else { else {
this->itemAuthor->SetText(info.strings.author); this->itemAuthor->SetText(info.strings.author);
@ -632,7 +637,7 @@ namespace ui {
auto foldr = g_EntryList.folders[realidx]; auto foldr = g_EntryList.folders[realidx];
this->bannerImage->SetImage(cfg::GetAssetByTheme(g_Theme, "ui/BannerFolder.png")); this->bannerImage->SetImage(cfg::GetAssetByTheme(g_Theme, "ui/BannerFolder.png"));
auto sz = foldr.titles.size(); auto sz = foldr.titles.size();
this->itemAuthor->SetText(std::to_string(sz) + " " + ((sz == 1) ? cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "folder_entry_single") : cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "folder_entry_mult"))); this->itemAuthor->SetText(std::to_string(sz) + " " + ((sz == 1) ? GetLanguageString("folder_entry_single") : GetLanguageString("folder_entry_mult")));
this->itemVersion->SetVisible(false); this->itemVersion->SetVisible(false);
this->itemName->SetText(foldr.name); this->itemName->SetText(foldr.name);
titleidx = -1; titleidx = -1;
@ -643,14 +648,14 @@ namespace ui {
auto info = cfg::GetRecordInformation(title); auto info = cfg::GetRecordInformation(title);
if(info.strings.name.empty()) { if(info.strings.name.empty()) {
this->itemName->SetText(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "unknown")); this->itemName->SetText(GetLanguageString("unknown"));
} }
else { else {
this->itemName->SetText(info.strings.name); this->itemName->SetText(info.strings.name);
} }
if(info.strings.author.empty()) { if(info.strings.author.empty()) {
this->itemAuthor->SetText(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "unknown")); this->itemAuthor->SetText(GetLanguageString("unknown"));
} }
else { else {
this->itemAuthor->SetText(info.strings.author); this->itemAuthor->SetText(info.strings.author);
@ -703,7 +708,7 @@ namespace ui {
else { else {
if(name.empty()) { if(name.empty()) {
// Remove empty folders // Remove empty folders
STL_REMOVE_IF(g_EntryList.folders, fldr, (fldr.titles.empty())) STL_REMOVE_IF(g_EntryList.folders, fldr, (fldr.titles.empty()));
for(auto folder: g_EntryList.folders) { for(auto folder: g_EntryList.folders) {
this->itemsMenu->AddItem(cfg::GetAssetByTheme(g_Theme, "ui/Folder.png"), folder.name); this->itemsMenu->AddItem(cfg::GetAssetByTheme(g_Theme, "ui/Folder.png"), folder.name);
} }
@ -764,14 +769,14 @@ namespace ui {
pu::audio::Play(this->sfxMenuToggle); pu::audio::Play(this->sfxMenuToggle);
this->homebrew_mode = !this->homebrew_mode; this->homebrew_mode = !this->homebrew_mode;
if(this->select_on) { if(this->select_on) {
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_multiselect_cancel")); g_MenuApplication->ShowNotification(GetLanguageString("menu_multiselect_cancel"));
this->StopMultiselect(); this->StopMultiselect();
} }
this->MoveFolder("", true); this->MoveFolder("", true);
} }
void MenuLayout::HandleCloseSuspended() { void MenuLayout::HandleCloseSuspended() {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "suspended_app"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "suspended_close"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "no") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("suspended_app"), GetLanguageString("suspended_close"), { GetLanguageString("yes"), GetLanguageString("no") }, true);
if(sopt == 0) { if(sopt == 0) {
this->DoTerminateApplication(); this->DoTerminateApplication();
} }
@ -779,18 +784,15 @@ namespace ui {
void MenuLayout::HandleHomebrewLaunch(cfg::TitleRecord &rec) { void MenuLayout::HandleHomebrewLaunch(cfg::TitleRecord &rec) {
u32 launchmode = 0; u32 launchmode = 0;
if(g_Config.system_title_override_enabled) { u64 title_takeover_id;
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "hb_launch"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "hb_launch_conf"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "hb_applet"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "hb_app"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::HomebrewApplicationTakeoverApplicationId, title_takeover_id));
if(sopt == 0) { auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("hb_launch"), GetLanguageString("hb_launch_conf"), { GetLanguageString("hb_applet"), GetLanguageString("hb_app"), GetLanguageString("cancel") }, true);
launchmode = 1; if(sopt == 0) {
}
else if(sopt == 1) {
launchmode = 2;
}
}
else {
launchmode = 1; launchmode = 1;
} }
else if(sopt == 1) {
launchmode = 2;
}
if(launchmode == 1) { if(launchmode == 1) {
pu::audio::Play(this->sfxTitleLaunch); pu::audio::Play(this->sfxTitleLaunch);
hb::HbTargetParams ipt = {}; hb::HbTargetParams ipt = {};
@ -815,8 +817,7 @@ namespace ui {
return; return;
} }
else if(launchmode == 2) { else if(launchmode == 2) {
if(g_Config.homebrew_title_application_id != 0) if(title_takeover_id != 0) {
{
bool launch = true; bool launch = true;
if(g_MenuApplication->IsSuspended()) { if(g_MenuApplication->IsSuspended()) {
launch = false; launch = false;
@ -837,7 +838,7 @@ namespace ui {
strncpy(ipt.nro_argv, rec.nro_target.nro_argv, sizeof(ipt.nro_argv) - 1); strncpy(ipt.nro_argv, rec.nro_target.nro_argv, sizeof(ipt.nro_argv) - 1);
} }
auto rc = dmi::menu::SendCommand(dmi::DaemonMessage::LaunchHomebrewApplication, [&](dmi::menu::MenuScopedStorageWriter &writer) { auto rc = dmi::menu::SendCommand(dmi::DaemonMessage::LaunchHomebrewApplication, [&](dmi::menu::MenuScopedStorageWriter &writer) {
writer.Push(g_Config.homebrew_title_application_id); writer.Push(title_takeover_id);
writer.Push(ipt); writer.Push(ipt);
return ResultSuccess; return ResultSuccess;
}, },
@ -852,12 +853,12 @@ namespace ui {
return; return;
} }
else { else {
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_launch_error") + ": " + util::FormatResult(rc)); g_MenuApplication->ShowNotification(GetLanguageString("app_launch_error") + ": " + util::FormatResult(rc));
} }
} }
} }
else { else {
g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_launch"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_no_take_over_title") + "\n" + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "app_take_over_title_select"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "ok") }, true); g_MenuApplication->CreateShowDialog(GetLanguageString("app_launch"), GetLanguageString("app_no_take_over_title") + "\n" + GetLanguageString("app_take_over_title_select"), { GetLanguageString("ok") }, true);
} }
} }
} }

View file

@ -15,7 +15,7 @@ namespace ui {
template<typename T> template<typename T>
inline std::string EncodeForSettings(T t) { inline std::string EncodeForSettings(T t) {
return cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_unknown_value"); return GetLanguageString("set_unknown_value");
} }
template<> template<>
@ -30,7 +30,7 @@ namespace ui {
template<> template<>
inline std::string EncodeForSettings<bool>(bool t) { inline std::string EncodeForSettings<bool>(bool t) {
return t ? cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_true_value") : cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_false_value"); return t ? GetLanguageString("set_true_value") : GetLanguageString("set_false_value");
} }
SettingsMenuLayout::SettingsMenuLayout() { SettingsMenuLayout::SettingsMenuLayout() {
@ -40,7 +40,7 @@ namespace ui {
pu::ui::Color menufocusclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_focus_color", "#5ebcffff")); pu::ui::Color menufocusclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_focus_color", "#5ebcffff"));
pu::ui::Color menubgclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_bg_color", "#0094ffff")); pu::ui::Color menubgclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_bg_color", "#0094ffff"));
this->infoText = pu::ui::elm::TextBlock::New(0, 100, cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_info_text")); this->infoText = pu::ui::elm::TextBlock::New(0, 100, GetLanguageString("set_info_text"));
this->infoText->SetColor(textclr); this->infoText->SetColor(textclr);
this->infoText->SetHorizontalAlign(pu::ui::elm::HorizontalAlign::Center); this->infoText->SetHorizontalAlign(pu::ui::elm::HorizontalAlign::Center);
g_MenuApplication->ApplyConfigForElement("settings_menu", "info_text", this->infoText); g_MenuApplication->ApplyConfigForElement("settings_menu", "info_text", this->infoText);
@ -72,53 +72,54 @@ namespace ui {
SetSysDeviceNickName console_name = {}; SetSysDeviceNickName console_name = {};
setsysGetDeviceNickname(&console_name); setsysGetDeviceNickname(&console_name);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_console_nickname"), EncodeForSettings<std::string>(console_name.nickname), 0); this->PushSettingItem(GetLanguageString("set_console_nickname"), EncodeForSettings<std::string>(console_name.nickname), 0);
TimeLocationName loc = {}; TimeLocationName loc = {};
timeGetDeviceLocationName(&loc); timeGetDeviceLocationName(&loc);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_console_timezone"), EncodeForSettings<std::string>(loc.name), -1); this->PushSettingItem(GetLanguageString("set_console_timezone"), EncodeForSettings<std::string>(loc.name), -1);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_viewer_enabled"), EncodeForSettings(g_Config.viewer_usb_enabled), 1); bool viewer_usb_enabled;
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_flog_enabled"), EncodeForSettings(g_Config.system_title_override_enabled), 2); UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::ViewerUsbEnabled, viewer_usb_enabled));
auto connectednet = cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_wifi_none"); this->PushSettingItem(GetLanguageString("set_viewer_enabled"), EncodeForSettings(viewer_usb_enabled), 1);
auto connectednet = GetLanguageString("set_wifi_none");
if(net::HasConnection()) { if(net::HasConnection()) {
net::NetworkProfileData data = {}; net::NetworkProfileData data = {};
net::GetCurrentNetworkProfile(&data); net::GetCurrentNetworkProfile(&data);
connectednet = data.wifi_name; connectednet = data.wifi_name;
} }
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_wifi_name"), EncodeForSettings(connectednet), 3); this->PushSettingItem(GetLanguageString("set_wifi_name"), EncodeForSettings(connectednet), 2);
u64 lcode = 0; u64 lcode = 0;
auto ilang = SetLanguage_ENUS; auto ilang = SetLanguage_ENUS;
setGetLanguageCode(&lcode); setGetLanguageCode(&lcode);
setMakeLanguage(lcode, &ilang); setMakeLanguage(lcode, &ilang);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_console_lang"), EncodeForSettings(os::GetLanguageName(ilang)), 4); this->PushSettingItem(GetLanguageString("set_console_lang"), EncodeForSettings(os::GetLanguageName(ilang)), 3);
bool console_info_upload = false; bool console_info_upload = false;
setsysGetConsoleInformationUploadFlag(&console_info_upload); setsysGetConsoleInformationUploadFlag(&console_info_upload);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_console_info_upload"), EncodeForSettings(console_info_upload), 5); this->PushSettingItem(GetLanguageString("set_console_info_upload"), EncodeForSettings(console_info_upload), 4);
bool auto_titles_dl = false; bool auto_titles_dl = false;
setsysGetAutomaticApplicationDownloadFlag(&auto_titles_dl); setsysGetAutomaticApplicationDownloadFlag(&auto_titles_dl);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_auto_titles_dl"), EncodeForSettings(auto_titles_dl), 6); this->PushSettingItem(GetLanguageString("set_auto_titles_dl"), EncodeForSettings(auto_titles_dl), 5);
bool auto_update = false; bool auto_update = false;
setsysGetAutoUpdateEnableFlag(&auto_update); setsysGetAutoUpdateEnableFlag(&auto_update);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_auto_update"), EncodeForSettings(auto_update), 7); this->PushSettingItem(GetLanguageString("set_auto_update"), EncodeForSettings(auto_update), 6);
bool wireless_lan = false; bool wireless_lan = false;
setsysGetWirelessLanEnableFlag(&wireless_lan); setsysGetWirelessLanEnableFlag(&wireless_lan);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_wireless_lan"), EncodeForSettings(wireless_lan), 8); this->PushSettingItem(GetLanguageString("set_wireless_lan"), EncodeForSettings(wireless_lan), 7);
bool bluetooth = false; bool bluetooth = false;
setsysGetBluetoothEnableFlag(&bluetooth); setsysGetBluetoothEnableFlag(&bluetooth);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_bluetooth"), EncodeForSettings(bluetooth), 9); this->PushSettingItem(GetLanguageString("set_bluetooth"), EncodeForSettings(bluetooth), 8);
bool usb_30 = false; bool usb_30 = false;
setsysGetUsb30EnableFlag(&usb_30); setsysGetUsb30EnableFlag(&usb_30);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_usb_30"), EncodeForSettings(usb_30), 10); this->PushSettingItem(GetLanguageString("set_usb_30"), EncodeForSettings(usb_30), 9);
bool nfc = false; bool nfc = false;
setsysGetNfcEnableFlag(&nfc); setsysGetNfcEnableFlag(&nfc);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_nfc"), EncodeForSettings(nfc), 11); this->PushSettingItem(GetLanguageString("set_nfc"), EncodeForSettings(nfc), 10);
SetSysSerialNumber serial = {}; SetSysSerialNumber serial = {};
setsysGetSerialNumber(&serial); setsysGetSerialNumber(&serial);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_serial_no"), EncodeForSettings<std::string>(serial.number), -1); this->PushSettingItem(GetLanguageString("set_serial_no"), EncodeForSettings<std::string>(serial.number), -1);
u64 mac = 0; u64 mac = 0;
net::GetMACAddress(&mac); net::GetMACAddress(&mac);
auto strmac = net::FormatMACAddress(mac); auto strmac = net::FormatMACAddress(mac);
this->PushSettingItem(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_mac_addr"), EncodeForSettings(strmac), -1); this->PushSettingItem(GetLanguageString("set_mac_addr"), EncodeForSettings(strmac), -1);
auto ipstr = net::GetConsoleIPAddress(); auto ipstr = net::GetConsoleIPAddress();
// TODO: strings // TODO: strings
this->PushSettingItem("Console IP address", EncodeForSettings(ipstr), -1); this->PushSettingItem("Console IP address", EncodeForSettings(ipstr), -1);
@ -139,7 +140,7 @@ namespace ui {
case 0: { case 0: {
SwkbdConfig swkbd; SwkbdConfig swkbd;
swkbdCreate(&swkbd, 0); swkbdCreate(&swkbd, 0);
swkbdConfigSetGuideText(&swkbd, cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "swkbd_console_nick_guide").c_str()); swkbdConfigSetGuideText(&swkbd, GetLanguageString("swkbd_console_nick_guide").c_str());
SetSysDeviceNickName console_name = {}; SetSysDeviceNickName console_name = {};
setsysGetDeviceNickname(&console_name); setsysGetDeviceNickname(&console_name);
swkbdConfigSetInitialText(&swkbd, console_name.nickname); swkbdConfigSetInitialText(&swkbd, console_name.nickname);
@ -154,23 +155,18 @@ namespace ui {
break; break;
} }
case 1: { case 1: {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_viewer_enabled"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_viewer_info") + "\n" + (g_Config.viewer_usb_enabled ? cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_disable_conf") : cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_enable_conf")), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); bool viewer_usb_enabled;
UL_ASSERT_TRUE(g_Config.GetEntry(cfg::ConfigEntryId::ViewerUsbEnabled, viewer_usb_enabled));
auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("set_viewer_enabled"), GetLanguageString("set_viewer_info") + "\n" + (viewer_usb_enabled ? GetLanguageString("set_disable_conf") : GetLanguageString("set_enable_conf")), { GetLanguageString("yes"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
g_Config.viewer_usb_enabled = !g_Config.viewer_usb_enabled; viewer_usb_enabled = !viewer_usb_enabled;
UL_ASSERT_TRUE(g_Config.SetEntry(cfg::ConfigEntryId::ViewerUsbEnabled, viewer_usb_enabled));
reload_need = true; reload_need = true;
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_changed_reboot")); g_MenuApplication->ShowNotification(GetLanguageString("set_changed_reboot"));
} }
break; break;
} }
case 2: { case 2: {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_flog_enabled"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_flog_info") + "\n" + (g_Config.viewer_usb_enabled ? cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_disable_conf") : cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "set_enable_conf")), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true);
if(sopt == 0) {
g_Config.system_title_override_enabled = !g_Config.system_title_override_enabled;
reload_need = true;
}
break;
}
case 3: {
u8 in[28] = {0}; u8 in[28] = {0};
// 0 = normal, 1 = qlaunch, 2 = starter...? // 0 = normal, 1 = qlaunch, 2 = starter...?
*reinterpret_cast<u32*>(in) = 1; *reinterpret_cast<u32*>(in) = 1;
@ -188,14 +184,14 @@ namespace ui {
} }
break; break;
} }
case 4: { case 3: {
g_MenuApplication->FadeOut(); g_MenuApplication->FadeOut();
g_MenuApplication->LoadSettingsLanguagesMenu(); g_MenuApplication->LoadSettingsLanguagesMenu();
g_MenuApplication->FadeIn(); g_MenuApplication->FadeIn();
break; break;
} }
case 5: { case 4: {
auto console_info_upload = false; auto console_info_upload = false;
setsysGetConsoleInformationUploadFlag(&console_info_upload); setsysGetConsoleInformationUploadFlag(&console_info_upload);
setsysSetConsoleInformationUploadFlag(!console_info_upload); setsysSetConsoleInformationUploadFlag(!console_info_upload);
@ -203,7 +199,7 @@ namespace ui {
reload_need = true; reload_need = true;
break; break;
} }
case 6: { case 5: {
auto auto_titles_dl = false; auto auto_titles_dl = false;
setsysGetAutomaticApplicationDownloadFlag(&auto_titles_dl); setsysGetAutomaticApplicationDownloadFlag(&auto_titles_dl);
setsysSetAutomaticApplicationDownloadFlag(!auto_titles_dl); setsysSetAutomaticApplicationDownloadFlag(!auto_titles_dl);
@ -211,7 +207,7 @@ namespace ui {
reload_need = true; reload_need = true;
break; break;
} }
case 7: { case 6: {
auto auto_update = false; auto auto_update = false;
setsysGetAutoUpdateEnableFlag(&auto_update); setsysGetAutoUpdateEnableFlag(&auto_update);
setsysSetAutoUpdateEnableFlag(!auto_update); setsysSetAutoUpdateEnableFlag(!auto_update);
@ -219,7 +215,7 @@ namespace ui {
reload_need = true; reload_need = true;
break; break;
} }
case 8: { case 7: {
auto wireless_lan = false; auto wireless_lan = false;
setsysGetWirelessLanEnableFlag(&wireless_lan); setsysGetWirelessLanEnableFlag(&wireless_lan);
setsysSetWirelessLanEnableFlag(!wireless_lan); setsysSetWirelessLanEnableFlag(!wireless_lan);
@ -227,7 +223,7 @@ namespace ui {
reload_need = true; reload_need = true;
break; break;
} }
case 9: { case 8: {
auto bluetooth = false; auto bluetooth = false;
setsysGetBluetoothEnableFlag(&bluetooth); setsysGetBluetoothEnableFlag(&bluetooth);
setsysSetBluetoothEnableFlag(!bluetooth); setsysSetBluetoothEnableFlag(!bluetooth);
@ -235,7 +231,7 @@ namespace ui {
reload_need = true; reload_need = true;
break; break;
} }
case 10: { case 9: {
auto usb_30 = false; auto usb_30 = false;
setsysGetUsb30EnableFlag(&usb_30); setsysGetUsb30EnableFlag(&usb_30);
setsysSetUsb30EnableFlag(!usb_30); setsysSetUsb30EnableFlag(!usb_30);
@ -243,7 +239,7 @@ namespace ui {
reload_need = true; reload_need = true;
break; break;
} }
case 11: { case 10: {
auto nfc = false; auto nfc = false;
setsysGetNfcEnableFlag(&nfc); setsysGetNfcEnableFlag(&nfc);
setsysSetNfcEnableFlag(!nfc); setsysSetNfcEnableFlag(!nfc);

View file

@ -18,7 +18,7 @@ namespace ui {
auto menufocusclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_focus_color", "#5ebcffff")); auto menufocusclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_focus_color", "#5ebcffff"));
auto menubgclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_bg_color", "#0094ffff")); auto menubgclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("menu_bg_color", "#0094ffff"));
this->infoText = pu::ui::elm::TextBlock::New(35, 635, cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "startup_welcome_info") + "\n" + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "startup_control_info")); this->infoText = pu::ui::elm::TextBlock::New(35, 650, GetLanguageString("startup_welcome_info"));
this->infoText->SetColor(textclr); this->infoText->SetColor(textclr);
g_MenuApplication->ApplyConfigForElement("startup_menu", "info_text", this->infoText); g_MenuApplication->ApplyConfigForElement("startup_menu", "info_text", this->infoText);
this->Add(this->infoText); this->Add(this->infoText);
@ -36,7 +36,6 @@ namespace ui {
g_MenuApplication->FadeOut(); g_MenuApplication->FadeOut();
g_MenuApplication->LoadMenu(); g_MenuApplication->LoadMenu();
g_MenuApplication->FadeIn(); g_MenuApplication->FadeIn();
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "menu_quick_info"), 3000); // Show for 3s
} }
} }
@ -81,7 +80,7 @@ namespace ui {
} }
} }
auto citm = pu::ui::elm::MenuItem::New(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "startup_new_user")); auto citm = pu::ui::elm::MenuItem::New(GetLanguageString("startup_new_user"));
citm->SetColor(textclr); citm->SetColor(textclr);
citm->AddOnClick(std::bind(&StartupLayout::create_Click, this)); citm->AddOnClick(std::bind(&StartupLayout::create_Click, this));
this->usersMenu->AddItem(citm); this->usersMenu->AddItem(citm);

View file

@ -26,7 +26,7 @@ namespace ui {
g_MenuApplication->ApplyConfigForElement("themes_menu", "themes_menu_item", this->themesMenu); g_MenuApplication->ApplyConfigForElement("themes_menu", "themes_menu_item", this->themesMenu);
this->Add(this->themesMenu); this->Add(this->themesMenu);
this->curThemeText = pu::ui::elm::TextBlock::New(20, 540, cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_current") + ":"); this->curThemeText = pu::ui::elm::TextBlock::New(20, 540, GetLanguageString("theme_current") + ":");
this->curThemeText->SetFont("DefaultFont@30"); this->curThemeText->SetFont("DefaultFont@30");
this->curThemeText->SetColor(textclr); this->curThemeText->SetColor(textclr);
g_MenuApplication->ApplyConfigForElement("themes_menu", "current_theme_text", this->curThemeText); g_MenuApplication->ApplyConfigForElement("themes_menu", "current_theme_text", this->curThemeText);
@ -71,7 +71,7 @@ namespace ui {
void ThemeMenuLayout::Reload() { void ThemeMenuLayout::Reload() {
auto textclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("text_color", "#e1e1e1ff")); auto textclr = pu::ui::Color::FromHex(g_MenuApplication->GetUIConfigValue<std::string>("text_color", "#e1e1e1ff"));
if(cfg::ThemeIsDefault(g_Theme)) { if(cfg::ThemeIsDefault(g_Theme)) {
this->curThemeText->SetText(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_no_custom")); this->curThemeText->SetText(GetLanguageString("theme_no_custom"));
this->curThemeName->SetVisible(false); this->curThemeName->SetVisible(false);
this->curThemeAuthor->SetVisible(false); this->curThemeAuthor->SetVisible(false);
this->curThemeVersion->SetVisible(false); this->curThemeVersion->SetVisible(false);
@ -79,7 +79,7 @@ namespace ui {
this->curThemeIcon->SetVisible(false); this->curThemeIcon->SetVisible(false);
} }
else { else {
this->curThemeText->SetText(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_current") + ":"); this->curThemeText->SetText(GetLanguageString("theme_current") + ":");
this->curThemeName->SetVisible(true); this->curThemeName->SetVisible(true);
this->curThemeName->SetText(g_Theme.manifest.name); this->curThemeName->SetText(g_Theme.manifest.name);
this->curThemeAuthor->SetVisible(true); this->curThemeAuthor->SetVisible(true);
@ -98,14 +98,14 @@ namespace ui {
this->loadedThemes.clear(); this->loadedThemes.clear();
this->loadedThemes = cfg::LoadThemes(); this->loadedThemes = cfg::LoadThemes();
auto ditm = pu::ui::elm::MenuItem::New(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_reset")); auto ditm = pu::ui::elm::MenuItem::New(GetLanguageString("theme_reset"));
ditm->AddOnClick(std::bind(&ThemeMenuLayout::theme_Click, this)); ditm->AddOnClick(std::bind(&ThemeMenuLayout::theme_Click, this));
ditm->SetColor(textclr); ditm->SetColor(textclr);
ditm->SetIcon("romfs:/Logo.png"); ditm->SetIcon("romfs:/Logo.png");
this->themesMenu->AddItem(ditm); this->themesMenu->AddItem(ditm);
for(auto &ltheme: this->loadedThemes) { for(auto &ltheme: this->loadedThemes) {
auto itm = pu::ui::elm::MenuItem::New(ltheme.manifest.name + " (v" + ltheme.manifest.release + ", " + cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_by") + " " + ltheme.manifest.author + ")"); auto itm = pu::ui::elm::MenuItem::New(ltheme.manifest.name + " (v" + ltheme.manifest.release + ", " + GetLanguageString("theme_by") + " " + ltheme.manifest.author + ")");
itm->AddOnClick(std::bind(&ThemeMenuLayout::theme_Click, this)); itm->AddOnClick(std::bind(&ThemeMenuLayout::theme_Click, this));
itm->SetColor(textclr); itm->SetColor(textclr);
auto iconpath = ltheme.path + "/theme/Icon.png"; auto iconpath = ltheme.path + "/theme/Icon.png";
@ -118,17 +118,17 @@ namespace ui {
auto idx = this->themesMenu->GetSelectedIndex(); auto idx = this->themesMenu->GetSelectedIndex();
if(idx == 0) { if(idx == 0) {
if(cfg::ThemeIsDefault(g_Theme)) { if(cfg::ThemeIsDefault(g_Theme)) {
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_no_custom")); g_MenuApplication->ShowNotification(GetLanguageString("theme_no_custom"));
} }
else { else {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_reset"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_reset_conf"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("theme_reset"), GetLanguageString("theme_reset_conf"), { GetLanguageString("yes"), GetLanguageString("cancel") }, true);
if(sopt == 0) { if(sopt == 0) {
g_Config.theme_name = ""; UL_ASSERT_TRUE(g_Config.SetEntry(cfg::ConfigEntryId::ActiveThemeName, std::string()));
cfg::SaveConfig(g_Config); cfg::SaveConfig(g_Config);
g_MenuApplication->StopPlayBGM(); g_MenuApplication->StopPlayBGM();
g_MenuApplication->CloseWithFadeOut(); g_MenuApplication->CloseWithFadeOut();
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_changed")); g_MenuApplication->ShowNotification(GetLanguageString("theme_changed"));
UL_ASSERT(dmi::menu::SendCommand(dmi::DaemonMessage::RestartMenu, [&](dmi::menu::MenuScopedStorageWriter &writer) { UL_ASSERT(dmi::menu::SendCommand(dmi::DaemonMessage::RestartMenu, [&](dmi::menu::MenuScopedStorageWriter &writer) {
// ... // ...
@ -146,17 +146,17 @@ namespace ui {
auto seltheme = this->loadedThemes[idx]; auto seltheme = this->loadedThemes[idx];
auto iconpath = seltheme.path + "/theme/Icon.png"; auto iconpath = seltheme.path + "/theme/Icon.png";
if(seltheme.base_name == g_Theme.base_name) { if(seltheme.base_name == g_Theme.base_name) {
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_active_this")); g_MenuApplication->ShowNotification(GetLanguageString("theme_active_this"));
} }
else { else {
auto sopt = g_MenuApplication->CreateShowDialog(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_set"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_set_conf"), { cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "yes"), cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "cancel") }, true, iconpath); auto sopt = g_MenuApplication->CreateShowDialog(GetLanguageString("theme_set"), GetLanguageString("theme_set_conf"), { GetLanguageString("yes"), GetLanguageString("cancel") }, true, iconpath);
if(sopt == 0) { if(sopt == 0) {
g_Config.theme_name = seltheme.base_name; UL_ASSERT_TRUE(g_Config.SetEntry(cfg::ConfigEntryId::ActiveThemeName, seltheme.base_name));
cfg::SaveConfig(g_Config); cfg::SaveConfig(g_Config);
g_MenuApplication->StopPlayBGM(); g_MenuApplication->StopPlayBGM();
g_MenuApplication->CloseWithFadeOut(); g_MenuApplication->CloseWithFadeOut();
g_MenuApplication->ShowNotification(cfg::GetLanguageString(g_Config.main_lang, g_Config.default_lang, "theme_changed")); g_MenuApplication->ShowNotification(GetLanguageString("theme_changed"));
UL_ASSERT(dmi::menu::SendCommand(dmi::DaemonMessage::RestartMenu, [&](dmi::menu::MenuScopedStorageWriter &writer) { UL_ASSERT(dmi::menu::SendCommand(dmi::DaemonMessage::RestartMenu, [&](dmi::menu::MenuScopedStorageWriter &writer) {
// ... // ...