#include "SysReqTableView.hpp" #include #include #include #include #include #include #include #include #include #include "FindBlender.hpp" #if _WIN32 #include #include #else #include #endif #if __APPLE__ #include "MacOSSystemVersion.hpp" #elif _WIN32 static QString GetWindowsVersionString() { if (IsWindows10OrGreater()) return QStringLiteral("Windows 10"); else if (IsWindows8Point1OrGreater()) return QStringLiteral("Windows 8.1"); else if (IsWindows8OrGreater()) return QStringLiteral("Windows 8"); else if (IsWindows7SP1OrGreater()) return QStringLiteral("Windows 7 SP1"); else if (IsWindows7OrGreater()) return QStringLiteral("Windows 7"); else if (IsWindowsVistaOrGreater()) return QStringLiteral("Windows Vista"); else if (IsWindowsXPOrGreater()) return QStringLiteral("Windows XP"); else return QStringLiteral("Windows Old And Won't Work"); } #endif SysReqTableModel::SysReqTableModel(QObject* parent) : QAbstractTableModel(parent) { #ifdef __linux__ QProcess lscpuProc; lscpuProc.start("lscpu", {"-J"}, QProcess::ReadOnly); lscpuProc.waitForFinished(); QJsonDocument lscpu = QJsonDocument::fromJson(lscpuProc.readAll()); QJsonValue lscpuObj = lscpu.object().take("lscpu"); if (lscpuObj.type() == QJsonValue::Array) { for (const QJsonValue& v: lscpuObj.toArray()) { QJsonObject vObj = v.toObject(); if (vObj.take("field").toString() == "CPU MHz:") { double speed = vObj.take("data").toString().toDouble(); m_cpuSpeed = speed; m_cpuSpeedStr.sprintf("%g GHz", speed / 1000.0); } } } #elif defined(__APPLE__) QProcess spProc; spProc.start("system_profiler", {"-xml", "SPHardwareDataType"}, QProcess::ReadOnly); spProc.waitForFinished(); QDomDocument spDoc; spDoc.setContent(spProc.readAll()); QDomElement spDocElem = spDoc.documentElement(); QDomElement n = spDocElem.firstChildElement("array").firstChildElement("dict").firstChildElement("key"); while (!n.isNull() && n.text() != "_items") n = n.nextSiblingElement("key"); if (!n.isNull()) { n = n.nextSiblingElement("array").firstChildElement("dict").firstChildElement("key"); while (!n.isNull() && n.text() != "current_processor_speed") n = n.nextSiblingElement("key"); if (!n.isNull()) { n = n.nextSiblingElement("string"); double speed = n.text().split(' ').front().toDouble(); m_cpuSpeed = uint64_t(speed * 1000.0); 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] = {}; zeus::getCpuInfo(0, regs); if (regs[0] >= 0x16) { zeus::getCpuInfo(0x16, regs); m_cpuSpeed = uint64_t(regs[0]); } m_cpuSpeedStr.sprintf("%g GHz", m_cpuSpeed / 1000.f); #endif #if _WIN32 ULONGLONG memSize; GetPhysicallyInstalledSystemMemory(&memSize); m_memorySize = memSize * 1024; #else m_memorySize = uint64_t(sysconf(_SC_PHYS_PAGES)) * sysconf(_SC_PAGESIZE); #endif m_memorySizeStr.sprintf("%g GiB", m_memorySize / 1024.f / 1024.f / 1024.f); #ifdef __APPLE__ GetMacOSSystemVersion(m_macosMajor, m_macosMinor, m_macosPatch); if (m_macosPatch == 0) m_osVersion.sprintf("macOS %d.%d", m_macosMajor, m_macosMinor); else m_osVersion.sprintf("macOS %d.%d.%d", m_macosMajor, m_macosMinor, m_macosPatch); #elif _WIN32 m_win7SP1OrGreater = IsWindows7SP1OrGreater(); m_osVersion = GetWindowsVersionString(); #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(""); } 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 7; } int SysReqTableModel::columnCount(const QModelIndex& parent) const { return 2; } QVariant SysReqTableModel::data(const QModelIndex& index, int role) const { if (role != Qt::DisplayRole && role != Qt::UserRole) { return {}; } if (role == Qt::UserRole) { switch (index.row()) { case 0: return true; case 1: return m_cpuSpeed >= 1500; 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) return m_win7SP1OrGreater; #else return true; #endif case 5: return isBlenderVersionOk(); } } else { if (index.column() == 0) { /* Recommended */ switch (index.row()) { case 0: #if ZEUS_ARCH_X86 || ZEUS_ARCH_X86_64 return QStringLiteral("x86_64"); #else return {}; #endif case 1: return QStringLiteral("1.5 GHz"); case 2: return QStringLiteral("3 GiB"); case 3: return QStringLiteral("16 GB (MP1)"); case 4: #ifdef __APPLE__ return QStringLiteral("macOS 10.9"); #elif defined(_WIN32) return QStringLiteral("Windows 7 SP1"); #elif defined(__linux__) return QStringLiteral("Linux"); #else return {}; #endif case 5: return QStringLiteral("Blender 2.78"); } } else if (index.column() == 1) { /* Your System */ switch (index.row()) { case 0: #if ZEUS_ARCH_X86 || ZEUS_ARCH_X86_64 return CurArchitectureString; #else return {}; #endif case 1: return m_cpuSpeedStr; case 2: return m_memorySizeStr; case 3: return m_freeDiskSpaceStr; case 4: return m_osVersion; case 5: return m_blendVersionStr; } } } return {}; } QVariant SysReqTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return {}; } if (orientation == Qt::Horizontal) { switch (section) { case 0: default: return QStringLiteral("Recommended"); case 1: return QStringLiteral("Your System"); } } else { switch (section) { case 0: default: return QStringLiteral("Architecture"); case 1: return QStringLiteral("CPU Speed"); case 2: return QStringLiteral("Memory"); case 3: return QStringLiteral("Disk Space"); case 4: return QStringLiteral("OS"); case 5: return QStringLiteral("Blender"); case 6: return QStringLiteral("Vector ISA"); } } } 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 < 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(animation->animationAt(1)); bool& running = std::get<2>(m_backgroundWidgets[i]); if (!running) { w->setGeometry(QRect(tableX, tableY + rowViewportPosition(i), 0, rowHeight(i))); pAnimation->setStartValue(QRect(tableX, tableY + rowViewportPosition(i), 0, rowHeight(i))); pAnimation->setEndValue(QRect(tableX, tableY + rowViewportPosition(i), tableWidth, rowHeight(i))); animation->start(); running = true; } if (animation->state() == QAbstractAnimation::State::Running) pAnimation->setEndValue(QRect(tableX, tableY + rowViewportPosition(i), tableWidth, rowHeight(i))); else w->setGeometry(QRect(tableX, tableY + rowViewportPosition(i), tableWidth, rowHeight(i))); } QTableView::paintEvent(e); } SysReqTableView::SysReqTableView(QWidget* parent) : QTableView(parent), m_vectorISATable(this) { setModel(&m_model); 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 < 6; ++i) { QWidget* w = new QWidget(this); std::get<0>(m_backgroundWidgets[i]) = w; 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->setAutoFillBackground(true); w->setPalette(pal); w->lower(); w->show(); QPropertyAnimation* animation = new QPropertyAnimation(w, "geometry", this); animation->setDuration(2000); animation->setEasingCurve(QEasingCurve::Type::InOutCubic); QSequentialAnimationGroup* seq = new QSequentialAnimationGroup(this); std::get<1>(m_backgroundWidgets[i]) = seq; seq->addPause(i * 100); seq->addAnimation(animation); } }