@@ -80,6 +80,7 @@ public:
|
|||||||
static auto GetThemeShuffleEnable() -> bool;
|
static auto GetThemeShuffleEnable() -> bool;
|
||||||
static auto GetThemeMusicEnable() -> bool;
|
static auto GetThemeMusicEnable() -> bool;
|
||||||
static auto GetLanguage() -> long;
|
static auto GetLanguage() -> long;
|
||||||
|
static auto GetTextScrollSpeed() -> long;
|
||||||
|
|
||||||
static void SetMtpEnable(bool enable);
|
static void SetMtpEnable(bool enable);
|
||||||
static void SetFtpEnable(bool enable);
|
static void SetFtpEnable(bool enable);
|
||||||
@@ -92,6 +93,7 @@ public:
|
|||||||
static void SetThemeShuffleEnable(bool enable);
|
static void SetThemeShuffleEnable(bool enable);
|
||||||
static void SetThemeMusicEnable(bool enable);
|
static void SetThemeMusicEnable(bool enable);
|
||||||
static void SetLanguage(long index);
|
static void SetLanguage(long index);
|
||||||
|
static void SetTextScrollSpeed(long index);
|
||||||
|
|
||||||
static auto Install(OwoConfig& config) -> Result;
|
static auto Install(OwoConfig& config) -> Result;
|
||||||
static auto Install(ui::ProgressBox* pbox, OwoConfig& config) -> Result;
|
static auto Install(ui::ProgressBox* pbox, OwoConfig& config) -> Result;
|
||||||
@@ -161,6 +163,8 @@ public:
|
|||||||
option::OptionBool m_theme_shuffle{INI_SECTION, "theme_shuffle", false};
|
option::OptionBool m_theme_shuffle{INI_SECTION, "theme_shuffle", false};
|
||||||
option::OptionBool m_theme_music{INI_SECTION, "theme_music", true};
|
option::OptionBool m_theme_music{INI_SECTION, "theme_music", true};
|
||||||
option::OptionLong m_language{INI_SECTION, "language", 0}; // auto
|
option::OptionLong m_language{INI_SECTION, "language", 0}; // auto
|
||||||
|
// todo: move this into it's own menu
|
||||||
|
option::OptionLong m_text_scroll_speed{"accessibility", "text_scroll_speed", 1}; // normal
|
||||||
|
|
||||||
PLSR_BFSAR m_qlaunch_bfsar{};
|
PLSR_BFSAR m_qlaunch_bfsar{};
|
||||||
PLSR_PlayerSoundId m_sound_ids[SoundEffect_MAX]{};
|
PLSR_PlayerSoundId m_sound_ids[SoundEffect_MAX]{};
|
||||||
|
|||||||
@@ -57,12 +57,16 @@ public:
|
|||||||
SidebarEntryArray(std::string title, Items items, std::string& index);
|
SidebarEntryArray(std::string title, Items items, std::string& index);
|
||||||
|
|
||||||
auto Draw(NVGcontext* vg, Theme* theme) -> void override;
|
auto Draw(NVGcontext* vg, Theme* theme) -> void override;
|
||||||
|
auto OnFocusGained() noexcept -> void override;
|
||||||
|
auto OnFocusLost() noexcept -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Items m_items;
|
Items m_items;
|
||||||
ListCallback m_list_callback;
|
ListCallback m_list_callback;
|
||||||
Callback m_callback;
|
Callback m_callback;
|
||||||
s64 m_index;
|
s64 m_index;
|
||||||
|
s64 m_tick{};
|
||||||
|
float m_text_yoff{};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@@ -585,6 +585,10 @@ auto App::GetLanguage() -> long {
|
|||||||
return g_app->m_language.Get();
|
return g_app->m_language.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto App::GetTextScrollSpeed() -> long {
|
||||||
|
return g_app->m_text_scroll_speed.Get();
|
||||||
|
}
|
||||||
|
|
||||||
void App::SetNxlinkEnable(bool enable) {
|
void App::SetNxlinkEnable(bool enable) {
|
||||||
if (App::GetNxlinkEnable() != enable) {
|
if (App::GetNxlinkEnable() != enable) {
|
||||||
g_app->m_nxlink_enabled.Set(enable);
|
g_app->m_nxlink_enabled.Set(enable);
|
||||||
@@ -767,6 +771,10 @@ void App::SetLanguage(long index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::SetTextScrollSpeed(long index) {
|
||||||
|
g_app->m_text_scroll_speed.Set(index);
|
||||||
|
}
|
||||||
|
|
||||||
auto App::Install(OwoConfig& config) -> Result {
|
auto App::Install(OwoConfig& config) -> Result {
|
||||||
R_TRY(romfsInit());
|
R_TRY(romfsInit());
|
||||||
ON_SCOPE_EXIT(romfsExit());
|
ON_SCOPE_EXIT(romfsExit());
|
||||||
|
|||||||
@@ -329,6 +329,11 @@ MainMenu::MainMenu() {
|
|||||||
install_items.push_back("System memory"_i18n);
|
install_items.push_back("System memory"_i18n);
|
||||||
install_items.push_back("microSD card"_i18n);
|
install_items.push_back("microSD card"_i18n);
|
||||||
|
|
||||||
|
SidebarEntryArray::Items text_scroll_speed_items;
|
||||||
|
text_scroll_speed_items.push_back("Slow"_i18n);
|
||||||
|
text_scroll_speed_items.push_back("Normal"_i18n);
|
||||||
|
text_scroll_speed_items.push_back("Fast"_i18n);
|
||||||
|
|
||||||
options->Add(std::make_shared<SidebarEntryBool>("Logging"_i18n, App::GetLogEnable(), [this](bool& enable){
|
options->Add(std::make_shared<SidebarEntryBool>("Logging"_i18n, App::GetLogEnable(), [this](bool& enable){
|
||||||
App::SetLogEnable(enable);
|
App::SetLogEnable(enable);
|
||||||
}, "Enabled"_i18n, "Disabled"_i18n));
|
}, "Enabled"_i18n, "Disabled"_i18n));
|
||||||
@@ -348,6 +353,10 @@ MainMenu::MainMenu() {
|
|||||||
options->Add(std::make_shared<SidebarEntryBool>("Show install warning"_i18n, App::GetInstallPrompt(), [this](bool& enable){
|
options->Add(std::make_shared<SidebarEntryBool>("Show install warning"_i18n, App::GetInstallPrompt(), [this](bool& enable){
|
||||||
App::SetInstallPrompt(enable);
|
App::SetInstallPrompt(enable);
|
||||||
}, "Enabled"_i18n, "Disabled"_i18n));
|
}, "Enabled"_i18n, "Disabled"_i18n));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<SidebarEntryArray>("Text scroll speed"_i18n, text_scroll_speed_items, [this](s64& index_out){
|
||||||
|
App::SetTextScrollSpeed(index_out);
|
||||||
|
}, (s64)App::GetTextScrollSpeed()));
|
||||||
}));
|
}));
|
||||||
}})
|
}})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,6 +7,14 @@
|
|||||||
namespace sphaira::ui {
|
namespace sphaira::ui {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
auto GetTextScrollSpeed() -> float {
|
||||||
|
switch (App::GetTextScrollSpeed()) {
|
||||||
|
case 0: return 0.5;
|
||||||
|
default: case 1: return 1.0;
|
||||||
|
case 2: return 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto DistanceBetweenY(Vec4 va, Vec4 vb) -> Vec4 {
|
auto DistanceBetweenY(Vec4 va, Vec4 vb) -> Vec4 {
|
||||||
return Vec4{
|
return Vec4{
|
||||||
va.x, va.y,
|
va.x, va.y,
|
||||||
@@ -147,11 +155,59 @@ auto SidebarEntryArray::Draw(NVGcontext* vg, Theme* theme) -> void {
|
|||||||
SidebarEntryBase::Draw(vg, theme);
|
SidebarEntryBase::Draw(vg, theme);
|
||||||
|
|
||||||
const auto& text_entry = m_items[m_index];
|
const auto& text_entry = m_items[m_index];
|
||||||
// const auto& colour = HasFocus() ? theme->GetColour(ThemeEntryID_TEXT_SELECTED) : theme->GetColour(ThemeEntryID_TEXT);
|
|
||||||
const auto& colour = theme->GetColour(ThemeEntryID_TEXT);
|
|
||||||
|
|
||||||
gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, colour, m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
// scrolling text
|
||||||
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), text_entry.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
|
// todo: move below in a flexible class and use it for all text drawing.
|
||||||
|
float bounds[4];
|
||||||
|
nvgFontSize(vg, 20);
|
||||||
|
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||||
|
nvgTextBounds(vg, 0, 0, m_title.c_str(), nullptr, bounds);
|
||||||
|
const float start_x = bounds[2] + 50;
|
||||||
|
const float max_off = m_pos.w - start_x - 15.f;
|
||||||
|
|
||||||
|
auto value_str = m_items[m_index];
|
||||||
|
nvgTextBounds(vg, 0, 0, value_str.c_str(), nullptr, bounds);
|
||||||
|
|
||||||
|
if (HasFocus()) {
|
||||||
|
const auto scroll_amount = GetTextScrollSpeed();
|
||||||
|
if (bounds[2] > max_off) {
|
||||||
|
value_str += " ";
|
||||||
|
nvgTextBounds(vg, 0, 0, value_str.c_str(), nullptr, bounds);
|
||||||
|
|
||||||
|
if (!m_text_yoff) {
|
||||||
|
m_tick++;
|
||||||
|
if (m_tick >= 90) {
|
||||||
|
m_tick = 0;
|
||||||
|
m_text_yoff += scroll_amount;
|
||||||
|
}
|
||||||
|
} else if (bounds[2] > m_text_yoff) {
|
||||||
|
m_text_yoff += std::min(scroll_amount, bounds[2] - m_text_yoff);
|
||||||
|
} else {
|
||||||
|
m_text_yoff = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_str += text_entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
nvgSave(vg);
|
||||||
|
const float xpos = m_pos.x + m_pos.w - 15.f - std::min(max_off, bounds[2]);
|
||||||
|
nvgIntersectScissor(vg, xpos, GetY(), max_off, GetH());
|
||||||
|
const Vec2 value_text_pos{xpos - m_text_yoff, m_pos.y + (m_pos.h / 2.f)};
|
||||||
|
gfx::drawText(vg, value_text_pos, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), value_str.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||||
|
nvgRestore(vg);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SidebarEntryArray::OnFocusGained() noexcept -> void {
|
||||||
|
Widget::OnFocusGained();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SidebarEntryArray::OnFocusLost() noexcept -> void {
|
||||||
|
Widget::OnFocusLost();
|
||||||
|
m_text_yoff = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sidebar::Sidebar(std::string title, Side side, Items&& items)
|
Sidebar::Sidebar(std::string title, Side side, Items&& items)
|
||||||
|
|||||||
Reference in New Issue
Block a user