simplify right-side shortcuts impl, add gamecard and themezer to shortcut list, fix l2/r2 using wrong icons, sort l2/r2 so l2 displays first.

some other changes:
- shorten the next page and prev page to just next/prev in themezer.
- remove misc shortcut name. the function itself still exists.
This commit is contained in:
ITotalJustice
2025-05-03 14:39:20 +01:00
parent df5e27dd06
commit 16a2c84edd
8 changed files with 108 additions and 70 deletions

View File

@@ -46,6 +46,7 @@ struct Menu final : MenuBase {
auto GetShortTitle() const -> const char* override { return "GC"; };
void Update(Controller* controller, TouchInfo* touch) override;
void Draw(NVGcontext* vg, Theme* theme) override;
void OnFocusGained() override;
private:
Result GcMount();

View File

@@ -17,6 +17,32 @@ enum class UpdateState {
Error,
};
using MiscMenuFunction = std::function<std::shared_ptr<ui::menu::MenuBase>(void)>;
enum MiscMenuFlag : u8 {
// can be set as the rightside menu.
MiscMenuFlag_Shortcut = 1 << 0,
// needs install option to be enabled.
MiscMenuFlag_Install = 1 << 1,
};
struct MiscMenuEntry {
const char* name;
const char* title;
MiscMenuFunction func;
u8 flag;
auto IsShortcut() const -> bool {
return flag & MiscMenuFlag_Shortcut;
}
auto IsInstall() const -> bool {
return flag & MiscMenuFlag_Install;
}
};
auto GetMiscMenuEntries() -> std::span<const MiscMenuEntry>;
// this holds 2 menus and allows for switching between them
struct MainMenu final : Widget {
MainMenu();

View File

@@ -7,14 +7,6 @@
#include "ui/error_box.hpp"
#include "ui/menus/main_menu.hpp"
#include "ui/menus/irs_menu.hpp"
#include "ui/menus/themezer.hpp"
#include "ui/menus/ghdl.hpp"
#include "ui/menus/usb_menu.hpp"
#include "ui/menus/ftp_menu.hpp"
#include "ui/menus/gc_menu.hpp"
#include "ui/menus/game_menu.hpp"
#include "ui/menus/appstore.hpp"
#include "app.hpp"
#include "log.hpp"
@@ -1520,24 +1512,19 @@ void App::DisplayMiscOptions(bool left_side) {
auto options = std::make_shared<ui::Sidebar>("Misc Options"_i18n, left_side ? ui::Sidebar::Side::LEFT : ui::Sidebar::Side::RIGHT);
ON_SCOPE_EXIT(App::Push(options));
const auto push_if_not_same = [&]<typename T>(const char* name, const char* title){
if (g_app->m_right_side_menu.Get() != name) {
options->Add(std::make_shared<ui::SidebarEntryCallback>(i18n::get(title), [](){
App::Push(std::make_shared<T>());
}));
for (auto& e : ui::menu::main::GetMiscMenuEntries()) {
if (e.name == g_app->m_right_side_menu.Get()) {
continue;
}
};
push_if_not_same.template operator()<ui::menu::appstore::Menu>("Appstore", "Appstore");
push_if_not_same.template operator()<ui::menu::game::Menu>("Games", "Games");
push_if_not_same.template operator()<ui::menu::themezer::Menu>("Themezer", "Themezer");
push_if_not_same.template operator()<ui::menu::gh::Menu>("GitHub", "GitHub");
if (App::GetInstallEnable()) {
push_if_not_same.template operator()<ui::menu::ftp::Menu>("FTP", "FTP Install");
push_if_not_same.template operator()<ui::menu::usb::Menu>("USB", "USB Install");
push_if_not_same.template operator()<ui::menu::gc::Menu>("GameCard", "GameCard Install");
if (e.IsInstall() && !App::GetInstallEnable()) {
continue;
}
options->Add(std::make_shared<ui::SidebarEntryCallback>(i18n::get(e.title), [e](){
App::Push(e.func());
}));
}
push_if_not_same.template operator()<ui::menu::irs::Menu>("IRS", "IRS (Infrared Joycon Camera)");
}
void App::DisplayAdvancedOptions(bool left_side) {
@@ -1549,12 +1536,18 @@ void App::DisplayAdvancedOptions(bool left_side) {
text_scroll_speed_items.push_back("Normal"_i18n);
text_scroll_speed_items.push_back("Fast"_i18n);
static constexpr std::array menu_names{
"Appstore",
"Games",
"GitHub",
"IRS",
};
std::vector<const char*> menu_names;
for (auto& e : ui::menu::main::GetMiscMenuEntries()) {
if (!e.IsShortcut()) {
continue;
}
if (e.IsInstall() && !App::GetInstallEnable()) {
continue;
}
menu_names.emplace_back(e.name);
}
ui::SidebarEntryArray::Items right_side_menu_items;
for (auto& str : menu_names) {
@@ -1578,7 +1571,7 @@ void App::DisplayAdvancedOptions(bool left_side) {
App::SetTextScrollSpeed(index_out);
}, App::GetTextScrollSpeed()));
options->Add(std::make_shared<ui::SidebarEntryArray>("Set right-side menu"_i18n, right_side_menu_items, [](s64& index_out){
options->Add(std::make_shared<ui::SidebarEntryArray>("Set right-side menu"_i18n, right_side_menu_items, [menu_names](s64& index_out){
const auto e = menu_names[index_out];
if (g_app->m_right_side_menu.Get() != e) {
g_app->m_right_side_menu.Set(e);

View File

@@ -184,8 +184,6 @@ Menu::Menu() : MenuBase{"GameCard"_i18n} {
fsOpenDeviceOperator(std::addressof(m_dev_op));
fsOpenGameCardDetectionEventNotifier(std::addressof(m_event_notifier));
fsEventNotifierGetEventHandle(std::addressof(m_event_notifier), std::addressof(m_event), true);
GcOnEvent();
UpdateStorageSize();
}
Menu::~Menu() {
@@ -269,6 +267,13 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
});
}
void Menu::OnFocusGained() {
MenuBase::OnFocusGained();
GcOnEvent();
UpdateStorageSize();
}
Result Menu::GcMount() {
GcUnmount();
@@ -391,20 +396,18 @@ Result Menu::GcMount() {
} else {
App::Notify("Gc install failed!"_i18n);
}
UpdateStorageSize();
}));
}
}
}});
if (m_entries.size() > 1) {
SetAction(Button::L, Action{"Prev"_i18n, [this](){
SetAction(Button::L2, Action{"Prev"_i18n, [this](){
if (m_entry_index != 0) {
OnChangeIndex(m_entry_index - 1);
}
}});
SetAction(Button::R, Action{"Next"_i18n, [this](){
SetAction(Button::R2, Action{"Next"_i18n, [this](){
if (m_entry_index < m_entries.size()) {
OnChangeIndex(m_entry_index + 1);
}
@@ -424,8 +427,8 @@ void Menu::GcUnmount() {
m_lang_entry = {};
FreeImage();
RemoveAction(Button::L);
RemoveAction(Button::R);
RemoveAction(Button::L2);
RemoveAction(Button::R2);
}
Result Menu::GcPoll(bool* inserted) {

View File

@@ -31,6 +31,22 @@ namespace {
constexpr const char* GITHUB_URL{"https://api.github.com/repos/ITotalJustice/sphaira/releases/latest"};
constexpr fs::FsPath CACHE_PATH{"/switch/sphaira/cache/sphaira_latest.json"};
template<typename T>
auto MiscMenuFuncGenerator() {
return std::make_shared<T>();
}
const MiscMenuEntry MISC_MENU_ENTRIES[] = {
{ .name = "Appstore", .title = "Appstore", .func = MiscMenuFuncGenerator<ui::menu::appstore::Menu>, .flag = MiscMenuFlag_Shortcut },
{ .name = "Games", .title = "Games", .func = MiscMenuFuncGenerator<ui::menu::game::Menu>, .flag = MiscMenuFlag_Shortcut },
{ .name = "Themezer", .title = "Themezer", .func = MiscMenuFuncGenerator<ui::menu::themezer::Menu>, .flag = MiscMenuFlag_Shortcut },
{ .name = "GitHub", .title = "GitHub", .func = MiscMenuFuncGenerator<ui::menu::gh::Menu>, .flag = MiscMenuFlag_Shortcut },
{ .name = "FTP", .title = "FTP Install", .func = MiscMenuFuncGenerator<ui::menu::ftp::Menu>, .flag = MiscMenuFlag_Install },
{ .name = "USB", .title = "USB Install", .func = MiscMenuFuncGenerator<ui::menu::usb::Menu>, .flag = MiscMenuFlag_Install },
{ .name = "GameCard", .title = "GameCard Install", .func = MiscMenuFuncGenerator<ui::menu::gc::Menu>, .flag = MiscMenuFlag_Shortcut|MiscMenuFlag_Install },
{ .name = "IRS", .title = "IRS (Infrared Joycon Camera)", .func = MiscMenuFuncGenerator<ui::menu::irs::Menu>, .flag = MiscMenuFlag_Shortcut },
};
auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string version) -> bool {
static fs::FsPath zip_out{"/switch/sphaira/cache/update.zip"};
constexpr auto chunk_size = 1024 * 512; // 512KiB
@@ -151,22 +167,10 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
auto CreateRightSideMenu() -> std::shared_ptr<MenuBase> {
const auto name = App::GetApp()->m_right_side_menu.Get();
if ("Games" == name) {
return std::make_shared<ui::menu::game::Menu>();
}/*else if ("Themezer" == name) {
return std::make_shared<ui::menu::themezer::Menu>();
}*/else if ("GitHub" == name) {
return std::make_shared<ui::menu::gh::Menu>();
} else if ("IRS" == name) {
return std::make_shared<ui::menu::irs::Menu>();
} else if (App::GetInstallEnable()) {
// if ("FTP" == name) {
// return std::make_shared<ui::menu::ftp::Menu>();
// } else if ("USB" == name) {
// return std::make_shared<ui::menu::usb::Menu>();
// } else if ("GameCard" == name) {
// return std::make_shared<ui::menu::gc::Menu>();
// }
for (auto& e : GetMiscMenuEntries()) {
if (e.name == name) {
return e.func();
}
}
return std::make_shared<ui::menu::appstore::Menu>();
@@ -174,6 +178,10 @@ auto CreateRightSideMenu() -> std::shared_ptr<MenuBase> {
} // namespace
auto GetMiscMenuEntries() -> std::span<const MiscMenuEntry> {
return MISC_MENU_ENTRIES;
}
MainMenu::MainMenu() {
curl::Api().ToFileAsync(
curl::Url{GITHUB_URL},
@@ -241,9 +249,7 @@ MainMenu::MainMenu() {
this->SetActions(
std::make_pair(Button::START, Action{App::Exit}),
std::make_pair(Button::SELECT, Action{"Misc"_i18n, [this](){
App::DisplayMiscOptions();
}}),
std::make_pair(Button::SELECT, Action{App::DisplayMiscOptions}),
std::make_pair(Button::Y, Action{"Menu"_i18n, [this](){
auto options = std::make_shared<Sidebar>("Menu Options"_i18n, "v" APP_VERSION_HASH, Sidebar::Side::LEFT);
ON_SCOPE_EXIT(App::Push(options));

View File

@@ -453,7 +453,7 @@ Menu::Menu() : MenuBase{"Themezer"_i18n} {
}
}));
}}),
std::make_pair(Button::R, Action{"Next Page"_i18n, [this](){
std::make_pair(Button::R2, Action{"Next"_i18n, [this](){
m_page_index++;
if (m_page_index >= m_page_index_max) {
m_page_index = m_page_index_max - 1;
@@ -461,7 +461,7 @@ Menu::Menu() : MenuBase{"Themezer"_i18n} {
PackListDownload();
}
}}),
std::make_pair(Button::L, Action{"Prev Page"_i18n, [this](){
std::make_pair(Button::L2, Action{"Prev"_i18n, [this](){
if (m_page_index) {
m_page_index--;
PackListDownload();

View File

@@ -21,10 +21,8 @@ constexpr std::array buttons = {
std::pair{Button::Y, "\uE0E3"},
std::pair{Button::L, "\uE0E4"},
std::pair{Button::R, "\uE0E5"},
std::pair{Button::L, "\uE0E6"},
std::pair{Button::R, "\uE0E7"},
std::pair{Button::L2, "\uE0E8"},
std::pair{Button::R2, "\uE0E9"},
std::pair{Button::L2, "\uE0E6"},
std::pair{Button::R2, "\uE0E7"},
std::pair{Button::UP, "\uE0EB"},
std::pair{Button::DOWN, "\uE0EC"},
std::pair{Button::LEFT, "\uE0ED"},

View File

@@ -86,6 +86,11 @@ auto Widget::GetUiButtons() const -> uiButtons {
uiButtons draw_actions;
draw_actions.reserve(m_actions.size());
const std::pair<Button, Button> swap_buttons[] = {
{Button::L, Button::R},
{Button::L2, Button::R2},
};
// build array
for (const auto& [button, action] : m_actions) {
if (action.IsHidden() || action.m_hint.empty()) {
@@ -94,13 +99,19 @@ auto Widget::GetUiButtons() const -> uiButtons {
uiButton ui_button{button, action};
// swap
if (button == Button::R && draw_actions.size() && draw_actions.back().m_button == Button::L) {
const auto s = draw_actions.back();
draw_actions.back().m_button = button;
draw_actions.back().m_action = action;
draw_actions.emplace_back(s);
} else {
bool should_swap = false;
for (auto [left, right] : swap_buttons) {
if (button == right && draw_actions.size() && draw_actions.back().m_button == left) {
const auto s = draw_actions.back();
draw_actions.back().m_button = button;
draw_actions.back().m_action = action;
draw_actions.emplace_back(s);
should_swap = true;
break;
}
}
if (!should_swap) {
draw_actions.emplace_back(ui_button);
}
}