mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-10-01 13:46:52 -05:00
File mode progress.
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
#include "JKSV.hpp"
|
||||
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/FileModeState.hpp"
|
||||
#include "appstates/MainMenuState.hpp"
|
||||
#include "appstates/TaskState.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "curl/curl.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "sdl.hpp"
|
||||
@@ -30,9 +31,21 @@ namespace
|
||||
/// @brief Build month.
|
||||
constexpr uint8_t BUILD_MON = 8;
|
||||
/// @brief Build day.
|
||||
constexpr uint8_t BUILD_DAY = 25;
|
||||
constexpr uint8_t BUILD_DAY = 29;
|
||||
/// @brief Year.
|
||||
constexpr uint16_t BUILD_YEAR = 2025;
|
||||
|
||||
/// @brief Config for socket.
|
||||
constexpr SocketInitConfig SOCKET_INIT_CONFIG = {.tcp_tx_buf_size = 0x20000,
|
||||
.tcp_rx_buf_size = 0x20000,
|
||||
.tcp_tx_buf_max_size = 0x80000,
|
||||
.tcp_rx_buf_max_size = 0x80000,
|
||||
.udp_tx_buf_size = 0x2400,
|
||||
.udp_rx_buf_size = 0xA500,
|
||||
.sb_efficiency = 8,
|
||||
.num_bsd_sessions = 3,
|
||||
.bsd_service_type = BsdServiceType_User};
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename... Args>
|
||||
@@ -47,12 +60,30 @@ static bool initialize_service(Result (*function)(Args...), const char *serviceN
|
||||
return true;
|
||||
}
|
||||
|
||||
class BootTimer final
|
||||
{
|
||||
public:
|
||||
BootTimer()
|
||||
: m_start(std::chrono::high_resolution_clock::now()) {};
|
||||
|
||||
~BootTimer()
|
||||
{
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto microSeconds = std::chrono::duration_cast<std::chrono::microseconds>(end - m_start);
|
||||
logger::log("Boot time: %llu microseconds", microSeconds);
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::system_clock::time_point m_start{};
|
||||
};
|
||||
|
||||
// Definition at bottom.
|
||||
static void finish_initialization();
|
||||
|
||||
// This can't really have an initializer list since it sets everything up.
|
||||
JKSV::JKSV()
|
||||
{
|
||||
BootTimer timer{};
|
||||
appletSetCpuBoostMode(ApmCpuBoostMode_FastLoad);
|
||||
ABORT_ON_FAILURE(JKSV::initialize_services());
|
||||
ABORT_ON_FAILURE(JKSV::initialize_filesystem());
|
||||
@@ -86,7 +117,7 @@ JKSV::~JKSV()
|
||||
JKSV::exit_services();
|
||||
sdl::text::exit();
|
||||
sdl::exit();
|
||||
fslib::exit();
|
||||
|
||||
appletSetCpuBoostMode(ApmCpuBoostMode_Normal);
|
||||
}
|
||||
|
||||
@@ -133,10 +164,11 @@ void JKSV::render()
|
||||
bool JKSV::initialize_filesystem()
|
||||
{
|
||||
// This needs to be in this specific order
|
||||
const bool fslib = fslib::initialize();
|
||||
const bool fslib = fslib::is_initialized();
|
||||
const bool romfs = initialize_service(romfsInit, "RomFS");
|
||||
const bool fslibDev = fslib && fslib::dev::initialize_sdmc();
|
||||
if (!fslib || !romfs || !fslibDev) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -150,7 +182,7 @@ bool JKSV::initialize_services()
|
||||
serviceInit = serviceInit && initialize_service(pmshellInitialize, "PMShell");
|
||||
serviceInit = serviceInit && initialize_service(setInitialize, "Set");
|
||||
serviceInit = serviceInit && initialize_service(setsysInitialize, "SetSys");
|
||||
serviceInit = serviceInit && initialize_service(socketInitializeDefault, "Socket");
|
||||
serviceInit = serviceInit && initialize_service(socketInitialize, "Socket", &SOCKET_INIT_CONFIG);
|
||||
serviceInit = serviceInit && initialize_service(nifmInitialize, "NIFM", NifmServiceType_User);
|
||||
return serviceInit;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ void StateManager::update()
|
||||
|
||||
if (stateVector.empty()) { return; }
|
||||
|
||||
// Run sub update routines.
|
||||
for (auto &state : stateVector) { state->sub_update(); }
|
||||
|
||||
std::shared_ptr<BaseState> &back = stateVector.back();
|
||||
if (!back->has_focus()) { back->give_focus(); }
|
||||
back->update();
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
#include "appstates/FadeState.hpp"
|
||||
#include "appstates/ProgressState.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "keyboard.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
@@ -127,7 +127,7 @@ void BackupMenuState::refresh()
|
||||
}
|
||||
|
||||
int index{};
|
||||
for (const fslib::DirectoryEntry &entry : m_directoryListing.list())
|
||||
for (const fslib::DirectoryEntry &entry : m_directoryListing)
|
||||
{
|
||||
sm_backupMenu->add_option(entry.get_filename());
|
||||
m_menuEntries.push_back({MenuEntryType::Local, index++});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "appstates/BaseState.hpp"
|
||||
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include "appstates/MainMenuState.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logging/error.hpp"
|
||||
|
||||
BlacklistEditState::BlacklistEditState()
|
||||
: BaseState()
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "appstates/ExtrasMenuState.hpp"
|
||||
|
||||
#include "appstates/FileModeState.hpp"
|
||||
#include "appstates/MainMenuState.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "keyboard.hpp"
|
||||
@@ -50,7 +52,13 @@ void ExtrasMenuState::update()
|
||||
{
|
||||
switch (m_extrasMenu.get_selected())
|
||||
{
|
||||
case REINIT_DATA: ExtrasMenuState::reinitialize_data(); break;
|
||||
case REINIT_DATA: ExtrasMenuState::reinitialize_data(); break;
|
||||
case SD_TO_SD_BROWSER: ExtrasMenuState::sd_to_sd_browser(); break;
|
||||
case BIS_PRODINFO_F: ExtrasMenuState::prodinfof_to_sd(); break;
|
||||
case BIS_SAFE: ExtrasMenuState::safe_to_sd(); break;
|
||||
case BIS_SYSTEM: ExtrasMenuState::system_to_sd(); break;
|
||||
case BIS_USER: ExtrasMenuState::user_to_sd(); break;
|
||||
case TERMINATE_PROCESS: ExtrasMenuState::terminate_process(); break;
|
||||
}
|
||||
}
|
||||
else if (bPressed) { BaseState::deactivate(); }
|
||||
@@ -75,6 +83,42 @@ void ExtrasMenuState::initialize_menu()
|
||||
|
||||
void ExtrasMenuState::reinitialize_data() { data::launch_initialization(true, finish_reinitialization); }
|
||||
|
||||
void ExtrasMenuState::sd_to_sd_browser() { FileModeState::create_and_push("sdmc", "sdmc", false); }
|
||||
|
||||
void ExtrasMenuState::prodinfof_to_sd()
|
||||
{
|
||||
const bool mountError = error::fslib(fslib::open_bis_filesystem("prodinfo-f", FsBisPartitionId_CalibrationFile));
|
||||
if (mountError) { return; }
|
||||
|
||||
FileModeState::create_and_push("prodinfo-f", "sdmc", false);
|
||||
}
|
||||
|
||||
void ExtrasMenuState::safe_to_sd()
|
||||
{
|
||||
const bool mountError = error::fslib(fslib::open_bis_filesystem("safe", FsBisPartitionId_SafeMode));
|
||||
if (mountError) { return; }
|
||||
|
||||
FileModeState::create_and_push("safe", "sdmc", false);
|
||||
}
|
||||
|
||||
void ExtrasMenuState::system_to_sd()
|
||||
{
|
||||
const bool mountError = error::fslib(fslib::open_bis_filesystem("system", FsBisPartitionId_System));
|
||||
if (mountError) { return; }
|
||||
|
||||
FileModeState::create_and_push("system", "sdmc", false);
|
||||
}
|
||||
|
||||
void ExtrasMenuState::user_to_sd()
|
||||
{
|
||||
const bool mountError = error::fslib(fslib::open_bis_filesystem("user", FsBisPartitionId_User));
|
||||
if (mountError) { return; }
|
||||
|
||||
FileModeState::create_and_push("user", "sdmc", false);
|
||||
}
|
||||
|
||||
void ExtrasMenuState::terminate_process() {}
|
||||
|
||||
static void finish_reinitialization()
|
||||
{
|
||||
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
|
||||
|
||||
261
source/appstates/FileModeState.cpp
Normal file
261
source/appstates/FileModeState.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
#include "appstates/FileModeState.hpp"
|
||||
|
||||
#include "appstates/FileOptionState.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "mathutil.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
FileModeState::FileModeState(std::string_view mountA, std::string_view mountB, int64_t journalSize)
|
||||
: m_mountA(mountA)
|
||||
, m_mountB(mountB)
|
||||
, m_journalSize(journalSize)
|
||||
, m_y(720.f)
|
||||
, m_targetY(91.0f)
|
||||
, m_scaling(config::get_animation_scaling())
|
||||
{
|
||||
FileModeState::initialize_static_members();
|
||||
FileModeState::initialize_paths();
|
||||
FileModeState::initialize_menus();
|
||||
}
|
||||
|
||||
void FileModeState::update()
|
||||
{
|
||||
FileModeState::update_y_coord();
|
||||
if (!m_inPlace) { return; }
|
||||
|
||||
const bool hasFocus = BaseState::has_focus();
|
||||
|
||||
ui::Menu &menu = FileModeState::get_source_menu();
|
||||
fslib::Path &path = FileModeState::get_source_path();
|
||||
fslib::Directory &directory = FileModeState::get_source_directory();
|
||||
|
||||
const bool aPressed = input::button_pressed(HidNpadButton_A);
|
||||
const bool bPressed = input::button_pressed(HidNpadButton_B);
|
||||
const bool xPressed = input::button_pressed(HidNpadButton_X);
|
||||
const bool zlZRPressed = input::button_pressed(HidNpadButton_ZL) || input::button_pressed(HidNpadButton_ZR);
|
||||
const bool minusPressed = input::button_pressed(HidNpadButton_Minus);
|
||||
|
||||
if (aPressed) { FileModeState::enter_selected(path, directory, menu); }
|
||||
else if (bPressed) { FileModeState::up_one_directory(path, directory, menu); }
|
||||
else if (xPressed) { FileModeState::open_option_menu(directory, menu); }
|
||||
else if (zlZRPressed) { FileModeState::change_target(); }
|
||||
else if (minusPressed) { FileModeState::hide_dialog(); }
|
||||
else if (FileModeState::is_hidden()) { FileModeState::deactivate_state(); }
|
||||
|
||||
menu.update(hasFocus);
|
||||
}
|
||||
|
||||
void FileModeState::render()
|
||||
{
|
||||
const bool hasFocus = BaseState::has_focus();
|
||||
|
||||
sm_renderTarget->clear(colors::TRANSPARENT);
|
||||
|
||||
// This is here so it's rendered underneath the pop-up frame.
|
||||
if (hasFocus) { FileModeState::render_control_guide(); }
|
||||
|
||||
sdl::render_line(sm_renderTarget, 617, 0, 617, 538, colors::WHITE);
|
||||
sdl::render_line(sm_renderTarget, 618, 0, 618, 538, colors::DIALOG_DARK);
|
||||
|
||||
m_dirMenuA->render(sm_renderTarget, hasFocus && m_target == false);
|
||||
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);
|
||||
}
|
||||
|
||||
bool FileModeState::get_target() const noexcept { return m_target; }
|
||||
|
||||
fslib::Path FileModeState::get_source()
|
||||
{
|
||||
const fslib::Path &sourcePath = FileModeState::get_source_path();
|
||||
const fslib::Directory &sourceDir = FileModeState::get_source_directory();
|
||||
const ui::Menu &sourceMenu = FileModeState::get_source_menu();
|
||||
|
||||
const int selected = sourceMenu.get_selected();
|
||||
|
||||
// If 0, the current path is our target.
|
||||
if (selected == 0) { return sourcePath; }
|
||||
|
||||
const int dirIndex = selected - 2;
|
||||
const fslib::DirectoryEntry &entry = sourceDir[dirIndex];
|
||||
|
||||
return sourcePath / entry;
|
||||
}
|
||||
|
||||
fslib::Path FileModeState::get_destination()
|
||||
{
|
||||
const fslib::Path &destPath = FileModeState::get_destination_path();
|
||||
const fslib::Directory &destDir = FileModeState::get_destination_directory();
|
||||
const ui::Menu &destMenu = FileModeState::get_destination_menu();
|
||||
|
||||
const int selected = destMenu.get_selected();
|
||||
|
||||
if (selected == 0) { return destPath; }
|
||||
|
||||
const int dirIndex = selected - 1;
|
||||
const fslib::DirectoryEntry &entry = destDir[dirIndex];
|
||||
|
||||
return destPath / entry;
|
||||
}
|
||||
|
||||
bool FileModeState::commit_required() const noexcept { return m_target == false && m_journalSize > 0; }
|
||||
|
||||
int64_t FileModeState::get_journal_size() const noexcept { return m_journalSize; }
|
||||
|
||||
void FileModeState::render_control_guide() noexcept
|
||||
{
|
||||
sdl::text::render(sdl::Texture::Null, sm_controlGuideX, 673, 22, sdl::text::NO_WRAP, colors::WHITE, sm_controlGuide);
|
||||
}
|
||||
|
||||
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) { 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);
|
||||
}
|
||||
|
||||
void FileModeState::initialize_paths()
|
||||
{
|
||||
const std::string pathA = m_mountA + ":/";
|
||||
const std::string pathB = m_mountB + ":/";
|
||||
|
||||
m_pathA = pathA;
|
||||
m_pathB = pathB;
|
||||
}
|
||||
|
||||
void FileModeState::initialize_menus()
|
||||
{
|
||||
m_dirMenuA = ui::Menu::create(8, 8, 594, 22, 538);
|
||||
m_dirMenuB = ui::Menu::create(626, 8, 594, 22, 538);
|
||||
|
||||
FileModeState::initialize_directory_menu(m_pathA, m_dirA, *m_dirMenuA.get());
|
||||
FileModeState::initialize_directory_menu(m_pathB, m_dirB, *m_dirMenuB.get());
|
||||
}
|
||||
|
||||
void FileModeState::initialize_directory_menu(const fslib::Path &path, fslib::Directory &directory, ui::Menu &menu)
|
||||
{
|
||||
static constexpr const char *DIR_PREFIX = "[D] ";
|
||||
static constexpr const char *FILE_PREFIX = "[F] ";
|
||||
|
||||
directory.open(path);
|
||||
if (!directory.is_open()) { return; }
|
||||
|
||||
menu.reset();
|
||||
menu.add_option(".");
|
||||
menu.add_option("..");
|
||||
|
||||
for (const fslib::DirectoryEntry &entry : directory)
|
||||
{
|
||||
std::string option{};
|
||||
if (entry.is_directory()) { option = DIR_PREFIX; }
|
||||
else { option = FILE_PREFIX; }
|
||||
|
||||
option += entry.get_filename();
|
||||
menu.add_option(option);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (distance <= 4)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool FileModeState::is_hidden() noexcept { return m_inPlace && m_targetY == 720; }
|
||||
|
||||
void FileModeState::enter_selected(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu)
|
||||
{
|
||||
const int selected = menu.get_selected();
|
||||
|
||||
if (selected == 1) { FileModeState::up_one_directory(path, directory, menu); }
|
||||
else
|
||||
{
|
||||
const int dirIndex = selected - 2;
|
||||
const fslib::DirectoryEntry &entry = directory[dirIndex];
|
||||
if (entry.is_directory()) { FileModeState::enter_directory(path, directory, menu, entry); }
|
||||
}
|
||||
}
|
||||
|
||||
void FileModeState::open_option_menu(fslib::Directory &directory, ui::Menu &menu)
|
||||
{
|
||||
const int selected = menu.get_selected();
|
||||
|
||||
if (selected == 0 || selected > 1) { FileOptionState::create_and_push(this); }
|
||||
}
|
||||
|
||||
void FileModeState::change_target() { m_target = m_target ? false : true; }
|
||||
|
||||
void FileModeState::up_one_directory(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu)
|
||||
{
|
||||
if (FileModeState::path_is_root(path)) { return; }
|
||||
|
||||
size_t lastSlash = path.find_last_of('/');
|
||||
if (lastSlash == path.NOT_FOUND) { return; }
|
||||
else if (lastSlash <= 0) { lastSlash = 1; }
|
||||
|
||||
fslib::Path newPath{path.sub_path(lastSlash)};
|
||||
path = std::move(newPath);
|
||||
FileModeState::initialize_directory_menu(path, directory, menu);
|
||||
}
|
||||
|
||||
void FileModeState::enter_directory(fslib::Path &path,
|
||||
fslib::Directory &directory,
|
||||
ui::Menu &menu,
|
||||
const fslib::DirectoryEntry &entry)
|
||||
{
|
||||
if (!entry.is_directory()) { return; }
|
||||
|
||||
path /= entry.get_filename();
|
||||
FileModeState::initialize_directory_menu(path, directory, menu);
|
||||
}
|
||||
|
||||
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(); }
|
||||
|
||||
fslib::Path &FileModeState::get_source_path() noexcept { return m_target ? m_pathB : m_pathA; }
|
||||
|
||||
fslib::Path &FileModeState::get_destination_path() noexcept { return m_target ? m_pathA : m_pathB; }
|
||||
|
||||
fslib::Directory &FileModeState::get_source_directory() noexcept { return m_target ? m_dirB : m_dirA; }
|
||||
|
||||
fslib::Directory &FileModeState::get_destination_directory() noexcept { return m_target ? m_dirA : m_dirB; }
|
||||
|
||||
void FileModeState::deactivate_state() noexcept
|
||||
{
|
||||
sm_frame->set_y(720);
|
||||
fslib::close_file_system(m_mountA);
|
||||
fslib::close_file_system(m_mountB);
|
||||
BaseState::deactivate();
|
||||
}
|
||||
199
source/appstates/FileOptionState.cpp
Normal file
199
source/appstates/FileOptionState.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "appstates/FileOptionState.hpp"
|
||||
|
||||
#include "appstates/ConfirmState.hpp"
|
||||
#include "appstates/ProgressState.hpp"
|
||||
#include "appstates/TaskState.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "input.hpp"
|
||||
#include "keyboard.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "mathutil.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
#include "tasks/fileoptions.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
enum
|
||||
{
|
||||
COPY,
|
||||
DELETE,
|
||||
RENAME,
|
||||
CREATE_DIR,
|
||||
PROPERTIES,
|
||||
CLOSE
|
||||
};
|
||||
|
||||
// These make things easier to read and type.
|
||||
using TaskConfirm = ConfirmState<sys::Task, TaskState, FileOptionState::DataStruct>;
|
||||
using ProgressConfirm = ConfirmState<sys::ProgressTask, ProgressState, FileOptionState::DataStruct>;
|
||||
}
|
||||
|
||||
FileOptionState::FileOptionState(FileModeState *spawningState)
|
||||
: m_spawningState(spawningState)
|
||||
, m_commitData(m_spawningState->commit_required())
|
||||
, m_scaling(config::get_animation_scaling())
|
||||
, m_dataStruct(std::make_shared<FileOptionState::DataStruct>())
|
||||
{
|
||||
FileOptionState::initialize_static_members();
|
||||
FileOptionState::set_menu_side();
|
||||
}
|
||||
|
||||
void FileOptionState::update()
|
||||
{
|
||||
const bool hasFocus = BaseState::has_focus();
|
||||
|
||||
FileOptionState::update_x_coord();
|
||||
if (!m_inPlace) { return; }
|
||||
|
||||
sm_copyMenu->update(hasFocus);
|
||||
const int selected = sm_copyMenu->get_selected();
|
||||
const bool aPressed = input::button_pressed(HidNpadButton_A);
|
||||
const bool bPressed = input::button_pressed(HidNpadButton_B);
|
||||
|
||||
if (aPressed)
|
||||
{
|
||||
switch (selected)
|
||||
{
|
||||
case COPY: FileOptionState::copy_target(); break;
|
||||
case DELETE: FileOptionState::delete_target(); break;
|
||||
case RENAME: FileOptionState::rename_target(); break;
|
||||
}
|
||||
}
|
||||
else if (bPressed) { FileOptionState::close(); }
|
||||
else if (FileOptionState::is_closed()) { FileOptionState::deactivate_state(); }
|
||||
}
|
||||
|
||||
void FileOptionState::render()
|
||||
{
|
||||
const bool hasFocus = BaseState::has_focus();
|
||||
|
||||
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::initialize_static_members()
|
||||
{
|
||||
if (sm_copyMenu && sm_dialog) { return; }
|
||||
|
||||
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);
|
||||
|
||||
// This never changes, so...
|
||||
for (int i = 0; const char *menuOption = strings::get_by_name(strings::names::FILEOPTION_MENU, i); i++)
|
||||
{
|
||||
sm_copyMenu->add_option(menuOption);
|
||||
}
|
||||
}
|
||||
|
||||
void FileOptionState::set_menu_side()
|
||||
{
|
||||
const bool target = m_spawningState->get_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::update_x_coord()
|
||||
{
|
||||
if (m_x == m_targetX) { return; }
|
||||
|
||||
const int add = (m_targetX - m_x) / 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()
|
||||
{
|
||||
fslib::Path source = m_spawningState->get_source();
|
||||
fslib::Path dest = m_spawningState->get_destination();
|
||||
|
||||
const char *copyFormat = strings::get_by_name(strings::names::FILEOPTION_CONFS, 0);
|
||||
const std::string query = stringutil::get_formatted_string(copyFormat, source.string().c_str(), dest.string().c_str());
|
||||
|
||||
m_dataStruct->sourcePath = std::move(source);
|
||||
m_dataStruct->destPath = std::move(dest);
|
||||
m_dataStruct->journalSize = m_journalSize;
|
||||
|
||||
ProgressConfirm::create_push_fade(query, false, tasks::fileoptions::copy_source_to_destination, m_dataStruct);
|
||||
}
|
||||
|
||||
void FileOptionState::delete_target()
|
||||
{
|
||||
fslib::Path source = m_spawningState->get_source();
|
||||
|
||||
const char *deleteFormat = strings::get_by_name(strings::names::FILEOPTION_CONFS, 1);
|
||||
const std::string query = stringutil::get_formatted_string(deleteFormat, source.string().c_str());
|
||||
|
||||
m_dataStruct->sourcePath = std::move(source);
|
||||
m_dataStruct->journalSize = m_journalSize;
|
||||
|
||||
TaskConfirm::create_push_fade(query, true, tasks::fileoptions::delete_target, m_dataStruct);
|
||||
}
|
||||
|
||||
void FileOptionState::rename_target()
|
||||
{
|
||||
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
|
||||
const bool target = m_spawningState->get_target();
|
||||
const fslib::Path targetPath = target ? m_spawningState->get_destination() : m_spawningState->get_source();
|
||||
|
||||
char nameBuffer[FS_MAX_PATH] = {0};
|
||||
const char *filename = targetPath.get_filename();
|
||||
const char *keyboardFormat = strings::get_by_name(strings::names::KEYBOARD, 9);
|
||||
const std::string keyboardHeader = stringutil::get_formatted_string(keyboardFormat, filename);
|
||||
const bool validInput = keyboard::get_input(SwkbdType_QWERTY, filename, keyboardHeader, nameBuffer, FS_MAX_PATH);
|
||||
if (validInput) { return; }
|
||||
|
||||
size_t folderBegin = targetPath.find_last_of('/');
|
||||
if (folderBegin == targetPath.NOT_FOUND) { return; }
|
||||
else if (folderBegin < 1) { folderBegin = 1; }
|
||||
|
||||
fslib::Path newPath{targetPath.sub_path(folderBegin) / nameBuffer};
|
||||
|
||||
const bool isDir = fslib::directory_exists(targetPath);
|
||||
const bool renameDir = isDir && error::fslib(fslib::rename_directory(targetPath, newPath));
|
||||
const bool renameFile = !isDir && error::fslib(fslib::rename_file(targetPath, newPath));
|
||||
if (!renameDir && !renameFile)
|
||||
{
|
||||
const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 5);
|
||||
const std::string pop = stringutil::get_formatted_string(popFormat, filename);
|
||||
ui::PopMessageManager::push_message(popTicks, pop);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 4);
|
||||
const std::string pop = stringutil::get_formatted_string(popFormat, filename, nameBuffer);
|
||||
ui::PopMessageManager::push_message(popTicks, pop);
|
||||
}
|
||||
}
|
||||
|
||||
void FileOptionState::close()
|
||||
{
|
||||
const bool target = m_spawningState->get_target();
|
||||
|
||||
m_close = true;
|
||||
m_targetX = target ? 1280 : -240;
|
||||
}
|
||||
|
||||
bool FileOptionState::is_closed() { return m_close && m_x == m_targetX; }
|
||||
|
||||
void FileOptionState::deactivate_state()
|
||||
{
|
||||
sm_copyMenu->set_selected(0);
|
||||
BaseState::deactivate();
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/TaskState.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
#include "appstates/MessageState.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "keyboard.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
@@ -157,10 +157,10 @@ void SettingsState::change_working_directory()
|
||||
const char *popSuccessFormat = strings::get_by_name(strings::names::SETTINGS_POPS, 1);
|
||||
const char *popFailed = strings::get_by_name(strings::names::SETTINGS_POPS, 2);
|
||||
|
||||
const fslib::Path oldPath{config::get_working_directory()};
|
||||
const std::string oldPath = config::get_working_directory().string();
|
||||
std::array<char, FS_MAX_PATH> pathBuffer = {0};
|
||||
|
||||
const bool input = keyboard::get_input(SwkbdType_Normal, oldPath.full_path(), inputHeader, pathBuffer.data(), FS_MAX_PATH);
|
||||
const bool input = keyboard::get_input(SwkbdType_Normal, oldPath, inputHeader, pathBuffer.data(), FS_MAX_PATH);
|
||||
if (!input) { return; }
|
||||
|
||||
const fslib::Path newPath{pathBuffer.data()};
|
||||
@@ -179,7 +179,8 @@ void SettingsState::change_working_directory()
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string popMessage = stringutil::get_formatted_string(popSuccessFormat, newPath.full_path());
|
||||
const std::string newPathString = newPath.string();
|
||||
const std::string popMessage = stringutil::get_formatted_string(popSuccessFormat, newPathString);
|
||||
ui::PopMessageManager::push_message(popTicks, popMessage);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "appstates/TitleInfoState.hpp"
|
||||
|
||||
#include "StateManager.hpp"
|
||||
#include "error.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/ConfirmState.hpp"
|
||||
#include "appstates/FileModeState.hpp"
|
||||
#include "appstates/MainMenuState.hpp"
|
||||
#include "appstates/TitleInfoState.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "keyboard.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
@@ -57,25 +58,20 @@ void TitleOptionState::update()
|
||||
const bool hasFocus = BaseState::has_focus();
|
||||
|
||||
sm_slidePanel->update(hasFocus);
|
||||
const bool isOpen = sm_slidePanel->is_open();
|
||||
if (!isOpen) { return; }
|
||||
|
||||
const bool isOpen = sm_slidePanel->is_open();
|
||||
const bool aPressed = input::button_pressed(HidNpadButton_A);
|
||||
const bool bPressed = input::button_pressed(HidNpadButton_B);
|
||||
const int selected = sm_titleOptionMenu->get_selected();
|
||||
|
||||
// This is kind of tricky to handle, because the blacklist function uses both.
|
||||
if (m_refreshRequired)
|
||||
{
|
||||
// Refresh the views.
|
||||
MainMenuState::refresh_view_states();
|
||||
m_refreshRequired = false;
|
||||
// Return so nothing else happens. Not sure I like this, but w/e.
|
||||
return;
|
||||
}
|
||||
if (m_exitRequired) { sm_slidePanel->close(); }
|
||||
|
||||
if (aPressed)
|
||||
if (aPressed && isOpen)
|
||||
{
|
||||
switch (selected)
|
||||
{
|
||||
@@ -91,10 +87,16 @@ void TitleOptionState::update()
|
||||
case EXPORT_SVI: TitleOptionState::export_svi_file(); break;
|
||||
}
|
||||
}
|
||||
else if (bPressed) { sm_slidePanel->close(); }
|
||||
else if (bPressed || m_exitRequired)
|
||||
{
|
||||
sm_slidePanel->close();
|
||||
m_exitRequired = false;
|
||||
}
|
||||
else if (sm_slidePanel->is_closed()) { TitleOptionState::deactivate_state(); }
|
||||
}
|
||||
|
||||
void TitleOptionState::sub_update() { sm_slidePanel->sub_update(); }
|
||||
|
||||
void TitleOptionState::render()
|
||||
{
|
||||
const bool hasFocus = BaseState::has_focus();
|
||||
@@ -131,6 +133,7 @@ void TitleOptionState::initialize_data_struct()
|
||||
|
||||
void TitleOptionState::create_push_info_state()
|
||||
{
|
||||
sm_slidePanel->hide();
|
||||
auto titleInfoState = TitleInfoState::create(m_user, m_titleInfo);
|
||||
StateManager::push_state(titleInfoState);
|
||||
}
|
||||
@@ -194,7 +197,18 @@ void TitleOptionState::change_output_directory()
|
||||
ui::PopMessageManager::push_message(popTicks, popSuccess);
|
||||
}
|
||||
|
||||
void TitleOptionState::create_push_file_mode() {}
|
||||
void TitleOptionState::create_push_file_mode()
|
||||
{
|
||||
const uint64_t applicationID = m_titleInfo->get_application_id();
|
||||
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
|
||||
if (error::is_null(saveInfo)) { return; }
|
||||
|
||||
const bool saveOpened = fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *saveInfo);
|
||||
if (!saveOpened) { return; }
|
||||
|
||||
sm_slidePanel->hide();
|
||||
FileModeState::create_and_push(fs::DEFAULT_SAVE_MOUNT, "sdmc", true);
|
||||
}
|
||||
|
||||
void TitleOptionState::delete_all_local_backups()
|
||||
{
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
#include "appstates/TaskState.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
@@ -78,6 +78,8 @@ void UserOptionState::update()
|
||||
else if (sm_menuPanel->is_closed()) { UserOptionState::deactivate_state(); }
|
||||
}
|
||||
|
||||
void UserOptionState::sub_update() { sm_menuPanel->sub_update(); }
|
||||
|
||||
void UserOptionState::render()
|
||||
{
|
||||
// Render target user's title selection screen.
|
||||
@@ -131,7 +133,11 @@ void UserOptionState::backup_all()
|
||||
else { ProgressConfirm::create_and_push(query, true, tasks::useroptions::backup_all_for_user_local, m_dataStruct); }
|
||||
}
|
||||
|
||||
void UserOptionState::create_save_create() { SaveCreateState::create_and_push(m_user, m_titleSelect); }
|
||||
void UserOptionState::create_save_create()
|
||||
{
|
||||
sm_menuPanel->hide();
|
||||
SaveCreateState::create_and_push(m_user, m_titleSelect);
|
||||
}
|
||||
|
||||
void UserOptionState::create_all_save_data()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "JSON.hpp"
|
||||
#include "config/keys.hpp"
|
||||
#include "error.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
@@ -181,7 +180,7 @@ bool config::ConfigContext::load_config_file()
|
||||
const bool exists = fslib::file_exists(configPath);
|
||||
if (!exists) { return false; }
|
||||
|
||||
json::Object configJSON = json::new_object(json_object_from_file, configPath.full_path());
|
||||
json::Object configJSON = json::new_object(json_object_from_file, PATH_CONFIG_FILE.data());
|
||||
if (!configJSON) { return false; }
|
||||
|
||||
json_object_iterator configIter = json::iter_begin(configJSON);
|
||||
@@ -212,7 +211,8 @@ void config::ConfigContext::save_config_file()
|
||||
json::Object configJSON = json::new_object(json_object_new_object);
|
||||
if (!configJSON) { return; }
|
||||
|
||||
json_object *workDir = json_object_new_string(m_workingDirectory.full_path());
|
||||
const std::string workDirString = m_workingDirectory.string();
|
||||
json_object *workDir = json_object_new_string(workDirString.c_str());
|
||||
json::add_object(configJSON, config::keys::WORKING_DIRECTORY, workDir);
|
||||
|
||||
for (const auto &[key, value] : m_configMap)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "curl/curl.hpp"
|
||||
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "data/DataContext.hpp"
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
@@ -128,7 +128,7 @@ bool data::DataContext::title_is_loaded(uint64_t applicationID)
|
||||
void data::DataContext::load_title(uint64_t applicationID)
|
||||
{
|
||||
std::scoped_lock titleGuard{m_titleMutex, m_iconQueueMutex};
|
||||
m_titleInfo.emplace(applicationID, applicationID);
|
||||
m_titleInfo.try_emplace(applicationID, applicationID);
|
||||
m_iconQueue.push_back(&m_titleInfo.at(applicationID));
|
||||
}
|
||||
|
||||
@@ -171,7 +171,8 @@ void data::DataContext::import_svi_files(sys::Task *task)
|
||||
|
||||
task->set_status(statusLoadingSvi);
|
||||
|
||||
for (const fslib::DirectoryEntry &entry : sviDir.list())
|
||||
auto controlData = std::make_unique<NsApplicationControlData>();
|
||||
for (const fslib::DirectoryEntry &entry : sviDir)
|
||||
{
|
||||
const fslib::Path target{sviPath / entry};
|
||||
fslib::File sviFile{target, FsOpenMode_Read};
|
||||
@@ -180,7 +181,6 @@ void data::DataContext::import_svi_files(sys::Task *task)
|
||||
|
||||
uint32_t magic{};
|
||||
uint64_t applicationID{};
|
||||
auto controlData = std::make_unique<NsApplicationControlData>();
|
||||
const bool magicRead = sviFile.read(&magic, SIZE_UINT32) == SIZE_UINT32;
|
||||
const bool idRead = sviFile.read(&applicationID, SIZE_UINT64) == SIZE_UINT64;
|
||||
const bool exists = DataContext::title_is_loaded(applicationID);
|
||||
@@ -190,8 +190,7 @@ void data::DataContext::import_svi_files(sys::Task *task)
|
||||
if (!dataRead) { continue; }
|
||||
|
||||
std::scoped_lock multiGuard{m_iconQueueMutex, m_titleMutex};
|
||||
data::TitleInfo newTitle{applicationID, controlData};
|
||||
m_titleInfo.emplace(applicationID, std::move(newTitle));
|
||||
m_titleInfo.try_emplace(applicationID, applicationID, *controlData);
|
||||
m_iconQueue.push_back(&m_titleInfo.at(applicationID));
|
||||
}
|
||||
}
|
||||
@@ -214,8 +213,8 @@ bool data::DataContext::read_cache(sys::Task *task)
|
||||
const char *statusLoadingCache = strings::get_by_name(strings::names::DATA_LOADING_STATUS, 4);
|
||||
task->set_status(statusLoadingCache);
|
||||
|
||||
auto controlData = std::make_unique<NsApplicationControlData>();
|
||||
do {
|
||||
auto controlData = std::make_unique<NsApplicationControlData>();
|
||||
const bool dataRead = cacheZip.read(controlData.get(), SIZE_CTRL_DATA) == SIZE_CTRL_DATA;
|
||||
if (!dataRead) { continue; }
|
||||
|
||||
@@ -228,8 +227,7 @@ bool data::DataContext::read_cache(sys::Task *task)
|
||||
|
||||
std::scoped_lock multiGuard{m_iconQueueMutex, m_titleMutex};
|
||||
|
||||
data::TitleInfo newTitle{applicationID, controlData};
|
||||
m_titleInfo.emplace(applicationID, std::move(newTitle));
|
||||
m_titleInfo.try_emplace(applicationID, applicationID, *controlData);
|
||||
m_iconQueue.push_back(&m_titleInfo.at(applicationID));
|
||||
} while (cacheZip.next_file());
|
||||
m_cacheIsValid = true;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "data/TitleInfo.hpp"
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "graphics/gfxutil.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
@@ -11,28 +11,25 @@
|
||||
|
||||
data::TitleInfo::TitleInfo(uint64_t applicationID)
|
||||
: m_applicationID(applicationID)
|
||||
, m_data(std::make_unique<NsApplicationControlData>())
|
||||
{
|
||||
static constexpr size_t SIZE_CTRL_DATA = sizeof(NsApplicationControlData);
|
||||
|
||||
uint64_t controlSize{};
|
||||
NacpLanguageEntry *entry{};
|
||||
NsApplicationControlData *data = m_data.get();
|
||||
|
||||
// This will filter from even trying to fetch control data for system titles.
|
||||
const bool isSystem = applicationID & 0x8000000000000000;
|
||||
const bool getError = !isSystem && error::libnx(nsGetApplicationControlData(NsApplicationControlSource_Storage,
|
||||
m_applicationID,
|
||||
data,
|
||||
&m_data,
|
||||
SIZE_CTRL_DATA,
|
||||
&controlSize));
|
||||
const bool entryError = !getError && error::libnx(nacpGetLanguageEntry(&data->nacp, &entry));
|
||||
const bool entryError = !getError && error::libnx(nacpGetLanguageEntry(&m_data.nacp, &entry));
|
||||
if (isSystem || getError)
|
||||
{
|
||||
const std::string appIDHex = stringutil::get_formatted_string("%04X", m_applicationID & 0xFFFF);
|
||||
char *name = data->nacp.lang[SetLanguage_ENUS].name; // I'm hoping this is enough?
|
||||
char *name = m_data.nacp.lang[SetLanguage_ENUS].name; // I'm hoping this is enough?
|
||||
|
||||
std::memset(data, 0x00, SIZE_CTRL_DATA);
|
||||
std::snprintf(name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID);
|
||||
TitleInfo::get_create_path_safe_title();
|
||||
}
|
||||
@@ -44,48 +41,29 @@ data::TitleInfo::TitleInfo(uint64_t applicationID)
|
||||
}
|
||||
|
||||
// To do: Make this safer...
|
||||
data::TitleInfo::TitleInfo(uint64_t applicationID, std::unique_ptr<NsApplicationControlData> &controlData)
|
||||
data::TitleInfo::TitleInfo(uint64_t applicationID, NsApplicationControlData &controlData)
|
||||
: m_applicationID(applicationID)
|
||||
, m_data(std::move(controlData))
|
||||
{
|
||||
m_hasData = true;
|
||||
m_data = controlData;
|
||||
|
||||
NacpLanguageEntry *entry{};
|
||||
const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data->nacp, &entry));
|
||||
const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data.nacp, &entry));
|
||||
if (entryError) { std::snprintf(entry->name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID); }
|
||||
|
||||
TitleInfo::get_create_path_safe_title();
|
||||
}
|
||||
|
||||
data::TitleInfo::TitleInfo(data::TitleInfo &&titleInfo) { *this = std::move(titleInfo); }
|
||||
|
||||
data::TitleInfo &data::TitleInfo::operator=(data::TitleInfo &&titleInfo)
|
||||
{
|
||||
m_applicationID = titleInfo.m_applicationID;
|
||||
m_data = std::move(titleInfo.m_data);
|
||||
m_hasData = titleInfo.m_hasData;
|
||||
std::memcpy(m_pathSafeTitle, titleInfo.m_pathSafeTitle, TitleInfo::SIZE_PATH_SAFE);
|
||||
m_icon = titleInfo.m_icon;
|
||||
|
||||
titleInfo.m_applicationID = 0;
|
||||
titleInfo.m_data = nullptr;
|
||||
titleInfo.m_hasData = false;
|
||||
std::memset(titleInfo.m_pathSafeTitle, 0x00, TitleInfo::SIZE_PATH_SAFE);
|
||||
titleInfo.m_icon = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t data::TitleInfo::get_application_id() const { return m_applicationID; }
|
||||
|
||||
NsApplicationControlData *data::TitleInfo::get_control_data() { return m_data.get(); }
|
||||
NsApplicationControlData *data::TitleInfo::get_control_data() { return &m_data; }
|
||||
|
||||
bool data::TitleInfo::has_control_data() const { return m_hasData; }
|
||||
|
||||
const char *data::TitleInfo::get_title()
|
||||
{
|
||||
NacpLanguageEntry *entry{};
|
||||
const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data->nacp, &entry));
|
||||
const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data.nacp, &entry));
|
||||
if (entryError) { return nullptr; }
|
||||
return entry->name;
|
||||
}
|
||||
@@ -95,16 +73,16 @@ const char *data::TitleInfo::get_path_safe_title() const { return m_pathSafeTitl
|
||||
const char *data::TitleInfo::get_publisher()
|
||||
{
|
||||
NacpLanguageEntry *entry{};
|
||||
const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data->nacp, &entry));
|
||||
const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data.nacp, &entry));
|
||||
if (entryError) { return nullptr; }
|
||||
return entry->author;
|
||||
}
|
||||
|
||||
uint64_t data::TitleInfo::get_save_data_owner_id() const { return m_data->nacp.save_data_owner_id; }
|
||||
uint64_t data::TitleInfo::get_save_data_owner_id() const { return m_data.nacp.save_data_owner_id; }
|
||||
|
||||
int64_t data::TitleInfo::get_save_data_size(uint8_t saveType) const
|
||||
{
|
||||
const NacpStruct &nacp = m_data->nacp;
|
||||
const NacpStruct &nacp = m_data.nacp;
|
||||
switch (saveType)
|
||||
{
|
||||
case FsSaveDataType_Account: return nacp.user_account_save_data_size;
|
||||
@@ -118,7 +96,7 @@ int64_t data::TitleInfo::get_save_data_size(uint8_t saveType) const
|
||||
|
||||
int64_t data::TitleInfo::get_save_data_size_max(uint8_t saveType) const
|
||||
{
|
||||
const NacpStruct &nacp = m_data->nacp;
|
||||
const NacpStruct &nacp = m_data.nacp;
|
||||
switch (saveType)
|
||||
{
|
||||
case FsSaveDataType_Account: return std::max(nacp.user_account_save_data_size, nacp.user_account_save_data_size_max);
|
||||
@@ -132,7 +110,7 @@ int64_t data::TitleInfo::get_save_data_size_max(uint8_t saveType) const
|
||||
|
||||
int64_t data::TitleInfo::get_journal_size(uint8_t saveType) const
|
||||
{
|
||||
const NacpStruct &nacp = m_data->nacp;
|
||||
const NacpStruct &nacp = m_data.nacp;
|
||||
switch (saveType)
|
||||
{
|
||||
case FsSaveDataType_Account: return nacp.user_account_save_data_journal_size;
|
||||
@@ -146,7 +124,7 @@ int64_t data::TitleInfo::get_journal_size(uint8_t saveType) const
|
||||
|
||||
int64_t data::TitleInfo::get_journal_size_max(uint8_t saveType) const
|
||||
{
|
||||
const NacpStruct &nacp = m_data->nacp;
|
||||
const NacpStruct &nacp = m_data.nacp;
|
||||
switch (saveType)
|
||||
{
|
||||
case FsSaveDataType_Account:
|
||||
@@ -162,7 +140,7 @@ int64_t data::TitleInfo::get_journal_size_max(uint8_t saveType) const
|
||||
|
||||
bool data::TitleInfo::has_save_data_type(uint8_t saveType) const
|
||||
{
|
||||
const NacpStruct &nacp = m_data->nacp;
|
||||
const NacpStruct &nacp = m_data.nacp;
|
||||
switch (saveType)
|
||||
{
|
||||
case FsSaveDataType_Account: return nacp.user_account_save_data_size > 0 || nacp.user_account_save_data_size_max > 0;
|
||||
@@ -197,7 +175,7 @@ void data::TitleInfo::get_create_path_safe_title()
|
||||
}
|
||||
|
||||
const bool useTitleId = config::get_by_key(config::keys::USE_TITLE_IDS);
|
||||
const bool entryError = !useTitleId && error::libnx(nacpGetLanguageEntry(&m_data->nacp, &entry));
|
||||
const bool entryError = !useTitleId && error::libnx(nacpGetLanguageEntry(&m_data.nacp, &entry));
|
||||
const bool sanitized =
|
||||
!useTitleId && !entryError && stringutil::sanitize_string_for_path(entry->name, m_pathSafeTitle, SIZE_PATH_SAFE);
|
||||
if (useTitleId || entryError || !sanitized)
|
||||
@@ -214,7 +192,7 @@ void data::TitleInfo::load_icon()
|
||||
if (m_hasData)
|
||||
{
|
||||
const std::string textureName = stringutil::get_formatted_string("%016llX", m_applicationID);
|
||||
m_icon = sdl::TextureManager::load(textureName, m_data->icon, SIZE_ICON);
|
||||
m_icon = sdl::TextureManager::load(textureName, m_data.icon, SIZE_ICON);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "graphics/gfxutil.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "stringutil.hpp"
|
||||
@@ -164,15 +164,12 @@ void data::User::load_user_data()
|
||||
|
||||
while (infoReader.read())
|
||||
{
|
||||
const int64_t readCount = infoReader.get_read_count();
|
||||
|
||||
for (int64_t i = 0; i < readCount; i++)
|
||||
for (const FsSaveDataInfo &saveInfo : infoReader)
|
||||
{
|
||||
const FsSaveDataInfo &saveInfo = infoReader[i];
|
||||
const uint64_t saveInfoAppID = saveInfo.application_id;
|
||||
const uint64_t saveInfoSysID = saveInfo.system_save_data_id;
|
||||
const uint64_t applicationID = saveInfoAppID != 0 ? saveInfoAppID : saveInfoSysID;
|
||||
const uint8_t saveDataType = saveInfo.save_data_type;
|
||||
const uint64_t saveInfoAppID = saveInfo.application_id;
|
||||
const uint64_t saveInfoSysID = saveInfo.system_save_data_id;
|
||||
const uint64_t applicationID = saveInfoAppID != 0 ? saveInfoAppID : saveInfoSysID;
|
||||
const uint8_t saveDataType = saveInfo.save_data_type;
|
||||
const bool isSystemSave = saveDataType == FsSaveDataType_System || saveDataType == FsSaveDataType_SystemBcat;
|
||||
|
||||
const bool isBlacklisted = config::is_blacklisted(applicationID);
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
#include "appstates/DataLoadingState.hpp"
|
||||
#include "data/DataContext.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
#include "fslib.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "fs/MiniUnzip.hpp"
|
||||
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
|
||||
fs::MiniUnzip::MiniUnzip(const fslib::Path &path) { MiniUnzip::open(path); }
|
||||
@@ -12,7 +12,9 @@ bool fs::MiniUnzip::is_open() const { return m_isOpen; }
|
||||
bool fs::MiniUnzip::open(const fslib::Path &path)
|
||||
{
|
||||
MiniUnzip::close();
|
||||
m_unz = unzOpen64(path.full_path());
|
||||
|
||||
const std::string pathString = path.string();
|
||||
m_unz = unzOpen64(pathString.c_str());
|
||||
if (error::is_null(m_unz) || !MiniUnzip::reset()) { return false; }
|
||||
m_isOpen = true;
|
||||
return true;
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
#include "fs/MiniZip.hpp"
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
// Definition at bottom.
|
||||
static zip_fileinfo create_zip_file_info();
|
||||
|
||||
fs::MiniZip::MiniZip(const fslib::Path &path) { MiniZip::open(path); }
|
||||
fs::MiniZip::MiniZip(const fslib::Path &path)
|
||||
: m_level(config::get_by_key(config::keys::ZIP_COMPRESSION_LEVEL))
|
||||
{
|
||||
MiniZip::open(path);
|
||||
}
|
||||
|
||||
fs::MiniZip::~MiniZip() { MiniZip::close(); }
|
||||
|
||||
@@ -17,7 +22,9 @@ bool fs::MiniZip::is_open() const { return m_isOpen; }
|
||||
bool fs::MiniZip::open(const fslib::Path &path)
|
||||
{
|
||||
MiniZip::close();
|
||||
m_zip = zipOpen64(path.full_path(), APPEND_STATUS_CREATE);
|
||||
|
||||
const std::string pathString = path.string();
|
||||
m_zip = zipOpen64(pathString.c_str(), APPEND_STATUS_CREATE);
|
||||
if (error::is_null(m_zip)) { return false; }
|
||||
m_isOpen = true;
|
||||
return true;
|
||||
@@ -32,19 +39,21 @@ void fs::MiniZip::close()
|
||||
|
||||
bool fs::MiniZip::open_new_file(std::string_view filename, bool trimPath, size_t trimPlaces)
|
||||
{
|
||||
const uint8_t zipLevel = config::get_by_key(config::keys::ZIP_COMPRESSION_LEVEL);
|
||||
|
||||
const size_t pathBegin = filename.find_first_of('/');
|
||||
if (pathBegin != filename.npos) { filename = filename.substr(pathBegin + 1); }
|
||||
|
||||
const zip_fileinfo fileInfo = create_zip_file_info();
|
||||
return zipOpenNewFileInZip64(m_zip, filename.data(), &fileInfo, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, zipLevel, 0) ==
|
||||
return zipOpenNewFileInZip64(m_zip, filename.data(), &fileInfo, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, m_level, 0) ==
|
||||
ZIP_OK;
|
||||
}
|
||||
|
||||
bool fs::MiniZip::close_current_file() { return zipCloseFileInZip(m_zip) == ZIP_OK; }
|
||||
|
||||
bool fs::MiniZip::write(const void *buffer, size_t dataSize) { return zipWriteInFileInZip(m_zip, buffer, dataSize) == ZIP_OK; }
|
||||
bool fs::MiniZip::write(const void *buffer, size_t dataSize)
|
||||
{
|
||||
if (!m_isOpen) { return false; }
|
||||
return zipWriteInFileInZip(m_zip, buffer, dataSize) == ZIP_OK;
|
||||
}
|
||||
|
||||
static zip_fileinfo create_zip_file_info()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
fs::PathFilter::PathFilter(const fslib::Path &filePath)
|
||||
{
|
||||
json::Object filterJSON = json::new_object(json_object_from_file, filePath.full_path());
|
||||
const std::string pathString = filePath.string();
|
||||
json::Object filterJSON = json::new_object(json_object_from_file, pathString.c_str());
|
||||
if (!filterJSON) { return; }
|
||||
|
||||
json_object *filter = json::get_object(filterJSON, "filters");
|
||||
@@ -25,5 +26,5 @@ bool fs::PathFilter::has_paths() const { return !m_paths.empty(); }
|
||||
|
||||
bool fs::PathFilter::is_filtered(const fslib::Path &path)
|
||||
{
|
||||
return std::find(m_paths.begin(), m_paths.end(), path.full_path()) != m_paths.end();
|
||||
return std::find(m_paths.begin(), m_paths.end(), path) != m_paths.end();
|
||||
}
|
||||
|
||||
@@ -1,31 +1,20 @@
|
||||
#include "fs/SaveMetaData.hpp"
|
||||
|
||||
#include "error.hpp"
|
||||
#include "fs/directory_functions.hpp"
|
||||
#include "fs/save_data_functions.hpp"
|
||||
#include "fs/save_mount.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "logging/error.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr size_t SIZE_EXTRA_DATA = sizeof(FsSaveDataExtraData);
|
||||
}
|
||||
|
||||
bool fs::read_save_data_extra_info(const FsSaveDataInfo *saveInfo, FsSaveDataExtraData &dataOut)
|
||||
{
|
||||
const FsSaveDataSpaceId spaceID = static_cast<FsSaveDataSpaceId>(saveInfo->save_data_space_id);
|
||||
const uint64_t saveDataID = saveInfo->save_data_id;
|
||||
|
||||
const bool readError =
|
||||
error::libnx(fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(&dataOut, SIZE_EXTRA_DATA, spaceID, saveDataID));
|
||||
if (readError) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fs::fill_save_meta_data(const FsSaveDataInfo *saveInfo, fs::SaveMetaData &meta)
|
||||
{
|
||||
FsSaveDataExtraData extraData{};
|
||||
const bool extraRead = fs::read_save_data_extra_info(saveInfo, extraData);
|
||||
const bool extraRead = fs::read_save_extra_data(saveInfo, extraData);
|
||||
if (!extraRead) { return false; }
|
||||
|
||||
meta = {.magic = fs::SAVE_META_MAGIC,
|
||||
@@ -49,7 +38,7 @@ bool fs::fill_save_meta_data(const FsSaveDataInfo *saveInfo, fs::SaveMetaData &m
|
||||
bool fs::process_save_meta_data(const FsSaveDataInfo *saveInfo, const SaveMetaData &meta)
|
||||
{
|
||||
FsSaveDataExtraData extraData{};
|
||||
const bool extraRead = fs::read_save_data_extra_info(saveInfo, extraData);
|
||||
const bool extraRead = fs::read_save_extra_data(saveInfo, extraData);
|
||||
if (!extraRead) { return false; }
|
||||
|
||||
const bool needsExtend = extraData.data_size < meta.saveDataSize;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "fs/ScopedSaveMount.hpp"
|
||||
|
||||
#include "error.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "logging/error.hpp"
|
||||
|
||||
fs::ScopedSaveMount::ScopedSaveMount(std::string_view mount, const FsSaveDataInfo *saveInfo, bool log)
|
||||
: m_mountPoint(mount)
|
||||
|
||||
@@ -8,7 +8,7 @@ uint64_t fs::get_directory_total_size(const fslib::Path &targetPath)
|
||||
if (!targetDir.is_open()) { return 0; }
|
||||
|
||||
uint64_t directorySize = 0;
|
||||
for (const fslib::DirectoryEntry &entry : targetDir.list())
|
||||
for (const fslib::DirectoryEntry &entry : targetDir)
|
||||
{
|
||||
if (entry.is_directory())
|
||||
{
|
||||
@@ -26,7 +26,7 @@ bool fs::directory_has_contents(const fslib::Path &directoryPath)
|
||||
fslib::Directory testDir{directoryPath};
|
||||
if (!testDir.is_open()) { return false; }
|
||||
|
||||
for (const fslib::DirectoryEntry &entry : testDir.list())
|
||||
for (const fslib::DirectoryEntry &entry : testDir)
|
||||
{
|
||||
if (entry.get_filename() != fs::NAME_SAVE_META) { return true; }
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "fs/io.hpp"
|
||||
|
||||
#include "error.hpp"
|
||||
#include "fs/SaveMetaData.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
@@ -70,7 +70,8 @@ void fs::copy_file(const fslib::Path &source, const fslib::Path &destination, sy
|
||||
const int64_t sourceSize = sourceFile.get_size();
|
||||
if (task)
|
||||
{
|
||||
const std::string status = stringutil::get_formatted_string(statusTemplate, source.full_path());
|
||||
const std::string sourceString = source.string();
|
||||
const std::string status = stringutil::get_formatted_string(statusTemplate, sourceString.c_str());
|
||||
task->set_status(status);
|
||||
task->reset(static_cast<double>(sourceSize));
|
||||
}
|
||||
@@ -111,7 +112,6 @@ void fs::copy_file(const fslib::Path &source, const fslib::Path &destination, sy
|
||||
|
||||
void fs::copy_file_commit(const fslib::Path &source,
|
||||
const fslib::Path &destination,
|
||||
std::string_view device,
|
||||
int64_t journalSize,
|
||||
sys::ProgressTask *task)
|
||||
{
|
||||
@@ -126,7 +126,8 @@ void fs::copy_file_commit(const fslib::Path &source,
|
||||
const int64_t sourceSize = sourceFile.get_size();
|
||||
if (task)
|
||||
{
|
||||
const std::string status = stringutil::get_formatted_string(copyingStatus, source.full_path());
|
||||
const std::string sourceString = source.string();
|
||||
const std::string status = stringutil::get_formatted_string(copyingStatus, sourceString.c_str());
|
||||
task->set_status(status);
|
||||
task->reset(static_cast<double>(sourceSize));
|
||||
}
|
||||
@@ -163,7 +164,7 @@ void fs::copy_file_commit(const fslib::Path &source,
|
||||
if (needsCommit)
|
||||
{
|
||||
destFile.close();
|
||||
const bool commitError = error::fslib(fslib::commit_data_to_file_system(device));
|
||||
const bool commitError = error::fslib(fslib::commit_data_to_file_system(destination.get_device_name()));
|
||||
// To do: Handle this better. Threads current have no way of communicating errors.
|
||||
if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); }
|
||||
|
||||
@@ -180,7 +181,7 @@ void fs::copy_file_commit(const fslib::Path &source,
|
||||
readThread.join();
|
||||
destFile.close();
|
||||
|
||||
const bool commitError = error::fslib(fslib::commit_data_to_file_system(device));
|
||||
const bool commitError = error::fslib(fslib::commit_data_to_file_system(destination.get_device_name()));
|
||||
if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); }
|
||||
}
|
||||
|
||||
@@ -189,7 +190,7 @@ void fs::copy_directory(const fslib::Path &source, const fslib::Path &destinatio
|
||||
fslib::Directory sourceDir{source};
|
||||
if (error::fslib(sourceDir.is_open())) { return; }
|
||||
|
||||
for (const fslib::DirectoryEntry &entry : sourceDir.list())
|
||||
for (const fslib::DirectoryEntry &entry : sourceDir)
|
||||
{
|
||||
const char *filename = entry.get_filename();
|
||||
if (filename == fs::NAME_SAVE_META) { continue; }
|
||||
@@ -210,14 +211,13 @@ void fs::copy_directory(const fslib::Path &source, const fslib::Path &destinatio
|
||||
|
||||
void fs::copy_directory_commit(const fslib::Path &source,
|
||||
const fslib::Path &destination,
|
||||
std::string_view device,
|
||||
int64_t journalSize,
|
||||
sys::ProgressTask *task)
|
||||
{
|
||||
fslib::Directory sourceDir{source};
|
||||
if (error::fslib(sourceDir.is_open())) { return; }
|
||||
|
||||
for (const fslib::DirectoryEntry &entry : sourceDir.list())
|
||||
for (const fslib::DirectoryEntry &entry : sourceDir)
|
||||
{
|
||||
const char *filename = entry.get_filename();
|
||||
if (filename == fs::NAME_SAVE_META) { continue; }
|
||||
@@ -230,8 +230,8 @@ void fs::copy_directory_commit(const fslib::Path &source,
|
||||
const bool createError = !destExists && error::fslib(fslib::create_directory(fullDest));
|
||||
if (!destExists && createError) { continue; }
|
||||
|
||||
fs::copy_directory_commit(fullSource, fullDest, device, journalSize, task);
|
||||
fs::copy_directory_commit(fullSource, fullDest, journalSize, task);
|
||||
}
|
||||
else { fs::copy_file_commit(fullSource, fullDest, device, journalSize, task); }
|
||||
else { fs::copy_file_commit(fullSource, fullDest, journalSize, task); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "fs/save_data_functions.hpp"
|
||||
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
|
||||
bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo)
|
||||
@@ -29,8 +29,7 @@ bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo
|
||||
.save_data_space_id = FsSaveDataSpaceId_User};
|
||||
|
||||
// I want this recorded.
|
||||
const bool createError = error::libnx(fsCreateSaveDataFileSystem(&saveAttributes, &saveCreation, &saveMeta));
|
||||
return createError == false;
|
||||
return error::libnx(fsCreateSaveDataFileSystem(&saveAttributes, &saveCreation, &saveMeta)) == false;
|
||||
}
|
||||
|
||||
bool fs::delete_save_data(const FsSaveDataInfo *saveInfo)
|
||||
@@ -47,8 +46,7 @@ bool fs::delete_save_data(const FsSaveDataInfo *saveInfo)
|
||||
.save_data_rank = saveInfo->save_data_rank,
|
||||
.save_data_index = saveInfo->save_data_index};
|
||||
|
||||
const bool deleteError = error::libnx(fsDeleteSaveDataFileSystemBySaveDataAttribute(spaceID, &saveAttributes));
|
||||
return deleteError == false;
|
||||
return error::libnx(fsDeleteSaveDataFileSystemBySaveDataAttribute(spaceID, &saveAttributes)) == false;
|
||||
}
|
||||
|
||||
bool fs::extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t journalSize)
|
||||
@@ -56,11 +54,22 @@ bool fs::extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t
|
||||
const FsSaveDataSpaceId spaceID = static_cast<FsSaveDataSpaceId>(saveInfo->save_data_space_id);
|
||||
const uint64_t saveID = saveInfo->save_data_id;
|
||||
|
||||
const bool extendError = error::libnx(fsExtendSaveDataFileSystem(spaceID, saveID, size, journalSize));
|
||||
return extendError == false;
|
||||
return error::libnx(fsExtendSaveDataFileSystem(spaceID, saveID, size, journalSize)) == false;
|
||||
}
|
||||
|
||||
bool fs::is_system_save_data(const FsSaveDataInfo *saveInfo)
|
||||
{
|
||||
return saveInfo->save_data_type == FsSaveDataType_System || saveInfo->save_data_type == FsSaveDataType_SystemBcat;
|
||||
}
|
||||
|
||||
bool fs::read_save_extra_data(const FsSaveDataInfo *saveInfo, FsSaveDataExtraData &extraOut)
|
||||
{
|
||||
static constexpr size_t EXTRA_SIZE = sizeof(FsSaveDataExtraData);
|
||||
|
||||
const FsSaveDataSpaceId spaceID = static_cast<FsSaveDataSpaceId>(saveInfo->save_data_space_id);
|
||||
|
||||
const bool readError = error::libnx(
|
||||
fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(&extraOut, EXTRA_SIZE, spaceID, saveInfo->save_data_id));
|
||||
|
||||
return !readError;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "fs/zip.hpp"
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/SaveMetaData.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
@@ -100,14 +100,15 @@ void fs::copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys
|
||||
fslib::Directory sourceDir{source};
|
||||
if (error::fslib(sourceDir.is_open())) { return; }
|
||||
|
||||
for (const fslib::DirectoryEntry &entry : sourceDir.list())
|
||||
for (const fslib::DirectoryEntry &entry : sourceDir)
|
||||
{
|
||||
const fslib::Path fullSource{source / entry};
|
||||
if (entry.is_directory()) { fs::copy_directory_to_zip(fullSource, dest, task); }
|
||||
else
|
||||
{
|
||||
fslib::File sourceFile{fullSource, FsOpenMode_Read};
|
||||
const bool newZipFile = dest.open_new_file(fullSource.full_path());
|
||||
const std::string sourceString = fullSource.string();
|
||||
const bool newZipFile = dest.open_new_file(sourceString);
|
||||
if (error::fslib(sourceFile.is_open()) || !newZipFile) { continue; }
|
||||
|
||||
const int64_t fileSize = sourceFile.get_size();
|
||||
@@ -117,7 +118,7 @@ void fs::copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys
|
||||
|
||||
if (task)
|
||||
{
|
||||
const std::string status = stringutil::get_formatted_string(ioStatus, fullSource.full_path());
|
||||
const std::string status = stringutil::get_formatted_string(ioStatus, sourceString.c_str());
|
||||
task->set_status(status);
|
||||
task->reset(static_cast<double>(fileSize));
|
||||
}
|
||||
@@ -158,17 +159,13 @@ void fs::copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys
|
||||
}
|
||||
}
|
||||
|
||||
void fs::copy_zip_to_directory(fs::MiniUnzip &unzip,
|
||||
const fslib::Path &dest,
|
||||
int64_t journalSize,
|
||||
std::string_view commitDevice,
|
||||
sys::ProgressTask *task)
|
||||
void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, const fslib::Path &dest, int64_t journalSize, sys::ProgressTask *task)
|
||||
{
|
||||
if (!unzip.reset()) { return; }
|
||||
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
|
||||
const char *popCommitFailed = strings::get_by_name(strings::names::IO_POPS, 0);
|
||||
const char *statusTemplate = strings::get_by_name(strings::names::IO_STATUSES, 2);
|
||||
const bool needCommits = journalSize > 0 && !commitDevice.empty();
|
||||
const bool needCommits = journalSize > 0;
|
||||
|
||||
do {
|
||||
if (unzip.get_filename() == fs::NAME_SAVE_META) { continue; }
|
||||
@@ -178,9 +175,10 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip,
|
||||
if (lastDir == fullDest.NOT_FOUND) { continue; }
|
||||
|
||||
const fslib::Path dirPath{fullDest.sub_path(lastDir)};
|
||||
const bool exists = dirPath.is_valid() && fslib::directory_exists(dirPath);
|
||||
const bool createError = dirPath.is_valid() && !exists && error::fslib(fslib::create_directories_recursively(dirPath));
|
||||
if (dirPath.is_valid() && !exists && createError) { continue; }
|
||||
const bool isValid = dirPath.is_valid();
|
||||
const bool exists = isValid && fslib::directory_exists(dirPath);
|
||||
const bool createError = isValid && !exists && error::fslib(fslib::create_directories_recursively(dirPath));
|
||||
if (isValid && !exists && createError) { continue; }
|
||||
|
||||
const int64_t fileSize = unzip.get_uncompressed_size();
|
||||
fslib::File destFile{fullDest, FsOpenMode_Create | FsOpenMode_Write, fileSize};
|
||||
@@ -203,8 +201,8 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip,
|
||||
bool &bufferReady = sharedData->bufferReady;
|
||||
std::unique_ptr<sys::byte[]> &sharedBuffer = sharedData->sharedBuffer;
|
||||
|
||||
std::thread readThread(unzipReadThreadFunction, std::ref(unzip), sharedData);
|
||||
int64_t journalCount{};
|
||||
std::thread readThread(unzipReadThreadFunction, std::ref(unzip), sharedData);
|
||||
for (int64_t i = 0; i < fileSize;)
|
||||
{
|
||||
ssize_t localRead{};
|
||||
@@ -223,7 +221,7 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip,
|
||||
if (commitNeeded)
|
||||
{
|
||||
destFile.close();
|
||||
const bool commitError = error::fslib(fslib::commit_data_to_file_system(commitDevice));
|
||||
const bool commitError = error::fslib(fslib::commit_data_to_file_system(dest.get_device_name()));
|
||||
if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); } // To do: How to recover?
|
||||
|
||||
destFile.open(fullDest, FsOpenMode_Write);
|
||||
@@ -240,7 +238,7 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip,
|
||||
readThread.join();
|
||||
destFile.close();
|
||||
|
||||
const bool commitError = needCommits && error::fslib(fslib::commit_data_to_file_system(commitDevice));
|
||||
const bool commitError = needCommits && error::fslib(fslib::commit_data_to_file_system(dest.get_device_name()));
|
||||
if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); }
|
||||
} while (unzip.next_file());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "keyboard.hpp"
|
||||
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "JSON.hpp"
|
||||
#include "curl/curl.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/TaskState.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "remote/GoogleDrive.hpp"
|
||||
#include "remote/WebDav.hpp"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "JSON.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace
|
||||
{
|
||||
// This is the actual map where the strings are.
|
||||
std::map<std::pair<std::string, int>, std::string> s_stringMap;
|
||||
|
||||
// This map is for matching files to the language value
|
||||
std::unordered_map<SetLanguage, std::string_view> s_fileMap = {{SetLanguage_JA, "JA.json"},
|
||||
{SetLanguage_ENUS, "ENUS.json"},
|
||||
@@ -42,8 +43,8 @@ static void replace_buttons_in_string(std::string &target);
|
||||
|
||||
bool strings::initialize()
|
||||
{
|
||||
const fslib::Path filePath = get_file_path();
|
||||
json::Object stringJSON = json::new_object(json_object_from_file, filePath.full_path());
|
||||
const std::string stringPath = get_file_path().string();
|
||||
json::Object stringJSON = json::new_object(json_object_from_file, stringPath.c_str());
|
||||
if (!stringJSON) { return false; }
|
||||
|
||||
json_object_iterator stringIterator = json::iter_begin(stringJSON);
|
||||
|
||||
@@ -59,12 +59,12 @@ bool stringutil::sanitize_string_for_path(const char *stringIn, char *stringOut,
|
||||
const bool countCheck = count <= 0 || i + count >= stringOutSize;
|
||||
const bool codeCheck = codepoint < 0x20 || codepoint > 0x7E;
|
||||
if (countCheck) { break; }
|
||||
else if (codepoint == L'é') { stringOut[offset++] = 'e'; }
|
||||
else if (codeCheck) { return false; }
|
||||
|
||||
const bool forbidden = std::find(FORBIDDEN_PATH_CHARACTERS.begin(), FORBIDDEN_PATH_CHARACTERS.end(), codepoint) !=
|
||||
FORBIDDEN_PATH_CHARACTERS.end();
|
||||
if (forbidden) { stringOut[offset++] = 0x20; }
|
||||
else if (codepoint == L'é') { stringOut[offset++] = 'e'; }
|
||||
else
|
||||
{
|
||||
std::memcpy(&stringOut[offset], &stringIn[i], static_cast<size_t>(count));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "tasks/backup.hpp"
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
@@ -36,7 +36,8 @@ void tasks::backup::create_new_backup_local(sys::ProgressTask *task,
|
||||
if (error::is_null(task)) { return; }
|
||||
if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); }
|
||||
|
||||
const bool hasZipExt = std::strstr(target.full_path(), STRING_ZIP_EXT);
|
||||
const std::string targetString = target.string();
|
||||
const bool hasZipExt = std::strstr(targetString.c_str(), STRING_ZIP_EXT);
|
||||
const uint64_t applicationID = titleInfo->get_application_id();
|
||||
const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID);
|
||||
if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); }
|
||||
@@ -198,12 +199,16 @@ void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuStat
|
||||
const uint64_t applicationID = titleInfo->get_application_id();
|
||||
const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID);
|
||||
const uint8_t saveType = user->get_account_save_type();
|
||||
const uint64_t journalSize = titleInfo->get_journal_size(saveType);
|
||||
if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); }
|
||||
|
||||
const bool autoBackup = config::get_by_key(config::keys::AUTO_BACKUP_ON_RESTORE);
|
||||
const bool isDir = fslib::directory_exists(target);
|
||||
const bool hasZipExt = std::strstr(target.full_path(), STRING_ZIP_EXT);
|
||||
FsSaveDataExtraData extraData{};
|
||||
const bool readExtra = fs::read_save_extra_data(saveInfo, extraData);
|
||||
const int64_t journalSize = readExtra ? extraData.journal_size : titleInfo->get_journal_size(saveType);
|
||||
|
||||
const std::string targetString = target.string();
|
||||
const bool autoBackup = config::get_by_key(config::keys::AUTO_BACKUP_ON_RESTORE);
|
||||
const bool isDir = fslib::directory_exists(target);
|
||||
const bool hasZipExt = std::strstr(targetString.c_str(), STRING_ZIP_EXT);
|
||||
|
||||
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
|
||||
if (autoBackup) { auto_backup(task, taskData); }
|
||||
@@ -226,18 +231,18 @@ void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuStat
|
||||
|
||||
read_and_process_meta(unzip, taskData, task);
|
||||
auto scopedMount = create_scoped_mount(saveInfo);
|
||||
fs::copy_zip_to_directory(unzip, fs::DEFAULT_SAVE_ROOT, journalSize, fs::DEFAULT_SAVE_MOUNT, task);
|
||||
fs::copy_zip_to_directory(unzip, fs::DEFAULT_SAVE_ROOT, journalSize, task);
|
||||
}
|
||||
else if (isDir)
|
||||
{
|
||||
read_and_process_meta(target, taskData, task);
|
||||
auto scopedMount = create_scoped_mount(saveInfo);
|
||||
fs::copy_directory_commit(target, fs::DEFAULT_SAVE_ROOT, fs::DEFAULT_SAVE_MOUNT, journalSize, task);
|
||||
fs::copy_directory_commit(target, fs::DEFAULT_SAVE_ROOT, journalSize, task);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto scopedMount = create_scoped_mount(saveInfo);
|
||||
fs::copy_file_commit(target, fs::DEFAULT_SAVE_ROOT, fs::DEFAULT_SAVE_MOUNT, journalSize, task);
|
||||
fs::copy_file_commit(target, fs::DEFAULT_SAVE_ROOT, journalSize, task);
|
||||
}
|
||||
|
||||
spawningState->refresh();
|
||||
@@ -306,10 +311,12 @@ void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuSta
|
||||
|
||||
read_and_process_meta(backup, taskData, task);
|
||||
{
|
||||
const uint8_t saveType = user->get_account_save_type();
|
||||
const uint64_t journalSize = titleInfo->get_journal_size(saveType);
|
||||
FsSaveDataExtraData extraData{};
|
||||
const bool readExtra = fs::read_save_extra_data(saveInfo, extraData);
|
||||
const uint8_t saveType = user->get_account_save_type();
|
||||
const int64_t journalSize = readExtra ? extraData.journal_size : titleInfo->get_journal_size(saveType);
|
||||
fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, saveInfo};
|
||||
fs::copy_zip_to_directory(backup, fs::DEFAULT_SAVE_ROOT, journalSize, fs::DEFAULT_SAVE_MOUNT, task);
|
||||
fs::copy_zip_to_directory(backup, fs::DEFAULT_SAVE_ROOT, journalSize, task);
|
||||
}
|
||||
backup.close();
|
||||
|
||||
@@ -333,8 +340,9 @@ void tasks::backup::delete_backup_local(sys::Task *task, BackupMenuState::TaskDa
|
||||
|
||||
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
|
||||
{
|
||||
const char *statusFormat = strings::get_by_name(strings::names::IO_STATUSES, 3);
|
||||
const std::string status = stringutil::get_formatted_string(statusFormat, path.full_path());
|
||||
const std::string pathString = path.string();
|
||||
const char *statusFormat = strings::get_by_name(strings::names::IO_STATUSES, 3);
|
||||
const std::string status = stringutil::get_formatted_string(statusFormat, pathString.c_str());
|
||||
task->set_status(status);
|
||||
}
|
||||
|
||||
|
||||
42
source/tasks/fileoptions.cpp
Normal file
42
source/tasks/fileoptions.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "tasks/fileoptions.hpp"
|
||||
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "fslib.hpp"
|
||||
|
||||
void tasks::fileoptions::copy_source_to_destination(sys::ProgressTask *task, FileOptionState::TaskData taskData)
|
||||
{
|
||||
if (error::is_null(task)) { return; }
|
||||
|
||||
fslib::Path &source = taskData->sourcePath;
|
||||
fslib::Path &dest = taskData->destPath;
|
||||
int64_t journalSpace = taskData->journalSize;
|
||||
|
||||
const bool isDir = fslib::directory_exists(source);
|
||||
const bool needsCommit = journalSpace > 0;
|
||||
|
||||
if (isDir && needsCommit) { fs::copy_directory_commit(source, dest, journalSpace, task); }
|
||||
else if (!isDir && needsCommit) { fs::copy_file_commit(source, dest, journalSpace, task); }
|
||||
else if (isDir && !needsCommit) { fs::copy_directory(source, dest, task); }
|
||||
else if (!isDir && !needsCommit) { fs::copy_file(source, dest, task); }
|
||||
|
||||
task->complete();
|
||||
}
|
||||
|
||||
void tasks::fileoptions::delete_target(sys::Task *task, FileOptionState::TaskData taskData)
|
||||
{
|
||||
if (error::is_null(task)) { return; }
|
||||
|
||||
fslib::Path target = taskData->sourcePath;
|
||||
int64_t journalSpace = taskData->journalSize;
|
||||
|
||||
const bool isDir = fslib::directory_exists(target);
|
||||
bool needsCommit = journalSpace > 0;
|
||||
|
||||
if (isDir) { fslib::delete_directory_recursively(target); }
|
||||
else { fslib::delete_file(target); }
|
||||
|
||||
if (needsCommit) { fslib::commit_data_to_file_system(target.get_device_name()); }
|
||||
|
||||
task->complete();
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "stringutil.hpp"
|
||||
#include "tasks/backup.hpp"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "tasks/savecreate.hpp"
|
||||
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
#include "ui/PopMessageManager.hpp"
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "keyboard.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
@@ -208,7 +208,7 @@ void tasks::titleoptions::extend_save_data(sys::Task *task, TitleOptionState::Ta
|
||||
|
||||
std::array<char, 5> sizeBuffer = {0};
|
||||
FsSaveDataExtraData extraData{};
|
||||
const bool readExtra = fs::read_save_data_extra_info(saveInfo, extraData);
|
||||
const bool readExtra = fs::read_save_extra_data(saveInfo, extraData);
|
||||
|
||||
const int sizeMB = extraData.data_size / SIZE_MB;
|
||||
const char *keyboardHeader = strings::get_by_name(strings::names::KEYBOARD, 8);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "tasks/useroptions.hpp"
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
@@ -49,17 +49,13 @@ void ui::DialogBox::render(sdl::SharedTexture &target, bool hasFocus)
|
||||
CORNER_HEIGHT);
|
||||
}
|
||||
|
||||
void ui::DialogBox::set_xy(int x, int y)
|
||||
{
|
||||
if (x != DialogBox::NO_SET) { m_x = x; }
|
||||
if (y != DialogBox::NO_SET) { m_y = y; }
|
||||
}
|
||||
void ui::DialogBox::set_x(int x) { m_x = x; }
|
||||
|
||||
void ui::DialogBox::set_width_height(int width, int height)
|
||||
{
|
||||
if (width != DialogBox::NO_SET) { m_width = width; }
|
||||
if (height != DialogBox::NO_SET) { m_height = height; }
|
||||
}
|
||||
void ui::DialogBox::set_y(int y) { m_y = y; }
|
||||
|
||||
void ui::DialogBox::set_width(int width) { m_width = width; }
|
||||
|
||||
void ui::DialogBox::set_height(int height) { m_height = height; }
|
||||
|
||||
void ui::DialogBox::initialize_static_members()
|
||||
{
|
||||
|
||||
56
source/ui/Frame.cpp
Normal file
56
source/ui/Frame.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "ui/Frame.hpp"
|
||||
|
||||
#include "graphics/colors.hpp"
|
||||
|
||||
ui::Frame::Frame(int x, int y, int width, int height)
|
||||
: m_x(x)
|
||||
, m_y(y)
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
Frame::initialize_static_members();
|
||||
}
|
||||
|
||||
void ui::Frame::render(sdl::SharedTexture &target, bool hasFocus)
|
||||
{
|
||||
// This is the size of one of the "tiles" of the frame.
|
||||
static constexpr int TILE = 16;
|
||||
|
||||
const int midWidth = m_width - (TILE * 2);
|
||||
const int midHeight = m_height - (TILE * 2);
|
||||
const int rightEdge = (m_x + m_width) - TILE;
|
||||
const int bottomEdge = (m_y + m_height) - TILE;
|
||||
const int textureCorner = TILE * 2;
|
||||
|
||||
// Top.
|
||||
sm_frameCorners->render_part(target, m_x, m_y, 0, 0, TILE, TILE);
|
||||
sm_frameCorners->render_part_stretched(target, TILE, 0, TILE, TILE, m_x + TILE, m_y, midWidth, TILE);
|
||||
sm_frameCorners->render_part(target, rightEdge, m_y, 32, 0, TILE, TILE);
|
||||
|
||||
// Middle
|
||||
sm_frameCorners->render_part_stretched(target, 0, TILE, TILE, TILE, m_x, m_y + TILE, TILE, midHeight);
|
||||
sdl::render_rect_fill(target, m_x + TILE, m_y + TILE, midWidth, midHeight, colors::SLIDE_PANEL_CLEAR);
|
||||
sm_frameCorners->render_part_stretched(target, textureCorner, TILE, TILE, TILE, rightEdge, m_y + TILE, TILE, midHeight);
|
||||
|
||||
// Bottom
|
||||
sm_frameCorners->render_part(target, m_x, bottomEdge, 0, textureCorner, TILE, TILE);
|
||||
sm_frameCorners->render_part_stretched(target, TILE, textureCorner, TILE, TILE, m_x + TILE, bottomEdge, midWidth, TILE);
|
||||
sm_frameCorners->render_part(target, rightEdge, bottomEdge, textureCorner, textureCorner, TILE, TILE);
|
||||
}
|
||||
|
||||
void ui::Frame::set_x(int x) { m_x = x; }
|
||||
|
||||
void ui::Frame::set_y(int y) { m_y = y; }
|
||||
|
||||
void ui::Frame::set_width(int width) { m_width = width; }
|
||||
|
||||
void ui::Frame::set_height(int height) { m_height = height; }
|
||||
|
||||
void ui::Frame::initialize_static_members()
|
||||
{
|
||||
static constexpr std::string_view FRAME_NAME = "FrameCorners";
|
||||
static constexpr const char *FRAME_PATH = "romfs:/Textures/Frame.png";
|
||||
|
||||
if (sm_frameCorners) { return; }
|
||||
sm_frameCorners = sdl::TextureManager::load(FRAME_NAME, FRAME_PATH);
|
||||
}
|
||||
@@ -99,6 +99,10 @@ void ui::Menu::set_selected(int selected)
|
||||
|
||||
void ui::Menu::set_width(int width) { m_width = width; }
|
||||
|
||||
void ui::Menu::set_x(int x) { m_x = x; }
|
||||
|
||||
void ui::Menu::set_y(int y) { m_y = y; }
|
||||
|
||||
void ui::Menu::reset()
|
||||
{
|
||||
m_selected = 0;
|
||||
@@ -106,6 +110,8 @@ void ui::Menu::reset()
|
||||
m_options.clear();
|
||||
}
|
||||
|
||||
bool ui::Menu::is_empty() const { return m_options.empty(); }
|
||||
|
||||
void ui::Menu::update_scroll_text()
|
||||
{
|
||||
const std::string_view text = m_optionScroll->get_text();
|
||||
|
||||
@@ -51,7 +51,7 @@ void ui::PopMessage::update_y(double targetY)
|
||||
m_yMet = true;
|
||||
m_typeTimer.start(5);
|
||||
}
|
||||
m_dialog->set_xy(m_dialog->NO_SET, m_y - 6);
|
||||
m_dialog->set_y(m_y - 6);
|
||||
}
|
||||
|
||||
void ui::PopMessage::update_text_offset()
|
||||
@@ -76,7 +76,7 @@ void ui::PopMessage::update_text_offset()
|
||||
const int dialogX = m_textX - 16;
|
||||
const int dialogWidth = stringWidth + 32;
|
||||
|
||||
m_dialog->set_xy(dialogX, m_dialog->NO_SET);
|
||||
m_dialog->set_width_height(dialogWidth, m_dialog->NO_SET);
|
||||
m_dialog->set_x(dialogX);
|
||||
m_dialog->set_width(dialogWidth);
|
||||
if (m_substrOffset >= messageLength) { m_displayTimer.start(m_ticks); }
|
||||
}
|
||||
|
||||
@@ -25,11 +25,9 @@ ui::SlideOutPanel::SlideOutPanel(int width, Side side)
|
||||
|
||||
void ui::SlideOutPanel::update(bool hasFocus)
|
||||
{
|
||||
const bool openingFromLeft = !m_isOpen && m_side == Side::Left && m_x < m_targetX;
|
||||
const bool openingFromRight = !m_isOpen && m_side == Side::Right && m_x > m_targetX;
|
||||
if (hasFocus && SlideOutPanel::is_hidden()) { SlideOutPanel::unhide(); }
|
||||
|
||||
if (openingFromLeft) { SlideOutPanel::slide_out_left(); }
|
||||
else if (openingFromRight) { SlideOutPanel::slide_out_right(); }
|
||||
slide_out();
|
||||
|
||||
if (m_isOpen)
|
||||
{
|
||||
@@ -37,6 +35,8 @@ void ui::SlideOutPanel::update(bool hasFocus)
|
||||
}
|
||||
}
|
||||
|
||||
void ui::SlideOutPanel::sub_update() { SlideOutPanel::close_hide_panel(); }
|
||||
|
||||
void ui::SlideOutPanel::render(sdl::SharedTexture &target, bool hasFocus)
|
||||
{
|
||||
for (auto ¤tElement : m_elements) { currentElement->render(m_renderTarget, hasFocus); }
|
||||
@@ -55,27 +55,39 @@ void ui::SlideOutPanel::reset()
|
||||
|
||||
void ui::SlideOutPanel::close() { m_closePanel = true; }
|
||||
|
||||
void ui::SlideOutPanel::hide() { m_hidePanel = true; }
|
||||
|
||||
void ui::SlideOutPanel::unhide() { m_hidePanel = false; }
|
||||
|
||||
bool ui::SlideOutPanel::is_open() const { return m_isOpen; }
|
||||
|
||||
bool ui::SlideOutPanel::is_closed()
|
||||
{
|
||||
// I'm assuming this is going to be called, waiting for the panel to close so.
|
||||
const double scaling = config::get_animation_scaling();
|
||||
const bool closeToLeft = m_closePanel && m_side == Side::Left && m_x > -m_width;
|
||||
const bool closeToRight = m_closePanel && 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; }
|
||||
|
||||
close_hide_panel();
|
||||
const bool closed = m_side == Side::Left ? m_x <= -m_width : m_x >= SCREEN_WIDTH;
|
||||
return m_closePanel && closed;
|
||||
}
|
||||
|
||||
bool ui::SlideOutPanel::is_hidden() const { return m_hidePanel; }
|
||||
|
||||
void ui::SlideOutPanel::push_new_element(std::shared_ptr<ui::Element> newElement) { m_elements.push_back(newElement); }
|
||||
|
||||
void ui::SlideOutPanel::clear_elements() { m_elements.clear(); }
|
||||
|
||||
sdl::SharedTexture &ui::SlideOutPanel::get_target() { return m_renderTarget; }
|
||||
|
||||
void ui::SlideOutPanel::slide_out()
|
||||
{
|
||||
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()
|
||||
{
|
||||
const double scaling = config::get_animation_scaling();
|
||||
@@ -106,3 +118,16 @@ void ui::SlideOutPanel::slide_out_right()
|
||||
m_isOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ui::SlideOutPanel::close_hide_panel()
|
||||
{
|
||||
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; }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "ui/TitleView.hpp"
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "error.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logging/error.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
Reference in New Issue
Block a user