diff --git a/Include/AppStates/ExtrasMenuState.hpp b/Include/AppStates/ExtrasMenuState.hpp new file mode 100644 index 0000000..dc0b034 --- /dev/null +++ b/Include/AppStates/ExtrasMenuState.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "AppStates/AppState.hpp" +#include "SDL.hpp" +#include "UI/Menu.hpp" + +class ExtrasMenuState : public AppState +{ + public: + ExtrasMenuState(void); + ~ExtrasMenuState() {}; + + void Update(void); + void Render(void); + + private: + // Actual menu + UI::Menu m_ExtrasMenu; + // Render target + SDL::SharedTexture m_RenderTarget; +}; diff --git a/Include/AppStates/SettingsState.hpp b/Include/AppStates/SettingsState.hpp index 8acc0c8..480952e 100644 --- a/Include/AppStates/SettingsState.hpp +++ b/Include/AppStates/SettingsState.hpp @@ -17,4 +17,6 @@ class SettingsState : public AppState UI::Menu m_SettingsMenu; // Render target. SDL::SharedTexture m_RenderTarget = nullptr; + // Control guide X coordinate. + int m_ControlGuideX = 0; }; diff --git a/Include/AppStates/TextTitleSelectState.hpp b/Include/AppStates/TextTitleSelectState.hpp new file mode 100644 index 0000000..57d88b9 --- /dev/null +++ b/Include/AppStates/TextTitleSelectState.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "AppStates/TitleSelectCommon.hpp" +#include "Data/Data.hpp" +#include "SDL.hpp" +#include "UI/Menu.hpp" + +class TextTitleSelectState : public TitleSelectCommon +{ + public: + TextTitleSelectState(Data::User *User); + ~TextTitleSelectState() {}; + + void Update(void); + void Render(void); + + void Refresh(void); + + private: + // Pointer to user to save. + Data::User *m_User; + // Title select menu + UI::Menu m_TitleSelectMenu; + // Render target + SDL::SharedTexture m_RenderTarget; +}; diff --git a/Include/AppStates/TitleSelectCommon.hpp b/Include/AppStates/TitleSelectCommon.hpp new file mode 100644 index 0000000..507776f --- /dev/null +++ b/Include/AppStates/TitleSelectCommon.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "AppStates/AppState.hpp" + +class TitleSelectCommon : public AppState +{ + public: + TitleSelectCommon(void); + virtual ~TitleSelectCommon() {}; + + virtual void Update(void) = 0; + virtual void Render(void) = 0; + + virtual void Refresh(void) = 0; + + void RenderControlGuide(void); + + protected: + // X coordinate for control guide. Shared between all instances. Only should be calculated once. + static inline int m_TitleControlsX = 0; +}; diff --git a/Include/AppStates/TitleSelectState.hpp b/Include/AppStates/TitleSelectState.hpp index e2648de..622227a 100644 --- a/Include/AppStates/TitleSelectState.hpp +++ b/Include/AppStates/TitleSelectState.hpp @@ -1,10 +1,10 @@ #pragma once -#include "AppStates/AppState.hpp" +#include "AppStates/TitleSelectCommon.hpp" #include "Data/Data.hpp" #include "SDL.hpp" #include "UI/TitleView.hpp" -class TitleSelectState : public AppState +class TitleSelectState : public TitleSelectCommon { public: TitleSelectState(Data::User *User); @@ -13,6 +13,8 @@ class TitleSelectState : public AppState void Update(void); void Render(void); + void Refresh(void); + private: // Save pointer to user Data::User *m_User = nullptr; @@ -20,6 +22,4 @@ class TitleSelectState : public AppState SDL::SharedTexture m_RenderTarget = nullptr; // Title select view UI::TitleView m_TitleView; - // X coordinate for control guide. Shared between all instances. Only should be calculated once. - static inline int m_TitleControlsX = 0; }; diff --git a/Include/Config.hpp b/Include/Config.hpp index 3d66559..d58704f 100644 --- a/Include/Config.hpp +++ b/Include/Config.hpp @@ -12,6 +12,8 @@ namespace Config void Save(void); // Retrieves a value with its key. uint8_t GetByKey(std::string_view Key); + // Retrieves value by index. + uint8_t GetByIndex(int Index); // Gets the working directory. FsLib::Path GetWorkingDirectory(void); // Gets the UI's transition scaling @@ -33,6 +35,8 @@ namespace Config static constexpr std::string_view WorkingDirectory = "WorkingDirectory"; static constexpr std::string_view IncludeDeviceSaves = "IncludeDeviceSaves"; static constexpr std::string_view AutoBackupOnRestore = "AutoBackupOnRestore"; + static constexpr std::string_view AutoNameBackups = "AutoNameBackups"; + static constexpr std::string_view AutoUpload = "AutoUploadToRemote"; static constexpr std::string_view HoldForDeletion = "HoldForDeletion"; static constexpr std::string_view HoldForRestoration = "HoldForRestoration"; static constexpr std::string_view HoldForOverwrite = "HoldForOverWrite"; @@ -40,13 +44,12 @@ namespace Config static constexpr std::string_view ListAccountSystemSaves = "ListAccountSystemSaves"; static constexpr std::string_view AllowSystemSaveWriting = "AllowSystemSaveWriting"; static constexpr std::string_view ExportToZip = "ExportToZip"; + static constexpr std::string_view TitleSortType = "TitleSortType"; + static constexpr std::string_view JKSMTextMode = "JKSMTextMode"; static constexpr std::string_view ForceEnglish = "ForceEnglish"; static constexpr std::string_view EnableTrashBin = "EnableTrash"; - static constexpr std::string_view AutoNameBackups = "AutoNameBackups"; - static constexpr std::string_view TitleSortType = "TitleSortType"; + static constexpr std::string_view UIAnimationScaling = "UIAnimationScaling"; static constexpr std::string_view Favorites = "Favorites"; static constexpr std::string_view BlackList = "BlackList"; - static constexpr std::string_view AutoUpload = "AutoUploadToRemote"; - static constexpr std::string_view UIAnimationScaling = "UIAnimationScaling"; } // namespace Keys } // namespace Config diff --git a/Include/Data/AccountUID.hpp b/Include/Data/AccountUID.hpp index ff26e35..4fb851a 100644 --- a/Include/Data/AccountUID.hpp +++ b/Include/Data/AccountUID.hpp @@ -6,7 +6,7 @@ static inline bool operator==(AccountUid AccountID1, AccountUid AccountID2) return (AccountID1.uid[0] == AccountID2.uid[0]) && (AccountID1.uid[1] == AccountID2.uid[1]); } -static inline u128 AccountUIDToU128(AccountUid AccountID) +static inline bool operator==(AccountUid AccountID, u128 u128ID) { - return (static_cast(AccountID.uid[0]) << 64 | AccountID.uid[1]); + return AccountID.uid[0] == (u128ID >> 64 & 0xFFFFFFFFFFFFFFFF) && AccountID.uid[1] == (u128ID & 0xFFFFFFFFFFFFFFFF); } diff --git a/Include/Strings.hpp b/Include/Strings.hpp index ffdd91b..6152459 100644 --- a/Include/Strings.hpp +++ b/Include/Strings.hpp @@ -15,6 +15,7 @@ namespace Strings static constexpr std::string_view SaveDataTypes = "SaveDataTypes"; static constexpr std::string_view MainMenuNames = "MainMenuNames"; static constexpr std::string_view SettingsMenu = "SettingsMenu"; + static constexpr std::string_view ExtrasMenu = "ExtrasMenu"; static constexpr std::string_view OnOff = "OnOff"; } // namespace Names } // namespace Strings diff --git a/Include/UI/IconMenu.hpp b/Include/UI/IconMenu.hpp index a0ba86c..5001b56 100644 --- a/Include/UI/IconMenu.hpp +++ b/Include/UI/IconMenu.hpp @@ -7,7 +7,7 @@ namespace UI class IconMenu : public UI::Menu { public: - IconMenu(int X, int Y, int ScrollLength, int RenderTargetHeight); + IconMenu(int X, int Y, int RenderTargetHeight); ~IconMenu() {}; void Update(bool HasFocus); diff --git a/Include/UI/Menu.hpp b/Include/UI/Menu.hpp index b20256f..906ee44 100644 --- a/Include/UI/Menu.hpp +++ b/Include/UI/Menu.hpp @@ -10,51 +10,44 @@ namespace UI class Menu : public UI::Element { public: - // Coordinates to render to and dimensions of menu. - Menu(int X, int Y, int Width, int FontSize, int ScrollLength, int RenderTargetHeight); + Menu(int X, int Y, int Width, int FontSize, int RenderTargetHeight); ~Menu() {}; - // Required functions from Element. void Update(bool HasFocus); void Render(SDL_Texture *Target, bool HasFocus); - // Adds an option to the menu. void AddOption(std::string_view NewOption); - - // Returns the index of the selected item. int GetSelected(void) const; - // Sets the selected option void SetSelected(int Selected); - // Resets the menu. void Reset(void); protected: // X and Y coordinates. double m_X, m_Y; - // Font size - int m_FontSize; // Selected option. int m_Selected = 0; - // Color mod for rendering bounding box. + // Color pulse UI::ColorMod m_ColorMod; - // Actual length of the menu. - int m_OptionsLength = -1; - // Height of options. + // Calculated height of the options. int m_OptionHeight; - // Total height of menu in pixels. - int m_MenuHeight = 0; - // A small target to render the option to so it can't draw text outside of the bounding area. + // Render target for options so they can't render outside the bounding area. SDL::SharedTexture m_OptionTarget = nullptr; private: - // These are used for the scrolling effect. - double m_OriginalY, m_TargetY; - // How many options before scrolling starts happening. - int m_ScrollLength, m_MenuRenderLength; - // The height of the render target for scrolling calculations. - int m_RenderTargetHeight = 0; - // Width. + // Need to preserve the original Y. + double m_OriginalY; + // This is the TargetY the menu catches up to so-to-speak. + double m_TargetY; + // This is calculated according to the render target's length. + int m_ScrollLength; + // Maximum display length of options. int m_Width; + // Font size. + int m_FontSize; + // Vertical size of the destination render target in pixels. + int m_RenderTargetHeight; + // Maximum number of display options render target can show. + int m_MaxDisplayOptions; // Vector of options. std::vector m_Options; }; diff --git a/Include/UI/TitleView.hpp b/Include/UI/TitleView.hpp index 9d6314b..cdeb257 100644 --- a/Include/UI/TitleView.hpp +++ b/Include/UI/TitleView.hpp @@ -23,11 +23,11 @@ namespace UI // Saves pointer to the user passed. Data::User *m_User = nullptr; // Y coordinate. - double m_Y = 38; + double m_Y = 28.0f; // Currently highlighted/selected title. int m_Selected = 0; // This is to save the X and Y coordinates so the selected icon can be drawn last. - double m_SelectedX, m_SelectedY = 38.0f; + double m_SelectedX, m_SelectedY = 28.0f; // Color mod for pulse. UI::ColorMod m_ColorMod; // Vector of tiles. diff --git a/JKSV.7z b/JKSV.7z new file mode 100644 index 0000000..95f40ef Binary files /dev/null and b/JKSV.7z differ diff --git a/Libraries/SDLLib b/Libraries/SDLLib index 33e1262..3ffe1c9 160000 --- a/Libraries/SDLLib +++ b/Libraries/SDLLib @@ -1 +1 @@ -Subproject commit 33e12628aac70e862e36cf3ad5d6a7c08730aab3 +Subproject commit 3ffe1c9038227f6aa7cecb8e38be8a62ea263254 diff --git a/Makefile b/Makefile index 728d358..4a9f7b5 100644 --- a/Makefile +++ b/Makefile @@ -47,9 +47,9 @@ ICON := icon.jpg #--------------------------------------------------------------------------------- ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE -override CFLAGS += $(INCLUDE) -D__SWITCH__ -override CFLAGS += `sdl2-config --cflags` `freetype-config --cflags` `curl-config --cflags` -override CFLAGS += -g -Wall -O2 -ffunction-sections -ffast-math $(ARCH) $(DEFINES) +CFLAGS := $(INCLUDE) -D__SWITCH__ `sdl2-config --cflags` `freetype-config --cflags` \ + `curl-config --cflags` -g -Wall -Werror -O2 -ffunction-sections -ffast-math \ + $(ARCH) $(DEFINES) CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=c++23 diff --git a/RomFS/Text/ENUS.json b/RomFS/Text/ENUS.json index 3799800..07fa513 100644 --- a/RomFS/Text/ENUS.json +++ b/RomFS/Text/ENUS.json @@ -24,6 +24,7 @@ "Include Device Saves with users: %s", "Auto-backup on restore: %s", "Auto-name backups: %s", + "Auto-upload backups to remote storage: %s", "Hold to delete backups: %s", "Hold to restore backups: %s", "Hold to overwrite backups: %s", @@ -31,9 +32,21 @@ "Show account system saves: %s", "Enable writing to system saves and NAND: %s", "Export saves to ZIP: %s", + "Title sort type: %s", + "Text menu (JKSM) mode: %s", "Force English: %s", "Enable trash bin: %s", - "Animation scaling: %s" + "Animation scaling: %.02f" + ], + "ExtrasMenu" : [ + "Reload Titles", + "SD to SD Browser", + "BIS: ProfInfoF", + "BIS: Safe", + "BIS: System", + "BIS: User", + "Terminate Process", + "Mount System Save" ], "OnOff" : [ "Off", diff --git a/RomFS/Textures/ExtrasIcon.png b/RomFS/Textures/ExtrasIcon.png new file mode 100644 index 0000000..7d1034f Binary files /dev/null and b/RomFS/Textures/ExtrasIcon.png differ diff --git a/Source/AppStates/ExtrasMenuState.cpp b/Source/AppStates/ExtrasMenuState.cpp new file mode 100644 index 0000000..0ecdb03 --- /dev/null +++ b/Source/AppStates/ExtrasMenuState.cpp @@ -0,0 +1,39 @@ +#include "AppStates/ExtrasMenuState.hpp" +#include "Colors.hpp" +#include "Input.hpp" +#include "Strings.hpp" +#include + +namespace +{ + constexpr std::string_view SECONDARY_TARGET = "SecondaryTarget"; +} + +ExtrasMenuState::ExtrasMenuState(void) + : m_ExtrasMenu(32, 8, 1000, 32, 555), + m_RenderTarget(SDL::TextureManager::CreateLoadTexture(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET)) +{ + const char *ExtrasString = nullptr; + int CurrentString = 0; + while ((ExtrasString = Strings::GetByName(Strings::Names::ExtrasMenu, CurrentString++)) != nullptr) + { + m_ExtrasMenu.AddOption(ExtrasString); + } +} + +void ExtrasMenuState::Update(void) +{ + m_ExtrasMenu.Update(AppState::HasFocus()); + + if (Input::ButtonPressed(HidNpadButton_B)) + { + AppState::Deactivate(); + } +} + +void ExtrasMenuState::Render(void) +{ + m_RenderTarget->Clear(Colors::Transparent); + m_ExtrasMenu.Render(m_RenderTarget->Get(), AppState::HasFocus()); + m_RenderTarget->Render(NULL, 201, 91); +} diff --git a/Source/AppStates/MainMenuState.cpp b/Source/AppStates/MainMenuState.cpp index fec53ef..13ab6b4 100644 --- a/Source/AppStates/MainMenuState.cpp +++ b/Source/AppStates/MainMenuState.cpp @@ -1,4 +1,5 @@ #include "AppStates/MainMenuState.hpp" +#include "AppStates/ExtrasMenuState.hpp" #include "AppStates/SettingsState.hpp" #include "AppStates/TitleSelectState.hpp" #include "Colors.hpp" @@ -9,32 +10,27 @@ #include "SDL.hpp" #include "Strings.hpp" -namespace -{ - // Size of the font to use to make tweaking this easier. - static int ICON_FONT_SIZE = 50; -} // namespace - MainMenuState::MainMenuState(void) : m_RenderTarget(SDL::TextureManager::CreateLoadTexture("MainMenuTarget", 200, 555, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET)), - m_Background(SDL::TextureManager::CreateLoadTexture("MainMenuBackground", "romfs:/Textures/MenuBackground.png")), - m_MainMenu(50, 15, 1, 555), m_ControlGuide(Strings::GetByName(Strings::Names::ControlGuides, 0)), - m_ControlGuideX(1220 - SDL::Text::GetWidth(22, m_ControlGuide)) + m_Background(SDL::TextureManager::CreateLoadTexture("MainMenuBackground", "romfs:/Textures/MenuBackground.png")), m_MainMenu(50, 15, 555), + m_ControlGuide(Strings::GetByName(Strings::Names::ControlGuides, 0)), m_ControlGuideX(1220 - SDL::Text::GetWidth(22, m_ControlGuide)) { // Fetch user list. Data::GetUsers(m_Users); - // Loop through and add icons to menu + // Loop through add user's icon to menu and create states. for (size_t i = 0; i < m_Users.size(); i++) { m_MainMenu.AddOption(m_Users.at(i)->GetSharedIcon()); m_States.push_back(std::make_shared(m_Users.at(i))); } + // Add the settings and extras. m_States.push_back(std::make_shared()); + m_States.push_back(std::make_shared()); // Create icons for the other two. m_SettingsIcon = SDL::TextureManager::CreateLoadTexture("SettingsIcon", "romfs:/Textures/SettingsIcon.png"); - m_ExtrasIcon = SDL::TextureManager::CreateLoadTexture("ExtrasIcon", 256, 256, 0); + m_ExtrasIcon = SDL::TextureManager::CreateLoadTexture("ExtrasIcon", "romfs:/Textures/ExtrasIcon.png"); // Finally add them to the end. m_MainMenu.AddOption(m_SettingsIcon); @@ -45,13 +41,13 @@ void MainMenuState::Update(void) { m_MainMenu.Update(AppState::HasFocus()); - if (Input::ButtonPressed(HidNpadButton_A) && m_MainMenu.GetSelected() < m_Users.size() && + if (Input::ButtonPressed(HidNpadButton_A) && m_MainMenu.GetSelected() < static_cast(m_Users.size()) && m_Users.at(m_MainMenu.GetSelected())->GetTotalDataEntries() > 0) { m_States.at(m_MainMenu.GetSelected())->Reactivate(); JKSV::PushState(m_States.at(m_MainMenu.GetSelected())); } - else if (Input::ButtonPressed(HidNpadButton_A) && m_MainMenu.GetSelected() >= m_Users.size()) + else if (Input::ButtonPressed(HidNpadButton_A) && m_MainMenu.GetSelected() >= static_cast(m_Users.size())) { m_States.at(m_MainMenu.GetSelected())->Reactivate(); JKSV::PushState(m_States.at(m_MainMenu.GetSelected())); diff --git a/Source/AppStates/SettingsState.cpp b/Source/AppStates/SettingsState.cpp index 7dc87f0..3af31cb 100644 --- a/Source/AppStates/SettingsState.cpp +++ b/Source/AppStates/SettingsState.cpp @@ -1,6 +1,8 @@ #include "AppStates/SettingsState.hpp" #include "Colors.hpp" +#include "Config.hpp" #include "Input.hpp" +#include "StringUtil.hpp" #include "Strings.hpp" namespace @@ -9,17 +11,28 @@ namespace constexpr std::string_view SECONDARY_TARGET = "SecondaryTarget"; } // namespace +static inline const char *GetValueText(uint8_t Value) +{ + return Value == 1 ? Strings::GetByName(Strings::Names::OnOff, 0) : Strings::GetByName(Strings::Names::OnOff, 1); +} + SettingsState::SettingsState(void) - : m_SettingsMenu(32, 18, 1002, 32, 4, 555), + : m_SettingsMenu(32, 8, 1000, 32, 555), m_RenderTarget(SDL::TextureManager::CreateLoadTexture(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET)) { - // Loop through strings and add them until nullptr. - int CurrentString = 0; + // Add the first two, because they don't have values to display. + m_SettingsMenu.AddOption(Strings::GetByName(Strings::Names::SettingsMenu, 0)); + m_SettingsMenu.AddOption(Strings::GetByName(Strings::Names::SettingsMenu, 1)); + + int CurrentString = 2; const char *SettingsString = nullptr; - while ((SettingsString = Strings::GetByName(Strings::Names::SettingsMenu, CurrentString++)) != nullptr) + while (CurrentString < 16 && (SettingsString = Strings::GetByName(Strings::Names::SettingsMenu, CurrentString++)) != nullptr) { - m_SettingsMenu.AddOption(SettingsString); + m_SettingsMenu.AddOption(StringUtil::GetFormattedString(SettingsString, GetValueText(Config::GetByIndex(CurrentString - 1)))); } + // Add the scaling + m_SettingsMenu.AddOption( + StringUtil::GetFormattedString(Strings::GetByName(Strings::Names::SettingsMenu, 17), Config::GetAnimationScaling())); } void SettingsState::Update(void) diff --git a/Source/AppStates/TextTitleSelectState.cpp b/Source/AppStates/TextTitleSelectState.cpp new file mode 100644 index 0000000..9c754b8 --- /dev/null +++ b/Source/AppStates/TextTitleSelectState.cpp @@ -0,0 +1,38 @@ +#include "AppStates/TextTitleSelectState.hpp" +#include "Colors.hpp" +#include "SDL.hpp" +#include + +namespace +{ + constexpr std::string_view SECONDARY_TARGET = "SecondaryTarget"; +} + +TextTitleSelectState::TextTitleSelectState(Data::User *User) + : TitleSelectCommon(), m_User(User), m_TitleSelectMenu(32, 8, 1000, 20, 555), + m_RenderTarget(SDL::TextureManager::CreateLoadTexture(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET)) +{ + TextTitleSelectState::Refresh(); +} + +void TextTitleSelectState::Update(void) +{ + m_TitleSelectMenu.Update(AppState::HasFocus()); +} + +void TextTitleSelectState::Render(void) +{ + m_RenderTarget->Clear(Colors::Transparent); + m_TitleSelectMenu.Render(m_RenderTarget->Get(), AppState::HasFocus()); + TitleSelectCommon::RenderControlGuide(); + m_RenderTarget->Render(NULL, 201, 91); +} + +void TextTitleSelectState::Refresh(void) +{ + m_TitleSelectMenu.Reset(); + for (size_t i = 0; i < m_User->GetTotalDataEntries(); i++) + { + m_TitleSelectMenu.AddOption(Data::GetTitleInfoByID(m_User->GetApplicationIDAt(i))->GetTitle()); + } +} diff --git a/Source/AppStates/TitleSelectCommon.cpp b/Source/AppStates/TitleSelectCommon.cpp new file mode 100644 index 0000000..622a322 --- /dev/null +++ b/Source/AppStates/TitleSelectCommon.cpp @@ -0,0 +1,26 @@ +#include "AppStates/TitleSelectCommon.hpp" +#include "Colors.hpp" +#include "SDL.hpp" +#include "Strings.hpp" + +TitleSelectCommon::TitleSelectCommon(void) +{ + if (m_TitleControlsX == 0) + { + m_TitleControlsX = 1220 - SDL::Text::GetWidth(22, Strings::GetByName(Strings::Names::ControlGuides, 1)); + } +} + +void TitleSelectCommon::RenderControlGuide(void) +{ + if (AppState::HasFocus()) + { + SDL::Text::Render(NULL, + m_TitleControlsX, + 673, + 22, + SDL::Text::NO_TEXT_WRAP, + Colors::White, + Strings::GetByName(Strings::Names::ControlGuides, 1)); + } +} diff --git a/Source/AppStates/TitleSelectState.cpp b/Source/AppStates/TitleSelectState.cpp index 5b880e1..9c09ba3 100644 --- a/Source/AppStates/TitleSelectState.cpp +++ b/Source/AppStates/TitleSelectState.cpp @@ -13,15 +13,9 @@ namespace } // namespace TitleSelectState::TitleSelectState(Data::User *User) - : m_User(User), + : TitleSelectCommon(), m_User(User), m_RenderTarget(SDL::TextureManager::CreateLoadTexture(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET)), - m_TitleView(m_User) -{ - if (m_TitleControlsX == 0) - { - m_TitleControlsX = 1220 - SDL::Text::GetWidth(22, Strings::GetByName(Strings::Names::ControlGuides, 1)); - } -} + m_TitleView(m_User) {}; void TitleSelectState::Update(void) { @@ -44,16 +38,10 @@ void TitleSelectState::Render(void) { m_RenderTarget->Clear(Colors::Transparent); m_TitleView.Render(m_RenderTarget->Get(), AppState::HasFocus()); - - if (AppState::HasFocus()) - { - SDL::Text::Render(NULL, - m_TitleControlsX, - 673, - 22, - SDL::Text::NO_TEXT_WRAP, - Colors::White, - Strings::GetByName(Strings::Names::ControlGuides, 1)); - } + TitleSelectCommon::RenderControlGuide(); m_RenderTarget->Render(NULL, 201, 91); } + +void TitleSelectState::Refresh(void) +{ +} diff --git a/Source/Config.cpp b/Source/Config.cpp index baea6de..3439d20 100644 --- a/Source/Config.cpp +++ b/Source/Config.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include namespace @@ -14,8 +13,8 @@ namespace // Config path(s) const char *CONFIG_FOLDER = "sdmc:/config/JKSV"; const char *CONFIG_PATH = "sdmc:/config/JKSV/JKSV.json"; - // Map of config values - std::unordered_map s_ConfigMap; + // Vector to preserve order now. + std::vector> s_ConfigVector; // Working directory FsLib::Path s_WorkingDirectory; // UI animation scaling. @@ -86,7 +85,7 @@ void Config::Initialize(void) } else { - s_ConfigMap[KeyName] = json_object_get_uint64(ConfigValue); + s_ConfigVector.push_back(std::make_pair(KeyName, json_object_get_uint64(ConfigValue))); } json_object_iter_next(&ConfigIterator); } @@ -95,20 +94,21 @@ void Config::Initialize(void) void Config::ResetToDefault(void) { s_WorkingDirectory = "sdmc:/JKSV"; - s_ConfigMap[Config::Keys::IncludeDeviceSaves.data()] = 1; - s_ConfigMap[Config::Keys::AutoBackupOnRestore.data()] = 1; - s_ConfigMap[Config::Keys::HoldForDeletion.data()] = 1; - s_ConfigMap[Config::Keys::HoldForRestoration.data()] = 1; - s_ConfigMap[Config::Keys::HoldForOverwrite.data()] = 1; - s_ConfigMap[Config::Keys::OnlyListMountable.data()] = 1; - s_ConfigMap[Config::Keys::ListAccountSystemSaves.data()] = 0; - s_ConfigMap[Config::Keys::AllowSystemSaveWriting.data()] = 0; - s_ConfigMap[Config::Keys::ExportToZip.data()] = 1; - s_ConfigMap[Config::Keys::ForceEnglish.data()] = 0; - s_ConfigMap[Config::Keys::EnableTrashBin.data()] = 1; - s_ConfigMap[Config::Keys::AutoNameBackups.data()] = 0; - s_ConfigMap[Config::Keys::TitleSortType.data()] = 0; - s_ConfigMap[Config::Keys::AutoUpload.data()] = 0; + s_ConfigVector.push_back(std::make_pair(Config::Keys::IncludeDeviceSaves.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::AutoBackupOnRestore.data(), 1)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::AutoNameBackups.data(), 1)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::AutoUpload.data(), 1)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::HoldForDeletion.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::HoldForRestoration.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::HoldForOverwrite.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::OnlyListMountable.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::ListAccountSystemSaves.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::AllowSystemSaveWriting.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::ExportToZip.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::TitleSortType.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::JKSMTextMode.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::ForceEnglish.data(), 0)); + s_ConfigVector.push_back(std::make_pair(Config::Keys::EnableTrashBin.data(), 0)); s_UIAnimationScaling = 2.5f; } @@ -121,7 +121,7 @@ void Config::Save(void) json_object_object_add(ConfigJSON.get(), Config::Keys::WorkingDirectory.data(), WorkingDirectory); // Loop through map and add it. - for (auto &[Key, Value] : s_ConfigMap) + for (auto &[Key, Value] : s_ConfigVector) { json_object *JsonValue = json_object_new_uint64(Value); json_object_object_add(ConfigJSON.get(), Key.c_str(), JsonValue); @@ -157,11 +157,23 @@ void Config::Save(void) uint8_t Config::GetByKey(std::string_view Key) { - if (s_ConfigMap.find(Key.data()) == s_ConfigMap.end()) + auto FindKey = std::find_if(s_ConfigVector.begin(), s_ConfigVector.end(), [Key](const std::pair &ConfigPair) { + return Key == ConfigPair.first; + }); + if (FindKey == s_ConfigVector.end()) { return 0; } - return s_ConfigMap.at(Key.data()); + return FindKey->second; +} + +uint8_t Config::GetByIndex(int Index) +{ + if (Index < 0 || Index >= static_cast(s_ConfigVector.size())) + { + return 0; + } + return s_ConfigVector.at(Index).second; } FsLib::Path Config::GetWorkingDirectory(void) diff --git a/Source/Data/Data.cpp b/Source/Data/Data.cpp index 4096816..e5c9714 100644 --- a/Source/Data/Data.cpp +++ b/Source/Data/Data.cpp @@ -80,6 +80,38 @@ bool Data::Initialize(void) while (R_SUCCEEDED(fsSaveDataInfoReaderRead(&SaveInfoReader, &SaveInfo, 1, &TotalEntries)) && TotalEntries > 0) { + // Skip this stuff + if (!Config::GetByKey(Config::Keys::ListAccountSystemSaves) && SaveInfo.save_data_type == FsSaveDataType_System && + SaveInfo.uid != 0) + { + continue; + } + + switch (SaveInfo.save_data_type) + { + case FsSaveDataType_Bcat: + { + SaveInfo.uid = {FsSaveDataType_Bcat}; + } + break; + + case FsSaveDataType_Device: + { + SaveInfo.uid = {FsSaveDataType_Device}; + } + break; + + case FsSaveDataType_Cache: + { + SaveInfo.uid = {FsSaveDataType_Cache}; + } + break; + + default: + break; + } + + auto FindUser = std::find_if(s_UserVector.begin(), s_UserVector.end(), [&SaveInfo](UserIDPair &IDPair) { return IDPair.first == SaveInfo.uid; }); diff --git a/Source/Data/TitleInfo.cpp b/Source/Data/TitleInfo.cpp index d65275b..85004fc 100644 --- a/Source/Data/TitleInfo.cpp +++ b/Source/Data/TitleInfo.cpp @@ -26,8 +26,8 @@ Data::TitleInfo::TitleInfo(uint64_t ApplicationID) std::memset(&m_NACP, 0x00, sizeof(NacpStruct)); // Sprintf title ids to language entries for safety. - sprintf(m_NACP.lang[SetLanguage_ENUS].name, "%016llX", ApplicationID); - sprintf(m_PathSafeTitle, "%016llX", ApplicationID); + sprintf(m_NACP.lang[SetLanguage_ENUS].name, "%016lX", ApplicationID); + sprintf(m_PathSafeTitle, "%016lX", ApplicationID); // Create a place holder icon. int TextX = 128 - (SDL::Text::GetWidth(48, ApplicationIDHex.c_str()) / 2); @@ -42,7 +42,7 @@ Data::TitleInfo::TitleInfo(uint64_t ApplicationID) // Get a path safe version of the title. if (!StringUtil::SanitizeStringForPath(LanguageEntry->name, m_PathSafeTitle, 0x200)) { - std::sprintf(m_PathSafeTitle, "%016llX", ApplicationID); + std::sprintf(m_PathSafeTitle, "%016lX", ApplicationID); } // Load the icon. m_Icon = SDL::TextureManager::CreateLoadTexture(LanguageEntry->name, NsControlData.icon, NsAppControlSize - sizeof(NacpStruct)); diff --git a/Source/JKSV.cpp b/Source/JKSV.cpp index 863acb3..16e29e4 100644 --- a/Source/JKSV.cpp +++ b/Source/JKSV.cpp @@ -19,7 +19,7 @@ namespace { constexpr uint8_t BUILD_MON = 12; - constexpr uint8_t BUILD_DAY = 5; + constexpr uint8_t BUILD_DAY = 9; constexpr uint16_t BUILD_YEAR = 2024; } // namespace diff --git a/Source/UI/IconMenu.cpp b/Source/UI/IconMenu.cpp index 5a8a9f3..a31bbec 100644 --- a/Source/UI/IconMenu.cpp +++ b/Source/UI/IconMenu.cpp @@ -2,7 +2,7 @@ #include "Colors.hpp" #include "UI/RenderFunctions.hpp" -UI::IconMenu::IconMenu(int X, int Y, int ScrollLength, int RenderTargetHeight) : Menu(X, Y, 152, 88, ScrollLength, RenderTargetHeight) {}; +UI::IconMenu::IconMenu(int X, int Y, int RenderTargetHeight) : Menu(X, Y, 152, 80, RenderTargetHeight) {}; void UI::IconMenu::Update(bool HasFocus) { @@ -16,7 +16,7 @@ void UI::IconMenu::Render(SDL_Texture *Target, bool HasFocus) m_ColorMod.Update(); } - for (int i = 0, TempY = m_Y; i <= m_OptionsLength; i++, TempY += m_OptionHeight) + for (int i = 0, TempY = m_Y; i < static_cast(m_Options.size()); i++, TempY += m_OptionHeight) { // Clear target. m_OptionTarget->Clear(Colors::Transparent); diff --git a/Source/UI/Menu.cpp b/Source/UI/Menu.cpp index 727a37b..5f9e22d 100644 --- a/Source/UI/Menu.cpp +++ b/Source/UI/Menu.cpp @@ -5,15 +5,19 @@ #include "UI/RenderFunctions.hpp" #include -UI::Menu::Menu(int X, int Y, int Width, int FontSize, int ScrollLength, int RenderTargetHeight) - : m_X(X), m_Y(Y), m_OriginalY(Y), m_FontSize(FontSize), m_ScrollLength(ScrollLength), m_MenuRenderLength(ScrollLength * 2), m_Width(Width), - m_OptionHeight(std::ceil(static_cast(FontSize) * 1.8f)), m_TargetY(Y), m_RenderTargetHeight(RenderTargetHeight) +UI::Menu::Menu(int X, int Y, int Width, int FontSize, int RenderTargetHeight) + : m_X(X), m_Y(Y), m_OptionHeight(std::ceil(static_cast(FontSize) * 1.8f)), m_OriginalY(Y), m_TargetY(Y), m_Width(Width), + m_FontSize(FontSize), m_RenderTargetHeight(RenderTargetHeight) { + // Create render target for options static int MenuID = 0; - // Create target for menu option std::string MenuTargetName = "Menu_" + std::to_string(MenuID++); m_OptionTarget = SDL::TextureManager::CreateLoadTexture(MenuTargetName, m_Width, m_OptionHeight, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET); + + // Calculate around how many options can be shown on the render target at once. + m_MaxDisplayOptions = (RenderTargetHeight - m_OriginalY) / m_OptionHeight; + m_ScrollLength = std::floor(static_cast(m_MaxDisplayOptions) / 2.0f); } void UI::Menu::Update(bool HasFocus) @@ -24,36 +28,43 @@ void UI::Menu::Update(bool HasFocus) return; } - int PreviousSelected = m_Selected; + int OptionsSize = m_Options.size(); if (Input::ButtonPressed(HidNpadButton_AnyUp) && --m_Selected < 0) { - m_Selected = m_OptionsLength; + m_Selected = OptionsSize - 1; } - else if (Input::ButtonPressed(HidNpadButton_AnyDown) && ++m_Selected > m_OptionsLength) + else if (Input::ButtonPressed(HidNpadButton_AnyDown) && ++m_Selected >= static_cast(m_Options.size())) { m_Selected = 0; } - else if (Input::ButtonPressed(HidNpadButton_Left) && (m_Selected -= m_ScrollLength) < 0) + else if (Input::ButtonPressed(HidNpadButton_AnyLeft) && (m_Selected -= m_ScrollLength) < 0) { m_Selected = 0; } - else if (Input::ButtonPressed(HidNpadButton_AnyRight) && (m_Selected += m_ScrollLength) > m_OptionsLength) + else if (Input::ButtonPressed(HidNpadButton_AnyRight) && (m_Selected += m_ScrollLength) >= static_cast(m_Options.size())) { - m_Selected = m_OptionsLength; + m_Selected = OptionsSize - 1; } - // To do: Refine this further. It's so close. - if (PreviousSelected != m_Selected && m_Selected < m_ScrollLength) + // Don't bother continuing further if there's no reason to scroll. + if (static_cast(m_Options.size()) <= m_MaxDisplayOptions) + { + return; + } + + if (m_Selected < m_ScrollLength) { m_TargetY = m_OriginalY; } - else if (PreviousSelected != m_Selected && m_Selected >= m_ScrollLength && - (m_Selected > PreviousSelected || m_Selected < PreviousSelected) && m_Selected < (m_OptionsLength - m_ScrollLength)) + else if (m_Selected >= static_cast(m_Options.size()) - (m_MaxDisplayOptions - m_ScrollLength)) + { + m_TargetY = m_OriginalY - ((m_Options.size() - m_MaxDisplayOptions) * m_OptionHeight); + } + else if (m_Selected >= m_ScrollLength) { m_TargetY = m_OriginalY - ((m_Selected - m_ScrollLength) * m_OptionHeight); } - if (m_Y != m_TargetY) { m_Y += std::ceil((m_TargetY - m_Y) / Config::GetAnimationScaling()); @@ -72,12 +83,13 @@ void UI::Menu::Render(SDL_Texture *Target, bool HasFocus) // I hate doing this. int TargetHeight = 0; SDL_QueryTexture(Target, NULL, NULL, NULL, &TargetHeight); - for (int i = 0, TempY = m_Y; i <= m_OptionsLength; i++, TempY += m_OptionHeight) + for (int i = 0, TempY = m_Y; i < static_cast(m_Options.size()); i++, TempY += m_OptionHeight) { - if (TempY < 0 || TempY > TargetHeight) + if (TempY < -m_FontSize) { continue; } + // Clear target texture. m_OptionTarget->Clear(Colors::Transparent); @@ -93,11 +105,11 @@ void UI::Menu::Render(SDL_Texture *Target, bool HasFocus) } // Render text to target. SDL::Text::Render(m_OptionTarget->Get(), - 20, + 28, (m_OptionHeight / 2) - (m_FontSize / 2), m_FontSize, SDL::Text::NO_TEXT_WRAP, - i == m_Selected ? Colors::BlueGreen : Colors::White, + i == m_Selected && HasFocus ? Colors::BlueGreen : Colors::White, m_Options.at(i).c_str()); // Render target to target m_OptionTarget->Render(Target, m_X, TempY); @@ -107,8 +119,6 @@ void UI::Menu::Render(SDL_Texture *Target, bool HasFocus) void UI::Menu::AddOption(std::string_view NewOption) { m_Options.push_back(NewOption.data()); - ++m_OptionsLength; - m_MenuHeight += m_OptionHeight; } int UI::Menu::GetSelected(void) const @@ -123,6 +133,5 @@ void UI::Menu::SetSelected(int Selected) void UI::Menu::Reset(void) { - m_OptionsLength = -1; m_Options.clear(); } diff --git a/Source/UI/RenderFunctions.cpp b/Source/UI/RenderFunctions.cpp index ae4b0a1..18c7fe1 100644 --- a/Source/UI/RenderFunctions.cpp +++ b/Source/UI/RenderFunctions.cpp @@ -34,7 +34,7 @@ void UI::RenderBoundingBox(SDL_Texture *Target, int X, int Y, int Width, int Hei } // Setup color. - SDL::Color RenderMod = {(0x88 + ColorMod) << 16 | (0xC5 + (ColorMod / 2)) << 8 | 0xFF}; + SDL::Color RenderMod = {static_cast((0x88 + ColorMod) << 16 | (0xC5 + (ColorMod / 2)) << 8 | 0xFF)}; // This shouldn't fail, but I don't really care if it does. SDL_SetTextureColorMod(s_MenuBoundingCorners->Get(), RenderMod.RGBA[3], RenderMod.RGBA[2], RenderMod.RGBA[1]); diff --git a/Source/UI/TitleView.cpp b/Source/UI/TitleView.cpp index 8173c59..f0470fa 100644 --- a/Source/UI/TitleView.cpp +++ b/Source/UI/TitleView.cpp @@ -55,18 +55,18 @@ void UI::TitleView::Update(bool HasFocus) } double Scaling = Config::GetAnimationScaling(); - if (m_SelectedY > 280.0f) + if (m_SelectedY > 388.0f) { - m_Y += std::ceil((280.0f - m_SelectedY) / Scaling); + m_Y += std::ceil((388.0f - m_SelectedY) / Scaling); } - else if (m_SelectedY < 38.0f) + else if (m_SelectedY < 28.0f) { - m_Y += std::ceil((38.0f - m_SelectedY) / Scaling); + m_Y += std::ceil((28.0f - m_SelectedY) / Scaling); } for (size_t i = 0; i < m_TitleTiles.size(); i++) { - m_TitleTiles.at(i).Update(m_Selected == i ? true : false); + m_TitleTiles.at(i).Update(m_Selected == static_cast(i) ? true : false); } }