mirror of
https://github.com/XorTroll/uLaunch
synced 2025-02-16 12:38:29 +00:00
Some cleanup, add user and web icons
This commit is contained in:
parent
f6b946d282
commit
79de9de4a1
15 changed files with 171 additions and 74 deletions
|
@ -30,7 +30,8 @@ namespace am
|
|||
GetSuspendedInfo,
|
||||
LaunchHomebrewLibApplet,
|
||||
LaunchHomebrewApplication,
|
||||
OpenWebPage
|
||||
OpenWebPage,
|
||||
GetSelectedUser
|
||||
};
|
||||
|
||||
struct QSuspendedInfo
|
||||
|
|
|
@ -75,9 +75,11 @@ namespace cfg
|
|||
std::string icon_path;
|
||||
};
|
||||
|
||||
struct MenuConfig
|
||||
struct Config
|
||||
{
|
||||
std::string theme_name;
|
||||
bool system_title_override_enabled;
|
||||
|
||||
};
|
||||
|
||||
static constexpr u32 CurrentThemeFormatVersion = 0;
|
||||
|
@ -98,10 +100,10 @@ namespace cfg
|
|||
std::string ProcessedThemeResource(ProcessedTheme &base, std::string resource_base);
|
||||
ProcessedTheme ProcessTheme(Theme &base);
|
||||
|
||||
MenuConfig CreateNewAndLoadConfig();
|
||||
MenuConfig LoadConfig();
|
||||
MenuConfig EnsureConfig();
|
||||
void SaveConfig(MenuConfig &cfg);
|
||||
Config CreateNewAndLoadConfig();
|
||||
Config LoadConfig();
|
||||
Config EnsureConfig();
|
||||
void SaveConfig(Config &cfg);
|
||||
|
||||
void SaveRecord(TitleRecord &record);
|
||||
bool MoveRecordTo(TitleList &list, TitleRecord record, std::string folder);
|
||||
|
|
|
@ -31,6 +31,8 @@ using JSON = nlohmann::json;
|
|||
#error uLaunch's release version isn't defined.
|
||||
#endif
|
||||
|
||||
static constexpr size_t RawRGBAScreenBufferSize = 1280 * 720 * 4;
|
||||
|
||||
// Thanks SciresM
|
||||
#define R_TRY(res_expr) \
|
||||
({ \
|
||||
|
|
|
@ -206,31 +206,33 @@ namespace cfg
|
|||
return processed;
|
||||
}
|
||||
|
||||
MenuConfig CreateNewAndLoadConfig()
|
||||
Config CreateNewAndLoadConfig()
|
||||
{
|
||||
MenuConfig cfg = {};
|
||||
Config cfg = {};
|
||||
cfg.system_title_override_enabled = false; // Due to ban risk, have it disabled by default.
|
||||
SaveConfig(cfg);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
MenuConfig LoadConfig()
|
||||
Config LoadConfig()
|
||||
{
|
||||
MenuConfig cfg = {};
|
||||
Config cfg = {};
|
||||
auto [rc, cfgjson] = util::LoadJSONFromFile(CFG_CONFIG_JSON);
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
cfg.theme_name = cfgjson.value("theme_name", "");
|
||||
cfg.system_title_override_enabled = cfgjson.value("system_title_override_enabled", false);
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
MenuConfig EnsureConfig()
|
||||
Config EnsureConfig()
|
||||
{
|
||||
if(!fs::ExistsFile(CFG_CONFIG_JSON)) return CreateNewAndLoadConfig();
|
||||
return LoadConfig();
|
||||
}
|
||||
|
||||
void SaveConfig(MenuConfig &cfg)
|
||||
void SaveConfig(Config &cfg)
|
||||
{
|
||||
fs::DeleteFile(CFG_CONFIG_JSON);
|
||||
JSON j = JSON::object();
|
||||
|
|
|
@ -22,20 +22,28 @@ namespace ui
|
|||
void logo_Click();
|
||||
void settings_Click();
|
||||
void themes_Click();
|
||||
void users_Click();
|
||||
void web_Click();
|
||||
void MoveFolder(std::string name, bool fade);
|
||||
void OnInput(u64 down, u64 up, u64 held, pu::ui::Touch pos);
|
||||
|
||||
void SetUser(u128 user);
|
||||
bool HandleFolderChange(cfg::TitleRecord &rec);
|
||||
void HandleCloseSuspended();
|
||||
void HandleHomebrewLaunch(cfg::TitleRecord &rec);
|
||||
void HandleUserMenu();
|
||||
void HandleWebPageOpen();
|
||||
void HandleSettingsMenu();
|
||||
void HandleThemesMenu();
|
||||
private:
|
||||
void *susptr;
|
||||
bool last_hasconn;
|
||||
u32 last_batterylvl;
|
||||
bool last_charge;
|
||||
pu::ui::elm::Image::Ref topMenuImage;
|
||||
ClickableImage::Ref logo;
|
||||
pu::ui::elm::Image::Ref connIcon;
|
||||
ClickableImage::Ref users;
|
||||
ClickableImage::Ref web;
|
||||
ClickableImage::Ref logo;
|
||||
pu::ui::elm::TextBlock::Ref timeText;
|
||||
pu::ui::elm::TextBlock::Ref batteryText;
|
||||
pu::ui::elm::Image::Ref batteryIcon;
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 312 B |
Binary file not shown.
Before Width: | Height: | Size: 319 B After Width: | Height: | Size: 308 B |
BIN
LibraryAppletQMenu/RomFs/default/ui/WebIcon.png
Normal file
BIN
LibraryAppletQMenu/RomFs/default/ui/WebIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -17,7 +17,7 @@ extern "C"
|
|||
ui::QMenuApplication::Ref qapp;
|
||||
cfg::TitleList list;
|
||||
std::vector<cfg::TitleRecord> homebrew;
|
||||
cfg::MenuConfig config;
|
||||
cfg::Config config;
|
||||
cfg::ProcessedTheme theme;
|
||||
|
||||
namespace qmenu
|
||||
|
@ -68,7 +68,7 @@ int main()
|
|||
auto [rc, smode] = am::QMenu_ProcessInput();
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
app_buf = new u8[1280 * 720 * 4]();
|
||||
app_buf = new u8[RawRGBAScreenBufferSize]();
|
||||
qmenu::Initialize(smode == am::QMenuStartMode::StartupScreen); // Cache homebrew only on first launch
|
||||
auto [_rc, menulist] = cfg::LoadTitleList(true);
|
||||
list = menulist;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <ui/ui_MenuLayout.hpp>
|
||||
#include <os/os_Titles.hpp>
|
||||
#include <os/os_Account.hpp>
|
||||
#include <util/util_Convert.hpp>
|
||||
#include <util/util_Misc.hpp>
|
||||
#include <ui/ui_QMenuApplication.hpp>
|
||||
|
@ -9,7 +10,7 @@
|
|||
extern ui::QMenuApplication::Ref qapp;
|
||||
extern cfg::TitleList list;
|
||||
extern std::vector<cfg::TitleRecord> homebrew;
|
||||
extern cfg::MenuConfig config;
|
||||
extern cfg::Config config;
|
||||
extern cfg::ProcessedTheme theme;
|
||||
|
||||
namespace ui
|
||||
|
@ -40,8 +41,16 @@ namespace ui
|
|||
this->logo->SetHeight(60);
|
||||
this->logo->SetOnClick(std::bind(&MenuLayout::logo_Click, this));
|
||||
this->Add(this->logo);
|
||||
|
||||
this->connIcon = pu::ui::elm::Image::New(80, 53, cfg::ProcessedThemeResource(theme, "ui/NoConnectionIcon.png"));
|
||||
this->Add(this->connIcon);
|
||||
this->users = ClickableImage::New(270, 53, ""); // On layout creation, no user is still selected...
|
||||
this->users->SetOnClick(std::bind(&MenuLayout::users_Click, this));
|
||||
this->Add(this->users);
|
||||
this->web = ClickableImage::New(340, 53, cfg::ProcessedThemeResource(theme, "ui/WebIcon.png"));
|
||||
this->web->SetOnClick(std::bind(&MenuLayout::web_Click, this));
|
||||
this->Add(this->web);
|
||||
|
||||
auto curtime = util::GetCurrentTime();
|
||||
this->timeText = pu::ui::elm::TextBlock::New(515, 68, curtime);
|
||||
this->timeText->SetColor(textclr);
|
||||
|
@ -57,7 +66,6 @@ namespace ui
|
|||
this->settings = ClickableImage::New(880, 53, cfg::ProcessedThemeResource(theme, "ui/SettingsIcon.png"));
|
||||
this->settings->SetOnClick(std::bind(&MenuLayout::settings_Click, this));
|
||||
this->Add(this->settings);
|
||||
|
||||
this->themes = ClickableImage::New(950, 53, cfg::ProcessedThemeResource(theme, "ui/ThemesIcon.png"));
|
||||
this->themes->SetOnClick(std::bind(&MenuLayout::themes_Click, this));
|
||||
this->Add(this->themes);
|
||||
|
@ -503,28 +511,18 @@ namespace ui
|
|||
{
|
||||
if(!this->curfolder.empty()) this->MoveFolder("", true);
|
||||
}
|
||||
else if(down & KEY_MINUS)
|
||||
{
|
||||
SwkbdConfig swkbd;
|
||||
swkbdCreate(&swkbd, 0);
|
||||
swkbdConfigSetHeaderText(&swkbd, "Enter web page URL");
|
||||
char url[500] = {0};
|
||||
auto rc = swkbdShow(&swkbd, url, 500);
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
WebCommonConfig web = {};
|
||||
webPageCreate(&web, url);
|
||||
webConfigSetWhitelist(&web, ".*");
|
||||
else if(down & KEY_UP) this->menuToggle_Click();
|
||||
else if(down & KEY_ZL) this->HandleUserMenu();
|
||||
else if(down & KEY_L) this->HandleWebPageOpen();
|
||||
else if(down & KEY_R) this->HandleSettingsMenu();
|
||||
else if(down & KEY_ZR) this->HandleThemesMenu();
|
||||
}
|
||||
|
||||
am::QMenuCommandWriter writer(am::QDaemonMessage::OpenWebPage);
|
||||
writer.Write<WebCommonConfig>(web);
|
||||
writer.FinishWrite();
|
||||
|
||||
qapp->StopPlayBGM();
|
||||
qapp->CloseWithFadeOut();
|
||||
return;
|
||||
}
|
||||
}
|
||||
void MenuLayout::SetUser(u128 user)
|
||||
{
|
||||
this->users->SetImage(os::GetIconCacheImagePath(user));
|
||||
this->users->SetWidth(50);
|
||||
this->users->SetHeight(50);
|
||||
}
|
||||
|
||||
void MenuLayout::menuToggle_Click()
|
||||
|
@ -541,12 +539,22 @@ namespace ui
|
|||
|
||||
void MenuLayout::settings_Click()
|
||||
{
|
||||
qapp->CreateShowDialog("Settings", "Settings", {"Ok"}, true);
|
||||
this->HandleSettingsMenu();
|
||||
}
|
||||
|
||||
void MenuLayout::themes_Click()
|
||||
{
|
||||
qapp->CreateShowDialog("Themes", "Themes", {"Ok"}, true);
|
||||
this->HandleThemesMenu();
|
||||
}
|
||||
|
||||
void MenuLayout::users_Click()
|
||||
{
|
||||
this->HandleUserMenu();
|
||||
}
|
||||
|
||||
void MenuLayout::web_Click()
|
||||
{
|
||||
this->HandleWebPageOpen();
|
||||
}
|
||||
|
||||
bool MenuLayout::HandleFolderChange(cfg::TitleRecord &rec)
|
||||
|
@ -607,24 +615,66 @@ namespace ui
|
|||
}
|
||||
else if(sopt == 1)
|
||||
{
|
||||
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchHomebrewApplication);
|
||||
writer.Write<hb::TargetInput>(rec.nro_target);
|
||||
writer.FinishWrite();
|
||||
if(config.system_title_override_enabled)
|
||||
{
|
||||
am::QMenuCommandWriter writer(am::QDaemonMessage::LaunchHomebrewApplication);
|
||||
writer.Write<hb::TargetInput>(rec.nro_target);
|
||||
writer.FinishWrite();
|
||||
|
||||
am::QMenuCommandResultReader reader;
|
||||
if(reader && R_SUCCEEDED(reader.GetReadResult()))
|
||||
{
|
||||
pu::audio::Play(this->sfxTitleLaunch);
|
||||
qapp->StopPlayBGM();
|
||||
qapp->CloseWithFadeOut();
|
||||
return;
|
||||
am::QMenuCommandResultReader reader;
|
||||
if(reader && R_SUCCEEDED(reader.GetReadResult()))
|
||||
{
|
||||
pu::audio::Play(this->sfxTitleLaunch);
|
||||
qapp->StopPlayBGM();
|
||||
qapp->CloseWithFadeOut();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto rc = reader.GetReadResult();
|
||||
qapp->CreateShowDialog("Title launch", "An error ocurred attempting to launch the title:\n" + util::FormatResultDisplay(rc) + " (" + util::FormatResultHex(rc) + ")", { "Ok" }, true);
|
||||
}
|
||||
reader.FinishRead();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto rc = reader.GetReadResult();
|
||||
qapp->CreateShowDialog("Title launch", "An error ocurred attempting to launch the title:\n" + util::FormatResultDisplay(rc) + " (" + util::FormatResultHex(rc) + ")", { "Ok" }, true);
|
||||
}
|
||||
reader.FinishRead();
|
||||
else qapp->CreateShowDialog("Title launch", "System title launching (via flog) is disabled.\nYou can enable it in settings.\n\nNote that this system (unlike title override) could involve ban risk!\nUse it at your own risk.", { "Ok" }, true);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuLayout::HandleUserMenu()
|
||||
{
|
||||
qapp->CreateShowDialog("Users", "Users", {"Ok"}, true);
|
||||
}
|
||||
|
||||
void MenuLayout::HandleWebPageOpen()
|
||||
{
|
||||
SwkbdConfig swkbd;
|
||||
swkbdCreate(&swkbd, 0);
|
||||
swkbdConfigSetHeaderText(&swkbd, "Enter web page URL");
|
||||
char url[500] = {0};
|
||||
auto rc = swkbdShow(&swkbd, url, 500);
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
WebCommonConfig web = {};
|
||||
webPageCreate(&web, url);
|
||||
webConfigSetWhitelist(&web, ".*");
|
||||
|
||||
am::QMenuCommandWriter writer(am::QDaemonMessage::OpenWebPage);
|
||||
writer.Write<WebCommonConfig>(web);
|
||||
writer.FinishWrite();
|
||||
|
||||
qapp->StopPlayBGM();
|
||||
qapp->CloseWithFadeOut();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MenuLayout::HandleSettingsMenu()
|
||||
{
|
||||
qapp->CreateShowDialog("Settings", "Settings", {"Ok"}, true);
|
||||
}
|
||||
|
||||
void MenuLayout::HandleThemesMenu()
|
||||
{
|
||||
qapp->CreateShowDialog("Themes", "Themes", {"Ok"}, true);
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ namespace ui
|
|||
if(this->IsSuspended())
|
||||
{
|
||||
bool flag;
|
||||
appletGetLastApplicationCaptureImageEx(app_buf, 1280 * 720 * 4, &flag);
|
||||
appletGetLastApplicationCaptureImageEx(app_buf, RawRGBAScreenBufferSize, &flag);
|
||||
}
|
||||
|
||||
auto [_rc, jui] = util::LoadJSONFromFile(cfg::ProcessedThemeResource(theme, "ui/UI.json"));
|
||||
|
@ -45,8 +45,17 @@ namespace ui
|
|||
case am::QMenuStartMode::Menu:
|
||||
case am::QMenuStartMode::MenuApplicationSuspended:
|
||||
case am::QMenuStartMode::MenuLaunchFailure:
|
||||
{
|
||||
// Returned from applet/title, QDaemon has the user but we don't, so...
|
||||
am::QMenuCommandWriter writer(am::QDaemonMessage::GetSelectedUser);
|
||||
writer.FinishWrite();
|
||||
am::QMenuCommandResultReader res;
|
||||
this->selected_user = res.Read<u128>();
|
||||
res.FinishRead();
|
||||
|
||||
this->LoadMenu();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this->LoadLayout(this->startupLayout);
|
||||
break;
|
||||
|
@ -60,6 +69,7 @@ namespace ui
|
|||
|
||||
void QMenuApplication::LoadMenu()
|
||||
{
|
||||
this->menuLayout->SetUser(this->selected_user);
|
||||
this->LoadLayout(this->menuLayout);
|
||||
this->StartPlayBGM();
|
||||
}
|
||||
|
|
|
@ -16,11 +16,11 @@ namespace QForegroundViewer
|
|||
|
||||
public byte[][] CaptureBackups = new byte[][]
|
||||
{
|
||||
new byte[1280 * 720 * 4], // Backups (5) so that new captures made by the main form don't replace old ones
|
||||
new byte[1280 * 720 * 4],
|
||||
new byte[1280 * 720 * 4],
|
||||
new byte[1280 * 720 * 4],
|
||||
new byte[1280 * 720 * 4],
|
||||
new byte[ViewerMainForm.RawRGBAScreenBufferSize], // Backups (5) so that new captures made by the main form don't replace old ones
|
||||
new byte[ViewerMainForm.RawRGBAScreenBufferSize],
|
||||
new byte[ViewerMainForm.RawRGBAScreenBufferSize],
|
||||
new byte[ViewerMainForm.RawRGBAScreenBufferSize],
|
||||
new byte[ViewerMainForm.RawRGBAScreenBufferSize],
|
||||
};
|
||||
|
||||
public ScreenshotForm(ViewerMainForm main)
|
||||
|
|
|
@ -16,14 +16,16 @@ namespace QForegroundViewer
|
|||
private UsbK USB;
|
||||
private Thread USBThread;
|
||||
|
||||
public const long RawRGBAScreenBufferSize = 1280 * 720 * 4;
|
||||
|
||||
public byte[][] CaptureBlocks = new byte[][]
|
||||
{
|
||||
new byte[1280 * 720 * 4], // Current block
|
||||
new byte[1280 * 720 * 4], // Temporary blocks (5)
|
||||
new byte[1280 * 720 * 4],
|
||||
new byte[1280 * 720 * 4],
|
||||
new byte[1280 * 720 * 4],
|
||||
new byte[1280 * 720 * 4],
|
||||
new byte[RawRGBAScreenBufferSize], // Current block
|
||||
new byte[RawRGBAScreenBufferSize], // Temporary blocks (5)
|
||||
new byte[RawRGBAScreenBufferSize],
|
||||
new byte[RawRGBAScreenBufferSize],
|
||||
new byte[RawRGBAScreenBufferSize],
|
||||
new byte[RawRGBAScreenBufferSize],
|
||||
};
|
||||
|
||||
public ViewerMainForm()
|
||||
|
|
12
README.md
12
README.md
|
@ -72,6 +72,8 @@ uLaunch is split, as mentioned above, into several sub-projects:
|
|||
|
||||
### QDaemon (SystemAppletQDaemon)
|
||||
|
||||
> This sub-project replaces qlaunch, aka title 0100000000001000.
|
||||
|
||||
This is the technically actual qlaunch reimplementation. However, to avoid memory issues it does not use any kind of UI (except console for development debug, which is removed for releases), and thus it uses 16MB of heap, while official HOME menu uses 56MB.
|
||||
|
||||
Instead, it uses [QMenu custom library applet](#qmenu-libraryappletqmenu) (launches and communicates with it) in order to display a proper menu UI.
|
||||
|
@ -82,6 +84,8 @@ But, if all the functionality is handled by QMenu, why is this daemon process ne
|
|||
|
||||
### QMenu (LibraryAppletQMenu)
|
||||
|
||||
> This sub-project replaces eShop applet, aka title 010000000000100B.
|
||||
|
||||
This is the HOME menu the user will see and interact with. It contains all the UI and sounc functionality, password, themes...
|
||||
|
||||
### QHbTarget
|
||||
|
@ -90,10 +94,14 @@ This is the name for two related projects, whose aim is to target and launch hom
|
|||
|
||||
#### System application (SystemApplicationQHbTarget)
|
||||
|
||||
> This sub-project replaces flog system application, aka title 01008BB00013C000.
|
||||
|
||||
This is the process which runs instead of flog, which is used to launch homebrew as applications.
|
||||
|
||||
#### Library applet (LibraryAppletQHbTarget)
|
||||
|
||||
> This sub-project replaces Mii applet, aka title 010000000000100B.
|
||||
|
||||
This is the same process but, like in normal HOME menu and Album, it runs homebrew as an applet. However, exiting homebrew here will exit to HOME menu instead of exiting to hbmenu.
|
||||
|
||||
### QForegroundViewer
|
||||
|
@ -136,4 +144,6 @@ If you get a crash using uLaunch, please check:
|
|||
|
||||
- SciresM for [libstratosphere](https://github.com/Atmosphere-NX/libstratosphere).
|
||||
|
||||
- Switchbrew team for libnx and [hbloader](https://github.com/switchbrew/nx-hbloader), the base of *QHbTarget projects (they're some useful wrappers of hbloader in the end)
|
||||
- Switchbrew team for libnx and [hbloader](https://github.com/switchbrew/nx-hbloader), the base of *QHbTarget projects (they're some useful wrappers of hbloader in the end)
|
||||
|
||||
- [Icons8](https://icons8.com/) website for a big part of the icons used by the default style.
|
|
@ -262,6 +262,16 @@ void HandleQMenuMessage()
|
|||
|
||||
break;
|
||||
}
|
||||
case am::QDaemonMessage::GetSelectedUser:
|
||||
{
|
||||
reader.FinishRead();
|
||||
|
||||
am::QDaemonCommandResultWriter res(0);
|
||||
res.Write<u128>(selected_uid);
|
||||
res.FinishWrite();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -273,7 +283,7 @@ namespace qdaemon
|
|||
{
|
||||
void Initialize()
|
||||
{
|
||||
app_buf = new u8[1280 * 720 * 4]();
|
||||
app_buf = new u8[RawRGBAScreenBufferSize]();
|
||||
fs::CreateDirectory(Q_BASE_SD_DIR);
|
||||
|
||||
// Debug testing mode
|
||||
|
@ -340,15 +350,15 @@ namespace qdaemon
|
|||
|
||||
void ForegroundMain(void *arg)
|
||||
{
|
||||
u8 *demo = new (std::align_val_t(0x1000)) u8[1280 * 720 * 4]();
|
||||
u8 *demo = new (std::align_val_t(0x1000)) u8[RawRGBAScreenBufferSize]();
|
||||
|
||||
usbCommsInitialize();
|
||||
while(true)
|
||||
{
|
||||
appletUpdateLastForegroundCaptureImage();
|
||||
bool tmp;
|
||||
appletGetLastForegroundCaptureImageEx(demo, 1280 * 720 * 4, &tmp);
|
||||
usbCommsWrite(demo, 1280 * 720 * 4);
|
||||
appletGetLastForegroundCaptureImageEx(demo, RawRGBAScreenBufferSize, &tmp);
|
||||
usbCommsWrite(demo, RawRGBAScreenBufferSize);
|
||||
}
|
||||
usbCommsExit();
|
||||
delete[] demo;
|
||||
|
|
Loading…
Add table
Reference in a new issue