mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-09 11:15:39 +00:00
561 lines
23 KiB
C++
561 lines
23 KiB
C++
// SPDX-License-Identifier: MIT
|
|
//
|
|
// ES-DE
|
|
// GuiApplicationUpdater.cpp
|
|
//
|
|
// Installs application updates.
|
|
// Used in conjunction with ApplicationUpdater.
|
|
//
|
|
|
|
#include "guis/GuiApplicationUpdater.h"
|
|
|
|
#include "ApplicationVersion.h"
|
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
|
#include "guis/GuiTextEditPopup.h"
|
|
#include "utils/PlatformUtil.h"
|
|
|
|
#include <SDL2/SDL_timer.h>
|
|
|
|
#include <filesystem>
|
|
|
|
GuiApplicationUpdater::GuiApplicationUpdater()
|
|
: mRenderer {Renderer::getInstance()}
|
|
, mBackground {":/graphics/frame.svg"}
|
|
, mGrid {glm::ivec2 {4, 11}}
|
|
, mDownloadPercentage {0}
|
|
, mLinuxAppImage {false}
|
|
, mAbortDownload {false}
|
|
, mDownloading {false}
|
|
, mReadyToInstall {false}
|
|
, mHasDownloaded {false}
|
|
, mInstalling {false}
|
|
, mHasInstalled {false}
|
|
{
|
|
addChild(&mBackground);
|
|
addChild(&mGrid);
|
|
|
|
LOG(LogInfo) << "Starting Application Updater";
|
|
|
|
mPackage = ApplicationUpdater::getInstance().getPackageInfo();
|
|
mLinuxAppImage =
|
|
(mPackage.name == "LinuxAppImage" || mPackage.name == "LinuxSteamDeckAppImage");
|
|
setDownloadPath();
|
|
|
|
// Set up grid.
|
|
mTitle = std::make_shared<TextComponent>("APPLICATION UPDATER", Font::get(FONT_SIZE_LARGE),
|
|
mMenuColorTitle, ALIGN_CENTER);
|
|
mGrid.setEntry(mTitle, glm::ivec2 {0, 0}, false, true, glm::ivec2 {4, 1},
|
|
GridFlags::BORDER_BOTTOM);
|
|
|
|
mStatusHeader = std::make_shared<TextComponent>(
|
|
"INSTALLATION STEPS:", Font::get(FONT_SIZE_MINI), mMenuColorPrimary, ALIGN_LEFT);
|
|
mGrid.setEntry(mStatusHeader, glm::ivec2 {1, 1}, false, true, glm::ivec2 {2, 1});
|
|
|
|
const std::string step1Text {mLinuxAppImage ? "DOWNLOAD NEW RELEASE" :
|
|
"DOWNLOAD NEW RELEASE TO THIS DIRECTORY:"};
|
|
mProcessStep1 = std::make_shared<TextComponent>(step1Text, Font::get(FONT_SIZE_MEDIUM),
|
|
mMenuColorPrimary, ALIGN_LEFT);
|
|
mGrid.setEntry(mProcessStep1, glm::ivec2 {1, 2}, false, true, glm::ivec2 {2, 1});
|
|
|
|
#if defined(_WIN64)
|
|
const std::string step2Text {
|
|
Utils::String::replace(Utils::FileSystem::getParent(mDownloadPackageFilename), "/", "\\")};
|
|
#else
|
|
const std::string step2Text {mLinuxAppImage ?
|
|
"INSTALL PACKAGE" :
|
|
Utils::FileSystem::getParent(mDownloadPackageFilename)};
|
|
#endif
|
|
mProcessStep2 = std::make_shared<TextComponent>(step2Text, Font::get(FONT_SIZE_MEDIUM),
|
|
mMenuColorPrimary, ALIGN_LEFT);
|
|
mGrid.setEntry(mProcessStep2, glm::ivec2 {1, 3}, false, true, glm::ivec2 {2, 1});
|
|
|
|
const std::string step3Text {mLinuxAppImage ? "QUIT AND MANUALLY RESTART ES-DE" :
|
|
"QUIT AND MANUALLY UPGRADE ES-DE"};
|
|
mProcessStep3 = std::make_shared<TextComponent>(step3Text, Font::get(FONT_SIZE_MEDIUM),
|
|
mMenuColorPrimary, ALIGN_LEFT);
|
|
mGrid.setEntry(mProcessStep3, glm::ivec2 {1, 4}, false, true, glm::ivec2 {2, 1});
|
|
|
|
mStatusMessageHeader = std::make_shared<TextComponent>(
|
|
"STATUS MESSAGE:", Font::get(FONT_SIZE_MINI), mMenuColorPrimary, ALIGN_LEFT);
|
|
mGrid.setEntry(mStatusMessageHeader, glm::ivec2 {1, 6}, false, true, glm::ivec2 {2, 1});
|
|
|
|
mStatusMessage = std::make_shared<TextComponent>("", Font::get(FONT_SIZE_SMALL),
|
|
mMenuColorPrimary, ALIGN_LEFT);
|
|
mGrid.setEntry(mStatusMessage, glm::ivec2 {1, 7}, false, true, glm::ivec2 {2, 1});
|
|
|
|
mChangelogMessage = std::make_shared<TextComponent>("", Font::get(FONT_SIZE_SMALL),
|
|
mMenuColorPrimary, ALIGN_LEFT);
|
|
mGrid.setEntry(mChangelogMessage, glm::ivec2 {1, 8}, false, true, glm::ivec2 {2, 1});
|
|
|
|
// Buttons.
|
|
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
|
|
|
mButton1 = std::make_shared<ButtonComponent>("DOWNLOAD", "download new release", [this]() {
|
|
if (!mDownloading) {
|
|
if (!mLinuxAppImage) {
|
|
if (!Utils::FileSystem::exists(
|
|
Utils::FileSystem::getParent(mDownloadPackageFilename))) {
|
|
mMessage = "Download directory does not exist";
|
|
return;
|
|
}
|
|
}
|
|
mMessage = "";
|
|
mStatusMessage->setText(mMessage);
|
|
mDownloadPercentage = 0;
|
|
mDownloading = true;
|
|
if (mThread) {
|
|
mThread->join();
|
|
mThread.reset();
|
|
}
|
|
mThread = std::make_unique<std::thread>(&GuiApplicationUpdater::downloadPackage, this);
|
|
}
|
|
});
|
|
|
|
buttons.push_back(mButton1);
|
|
|
|
if (!mLinuxAppImage) {
|
|
mButton2 = std::make_shared<ButtonComponent>(
|
|
"CHANGE DIRECTORY", "change download directory", [this]() {
|
|
if (mDownloading || mHasDownloaded)
|
|
return;
|
|
#if defined(_WIN64)
|
|
std::string currentDownloadDirectory {Utils::String::replace(
|
|
Utils::FileSystem::getParent(mDownloadPackageFilename), "/", "\\")};
|
|
#else
|
|
std::string currentDownloadDirectory {
|
|
Utils::FileSystem::getParent(mDownloadPackageFilename)};
|
|
#endif
|
|
auto directoryFunc = [this,
|
|
currentDownloadDirectory](std::string newDownloadDirectory) {
|
|
if (currentDownloadDirectory != newDownloadDirectory) {
|
|
newDownloadDirectory.erase(
|
|
// Remove trailing / and \ characters.
|
|
std::find_if(newDownloadDirectory.rbegin(), newDownloadDirectory.rend(),
|
|
[](char c) { return c != '/' && c != '\\'; })
|
|
.base(),
|
|
newDownloadDirectory.end());
|
|
#if defined(_WIN64)
|
|
newDownloadDirectory =
|
|
Utils::String::replace(newDownloadDirectory, "/", "\\");
|
|
#else
|
|
newDownloadDirectory = Utils::String::replace(newDownloadDirectory, "\\", "/");
|
|
#endif
|
|
Settings::getInstance()->setString(
|
|
"ApplicationUpdaterDownloadDirectory",
|
|
Utils::String::trim(newDownloadDirectory));
|
|
Settings::getInstance()->saveFile();
|
|
setDownloadPath();
|
|
#if defined(_WIN64)
|
|
mProcessStep2->setValue(Utils::String::replace(
|
|
Utils::FileSystem::getParent(mDownloadPackageFilename), "/", "\\"));
|
|
#else
|
|
mProcessStep2->setValue(
|
|
Utils::FileSystem::getParent(mDownloadPackageFilename));
|
|
#endif
|
|
}
|
|
};
|
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
|
getHelpStyle(), 0.0f, "ENTER DOWNLOAD DIRECTORY", currentDownloadDirectory,
|
|
directoryFunc, false));
|
|
}
|
|
else {
|
|
mWindow->pushGui(
|
|
new GuiTextEditPopup(getHelpStyle(), "ENTER DOWNLOAD DIRECTORY",
|
|
currentDownloadDirectory, directoryFunc, false));
|
|
}
|
|
});
|
|
buttons.push_back(mButton2);
|
|
}
|
|
|
|
mButton3 = std::make_shared<ButtonComponent>("CANCEL", "cancel", [this]() {
|
|
mAbortDownload = true;
|
|
if (mThread) {
|
|
mThread->join();
|
|
mThread.reset();
|
|
}
|
|
if (mDownloading) {
|
|
mWindow->pushGui(
|
|
new GuiMsgBox(getHelpStyle(), "DOWNLOAD ABORTED\nNO PACKAGE SAVED TO DISK", "OK",
|
|
nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
|
(mRenderer->getIsVerticalOrientation() ?
|
|
0.70f :
|
|
0.45f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
|
}
|
|
else if (mHasDownloaded || mReadyToInstall) {
|
|
mWindow->pushGui(new GuiMsgBox(
|
|
getHelpStyle(), "PACKAGE WAS DOWNLOADED AND\nCAN BE MANUALLY INSTALLED", "OK",
|
|
nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
|
(mRenderer->getIsVerticalOrientation() ?
|
|
0.70f :
|
|
0.45f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
|
}
|
|
delete this;
|
|
});
|
|
|
|
buttons.push_back(mButton3);
|
|
|
|
mButtons = MenuComponent::makeButtonGrid(buttons);
|
|
mGrid.setEntry(mButtons, glm::ivec2 {0, 10}, true, false, glm::ivec2 {4, 1},
|
|
GridFlags::BORDER_TOP);
|
|
|
|
// Limit the width of the GUI on ultrawide monitors. The 1.778 aspect ratio value is
|
|
// the 16:9 reference.
|
|
const float aspectValue {1.778f / Renderer::getScreenAspectRatio()};
|
|
const float width {glm::clamp(0.70f * aspectValue, 0.55f,
|
|
(mRenderer->getIsVerticalOrientation() ? 0.95f : 0.85f)) *
|
|
mRenderer->getScreenWidth()};
|
|
setSize(width,
|
|
mTitle->getSize().y +
|
|
(FONT_SIZE_MEDIUM * 1.5f * (mRenderer->getIsVerticalOrientation() ? 8.0f : 7.0f)) +
|
|
mButtons->getSize().y);
|
|
|
|
setPosition((mRenderer->getScreenWidth() - mSize.x) / 2.0f,
|
|
(mRenderer->getScreenHeight() - mSize.y) / 2.0f);
|
|
|
|
setPosition((mRenderer->getScreenWidth() - mSize.x) / 2.0f,
|
|
std::round(mRenderer->getScreenHeight() * 0.13f));
|
|
|
|
mBusyAnim.setSize(mSize);
|
|
mBusyAnim.setText("DOWNLOADING 100%");
|
|
mBusyAnim.onSizeChanged();
|
|
}
|
|
|
|
GuiApplicationUpdater::~GuiApplicationUpdater()
|
|
{
|
|
mAbortDownload = true;
|
|
|
|
if (mThread)
|
|
mThread->join();
|
|
|
|
HttpReq::cleanupCurlMulti();
|
|
}
|
|
|
|
void GuiApplicationUpdater::setDownloadPath()
|
|
{
|
|
if (mLinuxAppImage) {
|
|
mDownloadPackageFilename = Utils::FileSystem::getParent(Utils::FileSystem::getEsBinary()) +
|
|
"/" + mPackage.filename + "_" + mPackage.version;
|
|
}
|
|
else {
|
|
#if defined(_WIN64)
|
|
const std::string downloadDirectory {Utils::String::replace(
|
|
Settings::getInstance()->getString("ApplicationUpdaterDownloadDirectory"), "\\", "/")};
|
|
#else
|
|
const std::string downloadDirectory {
|
|
Settings::getInstance()->getString("ApplicationUpdaterDownloadDirectory")};
|
|
#endif
|
|
if (downloadDirectory == "")
|
|
mDownloadPackageFilename = Utils::FileSystem::getSystemHomeDirectory() + "/Downloads/";
|
|
else
|
|
mDownloadPackageFilename = Utils::FileSystem::expandHomePath(downloadDirectory) + "/";
|
|
|
|
mDownloadPackageFilename = Utils::String::replace(mDownloadPackageFilename, "//", "/");
|
|
mDownloadPackageFilename.append(mPackage.filename);
|
|
}
|
|
}
|
|
|
|
bool GuiApplicationUpdater::downloadPackage()
|
|
{
|
|
mStatus = ASYNC_IN_PROGRESS;
|
|
mRequest = std::unique_ptr<HttpReq>(std::make_unique<HttpReq>(mPackage.url, false));
|
|
LOG(LogInfo) << "Downloading \"" << mPackage.filename << "\"...";
|
|
|
|
while (!mAbortDownload) {
|
|
// Add a small delay so we don't eat all CPU cycles checking for status updates.
|
|
SDL_Delay(5);
|
|
HttpReq::Status reqStatus {mRequest->status()};
|
|
if (reqStatus == HttpReq::REQ_SUCCESS) {
|
|
mStatus = ASYNC_DONE;
|
|
break;
|
|
}
|
|
else if (reqStatus != HttpReq::REQ_IN_PROGRESS) {
|
|
std::string errorMessage {"Network error (status: "};
|
|
errorMessage.append(std::to_string(reqStatus))
|
|
.append(") - ")
|
|
.append(mRequest->getErrorMsg());
|
|
mRequest.reset();
|
|
std::unique_lock<std::mutex> lock {mMutex};
|
|
mMessage = errorMessage;
|
|
return true;
|
|
}
|
|
else {
|
|
// Download progress as reported by curl.
|
|
const float downloadedBytes {static_cast<float>(mRequest->getDownloadedBytes())};
|
|
const float totalBytes {static_cast<float>(mRequest->getTotalBytes())};
|
|
if (downloadedBytes != 0.0f && totalBytes != 0.0f)
|
|
mDownloadPercentage =
|
|
static_cast<int>(std::round((downloadedBytes / totalBytes) * 100.0f));
|
|
}
|
|
}
|
|
|
|
if (mAbortDownload) {
|
|
if (mAbortDownload) {
|
|
LOG(LogInfo) << "Aborted package download";
|
|
}
|
|
mRequest.reset();
|
|
return false;
|
|
}
|
|
|
|
std::string fileContents {mRequest->getContent()};
|
|
mRequest.reset();
|
|
|
|
if (Utils::Math::md5Hash(fileContents, false) != mPackage.md5) {
|
|
const std::string errorMessage {"Downloaded file does not match expected MD5 checksum"};
|
|
LOG(LogError) << errorMessage;
|
|
std::unique_lock<std::mutex> lock {mMutex};
|
|
mMessage = "Error: " + errorMessage;
|
|
return true;
|
|
}
|
|
|
|
if (mLinuxAppImage) {
|
|
LOG(LogDebug)
|
|
<< "GuiApplicationUpdater::downloadPackage(): Package downloaded, writing it to \""
|
|
<< mDownloadPackageFilename << "\"";
|
|
|
|
if (Utils::FileSystem::isRegularFile(mDownloadPackageFilename)) {
|
|
LOG(LogInfo) << "Temporary package file already exists, deleting it";
|
|
Utils::FileSystem::removeFile(mDownloadPackageFilename);
|
|
if (Utils::FileSystem::exists(mDownloadPackageFilename)) {
|
|
const std::string errorMessage {
|
|
"Couldn't delete temporary package file, permission problems?"};
|
|
LOG(LogError) << errorMessage;
|
|
std::unique_lock<std::mutex> lock {mMutex};
|
|
mMessage = "Error: " + errorMessage;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::ofstream writeFile;
|
|
writeFile.open(mDownloadPackageFilename.c_str(), std::ofstream::binary);
|
|
|
|
if (writeFile.fail()) {
|
|
LOG(LogError) << "Couldn't write package file \"" << mDownloadPackageFilename
|
|
<< "\", permission problems?";
|
|
std::unique_lock<std::mutex> lock {mMutex};
|
|
mMessage = "Error: Couldn't write package file, permission problems?";
|
|
return true;
|
|
}
|
|
|
|
writeFile.write(&fileContents[0], fileContents.length());
|
|
writeFile.close();
|
|
|
|
fileContents.clear();
|
|
|
|
if (mLinuxAppImage) {
|
|
std::filesystem::permissions(
|
|
mDownloadPackageFilename,
|
|
std::filesystem::perms::owner_all | std::filesystem::perms::group_all |
|
|
std::filesystem::perms::others_read | std::filesystem::perms::others_exec);
|
|
|
|
if (std::filesystem::status(mDownloadPackageFilename).permissions() !=
|
|
(std::filesystem::perms::owner_all | std::filesystem::perms::group_all |
|
|
std::filesystem::perms::others_read | std::filesystem::perms::others_exec)) {
|
|
Utils::FileSystem::removeFile(mDownloadPackageFilename);
|
|
const std::string errorMessage {"Couldn't set permissions on AppImage file"};
|
|
LOG(LogError) << errorMessage;
|
|
std::unique_lock<std::mutex> lock {mMutex};
|
|
mMessage = "Error: " + errorMessage;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
LOG(LogInfo) << "Successfully downloaded package file \"" << mDownloadPackageFilename << "\"";
|
|
|
|
std::unique_lock<std::mutex> lock {mMutex};
|
|
mMessage = "Downloaded " + Utils::FileSystem::getFileName(mDownloadPackageFilename);
|
|
|
|
mDownloading = false;
|
|
mReadyToInstall = true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GuiApplicationUpdater::installAppImage()
|
|
{
|
|
LOG(LogDebug) << "GuiApplicationUpdater::installAppImage(): Attempting to install new package";
|
|
|
|
mReadyToInstall = false;
|
|
mInstalling = true;
|
|
|
|
const std::string packageTargetFile {Utils::FileSystem::getEsBinary()};
|
|
|
|
if (packageTargetFile !=
|
|
Utils::FileSystem::getParent(Utils::FileSystem::getEsBinary()) + "/" + mPackage.filename) {
|
|
LOG(LogWarning) << "Running AppImage seems to have a non-standard filename: \""
|
|
<< packageTargetFile << "\"";
|
|
}
|
|
|
|
if (Utils::FileSystem::isSymlink(packageTargetFile)) {
|
|
LOG(LogInfo)
|
|
<< "Target file is a symbolic link, this will be followed and the actual symlink file "
|
|
<< "will not be touched ";
|
|
}
|
|
|
|
// Extra precaution, make sure that the file was actually correctly written to disk.
|
|
std::ifstream readFile;
|
|
readFile.open(mDownloadPackageFilename.c_str(), std::ofstream::binary);
|
|
|
|
if (readFile.fail()) {
|
|
const std::string errorMessage {"Couldn't open AppImage update file for reading"};
|
|
LOG(LogError) << errorMessage;
|
|
mMessage = "Error: " + errorMessage;
|
|
mHasDownloaded = false;
|
|
return true;
|
|
}
|
|
|
|
readFile.seekg(0, std::ios::end);
|
|
const long fileLength {static_cast<long>(readFile.tellg())};
|
|
readFile.seekg(0, std::ios::beg);
|
|
std::string fileData(fileLength, 0);
|
|
readFile.read(&fileData[0], fileLength);
|
|
readFile.close();
|
|
|
|
if (Utils::Math::md5Hash(fileData, false) != mPackage.md5) {
|
|
const std::string errorMessage {"Downloaded file does not match expected MD5 checksum"};
|
|
LOG(LogError) << errorMessage;
|
|
mMessage = "Error: " + errorMessage;
|
|
mHasDownloaded = false;
|
|
return true;
|
|
}
|
|
|
|
const std::string packageOldFile {packageTargetFile + "_" + PROGRAM_VERSION_STRING + ".OLD"};
|
|
|
|
if (Utils::FileSystem::renameFile(packageTargetFile, packageOldFile, true)) {
|
|
const std::string errorMessage {
|
|
"Couldn't rename running AppImage file, permission problems?"};
|
|
LOG(LogError) << errorMessage;
|
|
mMessage = "Error: " + errorMessage;
|
|
LOG(LogInfo) << "Attempting to rename \"" << packageOldFile
|
|
<< "\" back to running AppImage";
|
|
Utils::FileSystem::renameFile(packageOldFile, packageTargetFile, true);
|
|
mInstalling = false;
|
|
return true;
|
|
}
|
|
|
|
LOG(LogInfo) << "Renamed running AppImage to \"" << packageOldFile << "\"";
|
|
|
|
if (Utils::FileSystem::renameFile(mDownloadPackageFilename, packageTargetFile, true)) {
|
|
const std::string errorMessage {
|
|
"Couldn't replace running AppImage file, permission problems?"};
|
|
LOG(LogError) << errorMessage;
|
|
mMessage = "Error: " + errorMessage;
|
|
LOG(LogInfo) << "Attempting to rename \"" << packageOldFile
|
|
<< "\" back to running AppImage";
|
|
Utils::FileSystem::renameFile(packageOldFile, packageTargetFile, true);
|
|
mInstalling = false;
|
|
return true;
|
|
}
|
|
|
|
LOG(LogInfo) << "Package was successfully installed as \"" << packageTargetFile << "\"";
|
|
|
|
std::unique_lock<std::mutex> lock {mMutex};
|
|
mMessage = "Successfully installed as " + Utils::FileSystem::getFileName(packageTargetFile);
|
|
mHasInstalled = true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void GuiApplicationUpdater::update(int deltaTime)
|
|
{
|
|
{
|
|
std::unique_lock<std::mutex> lock {mMutex};
|
|
if (mMessage != "") {
|
|
mStatusMessage->setText(mMessage);
|
|
mDownloading = false;
|
|
}
|
|
}
|
|
|
|
if (mDownloading) {
|
|
mBusyAnim.setText("DOWNLOADING " + std::to_string(mDownloadPercentage) + "%");
|
|
mBusyAnim.update(deltaTime);
|
|
}
|
|
else if (mLinuxAppImage && mReadyToInstall) {
|
|
mProcessStep1->setText(ViewController::TICKMARK_CHAR + " " + mProcessStep1->getValue());
|
|
mProcessStep1->setColor(mMenuColorGreen);
|
|
mButton1->setText("INSTALL", "install package", true, false);
|
|
mButton1->setPressedFunc([this] {
|
|
if (!mInstalling) {
|
|
mMessage = "";
|
|
mStatusMessage->setText(mMessage);
|
|
installAppImage();
|
|
}
|
|
});
|
|
mReadyToInstall = false;
|
|
mHasDownloaded = true;
|
|
}
|
|
else if ((mLinuxAppImage && mHasInstalled) || (!mLinuxAppImage && mReadyToInstall)) {
|
|
if (mLinuxAppImage) {
|
|
mProcessStep2->setText(ViewController::TICKMARK_CHAR + " " + mProcessStep2->getValue());
|
|
mProcessStep2->setColor(mMenuColorGreen);
|
|
}
|
|
else {
|
|
mProcessStep1->setText(ViewController::TICKMARK_CHAR + " " + mProcessStep1->getValue());
|
|
mProcessStep1->setColor(mMenuColorGreen);
|
|
}
|
|
mChangelogMessage->setText("Find the detailed changelog at https://es-de.org");
|
|
mGrid.removeEntry(mButtons);
|
|
mGrid.setEntry(MenuComponent::makeButtonGrid(std::vector<std::shared_ptr<ButtonComponent>> {
|
|
std::make_shared<ButtonComponent>("QUIT", "quit application",
|
|
[this]() {
|
|
delete this;
|
|
Utils::Platform::quitES();
|
|
})}),
|
|
glm::ivec2 {0, 10}, true, false, glm::ivec2 {4, 1}, GridFlags::BORDER_TOP);
|
|
mGrid.moveCursorTo(0, 10);
|
|
mReadyToInstall = false;
|
|
mHasInstalled = false;
|
|
mHasDownloaded = true;
|
|
}
|
|
}
|
|
|
|
void GuiApplicationUpdater::render(const glm::mat4& parentTrans)
|
|
{
|
|
glm::mat4 trans {parentTrans * getTransform()};
|
|
|
|
renderChildren(trans);
|
|
|
|
if (mDownloading)
|
|
mBusyAnim.render(trans);
|
|
}
|
|
|
|
void GuiApplicationUpdater::onSizeChanged()
|
|
{
|
|
const float screenSize {mRenderer->getIsVerticalOrientation() ? mRenderer->getScreenWidth() :
|
|
mRenderer->getScreenHeight()};
|
|
mGrid.setRowHeightPerc(0, (mTitle->getFont()->getLetterHeight() + screenSize * 0.2f) / mSize.y /
|
|
2.0f);
|
|
mGrid.setRowHeightPerc(1, (mStatusHeader->getFont()->getLetterHeight() + screenSize * 0.2f) /
|
|
mSize.y / 4.0f);
|
|
mGrid.setRowHeightPerc(2, (mProcessStep1->getFont()->getLetterHeight() + screenSize * 0.2f) /
|
|
mSize.y / 4.0f);
|
|
mGrid.setRowHeightPerc(3, (mProcessStep2->getFont()->getLetterHeight() + screenSize * 0.2f) /
|
|
mSize.y / 4.0f);
|
|
mGrid.setRowHeightPerc(4, (mProcessStep3->getFont()->getLetterHeight() + screenSize * 0.2f) /
|
|
mSize.y / 4.0f);
|
|
mGrid.setRowHeightPerc(
|
|
5,
|
|
(mStatusMessageHeader->getFont()->getLetterHeight() + screenSize * 0.2f) / mSize.y / 4.0f);
|
|
mGrid.setRowHeightPerc(
|
|
6,
|
|
(mStatusMessageHeader->getFont()->getLetterHeight() + screenSize * 0.2f) / mSize.y / 4.0f);
|
|
mGrid.setRowHeightPerc(7, (mStatusMessage->getFont()->getLetterHeight() + screenSize * 0.15f) /
|
|
mSize.y / 4.0f);
|
|
mGrid.setRowHeightPerc(
|
|
8, (mChangelogMessage->getFont()->getLetterHeight() + screenSize * 0.15f) / mSize.y / 4.0f);
|
|
mGrid.setRowHeightPerc(10, mButtons->getSize().y / mSize.y);
|
|
|
|
mGrid.setColWidthPerc(0, 0.01f);
|
|
mGrid.setColWidthPerc(3, 0.01f);
|
|
|
|
mGrid.setSize(mSize);
|
|
mBackground.fitTo(mSize);
|
|
}
|
|
|
|
std::vector<HelpPrompt> GuiApplicationUpdater::getHelpPrompts()
|
|
{
|
|
std::vector<HelpPrompt> prompts {mGrid.getHelpPrompts()};
|
|
return prompts;
|
|
}
|