src/mainwindow.cpp

Tue, 11 Apr 2023 20:27:04 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Tue, 11 Apr 2023 20:27:04 +0300
changeset 375
21a5ecbe34e4
parent 362
e1d646a4cbd8
permissions
-rw-r--r--

Simplify signature of updateRenderPreferences

#include "src/mainwindow.h"
#include "src/modelsubwindow.h"
#include "src/version.h"
#include <QTextBrowser>
#include <QOpenGLWidget>
#include <ui_about.h>
#include "src/settings.h"

static constexpr MemberData<MainWindow, QAction*, gl::RenderStyle> renderStyleButtons[] = {
	{ offsetof(MainWindow, actionRenderStyleNormal), gl::RenderStyle::Normal },
	{ offsetof(MainWindow, actionRenderStyleBfc), gl::RenderStyle::BfcRedGreen },
	{ offsetof(MainWindow, actionRenderStyleRandom), gl::RenderStyle::RandomColors },
	{ offsetof(MainWindow, actionRenderStylePickScene), gl::RenderStyle::PickScene },
};

MainWindow::MainWindow(QWidget *parent)
: QMainWindow{parent}
{
	this->setupUi(this);
	for (const auto& memberData : ::renderStyleButtons)
	{
		QAction* action = memberData.memberInstance(this);
		const gl::RenderStyle newStyle = memberData.payload;
		QObject::connect(action, &QAction::triggered, [this, newStyle]{
			Q_EMIT this->renderStyleSelected(newStyle);
			this->setRenderStyle(newStyle);
		});
	}
	this->connect(this->actionAbout, &QAction::triggered, this, &MainWindow::showAboutDialog);
	this->connect(this->mdiArea, &QMdiArea::subWindowActivated, this, &MainWindow::updateTitle);
	this->gridMatrix->setValue(DEFAULT_GRID_MATRIX);
	this->tabifyDockWidget(this->messageLogDock, this->toolOptionsDock);
	this->restoreGeometry(setting<Setting::MainWindowGeometry>());
	this->restoreState(setting<Setting::MainWindowState>());
	// If a dock is made floating and the app is closed, the dock becomes invisible
	// after the restoreState call. So we make them visible again here.
	for (QDockWidget* dock : this->findChildren<QDockWidget*>()) {
		dock->setVisible(true);
	}
	this->actionAbout->setText(this->actionAbout->text().arg(CMAKE_PROJECT_NAME));
	this->updateTitle();
	this->show();
}

void MainWindow::setRenderStyle(gl::RenderStyle style)
{
	for (const auto& memberData : ::renderStyleButtons)
	{
		QAction* const action = memberData.memberInstance(this);
		const gl::RenderStyle buttonRenderStyle = memberData.payload;
		action->setChecked(style == buttonRenderStyle);
	}
}

static QStringList getGLExtensions(QWidget* parent)
{
	// We need to have GL activated at least once in order to able to retrieve
	// GL extensions properly. To make sure this is the case, we create a
	// temporary, plain OpenGL widget. While it is active, we call glewInit().
	// If this is not done, this function will crash.
	QOpenGLWidget glWidget{parent};
	glWidget.show();
	glewInit();
	GLint numExtensions;
	glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
	QStringList extensionsList;
	for (GLint i = 0; i < numExtensions; i++) {
		const GLubyte* ext = glGetStringi(GL_EXTENSIONS, i);
		extensionsList.push_back(reinterpret_cast<const char*>(ext));
	}
	glWidget.hide();
	return extensionsList;
}

void MainWindow::showAboutDialog()
{
	QDialog dialog{this};
	Ui_About ui;
	ui.setupUi(&dialog);
	const char* glVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
	const QString extensions = getGLExtensions(this).join(" ");
	for (QTextBrowser* browser : dialog.findChildren<QTextBrowser*>()) {
		browser->setHtml(
			browser->toHtml()
			.replace("%APPNAME%", CMAKE_PROJECT_NAME)
			.replace("%COPYRIGHT%", COPYRIGHT)
			.replace("%QTVERSION%", qVersion())
			.replace("%VERSION%", detailedVersionString(QLocale::LongFormat))
			.replace("%REVDATE%", revisionDateString(QLocale::LongFormat))
			.replace("%BUILDTYPE%", CMAKE_BUILD_TYPE)
			.replace("%COMPILER_ID%", CMAKE_CXX_COMPILER_ID)
			.replace("%COMPILER_VERSION%", CMAKE_CXX_COMPILER_VERSION)
			.replace("%COMPILER_FLAGS%", CMAKE_CXX_FLAGS)
			.replace("%COMPILER_CPU%", CMAKE_SYSTEM_PROCESSOR)
			.replace("%COMPILER_SYSTEM%", CMAKE_SYSTEM)
			.replace("%GLMVERSIONSTRING%", GLM_VERSION_MESSAGE)
			.replace("%GL_VERSION%", glVersion)
			.replace("%GL_EXTENSIONS%", extensions)
		);
	}
	dialog.setWindowTitle(QObject::tr("About %1").arg(CMAKE_PROJECT_NAME));
	dialog.exec();
}

void MainWindow::rebuildRecentFilesMenu(const QStringList& strings)
{
	this->menuRecentFiles->clear();
	for (const QString& path : strings)
	{
		QAction* action = new QAction{path, this};
		this->menuRecentFiles->addAction(action);
		connect(action, &QAction::triggered, [&, path]{
			Q_EMIT this->recentFileSelected(path);
		});
	}
}

static QString title(MainWindow* ui)
{
	QMdiSubWindow* subWindow = ui->mdiArea->activeSubWindow();
	QString titlestring;
	const QString versionString = fullVersionString(QLocale::ShortFormat);
	if (subWindow != nullptr) {
		titlestring = QObject::tr("%1 - %2").arg(subWindow->windowTitle(), versionString);
	}
	else {
		titlestring = versionString;
	}
	if (/* DISABLES CODE */ (true)
		and std::strcmp(CMAKE_BUILD_TYPE, "Release") != 0
		and std::strcmp(CMAKE_BUILD_TYPE, "MinSizeRel") != 0
	) {
		titlestring += QObject::tr(" [%1]").arg(CMAKE_BUILD_TYPE);
	}
	return titlestring;
}

void MainWindow::updateTitle()
{
	this->setWindowTitle(title(this));
}

mercurial