Merge pull request #290 from J-D-K/dev

ui::Transition class, Guide string for extras, update git screenshot, remove repetitive transtion code in favor of ui::Transition, change button glyphs used in strings.
This commit is contained in:
JK 2025-09-10 21:41:30 -04:00 committed by GitHub
commit 5ef8da359e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
48 changed files with 477 additions and 299 deletions

View File

@ -51,7 +51,7 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
# NOTE: For some reason, devkitpro no longer has freetype-config included? Also, using pkg-config causes conflicts with
# my local pkg-config and I don't feel like dealing with CMake for all of this right now.
CFLAGS := $(INCLUDE) -D__SWITCH__ `sdl2-config --cflags` `curl-config --cflags`\
-g -Wall -O3 -ffunction-sections -ffast-math -fmax-errors=1 \
-g -Wall -O3 -Os -ffunction-sections -ffast-math -fmax-errors=1 \
$(ARCH) $(DEFINES)
CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=c++23

View File

@ -6,8 +6,7 @@ If you appreciate my work, or if JKSM or JKSV has gotten you out of a jam, pleas
<p align="center">
<a href='https://ko-fi.com/W7W51JF9W6' target='_blank'><img height='42' style='border:px;height:42px;' src='https://storage.ko-fi.com/cdn/kofi3.png?v=6' border='0' alt='Support me for the countless hours I poured into JKSV' /></a>
</p>
<img src="https://i.imgur.com/1nMbJte.png" />
<img src="https://i.imgur.com/aUrq46c.png" />
## Rewritten from the ground up:

View File

@ -1,6 +1,7 @@
#pragma once
#include "appstates/BaseState.hpp"
#include "sdl.hpp"
#include "ui/ControlGuide.hpp"
#include "ui/Menu.hpp"
/// @brief Extras menu.
@ -16,6 +17,9 @@ class ExtrasMenuState final : public BaseState
/// @brief Updates the menu.
void update() override;
/// @brief Sub-update routine.
void sub_update() override;
/// @brief Renders the menu to screen.
void render() override;
@ -26,6 +30,9 @@ class ExtrasMenuState final : public BaseState
/// @brief Render target for menu.
sdl::SharedTexture m_renderTarget{};
/// @brief Control guider for bottom right corner.
std::shared_ptr<ui::ControlGuide> m_controlGuide{};
/// @brief Creates and loads the menu strings.
void initialize_menu();

View File

@ -63,17 +63,11 @@ class FileModeState final : public BaseState
/// @brief Stores the size for committing data (if needed) to mountA.
int64_t m_journalSize{};
/// @brief The beginning Y coord of the dialog.
double m_y = 720.0f;
/// @brief Stores whether or not the panel should be closed.
bool m_close{};
/// @brief This is the targetY. Used for the opening and hiding effect.
double m_targetY = 91.0f;
/// @brief Config scaling for the "transition"
double m_scaling{};
/// @brief Stores whether or not the dialog has reached its targetted position.
bool m_inPlace{};
/// @brief Transition for the pop-up effect.
ui::Transition m_transition{};
/// @brief Stores whether the instance is dealing with sensitive data.
bool m_isSystem{};
@ -87,11 +81,8 @@ class FileModeState final : public BaseState
/// @brief This is the render target the browsers are rendered to.
static inline sdl::SharedTexture sm_renderTarget{};
/// @brief Stores a pointer to the guide in the bottom-right corner.
static inline const char *sm_controlGuide{};
/// @brief Calculated X coordinate of the control guide text.
static inline int sm_controlGuideX{};
/// @brief Control guide shared by all instances.
static inline std::shared_ptr<ui::ControlGuide> sm_controlGuide{};
/// @brief Initializes the members shared by all instances of FileModeState.
void initialize_static_members();
@ -105,9 +96,6 @@ class FileModeState final : public BaseState
/// @brief Loads the current directory listings and menus.
void initialize_directory_menu(const fslib::Path &path, fslib::Directory &directory, ui::Menu &menu);
/// @brief Updates the dialog's coordinates in the beginning.
void update_y_coord() noexcept;
/// @brief Starts the dialog hiding process.
void hide_dialog() noexcept;
@ -136,9 +124,6 @@ class FileModeState final : public BaseState
ui::Menu &menu,
const fslib::DirectoryEntry &entry);
/// @brief Renders the control guide string on the bottom of the screen.
void render_control_guide();
/// @brief Returns a reference to the currently active menu.
ui::Menu &get_source_menu() noexcept;

View File

@ -57,14 +57,11 @@ class FileOptionState final : public BaseState
/// @brief Pointer to spawning FileMode state.
FileModeState *m_spawningState{};
/// @brief X coordinate. This is set at construction according to the target from the spawning state.
int m_x{};
/// @brief Stores the target for easier access.
bool m_target{};
/// @brief X coordinate for the target to reach.
int m_targetX{};
/// @brief Whether or not the dialog/menu is in place.
bool m_inPlace{};
/// @brief Transition.
ui::Transition m_transition{};
/// @brief Whether or not the state should be closed.
bool m_close{};
@ -85,9 +82,6 @@ class FileOptionState final : public BaseState
/// @brief Ensures static members of all instances are allocated.
void initialize_static_members();
/// @brief Sets whether the dialog/menu are positioned left or right depending on the menu active in the spawning state.
void set_menu_side();
/// @brief Assigns the pointer to this.
void initialize_data_struct();
@ -97,9 +91,6 @@ class FileOptionState final : public BaseState
/// @brief Updates the FileModeState's destination data.
void update_filemode_dest();
/// @brief Updates the Y coordinate
void update_x_coord();
/// @brief Sets up and begins the copy task.
void copy_target();

View File

@ -3,6 +3,7 @@
#include "appstates/BaseState.hpp"
#include "data/data.hpp"
#include "sdl.hpp"
#include "ui/ControlGuide.hpp"
#include "ui/IconMenu.hpp"
#include <memory>
@ -28,6 +29,9 @@ class MainMenuState final : public BaseState
/// @brief Runs update routine.
void update() override;
/// @brief Runs the sub-update routine.
void sub_update() override;
/// @brief Renders menu to screen.
void render() override;
@ -62,11 +66,8 @@ class MainMenuState final : public BaseState
/// @brief Special menu type that uses icons.
std::shared_ptr<ui::IconMenu> m_mainMenu{};
/// @brief Pointer to control guide string so I don't need to call string::getByName every loop.
const char *m_controlGuide{};
/// @brief X coordinate of the control guide in the bottom right corner.
int m_controlGuideX{};
/// @brief Control guide in the bottom right.
std::shared_ptr<ui::ControlGuide> m_controlGuide{};
/// @brief This is the data struct passed to tasks.
MainMenuState::TaskData m_dataStruct{};

View File

@ -1,6 +1,7 @@
#pragma once
#include "appstates/BaseState.hpp"
#include "sdl.hpp"
#include "ui/ControlGuide.hpp"
#include "ui/Menu.hpp"
/// @brief The state for settings.
@ -16,6 +17,9 @@ class SettingsState final : public BaseState
/// @brief Runs the update routine.
void update() override;
/// @brief Sub update routine.
void sub_update() override;
/// @brief Runs the render routine.
void render() override;
@ -23,15 +27,12 @@ class SettingsState final : public BaseState
/// @brief Menu for selecting and toggling settings.
std::shared_ptr<ui::Menu> m_settingsMenu{};
/// @brief Pointer to the control guide string.
const char *m_controlGuide{};
// These are pointers to strings this state uses constantly.
const char *m_onOff[2]{};
const char *m_sortTypes[3]{};
/// @brief X coordinate of the control guide in the bottom right corner.
int m_controlGuideX{};
/// @brief Control guide.
std::shared_ptr<ui::ControlGuide> m_controlGuide{};
/// @brief Render target to render to.
sdl::SharedTexture m_renderTarget{};

