2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-07-06 16:05:53 +00:00

Additional usability features

This commit is contained in:
Jack Andersen 2018-01-09 20:19:48 -10:00
parent 00da24a134
commit f6195a64a6
22 changed files with 834 additions and 176 deletions

3
hecl-gui/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "quazip"]
path = quazip
url = https://github.com/mnafees/quazip.git

View File

@ -26,18 +26,31 @@ add_subdirectory(platforms/freedesktop)
declare_qticon_target() declare_qticon_target()
list(APPEND PLAT_SRCS mainicon_qt.cpp) list(APPEND PLAT_SRCS mainicon_qt.cpp)
file(GLOB QUAZIP_SRCS quazip/quazip/*.c quazip/quazip/*.cpp quazip/quazip/*.h)
list(REMOVE_ITEM QUAZIP_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/quazip/quazip/quagzipfile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/quazip/quazip/quagzipfile.h)
include_directories(quazip/quazip)
add_definitions(-DQUAZIP_STATIC=1)
add_executable(hecl-gui WIN32 MACOSX_BUNDLE add_executable(hecl-gui WIN32 MACOSX_BUNDLE
MainWindow.ui MainWindow.hpp MainWindow.cpp MainWindow.ui MainWindow.hpp MainWindow.cpp
LaunchMenu.hpp LaunchMenu.cpp
EscapeSequenceParser.hpp EscapeSequenceParser.cpp EscapeSequenceParser.hpp EscapeSequenceParser.cpp
FileDirDialog.hpp ErrorLabel.hpp FileDirDialog.hpp ErrorLabel.hpp
SysReqTableView.hpp SysReqTableView.cpp SysReqTableView.hpp SysReqTableView.cpp
VectorISATableView.hpp VectorISATableView.cpp VectorISATableView.hpp VectorISATableView.cpp
VectorISATableModel.hpp VectorISATableModelIntel.hpp VectorISATableModel.hpp VectorISATableModelIntel.hpp
FindBlender.hpp FindBlender.cpp
DownloadManager.hpp DownloadManager.cpp DownloadManager.hpp DownloadManager.cpp
ExtractZip.hpp ExtractZip.cpp ${QUAZIP_SRCS}
Common.hpp Common.cpp ${PLAT_SRCS} main.cpp) Common.hpp Common.cpp ${PLAT_SRCS} main.cpp)
set_target_properties(hecl-gui PROPERTIES set_target_properties(hecl-gui PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/platforms/mac/Info.plist") MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/platforms/mac/Info.plist")
target_link_libraries(hecl-gui ${PLAT_LIBS} target_link_libraries(hecl-gui ${PLAT_LIBS}
${Qt5Widgets_LIBRARIES} ${Qt5Network_LIBRARIES} ${Qt5Xml_LIBRARIES} zeus) ${Qt5Widgets_LIBRARIES}
${Qt5Network_LIBRARIES}
${Qt5Xml_LIBRARIES}
hecl-light logvisor zeus athena-core athena-libyaml xxhash z)

View File

@ -135,12 +135,16 @@ QString URDEVersion::fileString(bool withExtension) const
VectorISAToString(m_vectorISA)); VectorISAToString(m_vectorISA));
} }
#ifndef _WIN32
static void HUPHandler(int) {} static void HUPHandler(int) {}
#endif
void InitializePlatform() void InitializePlatform()
{ {
#ifndef _WIN32
/* This can happen when terminating hecl - do nothing */ /* This can happen when terminating hecl - do nothing */
signal(SIGHUP, HUPHandler); signal(SIGHUP, HUPHandler);
#endif
#if ZEUS_ARCH_X86_64 #if ZEUS_ARCH_X86_64
const_cast<Architecture&>(CurArchitecture) = Architecture::X86_64; const_cast<Architecture&>(CurArchitecture) = Architecture::X86_64;

View File

@ -1,5 +1,7 @@
#include "DownloadManager.hpp" #include "DownloadManager.hpp"
#include "Common.hpp" #include "Common.hpp"
#include <QBuffer>
#include <quazip.h>
static const char AxioDLPublicKeyPEM[] = static const char AxioDLPublicKeyPEM[] =
"-----BEGIN PUBLIC KEY-----\n" "-----BEGIN PUBLIC KEY-----\n"
@ -119,19 +121,19 @@ void DownloadManager::binaryFinished()
if (m_progBar) if (m_progBar)
m_progBar->setValue(100); m_progBar->setValue(100);
QFile fp(m_outPath); QByteArray all = m_binaryInProgress->readAll();
if (!fp.open(QIODevice::WriteOnly)) QBuffer buff(&all);
QuaZip zip(&buff);
if (!zip.open(QuaZip::mdUnzip))
{ {
setError(QNetworkReply::ContentAccessDenied, fp.errorString()); setError(QNetworkReply::UnknownContentError, "Unable to open zip archive.");
m_binaryInProgress->deleteLater(); m_binaryInProgress->deleteLater();
m_binaryInProgress = nullptr; m_binaryInProgress = nullptr;
return; return;
} }
fp.write(m_binaryInProgress->readAll());
fp.close();
if (m_completionHandler) if (m_completionHandler)
m_completionHandler(m_outPath); m_completionHandler(zip);
m_binaryInProgress->deleteLater(); m_binaryInProgress->deleteLater();
m_binaryInProgress = nullptr; m_binaryInProgress = nullptr;
@ -147,7 +149,7 @@ void DownloadManager::binaryError(QNetworkReply::NetworkError error)
m_progBar->setEnabled(false); m_progBar->setEnabled(false);
if (m_failedHandler) if (m_failedHandler)
m_failedHandler(m_outPath); m_failedHandler();
} }
void DownloadManager::binaryValidateCert() void DownloadManager::binaryValidateCert()

View File

@ -7,6 +7,8 @@
#include <QProgressBar> #include <QProgressBar>
#include <QLabel> #include <QLabel>
class QuaZip;
class DownloadManager : public QObject class DownloadManager : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -18,8 +20,8 @@ class DownloadManager : public QObject
QProgressBar* m_progBar = nullptr; QProgressBar* m_progBar = nullptr;
QLabel* m_errorLabel = nullptr; QLabel* m_errorLabel = nullptr;
std::function<void(const QStringList& index)> m_indexCompletionHandler; std::function<void(const QStringList& index)> m_indexCompletionHandler;
std::function<void(const QString& file)> m_completionHandler; std::function<void(QuaZip& file)> m_completionHandler;
std::function<void(const QString& file)> m_failedHandler; std::function<void()> m_failedHandler;
void resetError() void resetError()
{ {
@ -44,8 +46,8 @@ public:
: QObject(parent), m_netManager(this) {} : QObject(parent), m_netManager(this) {}
void connectWidgets(QProgressBar* progBar, QLabel* errorLabel, void connectWidgets(QProgressBar* progBar, QLabel* errorLabel,
std::function<void(const QStringList& index)>&& indexCompletionHandler, std::function<void(const QStringList& index)>&& indexCompletionHandler,
std::function<void(const QString& file)>&& completionHandler, std::function<void(QuaZip& file)>&& completionHandler,
std::function<void(const QString& file)>&& failedHandler) std::function<void()>&& failedHandler)
{ {
m_progBar = progBar; m_progBar = progBar;
m_errorLabel = errorLabel; m_errorLabel = errorLabel;

View File

@ -514,3 +514,85 @@ void ParseEscapeSequence(int attribute, QListIterator<QString>& i, QTextCharForm
} }
} }
} }
void ReturnInsert(QTextCursor& cur, const QString& text)
{
auto DoLine = [&](const QString& line)
{
auto DoReturn = [&](const QString& ret)
{
if (!ret.isEmpty())
{
cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, ret.size());
cur.insertText(ret);
}
};
QStringList list = line.split('\r');
DoReturn(list.front());
if (list.size() > 1)
{
for (auto it = list.begin() + 1; it != list.end(); ++it)
{
cur.movePosition(QTextCursor::StartOfBlock);
DoReturn(*it);
}
}
};
#if _WIN32
QStringList lineSplit = text.split("\r\n");
#else
QStringList lineSplit = text.split('\n');
#endif
DoLine(lineSplit.front());
if (lineSplit.size() > 1)
{
for (auto it = lineSplit.begin() + 1; it != lineSplit.end(); ++it)
{
cur.movePosition(QTextCursor::EndOfLine);
cur.insertBlock();
DoLine(*it);
}
}
}
void ReturnInsert(QTextCursor& cur, const QString& text, const QTextCharFormat& format)
{
auto DoLine = [&](const QString& line)
{
auto DoReturn = [&](const QString& ret)
{
if (!ret.isEmpty())
{
cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, ret.size());
cur.insertText(ret, format);
}
};
QStringList list = line.split('\r');
DoReturn(list.front());
if (list.size() > 1)
{
for (auto it = list.begin() + 1; it != list.end(); ++it)
{
cur.movePosition(QTextCursor::StartOfBlock);
DoReturn(*it);
}
}
};
#if _WIN32
QStringList lineSplit = text.split("\r\n");
#else
QStringList lineSplit = text.split('\n');
#endif
DoLine(lineSplit.front());
if (lineSplit.size() > 1)
{
for (auto it = lineSplit.begin() + 1; it != lineSplit.end(); ++it)
{
cur.movePosition(QTextCursor::EndOfLine);
cur.insertBlock();
DoLine(*it);
}
}
}

