mirror of https://github.com/AxioDL/metaforce.git
Additional usability features
This commit is contained in:
parent
00da24a134
commit
f6195a64a6
|
@ -0,0 +1,3 @@
|
|||
[submodule "quazip"]
|
||||
path = quazip
|
||||
url = https://github.com/mnafees/quazip.git
|
|
@ -26,18 +26,31 @@ add_subdirectory(platforms/freedesktop)
|
|||
declare_qticon_target()
|
||||
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
|
||||
MainWindow.ui MainWindow.hpp MainWindow.cpp
|
||||
LaunchMenu.hpp LaunchMenu.cpp
|
||||
EscapeSequenceParser.hpp EscapeSequenceParser.cpp
|
||||
FileDirDialog.hpp ErrorLabel.hpp
|
||||
SysReqTableView.hpp SysReqTableView.cpp
|
||||
VectorISATableView.hpp VectorISATableView.cpp
|
||||
VectorISATableModel.hpp VectorISATableModelIntel.hpp
|
||||
FindBlender.hpp FindBlender.cpp
|
||||
DownloadManager.hpp DownloadManager.cpp
|
||||
ExtractZip.hpp ExtractZip.cpp ${QUAZIP_SRCS}
|
||||
Common.hpp Common.cpp ${PLAT_SRCS} main.cpp)
|
||||
|
||||
set_target_properties(hecl-gui PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/platforms/mac/Info.plist")
|
||||
|
||||
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)
|
||||
|
|
|
@ -135,12 +135,16 @@ QString URDEVersion::fileString(bool withExtension) const
|
|||
VectorISAToString(m_vectorISA));
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static void HUPHandler(int) {}
|
||||
#endif
|
||||
|
||||
void InitializePlatform()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
/* This can happen when terminating hecl - do nothing */
|
||||
signal(SIGHUP, HUPHandler);
|
||||
#endif
|
||||
|
||||
#if ZEUS_ARCH_X86_64
|
||||
const_cast<Architecture&>(CurArchitecture) = Architecture::X86_64;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "DownloadManager.hpp"
|
||||
#include "Common.hpp"
|
||||
#include <QBuffer>
|
||||
#include <quazip.h>
|
||||
|
||||
static const char AxioDLPublicKeyPEM[] =
|
||||
"-----BEGIN PUBLIC KEY-----\n"
|
||||
|
@ -119,19 +121,19 @@ void DownloadManager::binaryFinished()
|
|||
if (m_progBar)
|
||||
m_progBar->setValue(100);
|
||||
|
||||
QFile fp(m_outPath);
|
||||
if (!fp.open(QIODevice::WriteOnly))
|
||||
QByteArray all = m_binaryInProgress->readAll();
|
||||
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 = nullptr;
|
||||
return;
|
||||
}
|
||||
fp.write(m_binaryInProgress->readAll());
|
||||
fp.close();
|
||||
|
||||
if (m_completionHandler)
|
||||
m_completionHandler(m_outPath);
|
||||
m_completionHandler(zip);
|
||||
|
||||
m_binaryInProgress->deleteLater();
|
||||
m_binaryInProgress = nullptr;
|
||||
|
@ -147,7 +149,7 @@ void DownloadManager::binaryError(QNetworkReply::NetworkError error)
|
|||
m_progBar->setEnabled(false);
|
||||
|
||||
if (m_failedHandler)
|
||||
m_failedHandler(m_outPath);
|
||||
m_failedHandler();
|
||||
}
|
||||
|
||||
void DownloadManager::binaryValidateCert()
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <QProgressBar>
|
||||
#include <QLabel>
|
||||
|
||||
class QuaZip;
|
||||
|
||||
class DownloadManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -18,8 +20,8 @@ class DownloadManager : public QObject
|
|||
QProgressBar* m_progBar = nullptr;
|
||||
QLabel* m_errorLabel = nullptr;
|
||||
std::function<void(const QStringList& index)> m_indexCompletionHandler;
|
||||
std::function<void(const QString& file)> m_completionHandler;
|
||||
std::function<void(const QString& file)> m_failedHandler;
|
||||
std::function<void(QuaZip& file)> m_completionHandler;
|
||||
std::function<void()> m_failedHandler;
|
||||
|
||||
void resetError()
|
||||
{
|
||||
|
@ -44,8 +46,8 @@ public:
|
|||
: QObject(parent), m_netManager(this) {}
|
||||
void connectWidgets(QProgressBar* progBar, QLabel* errorLabel,
|
||||
std::function<void(const QStringList& index)>&& indexCompletionHandler,
|
||||
std::function<void(const QString& file)>&& completionHandler,
|
||||
std::function<void(const QString& file)>&& failedHandler)
|
||||
std::function<void(QuaZip& file)>&& completionHandler,
|
||||
std::function<void()>&& failedHandler)
|
||||
{
|
||||
m_progBar = progBar;
|
||||
m_errorLabel = errorLabel;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,13 @@
|
|||
|
||||
#include <QString>
|
||||
#include <QTextCharFormat>
|
||||
#include <QTextCursor>
|
||||
|
||||
void ParseEscapeSequence(int attribute, QListIterator<QString>& i, QTextCharFormat& textCharFormat,
|
||||
const QTextCharFormat& defaultTextCharFormat);
|
||||
|
||||
void ReturnInsert(QTextCursor& cur, const QString& text);
|
||||
|
||||
void ReturnInsert(QTextCursor& cur, const QString& text, const QTextCharFormat& format);
|
||||
|
||||
#endif // GUI_ESCAPESEQUENCEPARSER_HPP
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -4,17 +4,68 @@
|
|||
#include <QMessageBox>
|
||||
#include "EscapeSequenceParser.hpp"
|
||||
#include "FileDirDialog.hpp"
|
||||
#include "ExtractZip.hpp"
|
||||
|
||||
#if _WIN32
|
||||
#include <Windows.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
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
m_ui(new Ui::MainWindow)
|
||||
QMainWindow(parent)
|
||||
, m_fileMgr(_S("urde"))
|
||||
, m_cvarManager(m_fileMgr)
|
||||
, m_cvarCommons(m_cvarManager)
|
||||
, m_ui(new Ui::MainWindow)
|
||||
, m_heclProc(this)
|
||||
, m_dlManager(this)
|
||||
, m_launchMenu(m_cvarCommons, this)
|
||||
, m_settings("AxioDL", "HECL", this)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
@ -41,7 +92,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
m_dlManager.connectWidgets(m_ui->downloadProgressBar, m_ui->downloadErrorLabel,
|
||||
std::bind(&MainWindow::onIndexDownloaded, 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();
|
||||
|
||||
|
@ -52,8 +103,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
m_heclProc.close();
|
||||
m_heclProc.terminate();
|
||||
KillProcessTree(m_heclProc);
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
@ -67,14 +117,17 @@ void MainWindow::onExtract()
|
|||
return;
|
||||
|
||||
m_ui->processOutput->clear();
|
||||
m_heclProc.close();
|
||||
m_heclProc.terminate();
|
||||
KillProcessTree(m_heclProc);
|
||||
m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels);
|
||||
m_heclProc.setWorkingDirectory(m_path);
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("TERM", "xterm-color");
|
||||
env.insert("ConEmuANSI", "ON");
|
||||
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);
|
||||
|
||||
|
@ -83,13 +136,12 @@ void MainWindow::onExtract()
|
|||
m_ui->extractBtn->setEnabled(true);
|
||||
disconnect(m_ui->extractBtn, SIGNAL(clicked()), nullptr, nullptr);
|
||||
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)
|
||||
{
|
||||
m_cursor.movePosition(QTextCursor::End);
|
||||
m_cursor.insertBlock();
|
||||
disconnect(m_ui->extractBtn, SIGNAL(clicked()), nullptr, nullptr);
|
||||
connect(m_ui->extractBtn, SIGNAL(clicked()), this, SLOT(onExtract()));
|
||||
checkDownloadedBinary();
|
||||
|
@ -100,14 +152,17 @@ void MainWindow::onPackage()
|
|||
if (m_path.isEmpty())
|
||||
return;
|
||||
m_ui->processOutput->clear();
|
||||
m_heclProc.close();
|
||||
m_heclProc.terminate();
|
||||
KillProcessTree(m_heclProc);
|
||||
m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels);
|
||||
m_heclProc.setWorkingDirectory(m_path);
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("TERM", "xterm-color");
|
||||
env.insert("ConEmuANSI", "ON");
|
||||
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);
|
||||
|
||||
|
@ -116,13 +171,12 @@ void MainWindow::onPackage()
|
|||
m_ui->packageBtn->setEnabled(true);
|
||||
disconnect(m_ui->packageBtn, SIGNAL(clicked()), nullptr, nullptr);
|
||||
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)
|
||||
{
|
||||
m_cursor.movePosition(QTextCursor::End);
|
||||
m_cursor.insertBlock();
|
||||
disconnect(m_ui->packageBtn, SIGNAL(clicked()), nullptr, nullptr);
|
||||
connect(m_ui->packageBtn, SIGNAL(clicked()), this, SLOT(onPackage()));
|
||||
checkDownloadedBinary();
|
||||
|
@ -133,33 +187,33 @@ void MainWindow::onLaunch()
|
|||
if (m_path.isEmpty())
|
||||
return;
|
||||
m_ui->processOutput->clear();
|
||||
m_heclProc.close();
|
||||
m_heclProc.terminate();
|
||||
KillProcessTree(m_heclProc);
|
||||
m_heclProc.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels);
|
||||
m_heclProc.setWorkingDirectory(m_path);
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("TERM", "xterm-color");
|
||||
env.insert("ConEmuANSI", "ON");
|
||||
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);
|
||||
|
||||
disableOperations();
|
||||
|
||||
disconnect(&m_heclProc, SIGNAL(finished(int)), nullptr, nullptr);
|
||||
connect(&m_heclProc, SIGNAL(finished(int)), this, SLOT(onLaunchFinished(int)));
|
||||
}
|
||||
|
||||
void MainWindow::onLaunchFinished(int returnCode)
|
||||
{
|
||||
m_cursor.movePosition(QTextCursor::End);
|
||||
m_cursor.insertBlock();
|
||||
checkDownloadedBinary();
|
||||
}
|
||||
|
||||
void MainWindow::doHECLTerminate()
|
||||
{
|
||||
m_heclProc.terminate();
|
||||
m_cursor.movePosition(QTextCursor::End);
|
||||
m_cursor.insertText("\n");
|
||||
KillProcessTree(m_heclProc);
|
||||
}
|
||||
|
||||
void MainWindow::onReturnPressed()
|
||||
|
@ -206,37 +260,26 @@ void MainWindow::onUpdateURDEPressed()
|
|||
onDownloadPressed();
|
||||
}
|
||||
|
||||
void MainWindow::onBinaryDownloaded(const QString& file)
|
||||
void MainWindow::onBinaryDownloaded(QuaZip& file)
|
||||
{
|
||||
QFileInfo path(file);
|
||||
#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);
|
||||
bool err = !ExtractZip::extractDir(file, m_path);
|
||||
|
||||
if (err)
|
||||
m_ui->downloadErrorLabel->setText(QStringLiteral("Error extracting ") + path.fileName());
|
||||
m_ui->downloadErrorLabel->setText(QStringLiteral("Error extracting zip"));
|
||||
else
|
||||
m_ui->downloadErrorLabel->setText(QStringLiteral("Download successful"), true);
|
||||
|
||||
m_ui->downloadButton->setEnabled(true);
|
||||
checkDownloadedBinary();
|
||||
|
||||
if (!err && m_ui->extractBtn->isEnabled())
|
||||
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);
|
||||
checkDownloadedBinary();
|
||||
|
@ -263,6 +306,9 @@ void MainWindow::enableOperations()
|
|||
|
||||
m_ui->downloadButton->setEnabled(true);
|
||||
|
||||
if (m_heclPath.isEmpty())
|
||||
return;
|
||||
|
||||
m_ui->extractBtn->setText(QStringLiteral("Extract"));
|
||||
m_ui->packageBtn->setText(QStringLiteral("Package"));
|
||||
m_ui->launchBtn->setText(QStringLiteral("Launch"));
|
||||
|
@ -275,7 +321,9 @@ void MainWindow::enableOperations()
|
|||
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.");
|
||||
else if (m_ui->packageBtn->isEnabled())
|
||||
insertContinueNote("Extract complete - Press 'Package' to continue.");
|
||||
|
@ -299,7 +347,6 @@ static bool GetDLPackage(const QString& path, QString& dlPackage)
|
|||
|
||||
bool MainWindow::checkDownloadedBinary()
|
||||
{
|
||||
disableOperations();
|
||||
m_updateURDEButton->hide();
|
||||
|
||||
m_urdePath = QString();
|
||||
|
@ -309,6 +356,7 @@ bool MainWindow::checkDownloadedBinary()
|
|||
{
|
||||
m_ui->heclTabs->setCurrentIndex(1);
|
||||
m_ui->downloadErrorLabel->setText(QStringLiteral("Set working directory to continue."), true);
|
||||
enableOperations();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -351,9 +399,9 @@ bool MainWindow::checkDownloadedBinary()
|
|||
m_ui->currentBinaryLabel->setText(QStringLiteral("unknown -- re-download recommended"));
|
||||
}
|
||||
|
||||
enableOperations();
|
||||
m_urdePath = urdePath;
|
||||
m_heclPath = heclPath;
|
||||
enableOperations();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -361,6 +409,7 @@ bool MainWindow::checkDownloadedBinary()
|
|||
m_ui->currentBinaryLabel->setText(QStringLiteral("none"));
|
||||
m_ui->heclTabs->setCurrentIndex(1);
|
||||
m_ui->downloadErrorLabel->setText(QStringLiteral("Press 'Download' to fetch latest URDE binary."), true);
|
||||
enableOperations();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -370,7 +419,7 @@ void MainWindow::setPath(const QString& path)
|
|||
{
|
||||
QFileInfo finfo(path);
|
||||
QString usePath = finfo.absoluteFilePath();
|
||||
if (!finfo.exists())
|
||||
if (!usePath.isEmpty() && !finfo.exists())
|
||||
{
|
||||
if (QMessageBox::question(this, QStringLiteral("Make Directory"),
|
||||
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->sysReqTable->updateFreeDiskSpace(m_path);
|
||||
checkDownloadedBinary();
|
||||
}
|
||||
|
||||
void MainWindow::initSlots()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
m_heclProc.setEnvironment(QProcessEnvironment::systemEnvironment().toStringList() + QStringList("ConEmuANSI=ON"));
|
||||
#endif
|
||||
connect(&m_heclProc, &QProcess::readyRead, [=](){
|
||||
setTextTermFormatting(m_heclProc.readAll());
|
||||
QByteArray bytes = m_heclProc.readAll();
|
||||
setTextTermFormatting(bytes);
|
||||
m_ui->processOutput->ensureCursorVisible();
|
||||
});
|
||||
|
||||
connect(m_ui->extractBtn, SIGNAL(clicked()), this, SLOT(onExtract()));
|
||||
connect(m_ui->packageBtn, SIGNAL(clicked()), this, SLOT(onPackage()));
|
||||
connect(m_ui->launchBtn, SIGNAL(clicked()), this, SLOT(onLaunch()));
|
||||
m_ui->launchMenuBtn->setMenu(&m_launchMenu);
|
||||
|
||||
connect(m_ui->browseBtn, &QPushButton::clicked, [=]() {
|
||||
FileDirDialog dialog(this);
|
||||
|
@ -437,80 +486,6 @@ void MainWindow::initSlots()
|
|||
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)
|
||||
{
|
||||
m_inContinueNote = false;
|
||||
|
@ -552,5 +527,6 @@ void MainWindow::insertContinueNote(const QString& text)
|
|||
m_cursor.movePosition(QTextCursor::End);
|
||||
QTextCharFormat textCharFormat = m_cursor.charFormat();
|
||||
textCharFormat.setForeground(QColor(0,255,0));
|
||||
m_cursor.insertText(text + '\n', textCharFormat);
|
||||
m_cursor.insertText(text, textCharFormat);
|
||||
m_cursor.insertBlock();
|
||||
}
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
#include <QTextCursor>
|
||||
#include <memory>
|
||||
#include "DownloadManager.hpp"
|
||||
#include "LaunchMenu.hpp"
|
||||
#include "Common.hpp"
|
||||
#include "hecl/Runtime.hpp"
|
||||
#include "hecl/CVarCommons.hpp"
|
||||
class QTextEdit;
|
||||
class QTextCharFormat;
|
||||
class QPushButton;
|
||||
class QuaZip;
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
|
@ -18,6 +22,9 @@ class MainWindow;
|
|||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
hecl::Runtime::FileStoreManager m_fileMgr;
|
||||
hecl::CVarManager m_cvarManager;
|
||||
hecl::CVarCommons m_cvarCommons;
|
||||
Ui::MainWindow* m_ui;
|
||||
QTextCursor m_cursor;
|
||||
QString m_path;
|
||||
|
@ -25,6 +32,7 @@ class MainWindow : public QMainWindow
|
|||
QString m_heclPath;
|
||||
QProcess m_heclProc;
|
||||
DownloadManager m_dlManager;
|
||||
LaunchMenu m_launchMenu;
|
||||
QSettings m_settings;
|
||||
URDEVersion m_recommendedVersion;
|
||||
QPushButton* m_updateURDEButton;
|
||||
|
@ -50,8 +58,8 @@ private:
|
|||
void setPath(const QString& path);
|
||||
void initSlots();
|
||||
void onIndexDownloaded(const QStringList& index);
|
||||
void onBinaryDownloaded(const QString& file);
|
||||
void onBinaryFailed(const QString& file);
|
||||
void onBinaryDownloaded(QuaZip& file);
|
||||
void onBinaryFailed();
|
||||
void disableOperations();
|
||||
void enableOperations();
|
||||
};
|
||||
|
|
|
@ -21,6 +21,74 @@
|
|||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<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>&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">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
|
@ -34,10 +102,10 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="5">
|
||||
<item row="1" column="0" colspan="6">
|
||||
<widget class="QTabWidget" name="heclTabs">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="dataTab">
|
||||
<attribute name="title">
|
||||
|
@ -216,7 +284,7 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
|
@ -637,7 +705,7 @@
|
|||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'.SF NS Text'; font-size:13pt; font-weight:400; font-style:normal;">
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.14286pt; font-weight:400; font-style:normal;">
|
||||
<p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Noto Sans'; font-size:10pt; font-weight:600;">About HECL Frontend</span></p>
|
||||
<p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Noto Sans'; font-size:10pt;"><br />The hecl frontend UI is designed and built by </span><a href="https://axiodl.com"><span style=" font-family:'Noto Sans'; font-size:10pt; text-decoration: underline; color:#007af4;">Axiomatic Data Laboratories</span></a><span style=" font-family:'Noto Sans'; font-size:10pt;"> Copyright 2018<br /><br /></span><span style=" font-family:'Noto Sans'; font-size:10pt; font-weight:600;">Authors:</span><span style=" font-family:'Noto Sans'; font-size:10pt;"><br />Phillip &quot;Antidote&quot; Stephens<br />Jack &quot;jackoalan&quot; Andersen</span></p>
|
||||
<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New'; font-size:10pt;">The MIT License</span></p>
|
||||
|
@ -665,6 +733,12 @@ p, li { white-space: pre-wrap; }
|
|||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Extract</string>
|
||||
</property>
|
||||
|
@ -675,22 +749,18 @@ p, li { white-space: pre-wrap; }
|
|||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Package</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QPushButton" name="launchBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Launch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<item row="2" column="5">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
|
@ -703,7 +773,7 @@ p, li { white-space: pre-wrap; }
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="5">
|
||||
<item row="0" column="0" colspan="6">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
|
@ -760,7 +830,6 @@ p, li { white-space: pre-wrap; }
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <QJsonArray>
|
||||
#include <QDomDocument>
|
||||
#include <QProcess>
|
||||
#include <QStorageInfo>
|
||||
#include "FindBlender.hpp"
|
||||
|
||||
#if _WIN32
|
||||
#include <Windows.h>
|
||||
|
@ -84,6 +86,22 @@ SysReqTableModel::SysReqTableModel(QObject* parent)
|
|||
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
|
||||
/* This only works for Skylake+ */
|
||||
int regs[4] = {};
|
||||
|
@ -115,11 +133,32 @@ SysReqTableModel::SysReqTableModel(QObject* parent)
|
|||
#elif __linux__
|
||||
m_osVersion = QStringLiteral("Linux");
|
||||
#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
|
||||
{
|
||||
return 5;
|
||||
return 7;
|
||||
}
|
||||
|
||||
int SysReqTableModel::columnCount(const QModelIndex& parent) const
|
||||
|
@ -145,6 +184,8 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
|
|||
case 2:
|
||||
return m_memorySize >= 0xC0000000;
|
||||
case 3:
|
||||
return m_freeDiskSpace >= qint64(16) * 1000 * 1000 * 1000;
|
||||
case 4:
|
||||
#ifdef __APPLE__
|
||||
return m_macosMajor > 10 || m_macosMinor >= 9;
|
||||
#elif defined(_WIN32)
|
||||
|
@ -152,6 +193,8 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
|
|||
#else
|
||||
return true;
|
||||
#endif
|
||||
case 5:
|
||||
return isBlenderVersionOk();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -172,6 +215,8 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
|
|||
case 2:
|
||||
return QStringLiteral("3 GB");
|
||||
case 3:
|
||||
return QStringLiteral("16 GB (MP1)");
|
||||
case 4:
|
||||
#ifdef __APPLE__
|
||||
return QStringLiteral("macOS 10.9");
|
||||
#elif defined(_WIN32)
|
||||
|
@ -181,6 +226,8 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
|
|||
#else
|
||||
return {};
|
||||
#endif
|
||||
case 5:
|
||||
return QStringLiteral("Blender 2.78");
|
||||
}
|
||||
}
|
||||
else if (index.column() == 1)
|
||||
|
@ -199,7 +246,11 @@ QVariant SysReqTableModel::data(const QModelIndex& index, int role) const
|
|||
case 2:
|
||||
return m_memorySizeStr;
|
||||
case 3:
|
||||
return m_freeDiskSpaceStr;
|
||||
case 4:
|
||||
return m_osVersion;
|
||||
case 5:
|
||||
return m_blendVersionStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,8 +287,12 @@ QVariant SysReqTableModel::headerData(int section, Qt::Orientation orientation,
|
|||
case 2:
|
||||
return QStringLiteral("Memory");
|
||||
case 3:
|
||||
return QStringLiteral("OS");
|
||||
return QStringLiteral("Disk Space");
|
||||
case 4:
|
||||
return QStringLiteral("OS");
|
||||
case 5:
|
||||
return QStringLiteral("Blender");
|
||||
case 6:
|
||||
return QStringLiteral("Vector ISA");
|
||||
}
|
||||
}
|
||||
|
@ -248,9 +303,17 @@ void SysReqTableView::paintEvent(QPaintEvent* e)
|
|||
int tableWidth = columnWidth(0) + columnWidth(1);
|
||||
int tableX = verticalHeader()->width() + columnViewportPosition(0);
|
||||
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]);
|
||||
|
||||
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]);
|
||||
QPropertyAnimation* pAnimation = static_cast<QPropertyAnimation*>(animation->animationAt(1));
|
||||
bool& running = std::get<2>(m_backgroundWidgets[i]);
|
||||
|
@ -274,15 +337,15 @@ SysReqTableView::SysReqTableView(QWidget* parent)
|
|||
: QTableView(parent), m_vectorISATable(this)
|
||||
{
|
||||
setModel(&m_model);
|
||||
setIndexWidget(m_model.index(4, 0), &m_vectorISATable);
|
||||
setSpan(4, 0, 1, 2);
|
||||
setIndexWidget(m_model.index(6, 0), &m_vectorISATable);
|
||||
setSpan(6, 0, 1, 2);
|
||||
|
||||
horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
setSelectionMode(QAbstractItemView::SelectionMode::NoSelection);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
QWidget* w = new QWidget(this);
|
||||
std::get<0>(m_backgroundWidgets[i]) = w;
|
||||
|
|
|
@ -13,6 +13,8 @@ class SysReqTableModel : public QAbstractTableModel
|
|||
QString m_cpuSpeedStr;
|
||||
uint64_t m_memorySize = 0;
|
||||
QString m_memorySizeStr;
|
||||
qint64 m_freeDiskSpace = 0;
|
||||
QString m_freeDiskSpaceStr = QStringLiteral("<Set Working Directory>");
|
||||
#if __APPLE__
|
||||
int m_macosMajor = 0;
|
||||
int m_macosMinor = 0;
|
||||
|
@ -21,12 +23,18 @@ class SysReqTableModel : public QAbstractTableModel
|
|||
bool m_win7SP1OrGreater = false;
|
||||
#endif
|
||||
QString m_osVersion;
|
||||
int m_blendMajor = 0;
|
||||
int m_blendMinor = 0;
|
||||
QString m_blendVersionStr;
|
||||
public:
|
||||
SysReqTableModel(QObject* parent = Q_NULLPTR);
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, 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
|
||||
|
@ -34,7 +42,7 @@ class SysReqTableView : public QTableView
|
|||
Q_OBJECT
|
||||
SysReqTableModel m_model;
|
||||
VectorISATableView m_vectorISATable;
|
||||
std::tuple<QWidget*, QSequentialAnimationGroup*, bool> m_backgroundWidgets[4] = {};
|
||||
std::tuple<QWidget*, QSequentialAnimationGroup*, bool> m_backgroundWidgets[6] = {};
|
||||
public:
|
||||
SysReqTableView(QWidget* parent = Q_NULLPTR);
|
||||
void paintEvent(QPaintEvent* e) Q_DECL_OVERRIDE;
|
||||
|
@ -45,6 +53,8 @@ public:
|
|||
return v.getArchitecture() == CurArchitecture && v.getPlatform() == CurPlatform &&
|
||||
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
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
void VectorISATableView::paintEvent(QPaintEvent* e)
|
||||
{
|
||||
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);
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
|
@ -89,7 +89,7 @@ VectorISATableView::VectorISATableView(QWidget* parent)
|
|||
|
||||
QSequentialAnimationGroup* seq = new QSequentialAnimationGroup(this);
|
||||
std::get<1>(m_backgroundWidgets[i]) = seq;
|
||||
seq->addPause(4 * 100);
|
||||
seq->addPause(6 * 100);
|
||||
seq->addAnimation(animation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,13 +28,13 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
InitializePlatform();
|
||||
|
||||
QApplication a(argc, argv);
|
||||
a.setStyle(QStyleFactory::create("Fusion"));
|
||||
#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
|
||||
a.setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
a.setWindowIcon(MakeAppIcon());
|
||||
QApplication::setStyle(QStyleFactory::create("Fusion"));
|
||||
QApplication a(argc, argv);
|
||||
QApplication::setWindowIcon(MakeAppIcon());
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, QColor(53,53,53));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?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">
|
||||
<description> my exe </description>
|
||||
<description>HECL-GUI</description>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
|
@ -15,4 +15,9 @@
|
|||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||
<dpiAware>true/PM</dpiAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit cf36e59d2ad38bac63447d02f1b1833276099ec0
|
Loading…
Reference in New Issue