View File

@ -1,5 +1,6 @@
#pragma once
#include "appstates/BaseState.hpp"
#include "ui/ControlGuide.hpp"
/// @brief Class that both view types are derived from.
class TitleSelectCommon : public BaseState
@ -15,19 +16,20 @@ class TitleSelectCommon : public BaseState
/// @brief Required, inherited.
virtual void update() = 0;
/// @brief Sub-update routine. Normally in a file, but I didn't feel like it really needed one.
void sub_update() override;
/// @brief Required, inherited.
virtual void render() = 0;
/// @brief Both derived classes need this function.
virtual void refresh() = 0;
/// @brief Renders the control guide string to the bottom right corner.
void render_control_guide();
protected:
/// @brief This is the control guide shared by all title selects.
static inline std::shared_ptr<ui::ControlGuide> sm_controlGuide{};
private:
/// @brief Pointer to the control guide string.
static inline const char *sm_controlGuide{};
/// @brief X coordinate the control guide is rendered at.
static inline int sm_controlGuideX{};
/// @brief Initializes the control guide if it hasn't been already.
void initialize_control_guide();
};

View File

@ -20,8 +20,8 @@ namespace colors
inline constexpr sdl::Color TRANSPARENT = {0x00000000};
inline constexpr sdl::Color SLIDE_PANEL_CLEAR = {0x000000CC};
inline constexpr sdl::Color DIV_COLOR = {0x707070FF};
inline constexpr sdl::Color GUIDE_COLOR = {0x0000007F};
inline constexpr uint8_t ALPHA_FADE_BEGIN = 0x00;
inline constexpr uint8_t ALPHA_FADE_END = 0x88;
} // namespace colors

View File

@ -0,0 +1,54 @@
#pragma once
#include "sdl.hpp"
#include "ui/Element.hpp"
#include "ui/Transition.hpp"
namespace ui
{
class ControlGuide final : public ui::Element
{
public:
/// @brief Creates a new control guide.
/// @param string Pointer to the control guide string to render.
ControlGuide(const char *guide);
static inline std::shared_ptr<ControlGuide> create(const char *guide)
{
return std::make_shared<ControlGuide>(guide);
}
/// @brief Update routine. Opens the guide.
void update(bool hasFocus) override;
/// @brief Sub update routine. Handles hiding the control guide.
void sub_update();
/// @brief Renders the control guide. Both arguments are ignored in this case.
void render(sdl::SharedTexture &target, bool hasFocus) override;
/// @brief This is a workaround for states where the guide can't really be hidden correctly. Ex: FileMode.
void reset() noexcept;
private:
/// @brief Stores the pointer to the guide string.
const char *m_guide{};
/// @brief Width of the control guide text.
int m_textWidth{};
/// @brief This stores the target X coordinate of the guide.
int m_targetX{};
/// @brief Width of the guide.
int m_guideWidth{};
/// @brief Transition for the guide string.
ui::Transition m_transition{};
/// @brief This is shared by all instances.
static inline sdl::SharedTexture sm_controlCap{};
/// @brief Ensures the control guide cap is loaded for all instances.
void initialize_static_members();
};
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "sdl.hpp"
#include "ui/Element.hpp"
#include "ui/Transition.hpp"
#include <memory>
#include <vector>
@ -90,9 +91,6 @@ namespace ui
/// @brief Whether or not to hide the panel.
bool m_hidePanel{};
/// @brief Current X coordinate to render to. Panels are always 720 pixels in height so no Y is required.
double m_x{};
/// @brief Width of the panel in pixels.
int m_width{};
@ -102,6 +100,9 @@ namespace ui
/// @brief Which side the panel is on.
SlideOutPanel::Side m_side{};
/// @brief Transition for the slide out effect.
ui::Transition m_transition{};
/// @brief Render target if panel.
sdl::SharedTexture m_renderTarget{};
@ -111,16 +112,10 @@ namespace ui
/// @brief Tracks the internal ID of render targets for panels.
static inline int sm_targetID{};
/// @brief Handles sliding out logic.
void slide_out() noexcept;
/// @brief Returns the target X to open the panel.
inline int get_target_open_x() { return m_side == Side::Left ? 0 : 1280 - m_width; }
/// @brief Slides the panel out from the left side.
void slide_out_left() noexcept;
/// @brief Slides the panel out from the right side.
void slide_out_right() noexcept;
/// @brief Contains the logic for hiding/closing the panel.
void close_hide_panel() noexcept;
/// @brief Returns the target X to close/hide the panel.
inline int get_target_close_x() { return m_side == Side::Left ? -m_width : 1280; }
};
} // namespace ui