View File

@ -3,8 +3,13 @@
#include <QString> #include <QString>
#include <QTextCharFormat> #include <QTextCharFormat>
#include <QTextCursor>
void ParseEscapeSequence(int attribute, QListIterator<QString>& i, QTextCharFormat& textCharFormat, void ParseEscapeSequence(int attribute, QListIterator<QString>& i, QTextCharFormat& textCharFormat,
const QTextCharFormat& defaultTextCharFormat); const QTextCharFormat& defaultTextCharFormat);
void ReturnInsert(QTextCursor& cur, const QString& text);
void ReturnInsert(QTextCursor& cur, const QString& text, const QTextCharFormat& format);
#endif // GUI_ESCAPESEQUENCEPARSER_HPP #endif // GUI_ESCAPESEQUENCEPARSER_HPP

141
hecl-gui/ExtractZip.cpp Normal file
View File

@ -0,0 +1,141 @@
#include "ExtractZip.hpp"
#include <QDir>
#include <quazip.h>
#include <quazipfile.h>
/**
* Modified JICompress utilities to operate on in-memory zip.
* Only contains directory extraction functionality.
*/
static bool copyData(QIODevice &inFile, QIODevice &outFile)
{
while (!inFile.atEnd()) {
char buf[4096];
qint64 readLen = inFile.read(buf, 4096);
if (readLen <= 0)
return false;
if (outFile.write(buf, readLen) != readLen)
return false;
}
return true;
}
QStringList ExtractZip::getFileList(QuaZip& zip)
{
// Estraggo i nomi dei file
QStringList lst;
QuaZipFileInfo64 info;
for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
if(!zip.getCurrentFileInfo(&info))
return {};
lst << info.name;
//info.name.toLocal8Bit().constData()
}
return lst;
}
/**OK
* Estrae il file fileName, contenuto nell'oggetto zip, con il nome fileDest.
* Se la funzione fallisce restituisce false e cancella il file che si e tentato di estrarre.
*
* La funzione fallisce se:
* * zip==NULL;
* * l'oggetto zip e stato aperto in una modalita non compatibile con l'estrazione di file;
* * non e possibile aprire il file all'interno dell'oggetto zip;
* * non e possibile creare il file estratto;
* * si e rilevato un errore nella copia dei dati (1);
* * non e stato possibile chiudere il file all'interno dell'oggetto zip (1);
*
* (1): prima di uscire dalla funzione cancella il file estratto.
*/
bool ExtractZip::extractFile(QuaZip& zip, QString fileName, QString fileDest)
{
// zip: oggetto dove aggiungere il file
// filename: nome del file reale
// fileincompress: nome del file all'interno del file compresso
// Controllo l'apertura dello zip
if (zip.getMode()!=QuaZip::mdUnzip) return false;
// Apro il file compresso
if (!fileName.isEmpty())
zip.setCurrentFile(fileName);
QuaZipFile inFile(&zip);
if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false;
// Controllo esistenza cartella file risultato
QDir curDir;
if (fileDest.endsWith('/')) {
if (!curDir.mkpath(fileDest)) {
return false;
}
} else {
if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) {
return false;
}
}
QuaZipFileInfo64 info;
if (!zip.getCurrentFileInfo(&info))
return false;
QFile::Permissions srcPerm = info.getPermissions();
if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir()) {
if (srcPerm != 0) {
QFile(fileDest).setPermissions(srcPerm);
}
return true;
}
// Apro il file risultato
QFile outFile;
outFile.setFileName(fileDest);
if(!outFile.open(QIODevice::WriteOnly)) return false;
// Copio i dati
if (!copyData(inFile, outFile) || inFile.getZipError()!=UNZ_OK) {
outFile.close();
return false;
}
outFile.close();
// Chiudo i file
inFile.close();
if (inFile.getZipError()!=UNZ_OK) {
return false;
}
if (srcPerm != 0) {
outFile.setPermissions(srcPerm);
}
return true;
}
/**OK
* Estrae il file fileCompressed nella cartella dir.
* Se dir = "" allora il file viene estratto nella cartella corrente.
* Se la funzione fallisce cancella i file che si e tentato di estrarre.
* Restituisce i nomi assoluti dei file estratti.
*
* La funzione fallisce se:
* * non si riesce ad aprire l'oggetto zip;
* * la compressione di un file fallisce;
* * non si riesce a chiudere l'oggetto zip;
*/
bool ExtractZip::extractDir(QuaZip& zip, QString dir)
{
QDir directory(dir);
if (!zip.goToFirstFile()) {
return false;
}
do {
QString name = zip.getCurrentFileName();
QString absFilePath = directory.absoluteFilePath(name);
if (!extractFile(zip, "", absFilePath))
return false;
} while (zip.goToNextFile());
return true;
}

16
hecl-gui/ExtractZip.hpp Normal file
View File

@ -0,0 +1,16 @@
#ifndef GUI_EXTRACTZIP_HPP
#define GUI_EXTRACTZIP_HPP
class QStringList;
class QuaZip;
class QString;
class ExtractZip
{
public:
static QStringList getFileList(QuaZip& zip);
static bool extractFile(QuaZip& zip, QString fileName, QString fileDest);
static bool extractDir(QuaZip& zip, QString dir);
};
#endif GUI_EXTRACTZIP_HPP

123
hecl-gui/FindBlender.cpp Normal file
View File

