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()
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)

View File

@ -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;

View File

@ -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()

View File

@ -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;

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 <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

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 "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();
}

View File

@ -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();
};

View File

@ -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>&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">
<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>&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;
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;&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;
@ -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>&amp;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>&amp;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>&amp;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>

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}

View File

@ -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));

View File

@ -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>

1
hecl-gui/quazip Submodule

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