Implement/complete TitleInfoState

This commit is contained in:
J-D-K
2025-06-12 16:25:22 -04:00
parent 95ecbec3e4
commit 8dd16c12bc
12 changed files with 289 additions and 60 deletions

View File

@@ -2,11 +2,22 @@
#include "colors.hpp"
#include "input.hpp"
#include "sdl.hpp"
#include "strings.hpp"
#include "stringutil.hpp"
namespace
{
/// @brief This is the width of the panel in pixels.
constexpr int SIZE_PANEL_WIDTH = 480;
/// @brief This is the gap on both sides
constexpr int SIZE_PANEL_SUB = 16;
/// @brief This is the size used for rendering text here.
constexpr int SIZE_FONT = 24;
/// @brief This is the vertical size in pixels of the render targets for title/publisher.
constexpr int SIZE_TEXT_TARGET_HEIGHT = 40;
} // namespace
TitleInfoState::TitleInfoState(data::User *user, data::TitleInfo *titleInfo)
@@ -17,12 +28,59 @@ TitleInfoState::TitleInfoState(data::User *user, data::TitleInfo *titleInfo)
{
// This is the slide panel everything is rendered to.
sm_slidePanel = std::make_unique<ui::SlideOutPanel>(SIZE_PANEL_WIDTH, ui::SlideOutPanel::Side::Right);
// This is the render target for the title.
sm_titleTarget = sdl::TextureManager::create_load_texture("infoTitleTarget",
SIZE_PANEL_WIDTH - 32,
32,
SIZE_PANEL_WIDTH - SIZE_PANEL_SUB,
SIZE_TEXT_TARGET_HEIGHT,
SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET);
// This is the render target for the publisher.
sm_publisherTarget =
sdl::TextureManager::create_load_texture("infoPublisherTarget",
SIZE_PANEL_WIDTH - SIZE_PANEL_SUB,
SIZE_TEXT_TARGET_HEIGHT,
SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET);
sm_initialized = true;
}
// Do this instead of calling the function everytime.
uint64_t applicationID = m_titleInfo->get_application_id();
// These is needed at some point.
FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
PdmPlayStatistics *playStats = m_user->get_play_stats_by_id(applicationID);
// Title text.
m_titleScroll
.create(m_titleInfo->get_title(), SIZE_FONT, SIZE_PANEL_WIDTH - SIZE_PANEL_SUB, 6, false, colors::WHITE);
// Publisher.
m_publisherScroll
.create(m_titleInfo->get_publisher(), SIZE_FONT, SIZE_PANEL_WIDTH - SIZE_PANEL_SUB, 6, false, colors::WHITE);
// Grab the application ID string.
m_applicationID =
stringutil::get_formatted_string(strings::get_by_name(strings::names::TITLE_INFO_STRINGS, 0), applicationID);
// Same here. I think these use lower case characters on the NAND?
m_saveDataID = stringutil::get_formatted_string(strings::get_by_name(strings::names::TITLE_INFO_STRINGS, 1),
saveInfo->save_data_id);
// This is simple.
m_totalLaunches = stringutil::get_formatted_string(strings::get_by_name(strings::names::TITLE_INFO_STRINGS, 3),
playStats->total_launches);
// This should be semi-simple.
m_saveDataType = stringutil::get_formatted_string(
strings::get_by_name(strings::names::TITLE_INFO_STRINGS, 4),
strings::get_by_name(strings::names::SAVE_DATA_TYPES, saveInfo->save_data_type));
// Calculate play time. We're going to use non-floating point to truncate the remainders.
int64_t seconds = playStats->playtime / static_cast<int64_t>(1e+9);
int64_t hours = seconds / 3600;
int64_t minutes = (seconds % 3600) / 60;
seconds %= 60;
m_playTime = stringutil::get_formatted_string(strings::get_by_name(strings::names::TITLE_INFO_STRINGS, 2),
hours,
minutes,
seconds);
}
TitleInfoState::~TitleInfoState()
@@ -33,8 +91,15 @@ TitleInfoState::~TitleInfoState()
void TitleInfoState::update(void)
{
// Grab this instead of calling the function over and over.
bool hasFocus = AppState::has_focus();
// Update slide panel.
sm_slidePanel->update(AppState::has_focus());
sm_slidePanel->update(hasFocus);
// Update the scrolling text.
m_titleScroll.update(hasFocus);
m_publisherScroll.update(hasFocus);
if (input::button_pressed(HidNpadButton_B))
{
@@ -49,18 +114,110 @@ void TitleInfoState::update(void)
void TitleInfoState::render(void)
{
// This is the vertical gap for rendering text.
static constexpr int SIZE_VERT_GAP = SIZE_TEXT_TARGET_HEIGHT + 4;
// This is the size to render the rectangles at.
static constexpr int SIZE_RECT_WIDTH = SIZE_PANEL_WIDTH - SIZE_PANEL_SUB;
// This is whether or not the state currently has focus.
bool hasFocus = AppState::has_focus();
// Clear the title and publisher targets.
sm_titleTarget->clear(colors::DIALOG_BOX);
sm_publisherTarget->clear(colors::CLEAR_COLOR);
// Grab the panel's target and clear it. To do: This how I originally intended to.
sm_slidePanel->clear_target();
// Grab the panel target for rendering to.
SDL_Texture *panelTarget = sm_slidePanel->get_target();
// This is our Y rendering coordinate. It's easier to adjust this as needed than change everything.
// This starts under the icon.
int y = 304;
// Start by rendering the icon.
m_icon->render(panelTarget, 112, 24);
m_icon->render_stretched(panelTarget, 80, 8, 320, 320);
// Clear the title target and render the text scroll to it.
sm_titleTarget->clear(colors::DIALOG_BOX);
// Render the textscroll to the target, then target to the panel target.
m_titleScroll.render(sm_titleTarget->get(), hasFocus);
sm_titleTarget->render(panelTarget, 8, (y += SIZE_VERT_GAP));
// Publisher.
m_publisherScroll.render(sm_publisherTarget->get(), hasFocus);
sm_publisherTarget->render(panelTarget, 8, (y += SIZE_VERT_GAP));
// These are different since the probably won't go outside the bounds of the rectangle.
sdl::render_rect_fill(panelTarget,
8,
(y += SIZE_VERT_GAP),
SIZE_RECT_WIDTH,
SIZE_TEXT_TARGET_HEIGHT,
colors::DIALOG_BOX);
// Text needs to be aligned like the scrolling text.
sdl::text::render(panelTarget,
16,
y + 6,
SIZE_FONT,
sdl::text::NO_TEXT_WRAP,
colors::WHITE,
m_applicationID.c_str());
// These are different since the probably won't go outside the bounds of the rectangle.
sdl::render_rect_fill(panelTarget,
8,
(y += SIZE_VERT_GAP),
SIZE_RECT_WIDTH,
SIZE_TEXT_TARGET_HEIGHT,
colors::CLEAR_COLOR);
// Text needs to be aligned like the scrolling text.
sdl::text::render(panelTarget, 16, y + 6, SIZE_FONT, sdl::text::NO_TEXT_WRAP, colors::WHITE, m_saveDataID.c_str());
// These are different since the probably won't go outside the bounds of the rectangle.
sdl::render_rect_fill(panelTarget,
8,
(y += SIZE_VERT_GAP),
SIZE_RECT_WIDTH,
SIZE_TEXT_TARGET_HEIGHT,
colors::DIALOG_BOX);
// Text needs to be aligned like the scrolling text.
sdl::text::render(panelTarget, 16, y + 6, SIZE_FONT, sdl::text::NO_TEXT_WRAP, colors::WHITE, m_playTime.c_str());
// These are different since the probably won't go outside the bounds of the rectangle.
sdl::render_rect_fill(panelTarget,
8,
(y += SIZE_VERT_GAP),
SIZE_RECT_WIDTH,
SIZE_TEXT_TARGET_HEIGHT,
colors::CLEAR_COLOR);
// Text needs to be aligned like the scrolling text.
sdl::text::render(panelTarget,
16,
y + 6,
SIZE_FONT,
sdl::text::NO_TEXT_WRAP,
colors::WHITE,
m_totalLaunches.c_str());
// These are different since the probably won't go outside the bounds of the rectangle.
sdl::render_rect_fill(panelTarget,
8,
(y += SIZE_VERT_GAP),
SIZE_RECT_WIDTH,
SIZE_TEXT_TARGET_HEIGHT,
colors::DIALOG_BOX);
// Text needs to be aligned like the scrolling text.
sdl::text::render(panelTarget,
16,
y + 6,
SIZE_FONT,
sdl::text::NO_TEXT_WRAP,
colors::WHITE,
m_saveDataType.c_str());
sm_slidePanel->render(NULL, AppState::has_focus());
}