@ -0,0 +1,123 @@
#include "FindBlender.hpp"
#include "hecl/SteamFinder.hpp"
#include "hecl/hecl.hpp"
namespace hecl::blender
{
#ifdef __APPLE__
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
#else
#define DEFAULT_BLENDER_BIN "blender"
#endif
static const std::regex regBlenderVersion(R"(Blender ([0-9]+).([0-9]+) )",
std::regex::ECMAScript|std::regex::optimize);
static bool RegFileExists(const hecl::SystemChar* path)
{
if (!path)
return false;
hecl::Sstat theStat;
return !hecl::Stat(path, &theStat) && S_ISREG(theStat.st_mode);
}
hecl::SystemString FindBlender(int& major, int& minor)
{
major = 0;
minor = 0;
/* User-specified blender path */
#if _WIN32
wchar_t BLENDER_BIN_BUF[2048];
const wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN");
#else
const char* blenderBin = getenv("BLENDER_BIN");
#endif
/* Steam blender */
hecl::SystemString steamBlender;
/* Child process of blender */
#if _WIN32
if (!blenderBin || !RegFileExists(blenderBin))
{
/* Environment not set; try steam */
steamBlender = hecl::FindCommonSteamApp(_S("Blender"));
if (steamBlender.size())
{
steamBlender += _S("\\blender.exe");
blenderBin = steamBlender.c_str();
}
if (!RegFileExists(blenderBin))
{
/* No steam; try default */
wchar_t progFiles[256];
if (GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256))
{
_snwprintf(BLENDER_BIN_BUF, 2048, L"%s\\Blender Foundation\\Blender\\blender.exe", progFiles);
blenderBin = BLENDER_BIN_BUF;
if (!RegFileExists(blenderBin))
blenderBin = nullptr;
}
else
blenderBin = nullptr;
}
}
#else
if (!RegFileExists(blenderBin))
{
/* Try steam */
steamBlender = hecl::FindCommonSteamApp(_S("Blender"));
if (steamBlender.size())
{
#ifdef __APPLE__
steamBlender += "/blender.app/Contents/MacOS/blender";
#else
steamBlender += "/blender";
#endif
blenderBin = steamBlender.c_str();
if (!RegFileExists(blenderBin))
{
blenderBin = DEFAULT_BLENDER_BIN;
if (!RegFileExists(blenderBin))
{
blenderBin = nullptr;
}
}
}
}
#endif
if (!blenderBin)
return {};
hecl::SystemString command = hecl::SystemString(_S("\"")) + blenderBin + _S("\" --version");
#if _WIN32
FILE* fp = _wpopen(command.c_str(), _S("r"));
#else
FILE* fp = popen(command.c_str(), "r");
#endif
char versionBuf[256];
size_t rdSize = fread(versionBuf, 1, 255, fp);
versionBuf[rdSize] = '\0';
#if _WIN32
_pclose(fp);
#else
pclose(fp);
#endif
std::cmatch match;
if (std::regex_search(versionBuf, match, regBlenderVersion))
{
major = atoi(match[1].str().c_str());
minor = atoi(match[2].str().c_str());
return blenderBin;
}
return blenderBin;
}
}

13
hecl-gui/FindBlender.hpp Normal file
View File

@ -0,0 +1,13 @@
#ifndef FINDBLENDER_HPP
#define FINDBLENDER_HPP
#include "hecl/hecl.hpp"
namespace hecl::blender
{
hecl::SystemString FindBlender(int& major, int& minor);
}
#endif // FINDBLENDER_HPP

89
hecl-gui/LaunchMenu.cpp Normal file
View File

@ -0,0 +1,89 @@
#include "LaunchMenu.hpp"
#include "hecl/CVarCommons.hpp"
LaunchMenu::LaunchMenu(hecl::CVarCommons& commons, QWidget* parent)
: QMenu("Launch Menu", parent),
m_commons(commons),
m_apiMenu("Graphics API", this),
m_msaaMenu("Anti-Aliasing", this),
m_anisoMenu("Anisotropic Filtering", this),
m_apiGroup(this),
m_msaaGroup(this),
m_anisoGroup(this)
{
#ifdef _WIN32
initApiAction(QStringLiteral("D3D11"));
initApiAction(QStringLiteral("Vulkan"));
initApiAction(QStringLiteral("OpenGL"));
#elif defined(__APPLE__)
initApiAction(QStringLiteral("Metal"));
initApiAction(QStringLiteral("OpenGL"));
#else
initApiAction(QStringLiteral("OpenGL"));
initApiAction(QStringLiteral("Vulkan"));
#endif
initMsaaAction(QStringLiteral("1"));
initMsaaAction(QStringLiteral("2"));
initMsaaAction(QStringLiteral("4"));
initMsaaAction(QStringLiteral("8"));
initMsaaAction(QStringLiteral("16"));
initAnisoAction(QStringLiteral("1"));
initAnisoAction(QStringLiteral("2"));
initAnisoAction(QStringLiteral("4"));
initAnisoAction(QStringLiteral("8"));
initAnisoAction(QStringLiteral("16"));
m_apiMenu.addActions(m_apiGroup.actions());
m_msaaMenu.addActions(m_msaaGroup.actions());
m_anisoMenu.addActions(m_anisoGroup.actions());
addMenu(&m_apiMenu);
addMenu(&m_msaaMenu);
addMenu(&m_anisoMenu);
}
void LaunchMenu::initApiAction(const QString& action)
{
QAction* act = m_apiGroup.addAction(action);
connect(act, SIGNAL(triggered()), this, SLOT(apiTriggered()));
act->setCheckable(true);
if (!action.compare(QString::fromStdString(m_commons.getGraphicsApi()), Qt::CaseInsensitive))
act->setChecked(true);
}
void LaunchMenu::initMsaaAction(const QString& action)
{
QAction* act = m_msaaGroup.addAction(action);
connect(act, SIGNAL(triggered()), this, SLOT(msaaTriggered()));
act->setCheckable(true);
if (!action.compare(QString::number(m_commons.getSamples()), Qt::CaseInsensitive))
act->setChecked(true);
}
void LaunchMenu::initAnisoAction(const QString& action)
{
QAction* act = m_anisoGroup.addAction(action);
connect(act, SIGNAL(triggered()), this, SLOT(anisoTriggered()));
act->setCheckable(true);
if (!action.compare(QString::number(m_commons.getAnisotropy()), Qt::CaseInsensitive))
act->setChecked(true);
}
void LaunchMenu::apiTriggered()
{
m_commons.setGraphicsApi(qobject_cast<QAction*>(sender())->text().toStdString());
m_commons.serialize();
}
void LaunchMenu::msaaTriggered()
{
m_commons.setSamples(qobject_cast<QAction*>(sender())->text().toInt());
m_commons.serialize();
}
void LaunchMenu::anisoTriggered()
{
m_commons.setAnisotropy(qobject_cast<QAction*>(sender())->text().toInt());
m_commons.serialize();
}

33
hecl-gui/LaunchMenu.hpp Normal file
View File

@ -0,0 +1,33 @@
#ifndef GUI_LAUNCHMENU_HPP
#define GUI_LAUNCHMENU_HPP
#include <QMenu>
namespace hecl { class CVarCommons; }
class LaunchMenu : public QMenu
{
Q_OBJECT
hecl::CVarCommons& m_commons;
QMenu m_apiMenu;
QMenu m_msaaMenu;
QMenu m_anisoMenu;
QActionGroup m_apiGroup;
QActionGroup m_msaaGroup;
QActionGroup m_anisoGroup;
void initApiAction(const QString& action);
void initMsaaAction(const QString& action);
void initAnisoAction(const QString& action);
public:
LaunchMenu(hecl::CVarCommons& commons, QWidget* parent = Q_NULLPTR);
public slots:
void apiTriggered();
void msaaTriggered();
void anisoTriggered();
};
#endif // GUI_LAUNCHMENU_HPP

View File

