display install options by default, but warn the user that installing is disabled an instruct them on how to enable.

This commit is contained in:
ITotalJustice
2025-07-31 02:48:19 +01:00
parent 92d747a0f5
commit c67266fe1a
6 changed files with 98 additions and 45 deletions

View File

@@ -339,6 +339,10 @@ public:
double m_delta_time{}; double m_delta_time{};
static constexpr const char* INSTALL_DEPENDS_STR =
"Installing is disabled.\n\n"
"Enable in the options by selecting Menu (Y) -> Advanced -> Install options -> Enable.";
private: // from nanovg decko3d example by adubbz private: // from nanovg decko3d example by adubbz
static constexpr unsigned NumFramebuffers = 2; static constexpr unsigned NumFramebuffers = 2;
static constexpr unsigned StaticCmdSize = 0x1000; static constexpr unsigned StaticCmdSize = 0x1000;

View File

@@ -11,17 +11,46 @@
namespace sphaira::ui { namespace sphaira::ui {
class SidebarEntryBase : public Widget { class SidebarEntryBase : public Widget {
public:
using DependsCallback = std::function<bool(void)>;
public: public:
explicit SidebarEntryBase(const std::string& title, const std::string& info); explicit SidebarEntryBase(const std::string& title, const std::string& info);
using Widget::Draw; using Widget::Draw;
virtual void Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos, bool left); virtual void Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos, bool left);
void Depends(const DependsCallback& callback, const std::string& depends_info) {
m_depends_callback = callback;
m_depends_info = depends_info;
}
void Depends(bool& value, const std::string& depends_info) {
m_depends_callback = [&value](){ return value; };
m_depends_info = depends_info;
}
void Depends(option::OptionBool& value, const std::string& depends_info) {
m_depends_callback = [&value](){ return value.Get(); };
m_depends_info = depends_info;
}
protected:
auto IsEnabled() -> bool {
if (m_depends_callback) {
return m_depends_callback();
}
return true;
}
protected: protected:
std::string m_title; std::string m_title;
private: private:
std::string m_info; std::string m_info{};
std::string m_depends_info{};
DependsCallback m_depends_callback{};
ScrollingText m_scolling_title{}; ScrollingText m_scolling_title{};
}; };
@@ -101,11 +130,11 @@ public:
auto OnFocusGained() noexcept -> void override; auto OnFocusGained() noexcept -> void override;
auto OnFocusLost() noexcept -> void override; auto OnFocusLost() noexcept -> void override;
void Add(std::unique_ptr<SidebarEntryBase>&& entry); auto Add(std::unique_ptr<SidebarEntryBase>&& entry) -> SidebarEntryBase*;
template<DerivedFromSidebarBase T, typename... Args> template<DerivedFromSidebarBase T, typename... Args>
void Add(Args&&... args) { auto Add(Args&&... args) -> SidebarEntryBase* {
Add(std::make_unique<T>(std::forward<Args>(args)...)); return Add(std::make_unique<T>(std::forward<Args>(args)...));
} }
private: private:

View File

@@ -1658,13 +1658,15 @@ void App::DisplayMiscOptions(bool left_side) {
continue; continue;
} else if (e.name == g_app->m_right_menu.Get()) { } else if (e.name == g_app->m_right_menu.Get()) {
continue; continue;
} else if (e.IsInstall() && !App::GetInstallEnable()) {
continue;
} }
options->Add<ui::SidebarEntryCallback>(i18n::get(e.title), [e](){ auto entry = options->Add<ui::SidebarEntryCallback>(i18n::get(e.title), [e](){
App::Push(e.func(ui::menu::MenuFlag_None)); App::Push(e.func(ui::menu::MenuFlag_None));
}, i18n::get(e.info)); }, i18n::get(e.info));
if (e.IsInstall()) {
entry->Depends(App::GetInstallEnable, i18n::get(App::INSTALL_DEPENDS_STR));
}
} }
if (App::IsApplication()) { if (App::IsApplication()) {
@@ -1714,10 +1716,6 @@ void App::DisplayAdvancedOptions(bool left_side) {
continue; continue;
} }
if (e.IsInstall() && !App::GetInstallEnable()) {
continue;
}
menu_names.emplace_back(e.name); menu_names.emplace_back(e.name);
menu_items.push_back(i18n::get(e.name)); menu_items.push_back(i18n::get(e.name));
} }

