add support for replacing the homebrew menu tab with another menu.

This commit is contained in:
ITotalJustice
2025-10-03 09:58:48 +01:00
parent 81e6bc5833
commit da051f8d8f
7 changed files with 87 additions and 9 deletions

View File

@@ -304,6 +304,7 @@ public:
option::OptionBool m_theme_music{INI_SECTION, "theme_music", true};
option::OptionBool m_show_ip_addr{INI_SECTION, "show_ip_addr", true};
option::OptionLong m_language{INI_SECTION, "language", 0}; // auto
option::OptionString m_center_menu{INI_SECTION, "center_side_menu", "Homebrew"};
option::OptionString m_left_menu{INI_SECTION, "left_side_menu", "FileBrowser"};
option::OptionString m_right_menu{INI_SECTION, "right_side_menu", "Appstore"};
option::OptionBool m_progress_boost_mode{INI_SECTION, "progress_boost_mode", true};

View File

@@ -7,6 +7,7 @@
#include "fs.hpp"
#include "option.hpp"
#include "hasher.hpp"
#include "nro.hpp"
#include <span>
namespace sphaira::ui::menu::filebrowser {
@@ -479,6 +480,15 @@ protected:
std::vector<std::string> m_filter{};
// local copy of nro entries that is loaded in LoadAssocEntriesPath()
// if homebrew::GetNroEntries() returns nothing, usually due to
// the menu not being loaded.
// this is a bit of a hack to support replacing the homebrew menu tab,
// sphaira wasn't really designed for this.
// however this will work for now, until i add support for additional
// nro scan mounts, at which point this won't scale.
std::vector<NroEntry> m_nro_entries{};
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_Alphabetical};
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending};
option::OptionBool m_show_hidden{INI_SECTION, "show_hidden", false};

View File