@ -4,17 +4,68 @@
#include <QMessageBox> #include <QMessageBox>
#include "EscapeSequenceParser.hpp" #include "EscapeSequenceParser.hpp"
#include "FileDirDialog.hpp" #include "FileDirDialog.hpp"
#include "ExtractZip.hpp"
#if _WIN32 #if _WIN32
#include <Windows.h> #include <Windows.h>
#include <shellapi.h> #include <shellapi.h>
#include <TlHelp32.h>
static void KillProcessTree(QProcess& proc)
{
Q_PID pid = proc.pid();
if (!pid)
return;
DWORD myprocID = pid->dwProcessId;
PROCESSENTRY32 pe = {};
pe.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (::Process32First(hSnap, &pe))
{
BOOL bContinue = TRUE;
// kill child processes
while (bContinue)
{
// only kill child processes
if (pe.th32ParentProcessID == myprocID)
{
HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
if (hChildProc)
{
::TerminateProcess(hChildProc, 1);
::CloseHandle(hChildProc);
}
}
bContinue = ::Process32Next(hSnap, &pe);
}
}
proc.close();
proc.terminate();
}
#else
static void KillProcessTree(QProcess& proc)
{
proc.close();
proc.terminate();
}
#endif #endif
MainWindow::MainWindow(QWidget *parent) : MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent)
m_ui(new Ui::MainWindow) , m_fileMgr(_S("urde"))
, m_cvarManager(m_fileMgr)
, m_cvarCommons(m_cvarManager)
, m_ui(new Ui::MainWindow)
, m_heclProc(this) , m_heclProc(this)
, m_dlManager(this) , m_dlManager(this)
, m_launchMenu(m_cvarCommons, this)
, m_settings("AxioDL", "HECL", this) , m_settings("AxioDL", "HECL", this)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@ -41,7 +92,7 @@ MainWindow::MainWindow(QWidget *parent) :
m_dlManager.connectWidgets(m_ui->downloadProgressBar, m_ui->downloadErrorLabel, m_dlManager.connectWidgets(m_ui->downloadProgressBar, m_ui->downloadErrorLabel,
std::bind(&MainWindow::onIndexDownloaded, this, std::placeholders::_1), std::bind(&MainWindow::onIndexDownloaded, this, std::placeholders::_1),
std::bind(&MainWindow::onBinaryDownloaded, this, std::placeholders::_1), std::bind(&MainWindow::onBinaryDownloaded, this, std::placeholders::_1),
std::bind(&MainWindow::onBinaryFailed, this, std::placeholders::_1)); std::bind(&MainWindow::onBinaryFailed, this));
initSlots(); initSlots();
@ -52,8 +103,7 @@ MainWindow::MainWindow(QWidget *parent) :
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
m_heclProc.close(); KillProcessTree(m_heclProc);
m_heclProc.terminate();
delete m_ui; delete m_ui;
} }
@ -67,14 +117,17 @@ void MainWindow::onExtract()
return; return;
m_ui->processOutput->clear(); m_ui->processOutput->clear();
m_heclProc.close(); KillProcessTree(m_heclProc);
m_heclProc.terminate();
m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels); m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels);
m_heclProc.setWorkingDirectory(m_path); m_heclProc.setWorkingDirectory(m_path);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("TERM", "xterm-color"); env.insert("TERM", "xterm-color");
env.insert("ConEmuANSI", "ON");
m_heclProc.setProcessEnvironment(env); m_heclProc.setProcessEnvironment(env);
m_heclProc.start(m_heclPath, {"extract", "-y", "-o", m_path, imgPath}); disconnect(&m_heclProc, SIGNAL(finished(int)), nullptr, nullptr);
connect(&m_heclProc, SIGNAL(finished(int)), this, SLOT(onExtractFinished(int)));
m_heclProc.start(m_heclPath, {"extract", "-y", "-g", "-o", m_path, imgPath},
QIODevice::ReadOnly | QIODevice::Unbuffered);
m_ui->heclTabs->setCurrentIndex(0); m_ui->heclTabs->setCurrentIndex(0);
@ -83,13 +136,12 @@ void MainWindow::onExtract()
m_ui->extractBtn->setEnabled(true); m_ui->extractBtn->setEnabled(true);
disconnect(m_ui->extractBtn, SIGNAL(clicked()), nullptr, nullptr); disconnect(m_ui->extractBtn, SIGNAL(clicked()), nullptr, nullptr);
connect(m_ui->extractBtn, SIGNAL(clicked()), this, SLOT(doHECLTerminate())); connect(m_ui->extractBtn, SIGNAL(clicked()), this, SLOT(doHECLTerminate()));
disconnect(&m_heclProc, SIGNAL(finished(int)), nullptr, nullptr);
connect(&m_heclProc, SIGNAL(finished(int)), this, SLOT(onExtractFinished(int)));
} }
void MainWindow::onExtractFinished(int returnCode) void MainWindow::onExtractFinished(int returnCode)
{ {
m_cursor.movePosition(QTextCursor::End);
m_cursor.insertBlock();
disconnect(m_ui->extractBtn, SIGNAL(clicked()), nullptr, nullptr); disconnect(m_ui->extractBtn, SIGNAL(clicked()), nullptr, nullptr);
connect(m_ui->extractBtn, SIGNAL(clicked()), this, SLOT(onExtract())); connect(m_ui->extractBtn, SIGNAL(clicked()), this, SLOT(onExtract()));
checkDownloadedBinary(); checkDownloadedBinary();
@ -100,14 +152,17 @@ void MainWindow::onPackage()
if (m_path.isEmpty()) if (m_path.isEmpty())
return; return;
m_ui->processOutput->clear(); m_ui->processOutput->clear();
m_heclProc.close(); KillProcessTree(m_heclProc);
m_heclProc.terminate();
m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels); m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels);
m_heclProc.setWorkingDirectory(m_path); m_heclProc.setWorkingDirectory(m_path);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("TERM", "xterm-color"); env.insert("TERM", "xterm-color");
env.insert("ConEmuANSI", "ON");
m_heclProc.setProcessEnvironment(env); m_heclProc.setProcessEnvironment(env);
m_heclProc.start(m_heclPath, {"package", "-y"}); disconnect(&m_heclProc, SIGNAL(finished(int)), nullptr, nullptr);
connect(&m_heclProc, SIGNAL(finished(int)), this, SLOT(onPackageFinished(int)));
m_heclProc.start(m_heclPath, {"package", "-y", "-g"},
QIODevice::ReadOnly | QIODevice::Unbuffered);
m_ui->heclTabs->setCurrentIndex(0); m_ui->heclTabs->setCurrentIndex(0);
@ -116,13 +171,12 @@ void MainWindow::onPackage()
m_ui->packageBtn->setEnabled(true); m_ui->packageBtn->setEnabled(true);
disconnect(m_ui->packageBtn, SIGNAL(clicked()), nullptr, nullptr); disconnect(m_ui->packageBtn, SIGNAL(clicked()), nullptr, nullptr);
connect(m_ui->packageBtn, SIGNAL(clicked()), this, SLOT(doHECLTerminate())); connect(m_ui->packageBtn, SIGNAL(clicked()), this, SLOT(doHECLTerminate()));
disconnect(&m_heclProc, SIGNAL(finished(int)), nullptr, nullptr);
connect(&m_heclProc, SIGNAL(finished(int)), this, SLOT(onPackageFinished(int)));
} }
void MainWindow::onPackageFinished(int returnCode) void MainWindow::onPackageFinished(int returnCode)
{ {
m_cursor.movePosition(QTextCursor::End);
m_cursor.insertBlock();
disconnect(m_ui->packageBtn, SIGNAL(clicked()), nullptr, nullptr); disconnect(m_ui->packageBtn, SIGNAL(clicked()), nullptr, nullptr);
connect(m_ui->packageBtn, SIGNAL(clicked()), this, SLOT(onPackage())); connect(m_ui->packageBtn, SIGNAL(clicked()), this, SLOT(onPackage()));
checkDownloadedBinary(); checkDownloadedBinary();
@ -133,33 +187,33 @@ void MainWindow::onLaunch()
if (m_path.isEmpty()) if (m_path.isEmpty())
return; return;
m_ui->processOutput->clear(); m_ui->processOutput->clear();
m_heclProc.close(); KillProcessTree(m_heclProc);
m_heclProc.terminate();
m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels); m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels);
m_heclProc.setWorkingDirectory(m_path); m_heclProc.setWorkingDirectory(m_path);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("TERM", "xterm-color"); env.insert("TERM", "xterm-color");
env.insert("ConEmuANSI", "ON");
m_heclProc.setProcessEnvironment(env); m_heclProc.setProcessEnvironment(env);
m_heclProc.start(m_urdePath, {"--no-shader-warmup", m_path + "/out"}); disconnect(&m_heclProc, SIGNAL(finished(int)), nullptr, nullptr);
connect(&m_heclProc, SIGNAL(finished(int)), this, SLOT(onLaunchFinished(int)));
m_heclProc.start(m_urdePath, {"--no-shader-warmup", m_path + "/out"},
QIODevice::ReadOnly | QIODevice::Unbuffered);
m_ui->heclTabs->setCurrentIndex(0); m_ui->heclTabs->setCurrentIndex(0);
disableOperations(); disableOperations();
disconnect(&m_heclProc, SIGNAL(finished(int)), nullptr, nullptr);
connect(&m_heclProc, SIGNAL(finished(int)), this, SLOT(onLaunchFinished(int)));
} }
void MainWindow::onLaunchFinished(int returnCode) void MainWindow::onLaunchFinished(int returnCode)
{ {
m_cursor.movePosition(QTextCursor::End);
m_cursor.insertBlock();
checkDownloadedBinary(); checkDownloadedBinary();
} }
void MainWindow::doHECLTerminate() void MainWindow::doHECLTerminate()
{ {
m_heclProc.terminate(); KillProcessTree(m_heclProc);
m_cursor.movePosition(QTextCursor::End);
m_cursor.insertText("\n");
} }
void MainWindow::onReturnPressed() void MainWindow::onReturnPressed()
@ -206,37 +260,26 @@ void MainWindow::onUpdateURDEPressed()
onDownloadPressed(); onDownloadPressed();
} }
void MainWindow::onBinaryDownloaded(const QString& file) void MainWindow::onBinaryDownloaded(QuaZip& file)
{ {
QFileInfo path(file); bool err = !ExtractZip::extractDir(file, m_path);
#ifndef _WIN32
QProcess unzip;
unzip.setWorkingDirectory(path.dir().absolutePath());
unzip.start("unzip", {"-o", path.fileName()});
unzip.waitForFinished();
int err = unzip.exitCode();
#else
SHFILEOPSTRUCT fileOp = {};
fileOp.wFunc = FO_COPY;
fileOp.pFrom = (path.absoluteFilePath().toStdWString() + L"\\*.*\0\0").c_str();
fileOp.pTo = (path.absolutePath().toStdWString() + L"\0\0").c_str();
fileOp.fFlags |= FOF_NOCONFIRMATION;
int err = SHFileOperationW(&fileOp);
if (fileOp.fAnyOperationsAborted)
err = 1;
#endif
QFile::remove(file);
if (err) if (err)
m_ui->downloadErrorLabel->setText(QStringLiteral("Error extracting ") + path.fileName()); m_ui->downloadErrorLabel->setText(QStringLiteral("Error extracting zip"));
else else
m_ui->downloadErrorLabel->setText(QStringLiteral("Download successful"), true); m_ui->downloadErrorLabel->setText(QStringLiteral("Download successful"), true);
m_ui->downloadButton->setEnabled(true); m_ui->downloadButton->setEnabled(true);
checkDownloadedBinary(); checkDownloadedBinary();
if (!err && m_ui->extractBtn->isEnabled()) if (!err && m_ui->extractBtn->isEnabled())
m_ui->downloadErrorLabel->setText(QStringLiteral("Download successful - Press 'Extract' to continue."), true); m_ui->downloadErrorLabel->setText(QStringLiteral("Download successful - Press 'Extract' to continue."), true);
if (!err && !m_ui->sysReqTable->isBlenderVersionOk())
m_ui->downloadErrorLabel->setText(
QStringLiteral("Blender 2.78+ must be installed. Please download via Steam or blender.org."));
} }
void MainWindow::onBinaryFailed(const QString& file) void MainWindow::onBinaryFailed()
{ {
m_ui->downloadButton->setEnabled(true); m_ui->downloadButton->setEnabled(true);
checkDownloadedBinary(); checkDownloadedBinary();
@ -263,6 +306,9 @@ void MainWindow::enableOperations()
m_ui->downloadButton->setEnabled(true); m_ui->downloadButton->setEnabled(true);
if (m_heclPath.isEmpty())
return;
m_ui->extractBtn->setText(QStringLiteral("Extract")); m_ui->extractBtn->setText(QStringLiteral("Extract"));
m_ui->packageBtn->setText(QStringLiteral("Package")); m_ui->packageBtn->setText(QStringLiteral("Package"));
m_ui->launchBtn->setText(QStringLiteral("Launch")); m_ui->launchBtn->setText(QStringLiteral("Launch"));
@ -275,7 +321,9 @@ void MainWindow::enableOperations()
m_ui->launchBtn->setEnabled(true); m_ui->launchBtn->setEnabled(true);
} }
if (m_ui->launchBtn->isEnabled()) if (!m_ui->sysReqTable->isBlenderVersionOk())
insertContinueNote("Blender 2.78+ must be installed. Please download via Steam or blender.org.");
else if (m_ui->launchBtn->isEnabled())
insertContinueNote("Package complete - Press 'Launch' to start URDE."); insertContinueNote("Package complete - Press 'Launch' to start URDE.");
else if (m_ui->packageBtn->isEnabled()) else if (m_ui->packageBtn->isEnabled())
insertContinueNote("Extract complete - Press 'Package' to continue."); insertContinueNote("Extract complete - Press 'Package' to continue.");
@ -299,7 +347,6 @@ static bool GetDLPackage(const QString& path, QString& dlPackage)
bool MainWindow::checkDownloadedBinary() bool MainWindow::checkDownloadedBinary()
{ {
disableOperations();
m_updateURDEButton->hide(); m_updateURDEButton->hide();
m_urdePath = QString(); m_urdePath = QString();
@ -309,6 +356,7 @@ bool MainWindow::checkDownloadedBinary()
{ {
m_ui->heclTabs->setCurrentIndex(1); m_ui->heclTabs->setCurrentIndex(1);
m_ui->downloadErrorLabel->setText(QStringLiteral("Set working directory to continue."), true); m_ui->downloadErrorLabel->setText(QStringLiteral("Set working directory to continue."), true);
enableOperations();
return false; return false;
} }
@ -351,9 +399,9 @@ bool MainWindow::checkDownloadedBinary()
m_ui->currentBinaryLabel->setText(QStringLiteral("unknown -- re-download recommended")); m_ui->currentBinaryLabel->setText(QStringLiteral("unknown -- re-download recommended"));
} }
enableOperations();
m_urdePath = urdePath; m_urdePath = urdePath;
m_heclPath = heclPath; m_heclPath = heclPath;
enableOperations();
return true; return true;
} }
else else
@ -361,6 +409,7 @@ bool MainWindow::checkDownloadedBinary()
m_ui->currentBinaryLabel->setText(QStringLiteral("none")); m_ui->currentBinaryLabel->setText(QStringLiteral("none"));
m_ui->heclTabs->setCurrentIndex(1); m_ui->heclTabs->setCurrentIndex(1);
m_ui->downloadErrorLabel->setText(QStringLiteral("Press 'Download' to fetch latest URDE binary."), true); m_ui->downloadErrorLabel->setText(QStringLiteral("Press 'Download' to fetch latest URDE binary."), true);
enableOperations();
} }
return false; return false;
@ -370,7 +419,7 @@ void MainWindow::setPath(const QString& path)
{ {
QFileInfo finfo(path); QFileInfo finfo(path);
QString usePath = finfo.absoluteFilePath(); QString usePath = finfo.absoluteFilePath();
if (!finfo.exists()) if (!usePath.isEmpty() && !finfo.exists())
{ {
if (QMessageBox::question(this, QStringLiteral("Make Directory"), if (QMessageBox::question(this, QStringLiteral("Make Directory"),
QStringLiteral("%1 does not exist. Create it now?").arg(usePath)) == QMessageBox::Yes) QStringLiteral("%1 does not exist. Create it now?").arg(usePath)) == QMessageBox::Yes)
@ -403,22 +452,22 @@ void MainWindow::setPath(const QString& path)
m_ui->currentBinaryLabel->setText(QStringLiteral("none")); m_ui->currentBinaryLabel->setText(QStringLiteral("none"));
} }
m_ui->sysReqTable->updateFreeDiskSpace(m_path);
checkDownloadedBinary(); checkDownloadedBinary();
} }
void MainWindow::initSlots() void MainWindow::initSlots()
{ {
#ifdef Q_OS_WIN
m_heclProc.setEnvironment(QProcessEnvironment::systemEnvironment().toStringList() + QStringList("ConEmuANSI=ON"));
#endif
connect(&m_heclProc, &QProcess::readyRead, [=](){ connect(&m_heclProc, &QProcess::readyRead, [=](){
setTextTermFormatting(m_heclProc.readAll()); QByteArray bytes = m_heclProc.readAll();
setTextTermFormatting(bytes);
m_ui->processOutput->ensureCursorVisible(); m_ui->processOutput->ensureCursorVisible();
}); });
connect(m_ui->extractBtn, SIGNAL(clicked()), this, SLOT(onExtract())); connect(m_ui->extractBtn, SIGNAL(clicked()), this, SLOT(onExtract()));
connect(m_ui->packageBtn, SIGNAL(clicked()), this, SLOT(onPackage())); connect(m_ui->packageBtn, SIGNAL(clicked()), this, SLOT(onPackage()));
connect(m_ui->launchBtn, SIGNAL(clicked()), this, SLOT(onLaunch())); connect(m_ui->launchBtn, SIGNAL(clicked()), this, SLOT(onLaunch()));
m_ui->launchMenuBtn->setMenu(&m_launchMenu);
connect(m_ui->browseBtn, &QPushButton::clicked, [=]() { connect(m_ui->browseBtn, &QPushButton::clicked, [=]() {
FileDirDialog dialog(this); FileDirDialog dialog(this);
@ -437,80 +486,6 @@ void MainWindow::initSlots()
connect(m_ui->downloadButton, SIGNAL(clicked()), this, SLOT(onDownloadPressed())); connect(m_ui->downloadButton, SIGNAL(clicked()), this, SLOT(onDownloadPressed()));
} }
static void ReturnInsert(QTextCursor& cur, const QString& text)
{
auto DoLine = [&](const QString& line)
{
auto DoReturn = [&](const QString& ret)
{
if (!ret.isEmpty())
{
cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, ret.size());
cur.insertText(ret);
}
};
QStringList list = line.split('\r');
DoReturn(list.front());
if (list.size() > 1)
{
for (auto it = list.begin() + 1; it != list.end(); ++it)
{
cur.movePosition(QTextCursor::StartOfLine);
DoReturn(*it);
}
}
};
QStringList lineSplit = text.split('\n');
DoLine(lineSplit.front());
if (lineSplit.size() > 1)
{
for (auto it = lineSplit.begin() + 1; it != lineSplit.end(); ++it)
{
cur.movePosition(QTextCursor::EndOfLine);
cur.insertText("\n");
DoLine(*it);
}
}
}
static void ReturnInsert(QTextCursor& cur, const QString& text, const QTextCharFormat& format)
{
auto DoLine = [&](const QString& line)
{
auto DoReturn = [&](const QString& ret)
{
if (!ret.isEmpty())
{
cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, ret.size());
cur.insertText(ret, format);
}
};
QStringList list = line.split('\r');
DoReturn(list.front());
if (list.size() > 1)
{
for (auto it = list.begin() + 1; it != list.end(); ++it)
{
cur.movePosition(QTextCursor::StartOfLine);
DoReturn(*it);
}
}
};
QStringList lineSplit = text.split('\n');
DoLine(lineSplit.front());
if (lineSplit.size() > 1)
{
for (auto it = lineSplit.begin() + 1; it != lineSplit.end(); ++it)
{
cur.movePosition(QTextCursor::EndOfLine);
cur.insertText("\n", format);
DoLine(*it);
}
}
}
void MainWindow::setTextTermFormatting(const QString& text) void MainWindow::setTextTermFormatting(const QString& text)
{ {
m_inContinueNote = false; m_inContinueNote = false;
@ -552,5 +527,6 @@ void MainWindow::insertContinueNote(const QString& text)
m_cursor.movePosition(QTextCursor::End); m_cursor.movePosition(QTextCursor::End);
QTextCharFormat textCharFormat = m_cursor.charFormat(); QTextCharFormat textCharFormat = m_cursor.charFormat();
textCharFormat.setForeground(QColor(0,255,0)); textCharFormat.setForeground(QColor(0,255,0));
m_cursor.insertText(text + '\n', textCharFormat); m_cursor.insertText(text, textCharFormat);
m_cursor.insertBlock();
} }

View File

@ -6,10 +6,14 @@
#include <QTextCursor> #include <QTextCursor>
#include <memory> #include <memory>
#include "DownloadManager.hpp" #include "DownloadManager.hpp"
#include "LaunchMenu.hpp"
#include "Common.hpp" #include "Common.hpp"
#include "hecl/Runtime.hpp"
#include "hecl/CVarCommons.hpp"
class QTextEdit; class QTextEdit;
class QTextCharFormat; class QTextCharFormat;
class QPushButton; class QPushButton;
class QuaZip;
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
@ -18,6 +22,9 @@ class MainWindow;
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
hecl::Runtime::FileStoreManager m_fileMgr;
hecl::CVarManager m_cvarManager;
hecl::CVarCommons m_cvarCommons;
Ui::MainWindow* m_ui; Ui::MainWindow* m_ui;
QTextCursor m_cursor; QTextCursor m_cursor;
QString m_path; QString m_path;
@ -25,6 +32,7 @@ class MainWindow : public QMainWindow
QString m_heclPath; QString m_heclPath;
QProcess m_heclProc; QProcess m_heclProc;
DownloadManager m_dlManager; DownloadManager m_dlManager;
LaunchMenu m_launchMenu;
QSettings m_settings; QSettings m_settings;
URDEVersion m_recommendedVersion; URDEVersion m_recommendedVersion;
QPushButton* m_updateURDEButton; QPushButton* m_updateURDEButton;
@ -50,8 +58,8 @@ private:
void setPath(const QString& path); void setPath(const QString& path);
void initSlots(); void initSlots();
void onIndexDownloaded(const QStringList& index); void onIndexDownloaded(const QStringList& index);
void onBinaryDownloaded(const QString& file); void onBinaryDownloaded(QuaZip& file);
void onBinaryFailed(const QString& file); void onBinaryFailed();
void disableOperations(); void disableOperations();
void enableOperations(); void enableOperations();
}; };