View File

@@ -359,7 +359,7 @@ FsView::FsView(Menu* menu, const fs::FsPath& path, const FsEntry& entry, ViewSid
nro_launch(GetNewPathCurrent()); nro_launch(GetNewPathCurrent());
} }
}); });
} else if (App::GetInstallEnable() && IsExtension(entry.GetExtension(), INSTALL_EXTENSIONS)) { } else if (IsExtension(entry.GetExtension(), INSTALL_EXTENSIONS)) {
InstallFiles(); InstallFiles();
} else if (IsSd()) { } else if (IsSd()) {
const auto assoc_list = m_menu->FindFileAssocFor(); const auto assoc_list = m_menu->FindFileAssocFor();
@@ -703,6 +703,16 @@ void FsView::InstallForwarder() {
} }
void FsView::InstallFiles() { void FsView::InstallFiles() {
if (!App::GetInstallEnable()) {
App::Push<ui::OptionBox>(
"Install disabled...\n"
"Please enable installing via the install options."_i18n,
"OK"_i18n
);
return;
}
const auto targets = GetSelectedEntries(); const auto targets = GetSelectedEntries();
App::Push<OptionBox>("Install Selected files?"_i18n, "No"_i18n, "Yes"_i18n, 0, [this, targets](auto op_index){ App::Push<OptionBox>("Install Selected files?"_i18n, "No"_i18n, "Yes"_i18n, 0, [this, targets](auto op_index){
@@ -1674,17 +1684,18 @@ void FsView::DisplayOptions() {
}; };
// if install is enabled, check if all currently selected files are installable. // if install is enabled, check if all currently selected files are installable.
if (m_entries_current.size() && App::GetInstallEnable()) { if (m_entries_current.size()) {
if (check_all_ext(INSTALL_EXTENSIONS)) { if (check_all_ext(INSTALL_EXTENSIONS)) {
options->Add<SidebarEntryCallback>("Install"_i18n, [this](){ auto entry = options->Add<SidebarEntryCallback>("Install"_i18n, [this](){
InstallFiles(); InstallFiles();
}); });
entry->Depends(App::GetInstallEnable, i18n::get(App::INSTALL_DEPENDS_STR));
} }
} }
if (IsSd() && m_entries_current.size() && !m_selected_count) { if (IsSd() && m_entries_current.size() && !m_selected_count) {
if (App::GetInstallEnable() && GetEntry().IsFile() && (IsSamePath(GetEntry().GetExtension(), "nro") || !m_menu->FindFileAssocFor().empty())) { if (GetEntry().IsFile() && (IsSamePath(GetEntry().GetExtension(), "nro") || !m_menu->FindFileAssocFor().empty())) {
options->Add<SidebarEntryCallback>("Install Forwarder"_i18n, [this](){; auto entry = options->Add<SidebarEntryCallback>("Install Forwarder"_i18n, [this](){;
if (App::GetInstallPrompt()) { if (App::GetInstallPrompt()) {
App::Push<OptionBox>( App::Push<OptionBox>(
"WARNING: Installing forwarders will lead to a ban!"_i18n, "WARNING: Installing forwarders will lead to a ban!"_i18n,
@@ -1698,6 +1709,7 @@ void FsView::DisplayOptions() {
InstallForwarder(); InstallForwarder();
} }
}); });
entry->Depends(App::GetInstallEnable, i18n::get(App::INSTALL_DEPENDS_STR));
} }
} }

View File

@@ -123,22 +123,22 @@ Menu::Menu() : grid::Menu{"Homebrew"_i18n, MenuFlag_Tab} {
); );
}, true); }, true);
if (App::GetInstallEnable()) { auto forwarder_entry = options->Add<SidebarEntryCallback>("Install Forwarder"_i18n, [this](){
options->Add<SidebarEntryCallback>("Install Forwarder"_i18n, [this](){ if (App::GetInstallPrompt()) {
if (App::GetInstallPrompt()) { App::Push<OptionBox>(
App::Push<OptionBox>( "WARNING: Installing forwarders will lead to a ban!"_i18n,
"WARNING: Installing forwarders will lead to a ban!"_i18n, "Back"_i18n, "Install"_i18n, 0, [this](auto op_index){
"Back"_i18n, "Install"_i18n, 0, [this](auto op_index){ if (op_index && *op_index) {
if (op_index && *op_index) { InstallHomebrew();
InstallHomebrew(); }
} }, m_entries[m_index].image
}, m_entries[m_index].image );
); } else {
} else { InstallHomebrew();
InstallHomebrew(); }
} }, true);
}, true);
} forwarder_entry->Depends(App::GetInstallEnable, i18n::get(App::INSTALL_DEPENDS_STR));
} }
}}) }})
); );