@@ -34,7 +34,7 @@ auto GetNroEntries() -> std::span<const NroEntry>;
void SignalChange();
struct Menu final : grid::Menu {
Menu();
Menu(u32 flags);
~Menu();
auto GetShortTitle() const -> const char* override { return "Apps"; };

View File

@@ -1506,6 +1506,7 @@ App::App(const char* argv0) {
else if (app->m_theme_music.LoadFrom(Key, Value)) {}
else if (app->m_show_ip_addr.LoadFrom(Key, Value)) {}
else if (app->m_language.LoadFrom(Key, Value)) {}
else if (app->m_center_menu.LoadFrom(Key, Value)) {}
else if (app->m_left_menu.LoadFrom(Key, Value)) {}
else if (app->m_right_menu.LoadFrom(Key, Value)) {}
else if (app->m_install_sysmmc.LoadFrom(Key, Value)) {}
@@ -1989,7 +1990,9 @@ void App::DisplayMenuOptions(bool left_side) {
ON_SCOPE_EXIT(App::Push(std::move(options)));
for (auto& e : ui::menu::main::GetMenuMenuEntries()) {
if (e.name == g_app->m_left_menu.Get()) {
if (e.name == g_app->m_center_menu.Get()) {
continue;
} else if (e.name == g_app->m_left_menu.Get()) {
continue;
} else if (e.name == g_app->m_right_menu.Get()) {
continue;
@@ -2078,11 +2081,33 @@ void App::DisplayAdvancedOptions(bool left_side) {
App::SetTextScrollSpeed(index_out);
}, App::GetTextScrollSpeed(), "Change how fast the scrolling text updates"_i18n);
options->Add<ui::SidebarEntryArray>("Set center menu"_i18n, menu_items, [menu_names](s64& index_out){
const auto e = menu_names[index_out];
if (g_app->m_center_menu.Get() != e) {
// swap menus around.
if (g_app->m_left_menu.Get() == e) {
g_app->m_left_menu.Set(g_app->m_left_menu.Get());
} else if (g_app->m_right_menu.Get() == e) {
g_app->m_right_menu.Set(g_app->m_left_menu.Get());
}
g_app->m_center_menu.Set(e);
App::Push<ui::OptionBox>(
"Press OK to restart Sphaira"_i18n, "OK"_i18n, [](auto){
App::ExitRestart();
}
);
}
}, i18n::get(g_app->m_center_menu.Get()), "Set the menu that appears on the center tab."_i18n);
options->Add<ui::SidebarEntryArray>("Set left-side menu"_i18n, menu_items, [menu_names](s64& index_out){
const auto e = menu_names[index_out];
if (g_app->m_left_menu.Get() != e) {
// swap menus around.
if (g_app->m_right_menu.Get() == e) {
if (g_app->m_center_menu.Get() == e) {
g_app->m_center_menu.Set(g_app->m_left_menu.Get());
} else if (g_app->m_right_menu.Get() == e) {
g_app->m_right_menu.Set(g_app->m_left_menu.Get());
}
g_app->m_left_menu.Set(e);
@@ -2099,7 +2124,9 @@ void App::DisplayAdvancedOptions(bool left_side) {
const auto e = menu_names[index_out];
if (g_app->m_right_menu.Get() != e) {
// swap menus around.
if (g_app->m_left_menu.Get() == e) {
if (g_app->m_center_menu.Get() == e) {
g_app->m_center_menu.Set(g_app->m_right_menu.Get());
} else if (g_app->m_left_menu.Get() == e) {
g_app->m_left_menu.Set(g_app->m_right_menu.Get());
}
g_app->m_right_menu.Set(e);

View File

@@ -2110,8 +2110,16 @@ void Base::LoadAssocEntriesPath(const fs::FsPath& path) {
if (!assoc.path.empty()) {
file_exists = view->m_fs->FileExists(assoc.path);
} else {
auto nros = homebrew::GetNroEntries();
if (nros.empty()) {
if (m_nro_entries.empty()) {
nro_scan("/switch", m_nro_entries);
nros = m_nro_entries;
}
}
const auto nro_name = assoc.name + ".nro";
for (const auto& nro : homebrew::GetNroEntries()) {
for (const auto& nro : nros) {
const auto len = std::strlen(nro.path);
if (len < nro_name.length()) {
continue;

View File

@@ -55,7 +55,7 @@ auto GetNroEntries() -> std::span<const NroEntry> {
return g_menu->GetHomebrewList();
}
Menu::Menu() : grid::Menu{"Homebrew"_i18n, MenuFlag_Tab} {
Menu::Menu(u32 flags) : grid::Menu{"Homebrew"_i18n, flags} {
g_menu = this;
this->SetActions(

View File

@@ -49,6 +49,10 @@ auto MiscMenuFuncGenerator(u32 flags) {
}
const MiscMenuEntry MISC_MENU_ENTRIES[] = {
{ .name = "Homebrew", .title = "Homebrew", .func = MiscMenuFuncGenerator<ui::menu::homebrew::Menu>, .flag = MiscMenuFlag_Shortcut, .info =
"The homebrew menu.\n\n"
"Allows you to launch, delete and mount homebrew!"},
{ .name = "Appstore", .title = "Appstore", .func = MiscMenuFuncGenerator<ui::menu::appstore::Menu>, .flag = MiscMenuFlag_Shortcut, .info =
"Download and update apps.\n\n"
"Internet connection required." },
@@ -163,9 +167,34 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
R_SUCCEED();
}
auto CreateLeftSideMenu(std::string& name_out) -> std::unique_ptr<MenuBase> {
auto CreateCenterMenu(std::string& name_out) -> std::unique_ptr<MenuBase> {
const auto name = App::GetApp()->m_center_menu.Get();
for (auto& e : GetMenuMenuEntries()) {
if (e.name == name) {
name_out = name;
return e.func(MenuFlag_Tab);
}
}
name_out = "Homebrew";
return std::make_unique<ui::menu::homebrew::Menu>(MenuFlag_Tab);
}
auto CreateLeftSideMenu(std::string_view center_name, std::string& name_out) -> std::unique_ptr<MenuBase> {
const auto name = App::GetApp()->m_left_menu.Get();
// handle if the user tries to mount the same menu twice.
if (name == center_name) {
// check if we can mount the default.
if (center_name != "FileBrowser") {
return std::make_unique<ui::menu::filebrowser::Menu>(MenuFlag_Tab);
} else {
// otherwise, fallback to center default.
return std::make_unique<ui::menu::homebrew::Menu>(MenuFlag_Tab);
}
}
for (auto& e : GetMenuMenuEntries()) {
if (e.name == name) {
name_out = name;
@@ -177,6 +206,7 @@ auto CreateLeftSideMenu(std::string& name_out) -> std::unique_ptr<MenuBase> {
return std::make_unique<ui::menu::filebrowser::Menu>(MenuFlag_Tab);
}
// todo: handle center / left menu being the same.
auto CreateRightSideMenu(std::string_view left_name) -> std::unique_ptr<MenuBase> {
const auto name = App::GetApp()->m_right_menu.Get();
@@ -378,11 +408,13 @@ MainMenu::MainMenu() {
}}
));
m_centre_menu = std::make_unique<homebrew::Menu>();
std::string center_name;
m_centre_menu = CreateCenterMenu(center_name);
m_current_menu = m_centre_menu.get();
std::string left_side_name;
m_left_menu = CreateLeftSideMenu(left_side_name);
m_left_menu = CreateLeftSideMenu(center_name, left_side_name);
m_right_menu = CreateRightSideMenu(left_side_name);
AddOnLRPress();