View File

@ -21,6 +21,74 @@
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="3">
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="launchBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>&amp;Launch</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="launchMenuBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>15</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0"> <item row="2" column="0">
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
@ -34,10 +102,10 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="1" column="0" colspan="5"> <item row="1" column="0" colspan="6">
<widget class="QTabWidget" name="heclTabs"> <widget class="QTabWidget" name="heclTabs">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="dataTab"> <widget class="QWidget" name="dataTab">
<attribute name="title"> <attribute name="title">
@ -216,7 +284,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -637,7 +705,7 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.SF NS Text'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.14286pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:600;&quot;&gt;About HECL Frontend&lt;/span&gt;&lt;/p&gt; &lt;p align=&quot;center&quot; style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:600;&quot;&gt;About HECL Frontend&lt;/span&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt;&quot;&gt;&lt;br /&gt;The hecl frontend UI is designed and built by &lt;/span&gt;&lt;a href=&quot;https://axiodl.com&quot;&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt; text-decoration: underline; color:#007af4;&quot;&gt;Axiomatic Data Laboratories&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt;&quot;&gt; Copyright 2018&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:600;&quot;&gt;Authors:&lt;/span&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt;&quot;&gt;&lt;br /&gt;Phillip &amp;quot;Antidote&amp;quot; Stephens&lt;br /&gt;Jack &amp;quot;jackoalan&amp;quot; Andersen&lt;/span&gt;&lt;/p&gt; &lt;p align=&quot;center&quot; style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt;&quot;&gt;&lt;br /&gt;The hecl frontend UI is designed and built by &lt;/span&gt;&lt;a href=&quot;https://axiodl.com&quot;&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt; text-decoration: underline; color:#007af4;&quot;&gt;Axiomatic Data Laboratories&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt;&quot;&gt; Copyright 2018&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:600;&quot;&gt;Authors:&lt;/span&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt;&quot;&gt;&lt;br /&gt;Phillip &amp;quot;Antidote&amp;quot; Stephens&lt;br /&gt;Jack &amp;quot;jackoalan&amp;quot; Andersen&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Courier New'; font-size:10pt;&quot;&gt;The MIT License&lt;/span&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Courier New'; font-size:10pt;&quot;&gt;The MIT License&lt;/span&gt;&lt;/p&gt;
@ -665,6 +733,12 @@ p, li { white-space: pre-wrap; }
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text"> <property name="text">
<string>&amp;Extract</string> <string>&amp;Extract</string>
</property> </property>
@ -675,22 +749,18 @@ p, li { white-space: pre-wrap; }
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text"> <property name="text">
<string>&amp;Package</string> <string>&amp;Package</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="3"> <item row="2" column="5">
<widget class="QPushButton" name="launchBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Launch</string>
</property>
</widget>
</item>
<item row="2" column="4">
<spacer name="horizontalSpacer_2"> <spacer name="horizontalSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -703,7 +773,7 @@ p, li { white-space: pre-wrap; }
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="0" colspan="5"> <item row="0" column="0" colspan="6">
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
@ -760,7 +830,6 @@ p, li { white-space: pre-wrap; }
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -7,6 +7,8 @@
#include <QJsonArray> #include <QJsonArray>
#include <QDomDocument> #include <QDomDocument>
#include <QProcess> #include <QProcess>
#include <QStorageInfo>
#include "FindBlender.hpp"
#if _WIN32 #if _WIN32
#include <Windows.h> #include <Windows.h>
@ -84,6 +86,22 @@ SysReqTableModel::SysReqTableModel(QObject* parent)
m_cpuSpeedStr.sprintf("%g GHz", speed); m_cpuSpeedStr.sprintf("%g GHz", speed);
} }
} }
#elif _WIN32
HKEY hkey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
_S("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
{
DWORD MHz;
DWORD size = sizeof(MHz);
if (RegQueryValueEx(hkey, _S("~MHz"), nullptr, nullptr,
(LPBYTE)&MHz, &size) == ERROR_SUCCESS)
{
m_cpuSpeed = uint64_t(MHz);
m_cpuSpeedStr.sprintf("%1.1f GHz", MHz / 1000.f);
}
}
RegCloseKey(hkey);
#else #else
/* This only works for Skylake+ */ /* This only works for Skylake+ */
int regs[4] = {}; int regs[4] = {};
@ -115,11 +133,32 @@ SysReqTableModel::SysReqTableModel(QObject* parent)
#elif __linux__ #elif __linux__
m_osVersion = QStringLiteral("Linux"); m_osVersion = QStringLiteral("Linux");
#endif #endif
hecl::blender::FindBlender(m_blendMajor, m_blendMinor);
if (m_blendMajor)
m_blendVersionStr = QStringLiteral("Blender ") + QString::number(m_blendMajor) +
'.' + QString::number(m_blendMinor);
else
m_blendVersionStr = QStringLiteral("Not Found");
}
void SysReqTableModel::updateFreeDiskSpace(const QString& path)
{
if (path.isEmpty())
{
m_freeDiskSpace = 0;
m_freeDiskSpaceStr = QStringLiteral("<Set Working Directory>");
}
else
{
m_freeDiskSpace = QStorageInfo(path).bytesFree();
m_freeDiskSpaceStr.sprintf("%1.1f GB", m_freeDiskSpace / 1000.f / 1000.f / 1000.f);
}
emit dataChanged(index(3, 0), index(3, 0));
} }
int SysReqTableModel::rowCount(const QModelIndex& parent) const int SysReqTableModel::rowCount(const QModelIndex& parent) const
{ {
return 5; return 7;
} }
int SysReqTableModel::columnCount(const QModelIndex& parent) const int SysReqTableModel::columnCount(const QModelIndex& parent) const
@ -145,6 +184,8 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
case 2: case 2:
return m_memorySize >= 0xC0000000; return m_memorySize >= 0xC0000000;
case 3: case 3:
return m_freeDiskSpace >= qint64(16) * 1000 * 1000 * 1000;
case 4:
#ifdef __APPLE__ #ifdef __APPLE__
return m_macosMajor > 10 || m_macosMinor >= 9; return m_macosMajor > 10 || m_macosMinor >= 9;
#elif defined(_WIN32) #elif defined(_WIN32)
@ -152,6 +193,8 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
#else #else
return true; return true;
#endif #endif
case 5:
return isBlenderVersionOk();
} }
} }
else else
@ -172,6 +215,8 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
case 2: case 2:
return QStringLiteral("3 GB"); return QStringLiteral("3 GB");
case 3: case 3:
return QStringLiteral("16 GB (MP1)");
case 4:
#ifdef __APPLE__ #ifdef __APPLE__
return QStringLiteral("macOS 10.9"); return QStringLiteral("macOS 10.9");
#elif defined(_WIN32) #elif defined(_WIN32)
@ -181,6 +226,8 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
#else #else
return {}; return {};
#endif #endif
case 5:
return QStringLiteral("Blender 2.78");
} }
} }
else if (index.column() == 1) else if (index.column() == 1)
@ -199,7 +246,11 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
case 2: case 2:
return m_memorySizeStr; return m_memorySizeStr;
case 3: case 3:
return m_freeDiskSpaceStr;
case 4:
return m_osVersion; return m_osVersion;
case 5:
return m_blendVersionStr;
} }
} }
} }
@ -236,8 +287,12 @@ QVariant SysReqTableModel::headerData(int section, Qt::Orientation orientation,
case 2: case 2:
return QStringLiteral("Memory"); return QStringLiteral("Memory");
case 3: case 3:
return QStringLiteral("OS"); return QStringLiteral("Disk Space");
case 4: case 4:
return QStringLiteral("OS");
case 5:
return QStringLiteral("Blender");
case 6:
return QStringLiteral("Vector ISA"); return QStringLiteral("Vector ISA");
} }
} }
@ -248,9 +303,17 @@ void SysReqTableView::paintEvent(QPaintEvent* e)
int tableWidth = columnWidth(0) + columnWidth(1); int tableWidth = columnWidth(0) + columnWidth(1);
int tableX = verticalHeader()->width() + columnViewportPosition(0); int tableX = verticalHeader()->width() + columnViewportPosition(0);
int tableY = horizontalHeader()->height(); int tableY = horizontalHeader()->height();
for (int i = 0; i < 4; ++i) for (int i = 0; i < 6; ++i)
{ {
QWidget* w = std::get<0>(m_backgroundWidgets[i]); QWidget* w = std::get<0>(m_backgroundWidgets[i]);
QPalette pal = palette();
if (m_model.data(m_model.index(i, 0), Qt::UserRole).toBool())
pal.setColor(QPalette::Background, QColor::fromRgbF(0.f, 1.f, 0.f, 0.2f));
else
pal.setColor(QPalette::Background, QColor::fromRgbF(1.f, 0.f, 0.f, 0.2f));
w->setPalette(pal);
QSequentialAnimationGroup* animation = std::get<1>(m_backgroundWidgets[i]); QSequentialAnimationGroup* animation = std::get<1>(m_backgroundWidgets[i]);
QPropertyAnimation* pAnimation = static_cast<QPropertyAnimation*>(animation->animationAt(1)); QPropertyAnimation* pAnimation = static_cast<QPropertyAnimation*>(animation->animationAt(1));
bool& running = std::get<2>(m_backgroundWidgets[i]); bool& running = std::get<2>(m_backgroundWidgets[i]);
@ -274,15 +337,15 @@ SysReqTableView::SysReqTableView(QWidget* parent)
: QTableView(parent), m_vectorISATable(this) : QTableView(parent), m_vectorISATable(this)
{ {
setModel(&m_model); setModel(&m_model);
setIndexWidget(m_model.index(4, 0), &m_vectorISATable); setIndexWidget(m_model.index(6, 0), &m_vectorISATable);
setSpan(4, 0, 1, 2); setSpan(6, 0, 1, 2);
horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
setSelectionMode(QAbstractItemView::SelectionMode::NoSelection); setSelectionMode(QAbstractItemView::SelectionMode::NoSelection);
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
for (int i = 0; i < 4; ++i) for (int i = 0; i < 6; ++i)
{ {
QWidget* w = new QWidget(this); QWidget* w = new QWidget(this);
std::get<0>(m_backgroundWidgets[i]) = w; std::get<0>(m_backgroundWidgets[i]) = w;

View File

@ -13,6 +13,8 @@ class SysReqTableModel : public QAbstractTableModel
QString m_cpuSpeedStr; QString m_cpuSpeedStr;
uint64_t m_memorySize = 0; uint64_t m_memorySize = 0;
QString m_memorySizeStr; QString m_memorySizeStr;
qint64 m_freeDiskSpace = 0;
QString m_freeDiskSpaceStr = QStringLiteral("<Set Working Directory>");
#if __APPLE__ #if __APPLE__
int m_macosMajor = 0; int m_macosMajor = 0;
int m_macosMinor = 0; int m_macosMinor = 0;
@ -21,12 +23,18 @@ class SysReqTableModel : public QAbstractTableModel
bool m_win7SP1OrGreater = false; bool m_win7SP1OrGreater = false;
#endif #endif
QString m_osVersion; QString m_osVersion;
int m_blendMajor = 0;
int m_blendMinor = 0;
QString m_blendVersionStr;
public: public:
SysReqTableModel(QObject* parent = Q_NULLPTR); SysReqTableModel(QObject* parent = Q_NULLPTR);
int rowCount(const QModelIndex& parent = QModelIndex()) const; int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
bool isBlenderVersionOk() const
{ return m_blendMajor > 2 || (m_blendMajor == 2 && m_blendMinor >= 78); }
void updateFreeDiskSpace(const QString& path);
}; };
class SysReqTableView : public QTableView class SysReqTableView : public QTableView
@ -34,7 +42,7 @@ class SysReqTableView : public QTableView
Q_OBJECT Q_OBJECT
SysReqTableModel m_model; SysReqTableModel m_model;
VectorISATableView m_vectorISATable; VectorISATableView m_vectorISATable;
std::tuple<QWidget*, QSequentialAnimationGroup*, bool> m_backgroundWidgets[4] = {}; std::tuple<QWidget*, QSequentialAnimationGroup*, bool> m_backgroundWidgets[6] = {};
public: public:
SysReqTableView(QWidget* parent = Q_NULLPTR); SysReqTableView(QWidget* parent = Q_NULLPTR);
void paintEvent(QPaintEvent* e) Q_DECL_OVERRIDE; void paintEvent(QPaintEvent* e) Q_DECL_OVERRIDE;
@ -45,6 +53,8 @@ public:
return v.getArchitecture() == CurArchitecture && v.getPlatform() == CurPlatform && return v.getArchitecture() == CurArchitecture && v.getPlatform() == CurPlatform &&
m_vectorISATable.willRun(v.getVectorISA()); m_vectorISATable.willRun(v.getVectorISA());
} }
bool isBlenderVersionOk() const { return m_model.isBlenderVersionOk(); }
void updateFreeDiskSpace(const QString& path) { m_model.updateFreeDiskSpace(path); }
}; };
#endif // GUI_SYSREQTABLEVIEW_HPP #endif // GUI_SYSREQTABLEVIEW_HPP

