Implement States for TitleInfoState

This commit is contained in:
J-D-K 2025-11-11 08:25:48 -05:00
parent 4b93de93f5
commit ed57e27d03
3 changed files with 75 additions and 46 deletions

View File

@ -42,6 +42,14 @@ class TitleInfoState final : public BaseState
void render() override;
private:
/// @brief States this state can be in.
enum class State : uint8_t
{
Opening,
Displaying,
Closing
};
/// @brief Pointer to user.
data::User *m_user{};
@ -51,17 +59,14 @@ class TitleInfoState final : public BaseState
/// @brief Save a pointer to the save info.
const FsSaveDataInfo *m_saveInfo{};
/// @brief Whether or not the state was "closed";
bool m_close{};
/// @brief This is a pointer to the title's icon.
sdl::SharedTexture m_icon{};
/// @brief Transition for the open/close effect.
ui::Transition m_transition{};
/// @brief Stores whether or not the timer is started for the tiling animation.
bool m_timerStarted{};
/// @brief State the current state is in.
TitleInfoState::State m_state{};
/// @brief This is to create the "tiled in" effect because I like it.
sys::Timer m_timer{};
@ -117,14 +122,14 @@ class TitleInfoState final : public BaseState
void create_save_data_type(const FsSaveDataInfo *saveInfo, int x, int &y);
/// @brief Updates the current count of fields to display.
void update_field_count() noexcept;
/// @brief Updates the dimensions of the frame. Handles conditional state shifting.
void update_dimensions() noexcept;
/// @brief Runs the update routine on all fields.
void update_fields(bool hasFocus) noexcept;
/// @brief Handles input and updating.
void update_handle_input() noexcept;
/// @brief Returns the color to clear the field with.
sdl::Color get_field_color() noexcept;
inline sdl::Color get_field_color() noexcept;
/// @brief Signals to close the state.
void close() noexcept;

View File

@ -24,7 +24,7 @@ void BaseTask::update_loading_glyph()
m_colorMod.update();
if (!m_frameTimer.is_triggered()) { return; }
if (++m_currentFrame % 8 == 0) { m_currentFrame = 0; }
else if (++m_currentFrame % 8 == 0) { m_currentFrame = 0; }
}
void BaseTask::pop_on_plus()
@ -36,5 +36,16 @@ void BaseTask::pop_on_plus()
void BaseTask::render_loading_glyph()
{
sdl::text::render(sdl::Texture::Null, 56, 673, 32, sdl::text::NO_WRAP, m_colorMod, sm_glyphArray[m_currentFrame]);
// Render coords.
static constexpr int RENDER_X = 56;
static constexpr int RENDER_Y = 673;
static constexpr int RENDER_SIZE = 32;
sdl::text::render(sdl::Texture::Null,
RENDER_X,
RENDER_Y,
RENDER_SIZE,
sdl::text::NO_WRAP,
m_colorMod,
sm_glyphArray[m_currentFrame]);
}

View File