72
include/ui/Transition.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
namespace ui
{
class Transition final
{
public:
/// @brief Default.
Transition() = default;
/// @brief Constructs a new transition.
/// @param x Beginning X coord.
/// @param y Beginning Y coord.
/// @param targetX Target X coord.
/// @param targetY Target Y coord.
/// @param threshold Gap, in pixels, before the x and/or y clamp into position.
Transition(int x, int y, int targetX, int targetY, int threshold) noexcept;
/// @brief Updates the transition.
void update() noexcept;
/// @brief Returns whether or not the transition has been met.
bool in_place() const noexcept;
/// @brief Returns the X coordinate.
int get_x() const noexcept;
/// @brief Returns the Y coordinate.
int get_y() const noexcept;
/// @brief Returns the target X.
int get_target_x() const noexcept;
/// @brief Returns the target Y.
int get_target_y() const noexcept;
/// @brief Sets the X coordinate.
void set_x(int x) noexcept;
/// @brief Sets the Y coordinate.
void set_y(int y) noexcept;
/// @brief Sets the target X coord.
void set_target_x(int targetX) noexcept;
/// @brief Sets the target Y coord.
void set_target_y(int targetY) noexcept;
private:
/// @brief Current X.
double m_x{};
/// @brief Current Y.
double m_y{};
/// @brief Target X.
double m_targetX{};
/// @brief Target Y.
double m_targetY{};
/// @brief Pixel gap threshold.
double m_threshold{};
/// @brief Scaling from config.
double m_scaling{};
void update_x_coord() noexcept;
void update_y_coord() noexcept;
};
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "ui/BoundingBox.hpp"
#include "ui/ColorMod.hpp"
#include "ui/ControlGuide.hpp"
#include "ui/DialogBox.hpp"
#include "ui/Element.hpp"
#include "ui/Frame.hpp"
@ -10,4 +11,4 @@
#include "ui/SlideOutPanel.hpp"
#include "ui/TextScroll.hpp"
#include "ui/TitleTile.hpp"
#include "ui/TitleView.hpp"
#include "ui/TitleView.hpp"

View File

@ -34,7 +34,8 @@
"1: [A] Auswählen [L] [R] Springen [Y] Favorit [X] Titeloptionen [B] Zurück",
"2: [A] Auswählen [Y] Wiederherstellen [X] Löschen [ZR] Hochladen [B] Schließen",
"3: [A] Umschalten [-] Beschreibung [X] Standardwerte [B] Zurück",
"4: [A] Eingeben [B] Zurück/Hoch [X] Optionen [ZL]/[ZR] Ziel wechseln [-] Schließen"
"4: [A] Eingeben [B] Zurück/Hoch [X] Optionen [ZL]/[ZR] Ziel wechseln [-] Schließen",
"5: [A] Auswählen"
],
"DataLoadingStatus": [
"0: Benutzerkonten vom System werden geladen...",

View File

@ -34,7 +34,8 @@
"1: [A] Select [L] [R] Jump [Y] Favourite [X] Title Options [B] Back",
"2: [A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close",
"3: [A] Toggle [-] Description [X] Defaults [B] Back",
"4: [A] Enter [B] Back/Up [X] Options [ZL]/[ZR] Change Target [-] Close"
"4: [A] Enter [B] Back/Up [X] Options [ZL]/[ZR] Change Target [-] Close",
"5: [A] Select"
],
"DataLoadingStatus": [
"0: Loading user accounts from system...",

View File

@ -34,7 +34,8 @@
"1: [A] Select [L] [R] Jump [Y] Favorite [X] Title Options [B] Back",
"2: [A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close",
"3: [A] Toggle [-] Description [X] Defaults [B] Back",
"4: [A] Enter [B] Back/Up [X] Options [ZL]/[ZR] Change Target [-] Close"
"4: [A] Enter [B] Back/Up [X] Options [ZL]/[ZR] Change Target [-] Close",
"5: [A] Select"
],
"DataLoadingStatus": [
"0: Loading user accounts from system...",

View File

@ -34,7 +34,8 @@
"1: [A] Seleccionar [L] [R] Saltar [Y] Favorito [X] Opciones de título [B] Volver",
"2: [A] Seleccionar [Y] Restaurar [X] Eliminar [ZR] Subir [B] Cerrar",
"3: [A] Alternar [-] Descripción [X] Valores por defecto [B] Volver",
"4: [A] Aceptar [B] Atrás/Arriba [X] Opciones [ZL]/[ZR] Cambiar objetivo [-] Cerrar"
"4: [A] Aceptar [B] Atrás/Arriba [X] Opciones [ZL]/[ZR] Cambiar objetivo [-] Cerrar",
"5: [A] Seleccionar"
],
"DataLoadingStatus": [
"0: Cargando cuentas de usuario desde el sistema...",

View File

@ -34,7 +34,8 @@
"1: [A] Seleccionar [L] [R] Saltar [Y] Favorito [X] Opciones del título [B] Atrás",
"2: [A] Seleccionar [Y] Restaurar [X] Eliminar [ZR] Subir [B] Cerrar",
"3: [A] Alternar [-] Descripción [X] Predeterminados [B] Atrás",
"4: [A] Aceptar [B] Atrás/Arriba [X] Opciones [ZL]/[ZR] Cambiar objetivo [-] Cerrar"
"4: [A] Aceptar [B] Atrás/Arriba [X] Opciones [ZL]/[ZR] Cambiar objetivo [-] Cerrar",
"5: [A] Seleccionar"
],
"DataLoadingStatus": [
"0: Cargando cuentas de usuario desde el sistema...",

View File

@ -34,7 +34,8 @@
"1: [A] Sélectionner [L] [R] Sauter [Y] Favori [X] Options du titre [B] Retour",
"2: [A] Sélectionner [Y] Restaurer [X] Supprimer [ZR] Téléverser [B] Fermer",
"3: [A] Basculer [-] Description [X] Valeurs par défaut [B] Retour",
"4: [A] Entrée [B] Retour/Haut [X] Options [ZL]/[ZR] Changer cible [-] Fermer"
"4: [A] Entrée [B] Retour/Haut [X] Options [ZL]/[ZR] Changer cible [-] Fermer",
"5: [A] Sélectionner"
],
"DataLoadingStatus": [
"0: Chargement des comptes utilisateur depuis le système...",

View File

@ -34,7 +34,8 @@
"1: [A] Sélectionner [L] [R] Sauter [Y] Favori [X] Options du titre [B] Retour",
"2: [A] Sélectionner [Y] Restaurer [X] Supprimer [ZR] Téléverser [B] Fermer",
"3: [A] Basculer [-] Description [X] Valeurs par défaut [B] Retour",
"4: [A] Entrée [B] Retour/Haut [X] Options [ZL]/[ZR] Changer la cible [-] Fermer"
"4: [A] Entrée [B] Retour/Haut [X] Options [ZL]/[ZR] Changer la cible [-] Fermer",
"5: [A] Sélectionner"
],
"DataLoadingStatus": [
"0: Chargement des comptes utilisateur depuis le système...",

View File

@ -34,7 +34,8 @@
"1: [A] Seleziona [L] [R] Salta [Y] Preferito [X] Opzioni titolo [B] Indietro",
"2: [A] Seleziona [Y] Ripristina [X] Elimina [ZR] Carica [B] Chiudi",
"3: [A] Attiva/disattiva [-] Descrizione [X] Predefiniti [B] Indietro",
"4: [A] Conferma [B] Indietro/Su [X] Opzioni [ZL]/[ZR] Cambia obiettivo [-] Chiudi"
"4: [A] Conferma [B] Indietro/Su [X] Opzioni [ZL]/[ZR] Cambia obiettivo [-] Chiudi",
"5: [A] Seleziona"
],
"DataLoadingStatus": [
"0: Caricamento account utente dal sistema...",

View File

@ -34,7 +34,8 @@
"1: [A] 選択 [L] [R] ジャンプ [Y] お気に入り [X] タイトル オプション [B] 戻る",
"2: [A] 選択 [Y] 復元 [X] 削除 [ZR] アップロード [B] 閉じる",
"3: [A] トグル [-] 説明 [X] デフォルト [B] 戻る",
"4: [A] 決定 [B] 戻る/上 [X] オプション [ZL]/[ZR] ターゲット切替 [-] 閉じる"
"4: [A] 決定 [B] 戻る/上 [X] オプション [ZL]/[ZR] ターゲット切替 [-] 閉じる",
"5: [A] 選択"
],
"DataLoadingStatus": [
"0: システムからユーザーアカウントを読み込み中...",

View File

@ -34,7 +34,8 @@
"1: [A] 선택 [L] [R] 점프 [Y] 즐겨찾기 [X] 타이틀 옵션 [B] 뒤로",
"2: [A] 선택 [Y] 복원 [X] 삭제 [ZR] 업로드 [B] 닫기",
"3: [A] 토글 [-] 설명 [X] 기본값 [B] 뒤로",
"4: [A] 선택 [B] 뒤로/위 [X] 옵션 [ZL]/[ZR] 대상 변경 [-] 닫기"
"4: [A] 선택 [B] 뒤로/위 [X] 옵션 [ZL]/[ZR] 대상 변경 [-] 닫기",
"5: [A] 선택"
],
"DataLoadingStatus": [
"0: 시스템에서 사용자 계정을 불러오는 중...",

View File

@ -34,7 +34,8 @@
"1: [A] Selecteer [L] [R] Spring [Y] Favoriet [X] Titelopties [B] Terug",
"2: [A] Selecteer [Y] Herstel [X] Verwijder [ZR] Upload [B] Sluit",
"3: [A] Wissel [-] Beschrijving [X] Standaardinstellingen [B] Terug",
"4: [A] Bevestigen [B] Terug/Omhoog [X] Opties [ZL]/[ZR] Doel wijzigen [-] Sluiten"
"4: [A] Bevestigen [B] Terug/Omhoog [X] Opties [ZL]/[ZR] Doel wijzigen [-] Sluiten",
"5: [A] Selecteer"
],
"DataLoadingStatus": [
"0: Gebruikersaccounts laden vanuit het systeem...",

View File

@ -34,7 +34,8 @@
"1: [A] Selecionar [L] [R] Saltar [Y] Favorito [X] Opções do Título [B] Voltar",
"2: [A] Selecionar [Y] Restaurar [X] Eliminar [ZR] Enviar [B] Fechar",
"3: [A] Alternar [-] Descrição [X] Padrões [B] Voltar",
"4: [A] Entrar [B] Voltar/Cima [X] Opções [ZL]/[ZR] Alterar alvo [-] Fechar"
"4: [A] Entrar [B] Voltar/Cima [X] Opções [ZL]/[ZR] Alterar alvo [-] Fechar",
"5: [A] Selecionar"
],
"DataLoadingStatus": [
"0: A carregar contas de utilizador a partir do sistema...",

View File

@ -34,7 +34,8 @@
"1: [A] Selecionar [L] [R] Pular [Y] Favorito [X] Opções do Título [B] Voltar",
"2: [A] Selecionar [Y] Restaurar [X] Deletar [ZR] Enviar [B] Fechar",
"3: [A] Alternar [-] Descrição [X] Padrões [B] Voltar",
"4: [A] Entrar [B] Voltar/Cima [X] Opções [ZL]/[ZR] Alterar alvo [-] Fechar"
"4: [A] Entrar [B] Voltar/Cima [X] Opções [ZL]/[ZR] Alterar alvo [-] Fechar",
"5: [A] Selecionar"
],
"DataLoadingStatus": [
"0: Carregando contas de usuário do sistema...",

View File

@ -34,7 +34,8 @@
"1: [A] Выбрать [L] [R] Прыжок [Y] В избранное [X] Опции заголовка [B] Назад",
"2: [A] Выбрать [Y] Восстановить [X] Удалить [ZR] Загрузить [B] Закрыть",
"3: [A] Переключить [-] Описание [X] По умолчанию [B] Назад",
"4: [A] Ввести [B] Назад/Вверх [X] Опции [ZL]/[ZR] Сменить цель [-] Закрыть"
"4: [A] Ввести [B] Назад/Вверх [X] Опции [ZL]/[ZR] Сменить цель [-] Закрыть",
"5: [A] Выбрать"
],
"DataLoadingStatus": [
"0: Загрузка учетных записей пользователей из системы...",

View File

@ -34,7 +34,8 @@
"1: [A] 选择 [L] [R] 跳转 [Y] 设为收藏 [X] 标题选项 [B] 返回",
"2: [A] 选择 [Y] 恢复 [X] 删除 [ZR] 上传 [B] 关闭",
"3: [A] 切换 [-] 描述 [X] 默认 [B] 返回",
"4: [A] 确认 [B] 返回/上 [X] 选项 [ZL]/[ZR] 切换目标 [-] 关闭"
"4: [A] 确认 [B] 返回/上 [X] 选项 [ZL]/[ZR] 切换目标 [-] 关闭",
"5: [A] 选择"
],
"DataLoadingStatus": [
"0: 从系统加载用户账户...",

View File

@ -34,7 +34,8 @@
"1: [A] 選擇 [L] [R] 翻頁 [Y] 最愛 [X] 遊戲選項 [B] 返回",
"2: [A] 選擇 [Y] 還原 [X] 刪除 [ZR] 上傳 [B] 關閉",
"3: [A] 切換 [-] 描述 [X] 預設 [B] 返回",
"4: [A] 確認 [B] 返回/上 [X] 選項 [ZL]/[ZR] 切換目標 [-] 關閉"
"4: [A] 確認 [B] 返回/上 [X] 選項 [ZL]/[ZR] 切換目標 [-] 關閉",
"5: [A] 選擇"
],
"DataLoadingStatus": [
"0: 從系統載入使用者帳號...",

BIN
romfs/Textures/GuideCap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

View File

@ -25,7 +25,7 @@ void StateManager::update()
if (stateVector.empty()) { return; }
// Run sub update routines.
for (auto &state : stateVector) { state->sub_update(); }
for (auto iter = stateVector.begin(); iter < stateVector.end() - 1; iter++) { (*iter)->sub_update(); }
std::shared_ptr<BaseState> &back = stateVector.back();
if (!back->has_focus()) { back->give_focus(); }

View File

@ -92,7 +92,10 @@ void BackupMenuState::render()
sdl::text::render(target, 32, 673, 22, sdl::text::NO_WRAP, colors::WHITE, m_controlGuide);
sm_menuRenderTarget->clear(colors::TRANSPARENT);
sm_backupMenu->render(sm_menuRenderTarget, hasFocus);
{
std::lock_guard menuGuard{sm_menuMutex};
sm_backupMenu->render(sm_menuRenderTarget, hasFocus);
}
sm_menuRenderTarget->render(target, 0, 43);
sm_slidePanel->render(sdl::Texture::Null, hasFocus);

View File

@ -35,6 +35,7 @@ static void finish_reinitialization();
ExtrasMenuState::ExtrasMenuState()
: m_renderTarget(sdl::TextureManager::load(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_TARGET))
, m_controlGuide(ui::ControlGuide::create(strings::get_by_name(strings::names::CONTROL_GUIDES, 5)))
{
ExtrasMenuState::initialize_menu();
}
@ -46,6 +47,7 @@ void ExtrasMenuState::update()
const bool bPressed = input::button_pressed(HidNpadButton_B);
m_extrasMenu->update(hasFocus);
m_controlGuide->update(hasFocus);
if (aPressed)
{
@ -63,6 +65,8 @@ void ExtrasMenuState::update()
else if (bPressed) { BaseState::deactivate(); }
}
void ExtrasMenuState::sub_update() { m_controlGuide->sub_update(); }
void ExtrasMenuState::render()
{
const bool hasFocus = BaseState::has_focus();
@ -70,6 +74,7 @@ void ExtrasMenuState::render()
m_renderTarget->clear(colors::TRANSPARENT);
m_extrasMenu->render(m_renderTarget, hasFocus);
m_renderTarget->render(sdl::Texture::Null, 201, 91);
m_controlGuide->render(sdl::Texture::Null, hasFocus);
}
void ExtrasMenuState::initialize_menu()

View File

@ -15,9 +15,7 @@ FileModeState::FileModeState(std::string_view mountA, std::string_view mountB, i
: m_mountA(mountA)
, m_mountB(mountB)
, m_journalSize(journalSize)
, m_y(720.f)
, m_targetY(91.0f)
, m_scaling(config::get_animation_scaling())
, m_transition(15, 720, 15, 87, 4)
, m_isSystem(isSystem)
, m_allowSystem(config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM))
{
@ -28,8 +26,15 @@ FileModeState::FileModeState(std::string_view mountA, std::string_view mountB, i
void FileModeState::update()
{
FileModeState::update_y_coord();
if (!m_inPlace) { return; }
m_transition.update();
if (!m_transition.in_place())
{
const int x = m_transition.get_x();
const int y = m_transition.get_y();
sm_frame->set_x(x);
sm_frame->set_y(y);
return;
}
const bool hasFocus = BaseState::has_focus();
@ -51,6 +56,7 @@ void FileModeState::update()
else if (FileModeState::is_hidden()) { FileModeState::deactivate_state(); }
menu.update(hasFocus);
sm_controlGuide->update(hasFocus);
}
void FileModeState::render()
@ -60,7 +66,7 @@ void FileModeState::render()
sm_renderTarget->clear(colors::TRANSPARENT);
// This is here so it's rendered underneath the pop-up frame.
if (hasFocus) { FileModeState::render_control_guide(); }
sm_controlGuide->render(sdl::Texture::Null, hasFocus);
sdl::render_line(sm_renderTarget, 617, 0, 617, 538, colors::WHITE);
sdl::render_line(sm_renderTarget, 618, 0, 618, 538, colors::DIALOG_DARK);
@ -69,21 +75,20 @@ void FileModeState::render()
m_dirMenuB->render(sm_renderTarget, hasFocus && m_target);
sm_frame->render(sdl::Texture::Null, true);
sm_renderTarget->render(sdl::Texture::Null, 23, m_y + 12);
const int y = m_transition.get_y();
sm_renderTarget->render(sdl::Texture::Null, 23, y + 12);
}
void FileModeState::initialize_static_members()
{
static constexpr std::string_view RENDER_TARGET_NAME = "FMRenderTarget";
static constexpr int CONTROL_GUIDE_START_X = 1220;
if (sm_frame && sm_renderTarget && sm_controlGuide) { return; }
if (sm_frame && sm_renderTarget) { return; }
sm_frame = ui::Frame::create(15, 720, 1250, 555);
sm_renderTarget = sdl::TextureManager::load(RENDER_TARGET_NAME, 1234, 538, SDL_TEXTUREACCESS_TARGET);
sm_controlGuide = strings::get_by_name(strings::names::CONTROL_GUIDES, 4);
sm_controlGuideX = CONTROL_GUIDE_START_X - sdl::text::get_width(22, sm_controlGuide);
sm_frame = ui::Frame::create(15, 720, 1250, 555);
sm_renderTarget = sdl::TextureManager::load(RENDER_TARGET_NAME, 1234, 538, SDL_TEXTUREACCESS_TARGET);
sm_controlGuide = ui::ControlGuide::create(strings::get_by_name(strings::names::CONTROL_GUIDES, 4));
}
void FileModeState::initialize_paths()
@ -127,31 +132,14 @@ void FileModeState::initialize_directory_menu(const fslib::Path &path, fslib::Di
}
}
void FileModeState::update_y_coord() noexcept
{
if (m_y == m_targetY) { return; }
const double add = (m_targetY - m_y) / m_scaling;
const double distance = math::Util<double>::absolute_distance(m_targetY, m_y);
m_y += std::round(add);
// The second condition is a fix for when scaling is 1.
if (distance <= 4 || m_y == m_targetY)
{
m_y = m_targetY;
m_inPlace = true;
}
sm_frame->set_y(m_y);
}
void FileModeState::hide_dialog() noexcept
{
if (!m_inPlace) { return; }
m_targetY = 720;
if (!m_transition.in_place()) { return; }
m_transition.set_target_y(720);
m_close = true;
}
bool FileModeState::is_hidden() noexcept { return m_inPlace && m_targetY == 720; }
bool FileModeState::is_hidden() noexcept { return m_close && m_transition.in_place(); }
void FileModeState::enter_selected(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu)
{
@ -204,11 +192,6 @@ void FileModeState::enter_directory(fslib::Path &path,
FileModeState::initialize_directory_menu(path, directory, menu);
}
void FileModeState::render_control_guide()
{
sdl::text::render(sdl::Texture::Null, sm_controlGuideX, 673, 22, sdl::text::NO_WRAP, colors::WHITE, sm_controlGuide);
}
ui::Menu &FileModeState::get_source_menu() noexcept { return m_target ? *m_dirMenuB.get() : *m_dirMenuA.get(); }
ui::Menu &FileModeState::get_destination_menu() noexcept { return m_target ? *m_dirMenuA.get() : *m_dirMenuB.get(); }
@ -224,6 +207,7 @@ fslib::Directory &FileModeState::get_destination_directory() noexcept { return m
void FileModeState::deactivate_state() noexcept
{
sm_frame->set_y(720);
sm_controlGuide->reset();
fslib::close_file_system(m_mountA);
fslib::close_file_system(m_mountB);
BaseState::deactivate();

View File

@ -41,20 +41,26 @@ static std::string get_size_string(int64_t totalSize);
FileOptionState::FileOptionState(FileModeState *spawningState)
: m_spawningState(spawningState)
, m_target(spawningState->m_target)
, m_transition(m_target ? 1280 : -240, 218, m_target ? 840 : 200, 218, 4)
, m_dataStruct(std::make_shared<FileOptionState::DataStruct>())
{
FileOptionState::initialize_static_members();
FileOptionState::set_menu_side();
FileOptionState::initialize_data_struct();
}
void FileOptionState::update()
{
m_transition.update();
if (!m_transition.in_place())
{
const int x = m_transition.get_x();
sm_dialog->set_x(x);
sm_copyMenu->set_x(x + 9);
return;
}
const bool hasFocus = BaseState::has_focus();
FileOptionState::update_x_coord();
if (!m_inPlace) { return; }
if (m_updateSource)
{
FileOptionState::update_filemode_source();
@ -93,9 +99,6 @@ void FileOptionState::render()
sm_dialog->render(sdl::Texture::Null, hasFocus);
sm_copyMenu->render(sdl::Texture::Null, hasFocus);
// I just didn't like this disappearing.
m_spawningState->render_control_guide();
}
void FileOptionState::update_source() { m_updateSource = true; }
@ -104,10 +107,17 @@ void FileOptionState::update_destination() { m_updateDest = true; }
void FileOptionState::initialize_static_members()
{
if (sm_copyMenu && sm_dialog) { return; }
if (sm_copyMenu && sm_dialog)
{
const int x = m_transition.get_x();
sm_copyMenu = ui::Menu::create(0, 236, 234, 20, 720); // High target height is a workaround.
sm_dialog = ui::DialogBox::create(520, 218, 256, 256);
sm_dialog->set_x(x);
sm_copyMenu->set_x(x + 9);
return;
}
sm_copyMenu = ui::Menu::create(1280, 236, 234, 20, 720); // High target height is a workaround.
sm_dialog = ui::DialogBox::create(1280, 218, 256, 256);
// This never changes, so...
for (int i = 0; const char *menuOption = strings::get_by_name(strings::names::FILEOPTION_MENU, i); i++)
@ -116,16 +126,6 @@ void FileOptionState::initialize_static_members()
}
}
void FileOptionState::set_menu_side()
{
const bool target = m_spawningState->m_target;
m_x = target ? 1280 : -240;
m_targetX = target ? 840 : 200;
sm_dialog->set_x(m_x);
sm_copyMenu->set_x(m_x + 9);
}
void FileOptionState::initialize_data_struct() { m_dataStruct->spawningState = this; }
void FileOptionState::update_filemode_source()
@ -146,24 +146,6 @@ void FileOptionState::update_filemode_dest()
m_spawningState->initialize_directory_menu(destPath, destDir, destMenu);
}
void FileOptionState::update_x_coord()
{
if (m_x == m_targetX) { return; }
// We're going to borrow the scaling from the FileMode
const int add = (m_targetX - m_x) / m_spawningState->m_scaling;
m_x += add;
const int distance = math::Util<int>::absolute_distance(m_x, m_targetX);
if (distance <= 4)
{
m_x = m_targetX;
m_inPlace = true;
}
sm_dialog->set_x(m_x);
sm_copyMenu->set_x(m_x + 9);
}
void FileOptionState::copy_target()
{
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
@ -285,7 +267,7 @@ void FileOptionState::rename_target()
const std::string newString = newPath.string();
// If this is false and there's a journaling size set, we need to commit on renaming for it to stick.
const bool isSource = !m_spawningState->m_target;
const bool isSource = !m_target;
const int64_t journalSize = m_spawningState->m_journalSize;
const bool commitNeeded = isSource && journalSize > 0;
@ -423,13 +405,12 @@ void FileOptionState::pop_system_error()
void FileOptionState::close()
{
const bool target = m_spawningState->m_target;
m_close = true;
m_targetX = target ? 1280 : -240;
m_close = true;
const int targetX = m_target ? 1280 : -240;
m_transition.set_target_x(targetX);
}
bool FileOptionState::is_closed() { return m_close && m_x == m_targetX; }
bool FileOptionState::is_closed() { return m_close && m_transition.in_place(); }
void FileOptionState::deactivate_state()
{

View File

@ -30,8 +30,7 @@ MainMenuState::MainMenuState()
, m_settingsIcon(sdl::TextureManager::load("settingsIcon", "romfs:/Textures/SettingsIcon.png"))
, m_extrasIcon(sdl::TextureManager::load("extrasIcon", "romfs:/Textures/ExtrasIcon.png"))
, m_mainMenu(ui::IconMenu::create(50, 15, 555))
, m_controlGuide(strings::get_by_name(strings::names::CONTROL_GUIDES, 0))
, m_controlGuideX(1220 - sdl::text::get_width(22, m_controlGuide))
, m_controlGuide(ui::ControlGuide::create(strings::get_by_name(strings::names::CONTROL_GUIDES, 0)))
, m_dataStruct(std::make_shared<MainMenuState::DataStruct>())
{
MainMenuState::initialize_settings_extras();
@ -55,8 +54,13 @@ void MainMenuState::update()
else if (yPressed) { MainMenuState::backup_all_for_all(); }
m_mainMenu->update(hasFocus);
m_controlGuide->update(hasFocus);
for (auto &state : sm_states) { state->sub_update(); }
}
void MainMenuState::sub_update() { m_controlGuide->sub_update(); }
void MainMenuState::render()
{
const bool hasFocus = BaseState::has_focus();
@ -65,13 +69,12 @@ void MainMenuState::render()
m_background->render(m_renderTarget, 0, 0);
m_mainMenu->render(m_renderTarget, hasFocus);
m_renderTarget->render(sdl::Texture::Null, 0, 91);
m_controlGuide->render(sdl::Texture::Null, hasFocus);
if (hasFocus)
{
BaseState *target = sm_states[selected].get();
target->render();
sdl::text::render(sdl::Texture::Null, m_controlGuideX, 673, 22, sdl::text::NO_WRAP, colors::WHITE, m_controlGuide);
}
}

View File

@ -63,8 +63,7 @@ namespace
SettingsState::SettingsState()
: m_settingsMenu(ui::Menu::create(32, 8, 1000, 24, 555))
, m_controlGuide(strings::get_by_name(strings::names::CONTROL_GUIDES, 3))
, m_controlGuideX(1220 - sdl::text::get_width(22, m_controlGuide))
, m_controlGuide(ui::ControlGuide::create(strings::get_by_name(strings::names::CONTROL_GUIDES, 3)))
, m_renderTarget(sdl::TextureManager::load(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_TARGET))
{
SettingsState::load_settings_menu();
@ -83,8 +82,12 @@ void SettingsState::update()
if (aPressed) { SettingsState::toggle_options(); }
else if (minusPressed) { SettingsState::create_push_description_message(); }
else if (bPressed) { BaseState::deactivate(); }
m_controlGuide->update(hasFocus);
}
void SettingsState::sub_update() { m_controlGuide->sub_update(); }
void SettingsState::render()
{
const bool hasFocus = BaseState::has_focus();
@ -92,11 +95,7 @@ void SettingsState::render()
m_renderTarget->clear(colors::TRANSPARENT);
m_settingsMenu->render(m_renderTarget, hasFocus);
m_renderTarget->render(sdl::Texture::Null, 201, 91);
if (hasFocus)
{
sdl::text::render(sdl::Texture::Null, m_controlGuideX, 673, 22, sdl::text::NO_WRAP, colors::WHITE, m_controlGuide);
}
m_controlGuide->render(sdl::Texture::Null, hasFocus);
}
void SettingsState::load_settings_menu()

View File

@ -43,13 +43,17 @@ void TextTitleSelectState::update()
else if (xPressed) { TextTitleSelectState::create_title_option_menu(); }
else if (yPressed) { TextTitleSelectState::add_remove_favorite(); }
else if (bPressed) { BaseState::deactivate(); }
sm_controlGuide->update(hasFocus);
}
void TextTitleSelectState::render()
{
const bool hasFocus = BaseState::has_focus();
m_renderTarget->clear(colors::TRANSPARENT);
m_titleSelectMenu->render(m_renderTarget, BaseState::has_focus());
TitleSelectCommon::render_control_guide();
m_titleSelectMenu->render(m_renderTarget, hasFocus);
sm_controlGuide->render(sdl::Texture::Null, hasFocus);
m_renderTarget->render(sdl::Texture::Null, 201, 91);
}

View File

@ -4,20 +4,13 @@
#include "sdl.hpp"
#include "strings/strings.hpp"
TitleSelectCommon::TitleSelectCommon()
TitleSelectCommon::TitleSelectCommon() { TitleSelectCommon::initialize_control_guide(); }
void TitleSelectCommon::sub_update() { sm_controlGuide->sub_update(); }
void TitleSelectCommon::initialize_control_guide()
{
if (sm_controlGuide && sm_controlGuideX != 0) { return; }
if (sm_controlGuide) { return; }
sm_controlGuide = strings::get_by_name(strings::names::CONTROL_GUIDES, 1);
sm_controlGuideX = 1220 - sdl::text::get_width(22, sm_controlGuide);
}
void TitleSelectCommon::render_control_guide()
{
const bool hasFocus = BaseState::has_focus();
if (hasFocus)
{
sdl::text::render(sdl::Texture::Null, sm_controlGuideX, 673, 22, sdl::text::NO_WRAP, colors::WHITE, sm_controlGuide);
}
}
sm_controlGuide = ui::ControlGuide::create(strings::get_by_name(strings::names::CONTROL_GUIDES, 1));
}

View File

@ -45,6 +45,7 @@ void TitleSelectState::update()
}
m_titleView->update(hasFocus);
sm_controlGuide->update(hasFocus);
}
void TitleSelectState::render()
@ -53,7 +54,7 @@ void TitleSelectState::render()
m_renderTarget->clear(colors::TRANSPARENT);
m_titleView->render(m_renderTarget, hasFocus);
TitleSelectCommon::render_control_guide();
sm_controlGuide->render(sdl::Texture::Null, hasFocus);
m_renderTarget->render(sdl::Texture::Null, 201, 91);
}