View File

@ -6,7 +6,7 @@
void VectorISATableView::paintEvent(QPaintEvent* e) void VectorISATableView::paintEvent(QPaintEvent* e)
{ {
QTableView* p = static_cast<QTableView*>(parent()->parent()); QTableView* p = static_cast<QTableView*>(parent()->parent());
int tableY = p->horizontalHeader()->height() + p->rowViewportPosition(4); int tableY = p->horizontalHeader()->height() + p->rowViewportPosition(6);
int rHeight = rowHeight(0); int rHeight = rowHeight(0);
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
{ {
@ -89,7 +89,7 @@ VectorISATableView::VectorISATableView(QWidget* parent)
QSequentialAnimationGroup* seq = new QSequentialAnimationGroup(this); QSequentialAnimationGroup* seq = new QSequentialAnimationGroup(this);
std::get<1>(m_backgroundWidgets[i]) = seq; std::get<1>(m_backgroundWidgets[i]) = seq;
seq->addPause(4 * 100); seq->addPause(6 * 100);
seq->addAnimation(animation); seq->addAnimation(animation);
} }
} }

View File

@ -28,13 +28,13 @@ int main(int argc, char* argv[])
{ {
InitializePlatform(); InitializePlatform();
QApplication a(argc, argv);
a.setStyle(QStyleFactory::create("Fusion"));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
a.setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif #endif
a.setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication::setStyle(QStyleFactory::create("Fusion"));
a.setWindowIcon(MakeAppIcon()); QApplication a(argc, argv);
QApplication::setWindowIcon(MakeAppIcon());
QPalette darkPalette; QPalette darkPalette;
darkPalette.setColor(QPalette::Window, QColor(53,53,53)); darkPalette.setColor(QPalette::Window, QColor(53,53,53));

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<description> my exe </description> <description>HECL-GUI</description>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application> <application>
<!-- Windows 10 --> <!-- Windows 10 -->
@ -15,4 +15,9 @@
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application> </application>
</compatibility> </compatibility>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly> </assembly>

1
hecl-gui/quazip Submodule

@ -0,0 +1 @@
Subproject commit cf36e59d2ad38bac63447d02f1b1833276099ec0