mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2025-10-30 07:11:05 +00:00
Add back button functionality to the installer. (#279)
* Add back button functionality to the installer. * Nuclear exits. * Adjust error code. * Rework waiting time into the installer process instead. * Extra waiting time during quitting. * Restore button max widths. * button_guide: set up Esc key texture * Update installer_wizard.cpp * Update resources submodule * installer_wizard: decrease nav button margin --------- Co-authored-by: Hyper <34012267+hyperbx@users.noreply.github.com>
This commit is contained in:
parent
b68dbec612
commit
ef51f04d4f
10 changed files with 368 additions and 143 deletions
|
|
@ -67,7 +67,7 @@ static std::unique_ptr<VirtualFileSystem> createFileSystemFromPath(const std::fi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, bool skipHashChecks, std::vector<uint8_t> &fileData, Journal &journal, const std::function<void()> &progressCallback) {
|
static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, bool skipHashChecks, std::vector<uint8_t> &fileData, Journal &journal, const std::function<bool()> &progressCallback) {
|
||||||
const std::string filename(pair.first);
|
const std::string filename(pair.first);
|
||||||
const uint32_t hashCount = pair.second;
|
const uint32_t hashCount = pair.second;
|
||||||
if (!sourceVfs.exists(filename))
|
if (!sourceVfs.exists(filename))
|
||||||
|
|
@ -139,7 +139,13 @@ static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFi
|
||||||
}
|
}
|
||||||
|
|
||||||
journal.progressCounter += fileData.size();
|
journal.progressCounter += fileData.size();
|
||||||
progressCallback();
|
|
||||||
|
if (!progressCallback())
|
||||||
|
{
|
||||||
|
journal.lastResult = Journal::Result::Cancelled;
|
||||||
|
journal.lastErrorMessage = "Installation was cancelled.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -266,7 +272,7 @@ bool Installer::computeTotalSize(std::span<const FilePair> filePairs, const uint
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Installer::copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback)
|
bool Installer::copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<bool()> &progressCallback)
|
||||||
{
|
{
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
if (!std::filesystem::exists(targetDirectory) && !std::filesystem::create_directories(targetDirectory, ec))
|
if (!std::filesystem::exists(targetDirectory) && !std::filesystem::create_directories(targetDirectory, ec))
|
||||||
|
|
@ -429,7 +435,7 @@ bool Installer::parseSources(const Input &input, Journal &journal, Sources &sour
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Installer::install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback)
|
bool Installer::install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function<bool()> &progressCallback)
|
||||||
{
|
{
|
||||||
// Install files in reverse order of importance. In case of a process crash or power outage, this will increase the likelihood of the installation
|
// Install files in reverse order of importance. In case of a process crash or power outage, this will increase the likelihood of the installation
|
||||||
// missing critical files required for the game to run. These files are used as the way to detect if the game is installed.
|
// missing critical files required for the game to run. These files are used as the way to detect if the game is installed.
|
||||||
|
|
@ -497,7 +503,22 @@ bool Installer::install(const Sources &sources, const std::filesystem::path &tar
|
||||||
|
|
||||||
// Update the progress with the artificial amount attributed to the patching.
|
// Update the progress with the artificial amount attributed to the patching.
|
||||||
journal.progressCounter += PatcherContribution;
|
journal.progressCounter += PatcherContribution;
|
||||||
progressCallback();
|
|
||||||
|
for (uint32_t i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
if (!progressCallback())
|
||||||
|
{
|
||||||
|
journal.lastResult = Journal::Result::Cancelled;
|
||||||
|
journal.lastErrorMessage = "Installation was cancelled.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
// Wait the specified amount of time to allow the consumer of the callbacks to animate, halt or cancel the installation for a while after it's finished.
|
||||||
|
std::this_thread::sleep_for(endWaitTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ struct Journal
|
||||||
enum class Result
|
enum class Result
|
||||||
{
|
{
|
||||||
Success,
|
Success,
|
||||||
|
Cancelled,
|
||||||
VirtualFileSystemFailed,
|
VirtualFileSystemFailed,
|
||||||
DirectoryCreationFailed,
|
DirectoryCreationFailed,
|
||||||
FileMissing,
|
FileMissing,
|
||||||
|
|
@ -75,10 +76,10 @@ struct Installer
|
||||||
static bool checkDLCInstall(const std::filesystem::path &baseDirectory, DLC dlc);
|
static bool checkDLCInstall(const std::filesystem::path &baseDirectory, DLC dlc);
|
||||||
static bool checkAllDLC(const std::filesystem::path &baseDirectory);
|
static bool checkAllDLC(const std::filesystem::path &baseDirectory);
|
||||||
static bool computeTotalSize(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, Journal &journal, uint64_t &totalSize);
|
static bool computeTotalSize(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, Journal &journal, uint64_t &totalSize);
|
||||||
static bool copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback);
|
static bool copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<bool()> &progressCallback);
|
||||||
static bool parseContent(const std::filesystem::path &sourcePath, std::unique_ptr<VirtualFileSystem> &targetVfs, Journal &journal);
|
static bool parseContent(const std::filesystem::path &sourcePath, std::unique_ptr<VirtualFileSystem> &targetVfs, Journal &journal);
|
||||||
static bool parseSources(const Input &input, Journal &journal, Sources &sources);
|
static bool parseSources(const Input &input, Journal &journal, Sources &sources);
|
||||||
static bool install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback);
|
static bool install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function<bool()> &progressCallback);
|
||||||
static void rollback(Journal &journal);
|
static void rollback(Journal &journal);
|
||||||
|
|
||||||
// Convenience method for checking if the specified file contains the game. This should be used when the user selects the file.
|
// Convenience method for checking if the specified file contains the game. This should be used when the user selects the file.
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,12 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
||||||
{ ELanguage::Italian, "SALTA" }
|
{ ELanguage::Italian, "SALTA" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Installer_Button_Retry",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "RETRY" }
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Installer_Button_AddFiles",
|
"Installer_Button_AddFiles",
|
||||||
{
|
{
|
||||||
|
|
@ -339,6 +345,20 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
||||||
{ ELanguage::Italian, "Questa opzione riavviera il gioco\nper farti installare qualsiasi DLC\nche non hai installato.\n\nHai già installato tutti i DLC.\n\nVuoi procedere comunque?" }
|
{ ELanguage::Italian, "Questa opzione riavviera il gioco\nper farti installare qualsiasi DLC\nche non hai installato.\n\nHai già installato tutti i DLC.\n\nVuoi procedere comunque?" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Notes: message appears when user chooses "Quit" on the first available installation screen.
|
||||||
|
"Installer_Message_Quit",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "Are you sure you want to quit?" },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Notes: message appears when user chooses "Cancel" during installation.
|
||||||
|
"Installer_Message_Cancel",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "Are you sure you want to cancel the installation?" },
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Notes: message appears when pressing B at the title screen.
|
// Notes: message appears when pressing B at the title screen.
|
||||||
"Title_Message_Quit",
|
"Title_Message_Quit",
|
||||||
|
|
@ -446,6 +466,18 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
||||||
{ ELanguage::Italian, "Indietro" }
|
{ ELanguage::Italian, "Indietro" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Common_Quit",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "Quit" },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Common_Cancel",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "Cancel" }
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Common_Reset",
|
"Common_Reset",
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -203,12 +203,12 @@ int main(int argc, char *argv[])
|
||||||
if (!Video::CreateHostDevice(sdlVideoDriver))
|
if (!Video::CreateHostDevice(sdlVideoDriver))
|
||||||
{
|
{
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
||||||
return 1;
|
std::_Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!InstallerWizard::Run(GAME_INSTALL_DIRECTORY, isGameInstalled && forceDLCInstaller))
|
if (!InstallerWizard::Run(GAME_INSTALL_DIRECTORY, isGameInstalled && forceDLCInstaller))
|
||||||
{
|
{
|
||||||
return 1;
|
std::_Exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,7 +223,7 @@ int main(int argc, char *argv[])
|
||||||
if (!Video::CreateHostDevice(sdlVideoDriver))
|
if (!Video::CreateHostDevice(sdlVideoDriver))
|
||||||
{
|
{
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
||||||
return 1;
|
std::_Exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
inline const char* g_credits[] =
|
inline std::array<const char*, 14> g_credits =
|
||||||
{
|
{
|
||||||
"Skyth",
|
"Skyth",
|
||||||
"Hyper",
|
"Hyper",
|
||||||
"Darío",
|
"Darío",
|
||||||
"Sajid",
|
"Sajid",
|
||||||
|
"DeaThProj",
|
||||||
"RadiantDerg",
|
"RadiantDerg",
|
||||||
"PTKay",
|
"PTKay",
|
||||||
"DeaThProj",
|
|
||||||
"SuperSonic16",
|
"SuperSonic16",
|
||||||
"NextinHKRY",
|
"NextinHKRY",
|
||||||
"M&M",
|
|
||||||
"saguinee",
|
"saguinee",
|
||||||
"LadyLunanova",
|
"LadyLunanova",
|
||||||
"LJSTAR"
|
"LJSTAR",
|
||||||
|
"Goalringmod27",
|
||||||
|
"M&M"
|
||||||
};
|
};
|
||||||
|
|
||||||
inline size_t g_creditsSize = 12;
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ std::unordered_map<EButtonIcon, float> g_iconWidths =
|
||||||
{ EButtonIcon::Start, 40 },
|
{ EButtonIcon::Start, 40 },
|
||||||
{ EButtonIcon::Back, 40 },
|
{ EButtonIcon::Back, 40 },
|
||||||
{ EButtonIcon::LMB, 40 },
|
{ EButtonIcon::LMB, 40 },
|
||||||
{ EButtonIcon::Enter, 40 }
|
{ EButtonIcon::Enter, 40 },
|
||||||
|
{ EButtonIcon::Escape, 40 },
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<EButtonIcon, float> g_iconHeights =
|
std::unordered_map<EButtonIcon, float> g_iconHeights =
|
||||||
|
|
@ -56,7 +57,8 @@ std::unordered_map<EButtonIcon, float> g_iconHeights =
|
||||||
{ EButtonIcon::Start, 40 },
|
{ EButtonIcon::Start, 40 },
|
||||||
{ EButtonIcon::Back, 40 },
|
{ EButtonIcon::Back, 40 },
|
||||||
{ EButtonIcon::LMB, 40 },
|
{ EButtonIcon::LMB, 40 },
|
||||||
{ EButtonIcon::Enter, 40 }
|
{ EButtonIcon::Enter, 40 },
|
||||||
|
{ EButtonIcon::Escape, 40 },
|
||||||
};
|
};
|
||||||
|
|
||||||
std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon icon)
|
std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon icon)
|
||||||
|
|
@ -124,12 +126,17 @@ std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EButtonIcon::LMB:
|
case EButtonIcon::LMB:
|
||||||
btn = PIXELS_TO_UV_COORDS(256, 128, 0, 0, 128, 128);
|
btn = PIXELS_TO_UV_COORDS(384, 128, 0, 0, 128, 128);
|
||||||
texture = g_upKBMIcons.get();
|
texture = g_upKBMIcons.get();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EButtonIcon::Enter:
|
case EButtonIcon::Enter:
|
||||||
btn = PIXELS_TO_UV_COORDS(256, 128, 128, 0, 128, 128);
|
btn = PIXELS_TO_UV_COORDS(384, 128, 128, 0, 128, 128);
|
||||||
|
texture = g_upKBMIcons.get();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EButtonIcon::Escape:
|
||||||
|
btn = PIXELS_TO_UV_COORDS(384, 128, 256, 0, 128, 128);
|
||||||
texture = g_upKBMIcons.get();
|
texture = g_upKBMIcons.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ enum class EButtonIcon
|
||||||
|
|
||||||
// Keyboard + Mouse (temporary)
|
// Keyboard + Mouse (temporary)
|
||||||
LMB,
|
LMB,
|
||||||
Enter
|
Enter,
|
||||||
|
Escape
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EButtonAlignment
|
enum class EButtonAlignment
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ static constexpr double CONTAINER_INNER_TIME = SCANLINES_ANIMATION_DURATION + CO
|
||||||
static constexpr double CONTAINER_INNER_DURATION = 15.0;
|
static constexpr double CONTAINER_INNER_DURATION = 15.0;
|
||||||
|
|
||||||
static constexpr double ALL_ANIMATIONS_FULL_DURATION = CONTAINER_INNER_TIME + CONTAINER_INNER_DURATION;
|
static constexpr double ALL_ANIMATIONS_FULL_DURATION = CONTAINER_INNER_TIME + CONTAINER_INNER_DURATION;
|
||||||
|
static constexpr double QUITTING_EXTRA_DURATION = 60.0;
|
||||||
|
|
||||||
static constexpr double INSTALL_ICONS_FADE_IN_ANIMATION_TIME = 0.0;
|
static constexpr double INSTALL_ICONS_FADE_IN_ANIMATION_TIME = 0.0;
|
||||||
static constexpr double INSTALL_ICONS_FADE_IN_ANIMATION_DURATION = 15.0;
|
static constexpr double INSTALL_ICONS_FADE_IN_ANIMATION_DURATION = 15.0;
|
||||||
|
|
@ -77,7 +78,7 @@ constexpr float CONTAINER_HEIGHT = 246.0f;
|
||||||
constexpr float SIDE_CONTAINER_WIDTH = CONTAINER_WIDTH / 2.0f;
|
constexpr float SIDE_CONTAINER_WIDTH = CONTAINER_WIDTH / 2.0f;
|
||||||
|
|
||||||
constexpr float BOTTOM_X_GAP = 4.0f;
|
constexpr float BOTTOM_X_GAP = 4.0f;
|
||||||
constexpr float BOTTOM_Y_GAP = 6.0f;
|
constexpr float BOTTOM_Y_GAP = 5.0f;
|
||||||
constexpr float CONTAINER_BUTTON_WIDTH = 250.0f;
|
constexpr float CONTAINER_BUTTON_WIDTH = 250.0f;
|
||||||
constexpr float CONTAINER_BUTTON_GAP = 9.0f;
|
constexpr float CONTAINER_BUTTON_GAP = 9.0f;
|
||||||
constexpr float BUTTON_HEIGHT = 22.0f;
|
constexpr float BUTTON_HEIGHT = 22.0f;
|
||||||
|
|
@ -98,6 +99,7 @@ static double g_arrowCircleCurrentRotation = 0.0;
|
||||||
static double g_appearTime = 0.0;
|
static double g_appearTime = 0.0;
|
||||||
static double g_disappearTime = DBL_MAX;
|
static double g_disappearTime = DBL_MAX;
|
||||||
static bool g_isDisappearing = false;
|
static bool g_isDisappearing = false;
|
||||||
|
static bool g_isQuitting = false;
|
||||||
|
|
||||||
static std::filesystem::path g_installPath;
|
static std::filesystem::path g_installPath;
|
||||||
static std::filesystem::path g_gameSourcePath;
|
static std::filesystem::path g_gameSourcePath;
|
||||||
|
|
@ -118,6 +120,8 @@ static double g_installerEndTime = DBL_MAX;
|
||||||
static float g_installerProgressRatioCurrent = 0.0f;
|
static float g_installerProgressRatioCurrent = 0.0f;
|
||||||
static std::atomic<float> g_installerProgressRatioTarget = 0.0f;
|
static std::atomic<float> g_installerProgressRatioTarget = 0.0f;
|
||||||
static std::atomic<bool> g_installerFinished = false;
|
static std::atomic<bool> g_installerFinished = false;
|
||||||
|
static std::atomic<bool> g_installerHalted = false;
|
||||||
|
static std::atomic<bool> g_installerCancelled = false;
|
||||||
static bool g_installerFailed = false;
|
static bool g_installerFailed = false;
|
||||||
static std::string g_installerErrorMessage;
|
static std::string g_installerErrorMessage;
|
||||||
|
|
||||||
|
|
@ -133,9 +137,17 @@ enum class WizardPage
|
||||||
InstallFailed,
|
InstallFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class MessagePromptSource
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Next,
|
||||||
|
Back
|
||||||
|
};
|
||||||
|
|
||||||
static WizardPage g_firstPage = WizardPage::SelectLanguage;
|
static WizardPage g_firstPage = WizardPage::SelectLanguage;
|
||||||
static WizardPage g_currentPage = g_firstPage;
|
static WizardPage g_currentPage = g_firstPage;
|
||||||
static std::string g_currentMessagePrompt = "";
|
static std::string g_currentMessagePrompt = "";
|
||||||
|
static MessagePromptSource g_currentMessagePromptSource = MessagePromptSource::Unknown;
|
||||||
static bool g_currentMessagePromptConfirmation = false;
|
static bool g_currentMessagePromptConfirmation = false;
|
||||||
static std::list<std::filesystem::path> g_currentPickerResults;
|
static std::list<std::filesystem::path> g_currentPickerResults;
|
||||||
static std::atomic<bool> g_currentPickerResultsReady = false;
|
static std::atomic<bool> g_currentPickerResultsReady = false;
|
||||||
|
|
@ -151,6 +163,7 @@ static ImVec2 g_joypadAxis = {};
|
||||||
static int g_currentCursorIndex = -1;
|
static int g_currentCursorIndex = -1;
|
||||||
static int g_currentCursorDefault = 0;
|
static int g_currentCursorDefault = 0;
|
||||||
static bool g_currentCursorAccepted = false;
|
static bool g_currentCursorAccepted = false;
|
||||||
|
static bool g_currentCursorBack = false;
|
||||||
static std::vector<std::pair<ImVec2, ImVec2>> g_currentCursorRects;
|
static std::vector<std::pair<ImVec2, ImVec2>> g_currentCursorRects;
|
||||||
static std::string g_creditsStr;
|
static std::string g_creditsStr;
|
||||||
|
|
||||||
|
|
@ -185,6 +198,9 @@ public:
|
||||||
case SDL_SCANCODE_KP_ENTER:
|
case SDL_SCANCODE_KP_ENTER:
|
||||||
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
|
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
|
||||||
break;
|
break;
|
||||||
|
case SDL_SCANCODE_ESCAPE:
|
||||||
|
g_currentCursorBack = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -209,6 +225,9 @@ public:
|
||||||
case SDL_CONTROLLER_BUTTON_A:
|
case SDL_CONTROLLER_BUTTON_A:
|
||||||
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
|
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
|
||||||
break;
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_B:
|
||||||
|
g_currentCursorBack = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -807,15 +826,47 @@ static void DrawDescriptionContainer()
|
||||||
DrawContainer(sideMin, sideMax, false);
|
DrawContainer(sideMin, sideMax, false);
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
|
|
||||||
if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
|
EButtonIcon backIcon;
|
||||||
|
EButtonIcon selectIcon;
|
||||||
|
if (hid::IsInputDeviceController())
|
||||||
{
|
{
|
||||||
auto icon = hid::IsInputDeviceController()
|
backIcon = EButtonIcon::B;
|
||||||
? EButtonIcon::A
|
selectIcon = EButtonIcon::A;
|
||||||
: hid::g_inputDevice == hid::EInputDevice::Keyboard
|
}
|
||||||
? EButtonIcon::Enter
|
else if (hid::g_inputDevice == hid::EInputDevice::Keyboard)
|
||||||
: EButtonIcon::LMB;
|
{
|
||||||
|
backIcon = EButtonIcon::Escape;
|
||||||
|
selectIcon = EButtonIcon::Enter;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backIcon = EButtonIcon::Escape;
|
||||||
|
selectIcon = EButtonIcon::LMB;
|
||||||
|
}
|
||||||
|
|
||||||
ButtonGuide::Open(Button(Localise("Common_Select"), icon));
|
if (g_currentPage == WizardPage::InstallSucceeded && textAlpha >= 1.0)
|
||||||
|
{
|
||||||
|
ButtonGuide::Open(Button(Localise("Common_Select"), selectIcon));
|
||||||
|
}
|
||||||
|
else if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
|
||||||
|
{
|
||||||
|
const char *backKey = "Common_Back";
|
||||||
|
if ((g_currentPage == g_firstPage) || (g_currentPage == WizardPage::InstallFailed))
|
||||||
|
{
|
||||||
|
backKey = "Common_Quit";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<Button, 2> buttons =
|
||||||
|
{
|
||||||
|
Button(Localise("Common_Select"), selectIcon),
|
||||||
|
Button(Localise(backKey), backIcon)
|
||||||
|
};
|
||||||
|
|
||||||
|
ButtonGuide::Open(buttons);
|
||||||
|
}
|
||||||
|
else if (g_currentPage == WizardPage::Installing)
|
||||||
|
{
|
||||||
|
ButtonGuide::Open(Button(Localise("Common_Cancel"), backIcon));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -966,9 +1017,9 @@ static void DrawProgressBar(float progressRatio)
|
||||||
float alpha = 1.0;
|
float alpha = 1.0;
|
||||||
const uint32_t innerColor0 = IM_COL32(0, 65, 0, 255 * alpha);
|
const uint32_t innerColor0 = IM_COL32(0, 65, 0, 255 * alpha);
|
||||||
const uint32_t innerColor1 = IM_COL32(0, 32, 0, 255 * alpha);
|
const uint32_t innerColor1 = IM_COL32(0, 32, 0, 255 * alpha);
|
||||||
float xPadding = Scale(6.0f);
|
float xPadding = Scale(4);
|
||||||
float yPadding = Scale(3.0f);
|
float yPadding = Scale(3);
|
||||||
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + BOTTOM_X_GAP, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
|
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + BOTTOM_X_GAP + Scale(1), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP)};
|
||||||
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
|
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
|
||||||
|
|
||||||
DrawButtonContainer(min, max, 0, 0, alpha);
|
DrawButtonContainer(min, max, 0, 0, alpha);
|
||||||
|
|
@ -985,8 +1036,8 @@ static void DrawProgressBar(float progressRatio)
|
||||||
|
|
||||||
const uint32_t sliderColor0 = IM_COL32(57, 241, 0, 255 * alpha);
|
const uint32_t sliderColor0 = IM_COL32(57, 241, 0, 255 * alpha);
|
||||||
const uint32_t sliderColor1 = IM_COL32(2, 106, 0, 255 * alpha);
|
const uint32_t sliderColor1 = IM_COL32(2, 106, 0, 255 * alpha);
|
||||||
xPadding += Scale(1.0f);
|
xPadding += Scale(1.5f);
|
||||||
yPadding += Scale(1.0f);
|
yPadding += Scale(1.5f);
|
||||||
|
|
||||||
ImVec2 sliderMin = { min.x + xPadding, min.y + yPadding };
|
ImVec2 sliderMin = { min.x + xPadding, min.y + yPadding };
|
||||||
ImVec2 sliderMax = { max.x - xPadding, max.y - yPadding };
|
ImVec2 sliderMax = { max.x - xPadding, max.y - yPadding };
|
||||||
|
|
@ -1178,27 +1229,23 @@ static void DrawSourcePickers()
|
||||||
std::list<std::filesystem::path> paths;
|
std::list<std::filesystem::path> paths;
|
||||||
if (g_currentPage == WizardPage::SelectGameAndUpdate || g_currentPage == WizardPage::SelectDLC)
|
if (g_currentPage == WizardPage::SelectGameAndUpdate || g_currentPage == WizardPage::SelectDLC)
|
||||||
{
|
{
|
||||||
constexpr float ADD_BUTTON_MAX_TEXT_WIDTH = 160.0f;
|
constexpr float ADD_BUTTON_MAX_TEXT_WIDTH = 168.0f;
|
||||||
const std::string &addFilesText = Localise("Installer_Button_AddFiles");
|
const std::string &addFilesText = Localise("Installer_Button_AddFiles");
|
||||||
float squashRatio;
|
float squashRatio;
|
||||||
ImVec2 textSize = ComputeTextSize(g_dfsogeistdFont, addFilesText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
|
ImVec2 textSize = ComputeTextSize(g_dfsogeistdFont, addFilesText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
|
||||||
textSize.x += BUTTON_TEXT_GAP;
|
|
||||||
|
|
||||||
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
|
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
|
||||||
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP + textSize.x * squashRatio), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
|
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP + textSize.x * squashRatio + BUTTON_TEXT_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
|
||||||
DrawButton(min, max, addFilesText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
DrawButton(min, max, addFilesText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
||||||
if (buttonPressed)
|
if (buttonPressed)
|
||||||
{
|
{
|
||||||
PickerShow(false);
|
PickerShow(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
min.x += Scale(BOTTOM_X_GAP + textSize.x * squashRatio);
|
min.x += Scale(BOTTOM_X_GAP + textSize.x * squashRatio + BUTTON_TEXT_GAP);
|
||||||
|
|
||||||
const std::string &addFolderText = Localise("Installer_Button_AddFolder");
|
const std::string &addFolderText = Localise("Installer_Button_AddFolder");
|
||||||
textSize = ComputeTextSize(g_dfsogeistdFont, addFolderText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
|
textSize = ComputeTextSize(g_dfsogeistdFont, addFolderText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
|
||||||
textSize.x += BUTTON_TEXT_GAP;
|
max.x = min.x + Scale(textSize.x * squashRatio + BUTTON_TEXT_GAP);
|
||||||
|
|
||||||
max.x = min.x + Scale(textSize.x * squashRatio);
|
|
||||||
DrawButton(min, max, addFolderText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
DrawButton(min, max, addFolderText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
||||||
if (buttonPressed)
|
if (buttonPressed)
|
||||||
{
|
{
|
||||||
|
|
@ -1244,8 +1291,14 @@ static void DrawInstallingProgress()
|
||||||
|
|
||||||
static void InstallerThread()
|
static void InstallerThread()
|
||||||
{
|
{
|
||||||
if (!Installer::install(g_installerSources, g_installPath, false, g_installerJournal, [&]() {
|
if (!Installer::install(g_installerSources, g_installPath, false, g_installerJournal, std::chrono::seconds(1), [&]() {
|
||||||
g_installerProgressRatioTarget = float(double(g_installerJournal.progressCounter) / double(g_installerJournal.progressTotal));
|
g_installerProgressRatioTarget = float(double(g_installerJournal.progressCounter) / double(g_installerJournal.progressTotal));
|
||||||
|
|
||||||
|
// If user is being asked for confirmation on cancelling the installation, halt the installer from progressing further.
|
||||||
|
g_installerHalted.wait(true);
|
||||||
|
|
||||||
|
// If user has confirmed they wish to cancel the installation, return false to indicate the installer should fail and stop.
|
||||||
|
return !g_installerCancelled.load();
|
||||||
}))
|
}))
|
||||||
{
|
{
|
||||||
g_installerFailed = true;
|
g_installerFailed = true;
|
||||||
|
|
@ -1255,9 +1308,8 @@ static void InstallerThread()
|
||||||
Installer::rollback(g_installerJournal);
|
Installer::rollback(g_installerJournal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rest for a bit after finishing the installation, the device is tired
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
||||||
g_installerFinished = true;
|
g_installerFinished = true;
|
||||||
|
g_installerCancelled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InstallerStart()
|
static void InstallerStart()
|
||||||
|
|
@ -1298,104 +1350,162 @@ static bool InstallerParseSources(std::string &errorMessage)
|
||||||
return sourcesParsed;
|
return sourcesParsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawNextButton()
|
static void DrawNavigationButton()
|
||||||
{
|
{
|
||||||
if (g_currentPage != WizardPage::Installing)
|
if (g_currentPage == WizardPage::Installing)
|
||||||
{
|
{
|
||||||
bool nextButtonEnabled = !g_isDisappearing;
|
// Navigation buttons are not offered during installation at the moment.
|
||||||
if (nextButtonEnabled && g_currentPage == WizardPage::SelectGameAndUpdate)
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nextButtonEnabled = !g_isDisappearing && (g_currentPage != WizardPage::Installing);
|
||||||
|
if (nextButtonEnabled && g_currentPage == WizardPage::SelectGameAndUpdate)
|
||||||
|
{
|
||||||
|
nextButtonEnabled = !g_gameSourcePath.empty() && !g_updateSourcePath.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skipButton = false;
|
||||||
|
if (g_currentPage == WizardPage::SelectDLC)
|
||||||
|
{
|
||||||
|
skipButton = std::all_of(g_dlcSourcePaths.begin(), g_dlcSourcePaths.end(), [](const std::filesystem::path &path) { return path.empty(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
float squashRatio;
|
||||||
|
constexpr float NAV_BUTTON_MAX_TEXT_WIDTH = 90.0f;
|
||||||
|
const char *nextButtonKey = "Installer_Button_Next";
|
||||||
|
if (skipButton)
|
||||||
|
{
|
||||||
|
nextButtonKey = "Installer_Button_Skip";
|
||||||
|
}
|
||||||
|
else if (g_currentPage == WizardPage::InstallFailed)
|
||||||
|
{
|
||||||
|
nextButtonKey = "Installer_Button_Retry";
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &nextButtonText = Localise(nextButtonKey);
|
||||||
|
ImVec2 nextTextSize = ComputeTextSize(g_newRodinFont, nextButtonText.c_str(), 20.0f, squashRatio, NAV_BUTTON_MAX_TEXT_WIDTH);
|
||||||
|
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - nextTextSize.x * squashRatio - BOTTOM_X_GAP - BUTTON_TEXT_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
|
||||||
|
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
|
||||||
|
|
||||||
|
bool buttonPressed = false;
|
||||||
|
DrawButton(min, max, nextButtonText.c_str(), false, nextButtonEnabled, buttonPressed, NAV_BUTTON_MAX_TEXT_WIDTH);
|
||||||
|
|
||||||
|
if (buttonPressed)
|
||||||
|
{
|
||||||
|
XexPatcher::Result patcherResult;
|
||||||
|
if (g_currentPage == WizardPage::SelectGameAndUpdate && (patcherResult = Installer::checkGameUpdateCompatibility(g_gameSourcePath, g_updateSourcePath), patcherResult != XexPatcher::Result::Success))
|
||||||
{
|
{
|
||||||
nextButtonEnabled = !g_gameSourcePath.empty() && !g_updateSourcePath.empty();
|
g_currentMessagePrompt = Localise("Installer_Message_IncompatibleGameData");
|
||||||
|
g_currentMessagePromptConfirmation = false;
|
||||||
}
|
}
|
||||||
|
else if (g_currentPage == WizardPage::SelectDLC)
|
||||||
bool skipButton = false;
|
|
||||||
if (g_currentPage == WizardPage::SelectDLC)
|
|
||||||
{
|
{
|
||||||
skipButton = std::all_of(g_dlcSourcePaths.begin(), g_dlcSourcePaths.end(), [](const std::filesystem::path &path) { return path.empty(); });
|
// Check if any of the DLC was not specified.
|
||||||
}
|
bool dlcIncomplete = false;
|
||||||
|
for (int i = 0; (i < int(DLC::Count)) && !dlcIncomplete; i++)
|
||||||
float squashRatio;
|
|
||||||
constexpr float NEXT_BUTTON_MAX_TEXT_WIDTH = 100.0f;
|
|
||||||
const std::string &buttonText = Localise(skipButton ? "Installer_Button_Skip" : "Installer_Button_Next");
|
|
||||||
ImVec2 textSize = ComputeTextSize(g_newRodinFont, buttonText.c_str(), 20.0f, squashRatio, NEXT_BUTTON_MAX_TEXT_WIDTH);
|
|
||||||
textSize.x += BUTTON_TEXT_GAP;
|
|
||||||
|
|
||||||
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - textSize.x * squashRatio - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
|
|
||||||
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
|
|
||||||
|
|
||||||
bool buttonPressed = false;
|
|
||||||
DrawButton(min, max, buttonText.c_str(), false, nextButtonEnabled, buttonPressed, NEXT_BUTTON_MAX_TEXT_WIDTH);
|
|
||||||
|
|
||||||
if (buttonPressed)
|
|
||||||
{
|
|
||||||
XexPatcher::Result patcherResult;
|
|
||||||
if (g_currentPage == WizardPage::SelectGameAndUpdate && (patcherResult = Installer::checkGameUpdateCompatibility(g_gameSourcePath, g_updateSourcePath), patcherResult != XexPatcher::Result::Success))
|
|
||||||
{
|
{
|
||||||
g_currentMessagePrompt = Localise("Installer_Message_IncompatibleGameData");
|
if (g_dlcSourcePaths[i].empty() && !g_dlcInstalled[i])
|
||||||
|
{
|
||||||
|
dlcIncomplete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dlcInstallerMode = g_gameSourcePath.empty();
|
||||||
|
std::string sourcesErrorMessage;
|
||||||
|
if (!InstallerParseSources(sourcesErrorMessage))
|
||||||
|
{
|
||||||
|
// Some of the sources that were provided to the installer are not valid. Restart the file selection process.
|
||||||
|
std::stringstream stringStream;
|
||||||
|
stringStream << Localise("Installer_Message_InvalidFiles");
|
||||||
|
if (!sourcesErrorMessage.empty()) {
|
||||||
|
stringStream << std::endl << std::endl << sourcesErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_currentMessagePrompt = stringStream.str();
|
||||||
g_currentMessagePromptConfirmation = false;
|
g_currentMessagePromptConfirmation = false;
|
||||||
|
g_currentPage = dlcInstallerMode ? WizardPage::SelectDLC : WizardPage::SelectGameAndUpdate;
|
||||||
}
|
}
|
||||||
else if (g_currentPage == WizardPage::SelectDLC)
|
else if (dlcIncomplete && !dlcInstallerMode)
|
||||||
{
|
{
|
||||||
// Check if any of the DLC was not specified.
|
// Not all the DLC was specified, we show a prompt and await a confirmation before starting the installer.
|
||||||
bool dlcIncomplete = false;
|
g_currentMessagePrompt = Localise("Installer_Message_DLCWarning");
|
||||||
for (int i = 0; (i < int(DLC::Count)) && !dlcIncomplete; i++)
|
g_currentMessagePromptSource = MessagePromptSource::Next;
|
||||||
{
|
g_currentMessagePromptConfirmation = true;
|
||||||
if (g_dlcSourcePaths[i].empty() && !g_dlcInstalled[i])
|
|
||||||
{
|
|
||||||
dlcIncomplete = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dlcInstallerMode = g_gameSourcePath.empty();
|
|
||||||
std::string sourcesErrorMessage;
|
|
||||||
if (!InstallerParseSources(sourcesErrorMessage))
|
|
||||||
{
|
|
||||||
// Some of the sources that were provided to the installer are not valid. Restart the file selection process.
|
|
||||||
std::stringstream stringStream;
|
|
||||||
stringStream << Localise("Installer_Message_InvalidFiles");
|
|
||||||
if (!sourcesErrorMessage.empty()) {
|
|
||||||
stringStream << std::endl << std::endl << sourcesErrorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_currentMessagePrompt = stringStream.str();
|
|
||||||
g_currentMessagePromptConfirmation = false;
|
|
||||||
g_currentPage = dlcInstallerMode ? WizardPage::SelectDLC : WizardPage::SelectGameAndUpdate;
|
|
||||||
}
|
|
||||||
else if (dlcIncomplete && !dlcInstallerMode)
|
|
||||||
{
|
|
||||||
// Not all the DLC was specified, we show a prompt and await a confirmation before starting the installer.
|
|
||||||
g_currentMessagePrompt = Localise("Installer_Message_DLCWarning");
|
|
||||||
g_currentMessagePromptConfirmation = true;
|
|
||||||
}
|
|
||||||
else if (skipButton && dlcInstallerMode)
|
|
||||||
{
|
|
||||||
// Nothing was selected and the installer was in DLC mode, just close it.
|
|
||||||
g_isDisappearing = true;
|
|
||||||
g_disappearTime = ImGui::GetTime();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_currentPage = WizardPage::CheckSpace;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (g_currentPage == WizardPage::CheckSpace)
|
else if (skipButton && dlcInstallerMode)
|
||||||
{
|
|
||||||
InstallerStart();
|
|
||||||
}
|
|
||||||
else if (g_currentPage == WizardPage::InstallSucceeded)
|
|
||||||
{
|
{
|
||||||
|
// Nothing was selected and the installer was in DLC mode, just close it.
|
||||||
g_isDisappearing = true;
|
g_isDisappearing = true;
|
||||||
g_disappearTime = ImGui::GetTime();
|
g_disappearTime = ImGui::GetTime();
|
||||||
}
|
}
|
||||||
else if (g_currentPage == WizardPage::InstallFailed)
|
|
||||||
{
|
|
||||||
g_currentPage = g_firstPage;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_currentPage = WizardPage(int(g_currentPage) + 1);
|
g_currentPage = WizardPage::CheckSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (g_currentPage == WizardPage::CheckSpace)
|
||||||
|
{
|
||||||
|
InstallerStart();
|
||||||
|
}
|
||||||
|
else if (g_currentPage == WizardPage::InstallSucceeded)
|
||||||
|
{
|
||||||
|
g_isDisappearing = true;
|
||||||
|
g_disappearTime = ImGui::GetTime();
|
||||||
|
}
|
||||||
|
else if (g_currentPage == WizardPage::InstallFailed)
|
||||||
|
{
|
||||||
|
g_currentPage = g_firstPage;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_currentPage = WizardPage(int(g_currentPage) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CheckCancelAction()
|
||||||
|
{
|
||||||
|
if (!g_currentCursorBack)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_currentCursorBack = false;
|
||||||
|
|
||||||
|
if (g_currentPage == WizardPage::InstallSucceeded)
|
||||||
|
{
|
||||||
|
// Nothing to back out on this page.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (g_currentPage == WizardPage::Installing && g_installerCancelled)
|
||||||
|
{
|
||||||
|
// Installer's already been cancelled, no need for more confirmations.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Game_PlaySound("sys_actstg_pausecansel");
|
||||||
|
|
||||||
|
if (g_currentPage == g_firstPage || g_currentPage == WizardPage::InstallFailed)
|
||||||
|
{
|
||||||
|
// Ask for confirmation if user wants to quit the installer.
|
||||||
|
g_currentMessagePrompt = Localise("Installer_Message_Quit");
|
||||||
|
g_currentMessagePromptSource = MessagePromptSource::Back;
|
||||||
|
g_currentMessagePromptConfirmation = true;
|
||||||
|
}
|
||||||
|
else if (g_currentPage == WizardPage::Installing)
|
||||||
|
{
|
||||||
|
// Ask for confirmation if the user wants to cancel the installation.
|
||||||
|
g_currentMessagePrompt = Localise("Installer_Message_Cancel");
|
||||||
|
g_currentMessagePromptSource = MessagePromptSource::Back;
|
||||||
|
g_currentMessagePromptConfirmation = true;
|
||||||
|
|
||||||
|
// Indicate to the installer that all progress should stop until the user confirms if they wish to cancel.
|
||||||
|
g_installerHalted = true;
|
||||||
|
}
|
||||||
|
else if (int(g_currentPage) > 0)
|
||||||
|
{
|
||||||
|
// Just go back to the previous page.
|
||||||
|
g_currentPage = WizardPage(int(g_currentPage) - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1492,17 +1602,52 @@ static void DrawMessagePrompt()
|
||||||
|
|
||||||
if (messageWindowReturned)
|
if (messageWindowReturned)
|
||||||
{
|
{
|
||||||
if (g_currentMessagePromptConfirmation && (g_currentMessageResult == 0) && (g_currentPage == WizardPage::SelectDLC))
|
if (g_currentMessagePromptConfirmation && (g_currentMessageResult == 0))
|
||||||
{
|
{
|
||||||
// If user confirms the message prompt that they wish to skip installing the DLC, proceed to the next step.
|
if (g_currentMessagePromptSource == MessagePromptSource::Back)
|
||||||
g_currentPage = WizardPage::CheckSpace;
|
{
|
||||||
|
if (g_currentPage == WizardPage::Installing)
|
||||||
|
{
|
||||||
|
// If user confirms they wish to cancel the installation, notify the installation thread it must finish as soon as possible.
|
||||||
|
g_installerCancelled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// In all cases, proceed to just quit the application.
|
||||||
|
g_isQuitting = true;
|
||||||
|
g_isDisappearing = true;
|
||||||
|
g_disappearTime = ImGui::GetTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (g_currentPage == WizardPage::SelectDLC)
|
||||||
|
{
|
||||||
|
// If user confirms the message prompt that they wish to skip installing the DLC, proceed to the next step.
|
||||||
|
g_currentPage = WizardPage::CheckSpace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_currentMessagePromptSource == MessagePromptSource::Back)
|
||||||
|
{
|
||||||
|
// Regardless of the confirmation, the installation thread must be resumed.
|
||||||
|
g_installerHalted = false;
|
||||||
|
g_installerHalted.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
g_currentMessagePrompt.clear();
|
g_currentMessagePrompt.clear();
|
||||||
|
g_currentMessagePromptSource = MessagePromptSource::Unknown;
|
||||||
g_currentMessageResult = -1;
|
g_currentMessageResult = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void PickerDrawForeground()
|
||||||
|
{
|
||||||
|
if (g_currentPickerVisible)
|
||||||
|
{
|
||||||
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
drawList->AddRectFilled({ 0.0f, 0.0f }, ImGui::GetIO().DisplaySize, IM_COL32(0, 0, 0, 190));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void PickerCheckTutorial()
|
static void PickerCheckTutorial()
|
||||||
{
|
{
|
||||||
if (!g_pickerTutorialTriggered || !g_currentMessagePrompt.empty())
|
if (!g_pickerTutorialTriggered || !g_currentMessagePrompt.empty())
|
||||||
|
|
@ -1557,10 +1702,10 @@ void InstallerWizard::Init()
|
||||||
g_pulseInstall = LOAD_ZSTD_TEXTURE(g_pulse_install);
|
g_pulseInstall = LOAD_ZSTD_TEXTURE(g_pulse_install);
|
||||||
g_upHedgeDev = LOAD_ZSTD_TEXTURE(g_hedgedev);
|
g_upHedgeDev = LOAD_ZSTD_TEXTURE(g_hedgedev);
|
||||||
|
|
||||||
for (int i = 0; i < g_creditsSize; i++)
|
for (int i = 0; i < g_credits.size(); i++)
|
||||||
{
|
{
|
||||||
g_creditsStr += g_credits[i];
|
g_creditsStr += g_credits[i];
|
||||||
g_creditsStr += " ";
|
g_creditsStr += " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1580,15 +1725,23 @@ void InstallerWizard::Draw()
|
||||||
DrawSourcePickers();
|
DrawSourcePickers();
|
||||||
DrawSources();
|
DrawSources();
|
||||||
DrawInstallingProgress();
|
DrawInstallingProgress();
|
||||||
DrawNextButton();
|
DrawNavigationButton();
|
||||||
|
CheckCancelAction();
|
||||||
DrawBorders();
|
DrawBorders();
|
||||||
DrawMessagePrompt();
|
DrawMessagePrompt();
|
||||||
|
PickerDrawForeground();
|
||||||
PickerCheckTutorial();
|
PickerCheckTutorial();
|
||||||
PickerCheckResults();
|
PickerCheckResults();
|
||||||
|
|
||||||
if (g_isDisappearing)
|
if (g_isDisappearing)
|
||||||
{
|
{
|
||||||
const double disappearDuration = ALL_ANIMATIONS_FULL_DURATION / 60.0;
|
double disappearDuration = ALL_ANIMATIONS_FULL_DURATION / 60.0;
|
||||||
|
if (g_isQuitting)
|
||||||
|
{
|
||||||
|
// Add some extra waiting time when quitting the application altogether.
|
||||||
|
disappearDuration += QUITTING_EXTRA_DURATION / 60.0;
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::GetTime() > (g_disappearTime + disappearDuration))
|
if (ImGui::GetTime() > (g_disappearTime + disappearDuration))
|
||||||
{
|
{
|
||||||
s_isVisible = false;
|
s_isVisible = false;
|
||||||
|
|
@ -1670,5 +1823,5 @@ bool InstallerWizard::Run(std::filesystem::path installPath, bool skipGame)
|
||||||
InstallerWizard::Shutdown();
|
InstallerWizard::Shutdown();
|
||||||
EmbeddedPlayer::Shutdown();
|
EmbeddedPlayer::Shutdown();
|
||||||
|
|
||||||
return true;
|
return !g_isQuitting;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ void MessageWindow::Draw()
|
||||||
|
|
||||||
textY += Scale(lines.size() % 2 == 0 ? 1.5f : 8.0f);
|
textY += Scale(lines.size() % 2 == 0 ? 1.5f : 8.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isController = hid::IsInputDeviceController();
|
bool isController = hid::IsInputDeviceController();
|
||||||
bool isKeyboard = hid::g_inputDevice == hid::EInputDevice::Keyboard;
|
bool isKeyboard = hid::g_inputDevice == hid::EInputDevice::Keyboard;
|
||||||
|
|
||||||
|
|
@ -397,20 +397,25 @@ void MessageWindow::Draw()
|
||||||
g_upWasHeld = upIsHeld;
|
g_upWasHeld = upIsHeld;
|
||||||
g_downWasHeld = downIsHeld;
|
g_downWasHeld = downIsHeld;
|
||||||
|
|
||||||
if (isController || (isKeyboard && App::s_isInit))
|
EButtonIcon selectIcon = EButtonIcon::A;
|
||||||
|
EButtonIcon backIcon = EButtonIcon::B;
|
||||||
|
if (isController || isKeyboard)
|
||||||
{
|
{
|
||||||
|
if (isKeyboard && !App::s_isInit)
|
||||||
|
{
|
||||||
|
// Only display keyboard prompt during installer.
|
||||||
|
selectIcon = EButtonIcon::Enter;
|
||||||
|
backIcon = EButtonIcon::Escape;
|
||||||
|
}
|
||||||
|
|
||||||
std::array<Button, 2> buttons =
|
std::array<Button, 2> buttons =
|
||||||
{
|
{
|
||||||
Button(Localise("Common_Select"), EButtonIcon::A),
|
Button(Localise("Common_Select"), selectIcon),
|
||||||
Button(Localise("Common_Back"), EButtonIcon::B),
|
Button(Localise("Common_Back"), backIcon),
|
||||||
};
|
};
|
||||||
|
|
||||||
ButtonGuide::Open(buttons);
|
ButtonGuide::Open(buttons);
|
||||||
}
|
}
|
||||||
else // Only display keyboard prompt during installer.
|
|
||||||
{
|
|
||||||
ButtonGuide::Open(Button(Localise("Common_Select"), EButtonIcon::Enter));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_isDeclined)
|
if (g_isDeclined)
|
||||||
{
|
{
|
||||||
|
|
@ -448,7 +453,13 @@ void MessageWindow::Draw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ButtonGuide::Open(Button(Localise("Common_Select"), EButtonIcon::LMB));
|
std::array<Button, 2> buttons =
|
||||||
|
{
|
||||||
|
Button(Localise("Common_Select"), EButtonIcon::LMB),
|
||||||
|
Button(Localise("Common_Back"), EButtonIcon::Escape),
|
||||||
|
};
|
||||||
|
|
||||||
|
ButtonGuide::Open(buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_selectedRowIndex != -1 && g_isAccepted)
|
if (g_selectedRowIndex != -1 && g_isAccepted)
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit b2026bbc8e1ac96858659aff76c77c5945c15ff2
|
Subproject commit 20dc53cf544eeb573be3df9406720f3fb003ad9d
|
||||||
Loading…
Add table
Reference in a new issue