View File

@ -135,12 +135,16 @@ void UserOptionState::backup_all()
void UserOptionState::create_save_create()
{
if (m_user->get_account_save_type() == FsSaveDataType_System) { return; }
sm_menuPanel->hide();
SaveCreateState::create_and_push(m_user, m_titleSelect);
}
void UserOptionState::create_all_save_data()
{
if (m_user->get_account_save_type() == FsSaveDataType_System) { return; }
const char *confirmFormat = strings::get_by_name(strings::names::USEROPTION_CONFS, 1);
const char *nickname = m_user->get_nickname();

View File

@ -224,7 +224,7 @@ void data::User::load_icon()
accountProfileClose(&profile);
m_icon = sdl::TextureManager::load(iconName, iconBuffer.get(), iconSize);
}
else { m_icon = gfxutil::create_generic_icon(iconName, SIZE_ICON_FONT, colors::DIALOG_DARK, colors::WHITE); }
else { m_icon = gfxutil::create_generic_icon(m_nickname, SIZE_ICON_FONT, colors::DIALOG_DARK, colors::WHITE); }
}
void data::User::load_account(AccountProfile &profile, AccountProfileBase &profileBase)

View File

@ -2,7 +2,7 @@
#include <switch.h>
int main()
int main(int argc, const char *argv[])
{
JKSV jksv{};
while (appletMainLoop() && jksv.is_running())

View File

@ -106,21 +106,21 @@ static fslib::Path get_file_path()
static void replace_buttons_in_string(std::string &target)
{
stringutil::replace_in_string(target, "[A]", "\ue0e0");
stringutil::replace_in_string(target, "[B]", "\ue0e1");
stringutil::replace_in_string(target, "[X]", "\ue0e2");
stringutil::replace_in_string(target, "[Y]", "\ue0e3");
stringutil::replace_in_string(target, "[L]", "\ue0e4");
stringutil::replace_in_string(target, "[R]", "\ue0e5");
stringutil::replace_in_string(target, "[ZL]", "\ue0e6");
stringutil::replace_in_string(target, "[ZR]", "\ue0e7");
stringutil::replace_in_string(target, "[SL]", "\ue0e8");
stringutil::replace_in_string(target, "[SR]", "\ue0e9");
stringutil::replace_in_string(target, "[DPAD]", "\ue0ea");
stringutil::replace_in_string(target, "[DUP]", "\ue0eb");
stringutil::replace_in_string(target, "[DDOWN]", "\ue0ec");
stringutil::replace_in_string(target, "[DLEFT]", "\ue0ed");
stringutil::replace_in_string(target, "[DRIGHT]", "\ue0ee");
stringutil::replace_in_string(target, "[+]", "\ue0ef");
stringutil::replace_in_string(target, "[-]", "\ue0f0");
stringutil::replace_in_string(target, "[A]", "\ue0a0");
stringutil::replace_in_string(target, "[B]", "\ue0a1");
stringutil::replace_in_string(target, "[X]", "\ue0a2");
stringutil::replace_in_string(target, "[Y]", "\ue0a3");
stringutil::replace_in_string(target, "[L]", "\ue0a4");
stringutil::replace_in_string(target, "[R]", "\ue0a5");
stringutil::replace_in_string(target, "[ZL]", "\ue0a6");
stringutil::replace_in_string(target, "[ZR]", "\ue0a7");
stringutil::replace_in_string(target, "[SL]", "\ue0a8");
stringutil::replace_in_string(target, "[SR]", "\ue0a9");
stringutil::replace_in_string(target, "[DPAD]", "\ue0d0");
stringutil::replace_in_string(target, "[DUP]", "\ue0d1");
stringutil::replace_in_string(target, "[DDOWN]", "\ue0d2");
stringutil::replace_in_string(target, "[DLEFT]", "\ue0d3");
stringutil::replace_in_string(target, "[DRIGHT]", "\ue0d4");
stringutil::replace_in_string(target, "[+]", "\ue0b3");
stringutil::replace_in_string(target, "[-]", "\ue0b4");
}

View File

@ -245,6 +245,7 @@ void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuStat
fs::copy_file_commit(target, fs::DEFAULT_SAVE_ROOT, journalSize, task);
}
spawningState->save_data_written();
spawningState->refresh();
task->complete();
}
@ -253,9 +254,10 @@ void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuSta
{
if (error::is_null(task)) { return; }
data::User *user = taskData->user;
data::TitleInfo *titleInfo = taskData->titleInfo;
remote::Storage *remote = remote::get_remote_storage();
data::User *user = taskData->user;
data::TitleInfo *titleInfo = taskData->titleInfo;
remote::Storage *remote = remote::get_remote_storage();
BackupMenuState *spawningState = taskData->spawningState;
if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(remote)) { TASK_FINISH_RETURN(task); }
const bool autoBackup = config::get_by_key(config::keys::AUTO_BACKUP_ON_RESTORE);
@ -327,6 +329,7 @@ void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuSta
ui::PopMessageManager::push_message(popTicks, popErrorDeleting);
}
spawningState->save_data_written();
task->complete();
}

