diff --git a/include/ui/ControlGuide.hpp b/include/ui/ControlGuide.hpp index e9d3e41..7af21e1 100644 --- a/include/ui/ControlGuide.hpp +++ b/include/ui/ControlGuide.hpp @@ -31,6 +31,15 @@ namespace ui void reset() noexcept; private: + /// @brief States the guide can be in. + enum class State : uint8_t + { + Opening, + Opened, + Hiding, + Hidden + }; + /// @brief Stores the pointer to the guide string. const char *m_guide{}; @@ -46,10 +55,19 @@ namespace ui /// @brief Transition for the guide string. ui::Transition m_transition{}; + /// @brief Current state of the control guide. + ControlGuide::State m_state{}; + /// @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(); + + /// @brief Updates the position of the guide. + void update_position_state() noexcept; + + /// @brief Updates the current state of the control guide. + void update_state(bool hasFocus) noexcept; }; } \ No newline at end of file diff --git a/source/ui/ControlGuide.cpp b/source/ui/ControlGuide.cpp index 48d05ad..9426016 100644 --- a/source/ui/ControlGuide.cpp +++ b/source/ui/ControlGuide.cpp @@ -14,6 +14,9 @@ namespace /// @brief This is the constant Y of the transition. constexpr int TRANS_Y = 662; + + /// @brief The padding for the control guide container. + constexpr int CONTAINER_PADDING = 24; } // ---- Construction ---- @@ -21,9 +24,10 @@ namespace ui::ControlGuide::ControlGuide(const char *guide) : m_guide(guide) , m_textWidth(sdl::text::get_width(GUIDE_TEXT_SIZE, m_guide)) - , m_targetX(GUIDE_X_OFFSET - (m_textWidth + 24)) + , m_targetX(GUIDE_X_OFFSET - (m_textWidth + CONTAINER_PADDING)) , m_guideWidth(graphics::SCREEN_WIDTH - m_targetX) , m_transition(graphics::SCREEN_WIDTH, TRANS_Y, 0, 0, m_targetX, TRANS_Y, 0, 0, ui::Transition::DEFAULT_THRESHOLD) + , m_state(State::Opening) { ui::ControlGuide::initialize_static_members(); } @@ -32,33 +36,36 @@ ui::ControlGuide::ControlGuide(const char *guide) 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); } + switch (m_state) + { + case State::Opening: + case State::Hiding: ControlGuide::update_position_state(); break; + default: ControlGuide::update_state(hasFocus); break; + } } void ui::ControlGuide::sub_update() { - const int targetX = m_transition.get_target_x(); - if (targetX != graphics::SCREEN_WIDTH) { m_transition.set_target_x(graphics::SCREEN_WIDTH); } - - m_transition.update(); + // To do: Maybe this differently? + ControlGuide::update(false); } void ui::ControlGuide::render(sdl::SharedTexture &target, bool hasFocus) { + // These are for the rectangle that makes up the rest of the container. static constexpr int RECT_OFFSET_X = 16; static constexpr int RECT_HEIGHT = 48; + // This is where the text is rendered and its size. static constexpr int TEXT_OFFSET_X = 24; static constexpr int TEXT_OFFSET_Y = 10; static constexpr int TEXT_FONT_SIZE = 24; + // Grab the X and Y. const int guideX = m_transition.get_x(); const int guideY = m_transition.get_y(); + // Render the cap and the rectangle. sm_controlCap->render(sdl::Texture::Null, guideX, guideY); sdl::render_rect_fill(sdl::Texture::Null, guideX + RECT_OFFSET_X, @@ -66,6 +73,8 @@ void ui::ControlGuide::render(sdl::SharedTexture &target, bool hasFocus) m_guideWidth - RECT_OFFSET_X, RECT_HEIGHT, colors::GUIDE_COLOR); + + // Guide text. sdl::text::render(sdl::Texture::Null, guideX + TEXT_OFFSET_X, guideY + TEXT_OFFSET_Y, @@ -79,15 +88,48 @@ void ui::ControlGuide::render(sdl::SharedTexture &target, bool hasFocus) void ui::ControlGuide::initialize_static_members() { + // Name for the texture manager. static constexpr std::string_view NAME_CAP = "ControlGuideCap"; + // If it's already loaded, return. if (sm_controlCap) { return; } - sm_controlCap = sdl::TextureManager::load(NAME_CAP, "romfs:/Textures/GuideCap.png"); } void ui::ControlGuide::reset() noexcept { + // Set both to the width of the screen. m_transition.set_target_x(graphics::SCREEN_WIDTH); m_transition.set_x(graphics::SCREEN_WIDTH); } + +void ui::ControlGuide::update_position_state() noexcept +{ + // Update the transition. + m_transition.update(); + + // State conditions. + const bool opened = m_state == State::Opening && m_transition.in_place_xy(); + const bool hidden = m_state == State::Hiding && m_transition.in_place_xy(); + if (opened) { m_state = State::Opened; } + else if (hidden) { m_state = State::Hidden; } +} + +void ui::ControlGuide::update_state(bool hasFocus) noexcept +{ + // Conditions. + const bool hide = (m_state == State::Opening || m_state == State::Opened) && !hasFocus; + const bool unhide = (m_state == State::Hiding || m_state == State::Hidden) && hasFocus; + if (hide) + { + // Set target to screen width. + m_transition.set_target_x(graphics::SCREEN_WIDTH); + m_state = State::Hiding; + } + else if (unhide) + { + // Set target to open. + m_transition.set_target_x(m_targetX); + m_state = State::Opening; + } +} \ No newline at end of file