@ -27,7 +27,7 @@ namespace
constexpr int SIZE_FONT = 24;
/// @brief Dimensions of the frame.
constexpr int SIZE_START_WIDTH_HEIGHT = 16;
constexpr int SIZE_START_WIDTH_HEIGHT = 48;
constexpr int SIZE_END_WIDTH = 960;
constexpr int SIZE_END_HEIGHT = 580;
@ -55,7 +55,8 @@ TitleInfoState::TitleInfoState(data::User *user, data::TitleInfo *titleInfo, con
0,
SIZE_END_WIDTH,
SIZE_END_HEIGHT,
m_transition.DEFAULT_THRESHOLD)
ui::Transition::DEFAULT_THRESHOLD)
, m_state(State::Opening)
{
TitleInfoState::initialize_static_members();
TitleInfoState::initialize_info_fields();
@ -66,31 +67,24 @@ TitleInfoState::TitleInfoState(data::User *user, data::TitleInfo *titleInfo, con
void TitleInfoState::update()
{
// Grab this instead of calling the function over and over.
const bool hasFocus = BaseState::has_focus();
m_transition.update();
sm_frame->set_from_transition(m_transition, true);
if (!m_transition.in_place()) { return; }
else if (m_transition.in_place() && !m_timerStarted)
switch (m_state)
{
m_timer.start(50);
m_timerStarted = true;
case State::Opening: TitleInfoState::update_dimensions(); break;
case State::Displaying: TitleInfoState::update_handle_input(); break;
case State::Closing: TitleInfoState::update_dimensions(); break;
}
TitleInfoState::update_field_count();
TitleInfoState::update_fields(hasFocus);
bool bPressed = input::button_pressed(HidNpadButton_B);
if (bPressed) { TitleInfoState::close(); }
else if (m_close && m_transition.in_place()) { TitleInfoState::deactivate_state(); }
}
void TitleInfoState::render()
{
// Grab cause needed everywhere.
const bool hasFocus = BaseState::has_focus();
sm_frame->render(sdl::Texture::Null, hasFocus);
if (!m_transition.in_place()) { return; }
// Render the frame. Only continue further if we're currently displaying.
sm_frame->render(sdl::Texture::Null, hasFocus);
if (m_state != State::Displaying) { return; }
// We only want to render what's been triggered so far for the tiling in effect.
for (int i = 0; i < m_fieldDisplayCount; i++)
{
auto &currentField = m_infoFields[i];
@ -162,6 +156,7 @@ void TitleInfoState::initialize_info_fields()
void TitleInfoState::create_title(int y)
{
// This only works because the string is so short.
static constexpr std::string BESTEST_STAR = "$\u2605$";
static constexpr int WIDTH = SIZE_END_WIDTH - 64;
static constexpr int X = 640 - (WIDTH / 2);
@ -369,24 +364,41 @@ void TitleInfoState::create_save_data_type(const FsSaveDataInfo *saveInfo, int x
y += VERT_GAP;
}
void TitleInfoState::update_field_count() noexcept
void TitleInfoState::update_dimensions() noexcept
{
const int fieldSize = m_infoFields.size();
if (m_fieldDisplayCount >= fieldSize || !m_timer.is_triggered()) { return; }
// Update the transition and set the frame according to it.
m_transition.update();
sm_frame->set_from_transition(m_transition, true);
++m_fieldDisplayCount;
}
void TitleInfoState::update_fields(bool hasFocus) noexcept
{
for (int i = 0; i < m_fieldDisplayCount; i++)
// State shifting conditions.
const bool opened = m_state == State::Opening && m_transition.in_place();
const bool closed = m_state == State::Closing && m_transition.in_place();
if (opened)
{
auto &field = m_infoFields[i];
field->update(hasFocus);
m_timer.start(50);
m_state = State::Displaying;
}
else if (closed) { TitleInfoState::deactivate_state(); }
}
sdl::Color TitleInfoState::get_field_color() noexcept
void TitleInfoState::update_handle_input() noexcept
{
// Grab a cache this since it's needed a lot.
const bool hasFocus = BaseState::has_focus();
// Update the field count if needed.
const int currentCount = m_infoFields.size();
if (m_fieldDisplayCount < currentCount && m_timer.is_triggered()) { ++m_fieldDisplayCount; }
// Update the actually displayed fields so the text scrolls if need be.
for (int i = 0; i < m_fieldDisplayCount; i++) { m_infoFields[i]->update(hasFocus); }
// Input bools.
const bool bPressed = input::button_pressed(HidNpadButton_B);
if (bPressed) { TitleInfoState::close(); }
}
inline sdl::Color TitleInfoState::get_field_color() noexcept
{
m_fieldClearSwitch = m_fieldClearSwitch ? false : true;
return m_fieldClearSwitch ? colors::DIALOG_DARK : colors::CLEAR_COLOR;
@ -394,9 +406,9 @@ sdl::Color TitleInfoState::get_field_color() noexcept
void TitleInfoState::close() noexcept
{
m_state = State::Closing;
m_transition.set_target_width(SIZE_START_WIDTH_HEIGHT);
m_transition.set_target_height(SIZE_START_WIDTH_HEIGHT);
m_close = true;
}
void TitleInfoState::deactivate_state() { BaseState::deactivate(); }
@ -415,7 +427,7 @@ static inline std::shared_ptr<ui::TextScroll> create_new_field(std::string &text
static bool is_a_best_game(uint64_t applicationID) noexcept
{
static constexpr std::array<uint64_t, 16> BESTEST_GAMES = {0x0100BC300CB48000,
static constexpr std::array<uint64_t, 17> BESTEST_GAMES = {0x0100BC300CB48000,
0x01006C300E9F0000,
0x010065301A2E0000,
0x01000EA014150000,
@ -430,7 +442,8 @@ static bool is_a_best_game(uint64_t applicationID) noexcept
0x01002C0008E52000,
0x0100FF500E34A000,
0x010015100B514000,
0x0100AC20128AC000};
0x0100AC20128AC000,
0x0100453019AA8000};
return std::find(BESTEST_GAMES.begin(), BESTEST_GAMES.end(), applicationID) != BESTEST_GAMES.end();
}