View File

@ -0,0 +1,56 @@
#include "ui/ControlGuide.hpp"
#include "graphics/colors.hpp"
#include "logging/logger.hpp"
ui::ControlGuide::ControlGuide(const char *guide)
: m_guide(guide)
, m_textWidth(sdl::text::get_width(23, m_guide))
, m_targetX(1220 - (m_textWidth + 24))
, m_guideWidth(1280 - m_targetX)
, m_transition(1280, 662, m_targetX, 662, 4)
{
ui::ControlGuide::initialize_static_members();
}
void ui::ControlGuide::update(bool hasFocus)
{
m_transition.update();
if (!m_transition.in_place()) { return; }
const int targetX = m_transition.get_target_x();
if (hasFocus && targetX != m_targetX) { m_transition.set_target_x(m_targetX); }
}
void ui::ControlGuide::sub_update()
{
const int targetX = m_transition.get_target_x();
if (targetX != 1280) { m_transition.set_target_x(1280); }
m_transition.update();
}
void ui::ControlGuide::render(sdl::SharedTexture &target, bool hasFocus)
{
const int guideX = m_transition.get_x();
const int guideY = m_transition.get_y();
sm_controlCap->render(sdl::Texture::Null, guideX, guideY);
sdl::render_rect_fill(sdl::Texture::Null, guideX + 16, guideY, m_guideWidth - 16, 48, colors::GUIDE_COLOR);
sdl::text::render(sdl::Texture::Null, guideX + 24, guideY + 10, 23, sdl::text::NO_WRAP, colors::WHITE, m_guide);
}
void ui::ControlGuide::initialize_static_members()
{
static constexpr std::string_view NAME_CAP = "ControlGuideCap";
if (sm_controlCap) { return; }
sm_controlCap = sdl::TextureManager::load(NAME_CAP, "romfs:/Textures/GuideCap.png");
}
void ui::ControlGuide::reset() noexcept
{
m_transition.set_target_x(1280);
m_transition.set_x(1280);
}