View File

@@ -35,7 +35,9 @@ void SidebarEntryBase::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos,
if (HasFocus()) { if (HasFocus()) {
gfx::drawRectOutline(vg, theme, 4.f, m_pos); gfx::drawRectOutline(vg, theme, 4.f, m_pos);
if (!m_info.empty()) { const auto& info = IsEnabled() ? m_info : m_depends_info;
if (!info.empty()) {
// reset clip here as the box will draw oob. // reset clip here as the box will draw oob.
nvgSave(vg); nvgSave(vg);
nvgScissor(vg, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); nvgScissor(vg, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -62,7 +64,7 @@ void SidebarEntryBase::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos,
nvgFontSize(vg, info_font_size); nvgFontSize(vg, info_font_size);
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
nvgTextLineHeight(vg, 1.7); nvgTextLineHeight(vg, 1.7);
nvgTextBoxBounds(vg, 0, 0, end_w, m_info.c_str(), nullptr, bounds); nvgTextBoxBounds(vg, 0, 0, end_w, info.c_str(), nullptr, bounds);
info_box.h = pad_after_title + info_pad * 2 + bounds[3] - bounds[1]; info_box.h = pad_after_title + info_pad * 2 + bounds[3] - bounds[1];
gfx::drawRect(vg, info_box, theme->GetColour(ThemeEntryID_SIDEBAR), 5); gfx::drawRect(vg, info_box, theme->GetColour(ThemeEntryID_SIDEBAR), 5);
@@ -71,7 +73,7 @@ void SidebarEntryBase::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos,
m_scolling_title.Draw(vg, true, x, y, end_w, title_font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str()); m_scolling_title.Draw(vg, true, x, y, end_w, title_font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str());
y += pad_after_title; y += pad_after_title;
gfx::drawTextBox(vg, x, y, info_font_size, end_w, theme->GetColour(ThemeEntryID_TEXT), m_info.c_str()); gfx::drawTextBox(vg, x, y, info_font_size, end_w, theme->GetColour(ThemeEntryID_TEXT), info.c_str());
} }
} }
} }
@@ -91,9 +93,10 @@ SidebarEntryBool::SidebarEntryBool(const std::string& title, bool option, Callba
} }
SetAction(Button::A, Action{"OK"_i18n, [this](){ SetAction(Button::A, Action{"OK"_i18n, [this](){
if (IsEnabled()) {
m_option ^= 1; m_option ^= 1;
m_callback(m_option); m_callback(m_option);
} } }
}); });
} }
@@ -126,7 +129,8 @@ void SidebarEntryBool::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos,
// } else { // } else {
// } // }
gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); const auto colour_id = IsEnabled() ? ThemeEntryID_TEXT : ThemeEntryID_TEXT_INFO;
gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(colour_id), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
if (m_option == true) { if (m_option == true) {
gfx::drawText(vg, Vec2{m_pos.x + m_pos.w - 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), m_true_str.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); gfx::drawText(vg, Vec2{m_pos.x + m_pos.w - 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), m_true_str.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
@@ -140,11 +144,12 @@ SidebarEntryCallback::SidebarEntryCallback(const std::string& title, Callback cb
, m_callback{cb} , m_callback{cb}
, m_pop_on_click{pop_on_click} { , m_pop_on_click{pop_on_click} {
SetAction(Button::A, Action{"OK"_i18n, [this](){ SetAction(Button::A, Action{"OK"_i18n, [this](){
if (IsEnabled()) {
m_callback(); m_callback();
if (m_pop_on_click) { if (m_pop_on_click) {
SetPop(); SetPop();
} }
} }}
}); });
} }
@@ -156,10 +161,11 @@ SidebarEntryCallback::SidebarEntryCallback(const std::string& title, Callback cb
void SidebarEntryCallback::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos, bool left) { void SidebarEntryCallback::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos, bool left) {
SidebarEntryBase::Draw(vg, theme, root_pos, left); SidebarEntryBase::Draw(vg, theme, root_pos, left);
const auto colour_id = IsEnabled() ? ThemeEntryID_TEXT : ThemeEntryID_TEXT_INFO;
// if (HasFocus()) { // if (HasFocus()) {
// gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); // gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
// } else { // } else {
gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(colour_id), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
// } // }
} }
@@ -205,15 +211,17 @@ SidebarEntryArray::SidebarEntryArray(const std::string& title, const Items& item
}; };
SetAction(Button::A, Action{"OK"_i18n, [this](){ SetAction(Button::A, Action{"OK"_i18n, [this](){
if (IsEnabled()) {
// m_callback(m_index); // m_callback(m_index);
m_list_callback(); m_list_callback();
} }}
}); });
} }
void SidebarEntryArray::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos, bool left) { void SidebarEntryArray::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos, bool left) {
SidebarEntryBase::Draw(vg, theme, root_pos, left); SidebarEntryBase::Draw(vg, theme, root_pos, left);
const auto colour_id = IsEnabled() ? ThemeEntryID_TEXT : ThemeEntryID_TEXT_INFO;
const auto& text_entry = m_items[m_index]; const auto& text_entry = m_items[m_index];
// scrolling text // scrolling text
@@ -251,7 +259,7 @@ void SidebarEntryArray::Draw(NVGcontext* vg, Theme* theme, const Vec4& root_pos,
} }
const Vec2 key_text_pos{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}; const Vec2 key_text_pos{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)};
gfx::drawText(vg, key_text_pos, 20.f, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); gfx::drawText(vg, key_text_pos, 20.f, theme->GetColour(colour_id), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
nvgSave(vg); nvgSave(vg);
const float xpos = m_pos.x + m_pos.w - 15.f - std::min(max_off, bounds[2]); const float xpos = m_pos.x + m_pos.w - 15.f - std::min(max_off, bounds[2]);
@@ -389,15 +397,17 @@ auto Sidebar::OnFocusLost() noexcept -> void {
SetHidden(true); SetHidden(true);
} }
void Sidebar::Add(std::unique_ptr<SidebarEntryBase>&& entry) { auto Sidebar::Add(std::unique_ptr<SidebarEntryBase>&& _entry) -> SidebarEntryBase* {
m_items.emplace_back(std::forward<decltype(entry)>(entry)); auto& entry = m_items.emplace_back(std::forward<decltype(_entry)>(_entry));
m_items.back()->SetPos(m_base_pos); entry->SetPos(m_base_pos);
// give focus to first entry. // give focus to first entry.
if (m_items.size() == 1) { if (m_items.size() == 1) {
m_items[m_index]->OnFocusGained(); entry->OnFocusGained();
SetupButtons(); SetupButtons();
} }
return entry.get();
} }
void Sidebar::SetIndex(s64 index) { void Sidebar::SetIndex(s64 index) {