View File

@ -13,58 +13,71 @@ namespace
}
ui::SlideOutPanel::SlideOutPanel(int width, Side side)
: m_x(side == Side::Left ? static_cast<double>(-width) : static_cast<double>(SCREEN_WIDTH))
, m_width(width)
: m_width(width)
, m_targetX(side == Side::Left ? 0.0f : static_cast<double>(SCREEN_WIDTH) - m_width)
, m_side(side)
, m_transition(m_side == Side::Left ? -m_width : SCREEN_WIDTH, 0, m_targetX, 0, 4)
, m_renderTarget(
sdl::TextureManager::load("PANEL_" + std::to_string(sm_targetID++), m_width, 720, SDL_TEXTUREACCESS_TARGET)) {};
void ui::SlideOutPanel::update(bool hasFocus)
{
if (hasFocus && SlideOutPanel::is_hidden()) { SlideOutPanel::unhide(); }
const int targetX = m_transition.get_target_x();
if (hasFocus && targetX != m_targetX) { SlideOutPanel::unhide(); }
slide_out();
m_transition.update();
if (m_isOpen)
if (m_transition.in_place())
{
for (auto &currentElement : m_elements) { currentElement->update(hasFocus); }
}
}
void ui::SlideOutPanel::sub_update() { SlideOutPanel::close_hide_panel(); }
void ui::SlideOutPanel::sub_update() { m_transition.update(); }
void ui::SlideOutPanel::render(sdl::SharedTexture &target, bool hasFocus)
{
for (auto &currentElement : m_elements) { currentElement->render(m_renderTarget, hasFocus); }
m_renderTarget->render(target, m_x, 0);
const int x = m_transition.get_x();
m_renderTarget->render(target, x, 0);
}
void ui::SlideOutPanel::clear_target() { m_renderTarget->clear(colors::SLIDE_PANEL_CLEAR); }
void ui::SlideOutPanel::reset() noexcept
{
m_x = m_side == Side::Left ? -(m_width) : SCREEN_WIDTH;
const int x = SlideOutPanel::get_target_close_x();
m_transition.set_x(x);
m_isOpen = false;
m_closePanel = false;
}
void ui::SlideOutPanel::close() noexcept { m_closePanel = true; }
void ui::SlideOutPanel::hide() noexcept { m_hidePanel = true; }
void ui::SlideOutPanel::unhide() noexcept { m_hidePanel = false; }
bool ui::SlideOutPanel::is_open() const noexcept { return m_isOpen; }
bool ui::SlideOutPanel::is_closed() noexcept
void ui::SlideOutPanel::close() noexcept
{
close_hide_panel();
const bool closed = m_side == Side::Left ? m_x <= -m_width : m_x >= SCREEN_WIDTH;
return m_closePanel && closed;
const int targetX = SlideOutPanel::get_target_close_x();
m_transition.set_target_x(targetX);
m_closePanel = true;
}
void ui::SlideOutPanel::hide() noexcept
{
const int targetX = SlideOutPanel::get_target_close_x();
m_transition.set_target_x(targetX);
m_hidePanel = true;
}
void ui::SlideOutPanel::unhide() noexcept
{
const int targetX = SlideOutPanel::get_target_open_x();
m_transition.set_target_x(targetX);
m_hidePanel = false;
}
bool ui::SlideOutPanel::is_open() const noexcept { return m_transition.in_place(); }
bool ui::SlideOutPanel::is_closed() noexcept { return m_closePanel && m_transition.in_place(); }
bool ui::SlideOutPanel::is_hidden() const noexcept { return m_hidePanel; }
void ui::SlideOutPanel::push_new_element(std::shared_ptr<ui::Element> newElement) { m_elements.push_back(newElement); }
@ -72,59 +85,3 @@ void ui::SlideOutPanel::push_new_element(std::shared_ptr<ui::Element> newElement
void ui::SlideOutPanel::clear_elements() { m_elements.clear(); }
sdl::SharedTexture &ui::SlideOutPanel::get_target() noexcept { return m_renderTarget; }
void ui::SlideOutPanel::slide_out() noexcept
{
const bool needsSlideOut = !m_isOpen && !m_closePanel && !m_hidePanel;
if (!needsSlideOut) { return; }
const bool slideRight = m_side == SlideOutPanel::Side::Left && m_x < 0;
const bool slideLeft = m_side == SlideOutPanel::Side::Right && m_x > SCREEN_WIDTH - m_width;
if (slideRight) { SlideOutPanel::slide_out_left(); }
else if (slideLeft) { SlideOutPanel::slide_out_right(); }
}
void ui::SlideOutPanel::slide_out_left() noexcept
{
const double scaling = config::get_animation_scaling();
m_x -= std::round(m_x / scaling);
// This is a workaround for the floating points never lining up quite right.
const int distance = math::Util<double>::absolute_distance(m_x, m_targetX);
if (distance <= 2)
{
m_x = m_targetX;
m_isOpen = true;
}
}
void ui::SlideOutPanel::slide_out_right() noexcept
{
const double scaling = config::get_animation_scaling();
const double screenWidth = static_cast<double>(SCREEN_WIDTH);
const double width = static_cast<double>(m_width);
const double pixels = (screenWidth - width - m_x) / scaling;
m_x += std::round(pixels);
const int distance = math::Util<double>::absolute_distance(m_x, m_targetX);
if (distance <= 2)
{
m_x = m_targetX;
m_isOpen = true;
}
}
void ui::SlideOutPanel::close_hide_panel() noexcept
{
const double scaling = config::get_animation_scaling();
const bool closeHide = m_closePanel || m_hidePanel;
const bool closeToLeft = closeHide && m_side == Side::Left && m_x > -m_width;
const bool closeToRight = closeHide && m_side == Side::Right && m_x < SCREEN_WIDTH;
if (closeToLeft) { m_x += -((m_width - m_x) / scaling); }
else if (closeToRight) { m_x += m_x / scaling; }
const bool closedOrHidden = (m_x <= -m_width) || (m_x >= SCREEN_WIDTH);
if (closedOrHidden) { m_isOpen = false; }
}

61
source/ui/Transition.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "ui/Transition.hpp"
#include "config/config.hpp"
#include "logging/logger.hpp"
#include "mathutil.hpp"
#include <cmath>
ui::Transition::Transition(int x, int y, int targetX, int targetY, int threshold) noexcept
: m_x(x)
, m_y(y)
, m_targetX(targetX)
, m_targetY(targetY)
, m_threshold(threshold)
, m_scaling(config::get_animation_scaling()) {};
void ui::Transition::update() noexcept
{
ui::Transition::update_x_coord();
ui::Transition::update_y_coord();
}
bool ui::Transition::in_place() const noexcept { return m_x == m_targetX && m_y == m_targetY; }
int ui::Transition::get_x() const noexcept { return static_cast<int>(m_x); }
int ui::Transition::get_y() const noexcept { return static_cast<int>(m_y); }
int ui::Transition::get_target_x() const noexcept { return static_cast<int>(m_targetX); }
int ui::Transition::get_target_y() const noexcept { return static_cast<int>(m_targetY); }
void ui::Transition::set_x(int x) noexcept { m_x = x; }
void ui::Transition::set_y(int y) noexcept { m_y = y; }
void ui::Transition::set_target_x(int targetX) noexcept { m_targetX = targetX; }
void ui::Transition::set_target_y(int targetY) noexcept { m_targetY = targetY; }
void ui::Transition::update_x_coord() noexcept
{
if (m_x == m_targetX) { return; }
const double add = (m_targetX - m_x) / m_scaling;
m_x += std::round(add);
const double distance = math::Util<double>::absolute_distance(m_x, m_targetX);
if (distance <= m_threshold) { m_x = m_targetX; }
}
void ui::Transition::update_y_coord() noexcept
{
if (m_y == m_targetY) { return; }
const double add = (m_targetY - m_y) / m_scaling;
m_y += std::round(add);
const double distance = math::Util<double>::absolute_distance(m_y, m_targetY);
if (distance <= m_threshold) { m_y = m_targetY; }
}