# HG changeset patch # User Teemu Piippo # Date 1680961300 -10800 # Node ID 91053052bb28688487e645c1432690844e0ad7f9 # Parent c229d38f04c624daa31621c589548e99af658b56 Readd the MainWindow class and renderstyle button handling to it diff -r c229d38f04c6 -r 91053052bb28 CMakeLists.txt --- a/CMakeLists.txt Sat Apr 08 16:12:12 2023 +0300 +++ b/CMakeLists.txt Sat Apr 08 16:41:40 2023 +0300 @@ -72,6 +72,7 @@ src/inputvertices.cpp src/invert.cpp src/main.cpp + src/mainwindow.cpp src/messagelog.cpp src/model.cpp src/parser.cpp @@ -105,6 +106,7 @@ src/ldrawalgorithm.h src/ldrawsyntaxhighlighter.h src/libraries.h + src/mainwindow.h src/messagelog.h src/model.h src/parser.h diff -r c229d38f04c6 -r 91053052bb28 src/basics.h --- a/src/basics.h Sat Apr 08 16:12:12 2023 +0300 +++ b/src/basics.h Sat Apr 08 16:41:40 2023 +0300 @@ -345,3 +345,14 @@ { return Message{.time = QDateTime::currentDateTime(), .type = Message::Error, .text = text}; } + +template +struct MemberData +{ + std::size_t member; + DataType payload; + constexpr MemberType memberInstance(BaseType* instance) const + { + return *reinterpret_cast(reinterpret_cast(instance) + this->member); + } +}; diff -r c229d38f04c6 -r 91053052bb28 src/main.cpp --- a/src/main.cpp Sat Apr 08 16:12:12 2023 +0300 +++ b/src/main.cpp Sat Apr 08 16:41:40 2023 +0300 @@ -8,12 +8,12 @@ #include #include #include -#include #include "src/gl/partrenderer.h" #include "src/layers/axeslayer.h" #include "src/layers/edittools.h" #include "src/layers/gridlayer.h" #include "src/ldrawalgorithm.h" +#include "src/mainwindow.h" #include "src/messagelog.h" #include "src/settings.h" #include "src/settingseditor/settingseditor.h" @@ -90,24 +90,6 @@ #endif } -template -struct MemberData -{ - std::size_t member; - DataType payload; - constexpr MemberType memberInstance(BaseType* instance) const - { - return *reinterpret_cast(reinterpret_cast(instance) + this->member); - } -}; - -static constexpr MemberData renderStyleButtons[] = { - { offsetof(Ui_MainWindow, actionRenderStyleNormal), gl::RenderStyle::Normal }, - { offsetof(Ui_MainWindow, actionRenderStyleBfc), gl::RenderStyle::BfcRedGreen }, - { offsetof(Ui_MainWindow, actionRenderStyleRandom), gl::RenderStyle::RandomColors }, - { offsetof(Ui_MainWindow, actionRenderStylePickScene), gl::RenderStyle::PickScene }, -}; - static std::optional openModelFromPath( const QString& path, const LibrariesModel* libraries, @@ -153,13 +135,13 @@ return documents->findPayload(modelId); } -static ModelSubWindow* currentModelSubWindow(Ui_MainWindow* ui) +static ModelSubWindow* currentModelSubWindow(MainWindow* ui) { auto* w = ui->mdiArea->activeSubWindow(); return qobject_cast(w); } -static ModelData* currentModelData(Ui_MainWindow* ui, const DocumentManager* documents) +static ModelData* currentModelData(MainWindow* ui, const DocumentManager* documents) { if (auto* const activeSubWindow = currentModelSubWindow(ui)) { return findModelData(documents, activeSubWindow->modelId); @@ -169,7 +151,7 @@ } } -static std::optional findCurrentModelId(Ui_MainWindow* ui) +static std::optional findCurrentModelId(MainWindow* ui) { ModelSubWindow* activeSubWindow = qobject_cast(ui->mdiArea->activeSubWindow()); if (activeSubWindow != nullptr) { @@ -180,7 +162,7 @@ } } -static QString title(Ui_MainWindow* ui) +static QString title(MainWindow* ui) { QMdiSubWindow* subWindow = ui->mdiArea->activeSubWindow(); QString titlestring; @@ -238,7 +220,7 @@ } static void updateRenderPreferences( - Ui_MainWindow* ui, + MainWindow* ui, const gl::RenderPreferences* renderPreferences, const DocumentManager* documents) { @@ -248,10 +230,7 @@ data->canvas->setLayerEnabled(data->axesLayer.get(), renderPreferences->drawAxes); } }); - for (auto data : ::renderStyleButtons) { - QAction* action = data.memberInstance(ui); - action->setChecked(renderPreferences->style == data.payload); - } + ui->setRenderStyle(renderPreferences->style); ui->actionDrawAxes->setChecked(renderPreferences->drawAxes); ui->actionWireframe->setChecked(renderPreferences->wireframe); } @@ -275,7 +254,7 @@ CircleToolOptionsWidget* circleToolOptions; }; -static void initializeTools(Ui_MainWindow* ui, ToolWidgets* toolWidgets, QWidget* parent) +static void initializeTools(MainWindow* ui, ToolWidgets* toolWidgets, QWidget* parent) { const struct { @@ -405,8 +384,7 @@ doQtRegistrations(); QApplication app{argc, argv}; QApplication::setWindowIcon(QIcon{":/icons/appicon.png"}); - QMainWindow mainWindow; - Ui_MainWindow ui; + MainWindow mainWindow; DocumentManager documents; QString currentLanguage = "en"; QTranslator translator{&mainWindow}; @@ -416,12 +394,11 @@ gl::RenderPreferences renderPreferences; MessageLog messageLog; Signal settingsChanged; - ui.setupUi(&mainWindow); ToolWidgets toolWidgets{ .circleToolOptions = new CircleToolOptionsWidget{&mainWindow}, }; - const auto updateTitle = [&ui, &mainWindow]{ - mainWindow.setWindowTitle(title(&ui)); + const auto updateTitle = [&mainWindow]{ + mainWindow.setWindowTitle(title(&mainWindow)); }; const uiutilities::KeySequenceMap defaultKeyboardShortcuts = uiutilities::makeKeySequenceMap(uiutilities::collectActions(&mainWindow)); @@ -447,8 +424,7 @@ &mainWindow, &messageLog, &renderPreferences, - &settingsChanged, - &ui] + &settingsChanged] (const ModelId modelId) { QTextDocument* model = documents.getModelById(modelId); @@ -514,7 +490,7 @@ &QWidget::setCursor); data->tools->setEditMode(SelectMode); const QFileInfo fileInfo{*documents.modelPath(modelId)}; - auto* const subWindow = createSubWindow(ui.mdiArea, modelId); + auto* const subWindow = createSubWindow(mainWindow.mdiArea, modelId); subWindow->setMinimumSize({96, 96}); subWindow->resize({320, 200}); subWindow->setWidget(data->canvas.get()); @@ -527,11 +503,10 @@ &libraries, &mainWindow, &openModelForEditing, - &recentlyOpenedFiles, - &ui] + &recentlyOpenedFiles] { - rebuildRecentFilesMenu(ui.menuRecentFiles, recentlyOpenedFiles, &mainWindow); - for (QAction* action : ui.menuRecentFiles->actions()) { + rebuildRecentFilesMenu(mainWindow.menuRecentFiles, recentlyOpenedFiles, &mainWindow); + for (QAction* action : mainWindow.menuRecentFiles->actions()) { QString path = action->data().toString(); QObject::connect( action, @@ -554,7 +529,6 @@ &recentlyOpenedFiles, &renderPreferences, &settingsChanged, - &ui, &updateRecentlyOpenedDocumentsMenu] { recentlyOpenedFiles = setting(); @@ -562,9 +536,9 @@ libraries.restoreFromSettings(); updateRecentlyOpenedDocumentsMenu(); colorTable = loadColors(&libraries); - updateRenderPreferences(&ui, &renderPreferences, &documents); - ui.mdiArea->setViewMode(setting()); - ui.retranslateUi(&mainWindow); + updateRenderPreferences(&mainWindow, &renderPreferences, &documents); + mainWindow.mdiArea->setViewMode(setting()); + mainWindow.retranslateUi(&mainWindow); mainWindow.setToolButtonStyle(setting()); settingsChanged.emit(); }; @@ -584,12 +558,12 @@ saveSettings(); updateRecentlyOpenedDocumentsMenu(); }; - QObject::connect(ui.actionNew, &QAction::triggered, + QObject::connect(mainWindow.actionNew, &QAction::triggered, [&documents, &openModelForEditing]{ openModelForEditing(documents.newModel()); } ); - QObject::connect(ui.actionOpen, &QAction::triggered, + QObject::connect(mainWindow.actionOpen, &QAction::triggered, [&addRecentlyOpenedFile, &documents, &libraries, &mainWindow, &openModelForEditing] { const QString path = getOpenModelPath(&mainWindow); @@ -603,16 +577,16 @@ } } ); - QObject::connect(ui.actionSettingsEditor, &QAction::triggered, [&defaultKeyboardShortcuts, &restoreSettings, &settingsChanged, &ui]{ - if (ui.mdiArea->findChildren().isEmpty()) { - auto* const settingsEditor = createSubWindow(ui.mdiArea, defaultKeyboardShortcuts); + QObject::connect(mainWindow.actionSettingsEditor, &QAction::triggered, [&defaultKeyboardShortcuts, &restoreSettings, &settingsChanged, &mainWindow]{ + if (mainWindow.mdiArea->findChildren().isEmpty()) { + auto* const settingsEditor = createSubWindow(mainWindow.mdiArea, defaultKeyboardShortcuts); QObject::connect(&settingsChanged, &Signal::triggered, settingsEditor, &SettingsEditor::loadSettings); QObject::connect(settingsEditor, &SettingsEditor::settingsChanged, restoreSettings); settingsEditor->setAttribute(Qt::WA_DeleteOnClose); settingsEditor->show(); } }); - QObject::connect(ui.actionQuit, &QAction::triggered, &mainWindow, &QMainWindow::close); + QObject::connect(mainWindow.actionQuit, &QAction::triggered, &mainWindow, &QMainWindow::close); #if 0 QObject::connect(ui.actionAdjustGridToView, &QAction::triggered, [&]{ if (ModelData* data = currentModelData(&ui, &documents)) { @@ -620,29 +594,29 @@ } }); #endif - QObject::connect(ui.actionClose, &QAction::triggered, [&ui, &documents]{ - if (ModelData* data = currentModelData(&ui, &documents)) { + QObject::connect(mainWindow.actionClose, &QAction::triggered, [&mainWindow, &documents]{ + if (ModelData* data = currentModelData(&mainWindow, &documents)) { // TODO } }); - const auto save = [&addRecentlyOpenedFile, &documents, &mainWindow](ModelId modelId){ + const auto save = [&addRecentlyOpenedFile, &mainWindow](DocumentManager* documents, ModelId modelId){ QString error; QTextStream errorStream{&error}; - const bool succeeded = documents.saveModel(modelId, errorStream); + const bool succeeded = documents->saveModel(modelId, errorStream); if (not succeeded) { QMessageBox::critical(&mainWindow, QObject::tr("Save error"), error); } else { - const QString* pathPtr = documents.modelPath(modelId); + const QString* pathPtr = documents->modelPath(modelId); if (pathPtr != nullptr) { addRecentlyOpenedFile(*pathPtr); } } - };; - const auto actionSaveAs = [&documents, &libraries, &mainWindow, &save, &ui]{ - const std::optional modelId = findCurrentModelId(&ui); + }; + const auto actionSaveAs = [&documents, &libraries, &mainWindow, &save]{ + const std::optional modelId = findCurrentModelId(&mainWindow); if (modelId.has_value()) { const QString* pathPtr = documents.modelPath(*modelId); @@ -657,88 +631,91 @@ QString error; QTextStream errorStream{&error}; documents.setModelPath(*modelId, newPath, libraries, errorStream); - QMdiSubWindow* const subWindow = ui.mdiArea->currentSubWindow(); + QMdiSubWindow* const subWindow = mainWindow.mdiArea->currentSubWindow(); if (subWindow != nullptr) { subWindow->setWindowTitle(tabName(QFileInfo{newPath})); } - save(*modelId); + save(&documents, *modelId); } } }; - QObject::connect(ui.actionSaveAs, &QAction::triggered, actionSaveAs); - QObject::connect(ui.actionSave, &QAction::triggered, [ + QObject::connect(mainWindow.actionSaveAs, &QAction::triggered, actionSaveAs); + QObject::connect(mainWindow.actionSave, &QAction::triggered, [ &actionSaveAs, &documents, &save, - &ui] + &mainWindow] { - const std::optional modelId = findCurrentModelId(&ui); + const std::optional modelId = findCurrentModelId(&mainWindow); if (modelId.has_value()) { const QString* path = documents.modelPath(*modelId); if (path == nullptr or path->isEmpty()) { actionSaveAs(); } else { - save(*modelId); + save(&documents, *modelId); } } }); - QObject::connect(ui.actionDrawAxes, &QAction::triggered, [ + QObject::connect(mainWindow.actionDrawAxes, &QAction::triggered, [ &documents, &renderPreferences, &saveSettings, - &ui] + &mainWindow] (bool drawAxes) { renderPreferences.drawAxes = drawAxes; saveSettings(); - updateRenderPreferences(&ui, &renderPreferences, &documents); + updateRenderPreferences(&mainWindow, &renderPreferences, &documents); }); - QObject::connect(ui.actionWireframe, &QAction::triggered, [ + QObject::connect(mainWindow.actionWireframe, &QAction::triggered, [ &documents, &renderPreferences, &saveSettings, - &ui] + &mainWindow] (bool enabled) { renderPreferences.wireframe = enabled; saveSettings(); - updateRenderPreferences(&ui, &renderPreferences, &documents); + updateRenderPreferences(&mainWindow, &renderPreferences, &documents); }); - for (auto data : ::renderStyleButtons) { - QAction* action = data.memberInstance(&ui); - QObject::connect(action, &QAction::triggered, [&, data]{ - renderPreferences.style = data.payload; - saveSettings(); - updateRenderPreferences(&ui, &renderPreferences, &documents); - }); - } - const auto checkEditingModeAction = [&ui, &documents](EditingMode mode) { - const bool hasDocument = currentModelData(&ui, &documents) != nullptr; - for (QAction* action : ui.editingModesToolBar->actions()) { + QObject::connect(&mainWindow, &MainWindow::renderStyleSelected, [ + &documents, + &mainWindow, + &renderPreferences, + &saveSettings] + (gl::RenderStyle newStyle) + { + renderPreferences.style = newStyle; + saveSettings(); + updateRenderPreferences(&mainWindow, &renderPreferences, &documents); + }); + const auto checkEditingModeAction = [&mainWindow, &documents](EditingMode mode) { + const bool hasDocument = currentModelData(&mainWindow, &documents) != nullptr; + for (QAction* action : mainWindow.editingModesToolBar->actions()) { action->setEnabled(hasDocument); action->setChecked(hasDocument and action->data().value() == mode); } }; - initializeTools(&ui, &toolWidgets, &mainWindow); - for (QAction* action : ui.editingModesToolBar->actions()) { + initializeTools(&mainWindow, &toolWidgets, &mainWindow); + for (QAction* action : mainWindow.editingModesToolBar->actions()) { QObject::connect(action, &QAction::triggered, [ action, &checkEditingModeAction, &documents, - &ui] + &mainWindow] { - if (ModelData* data = currentModelData(&ui, &documents)) { + if (ModelData* data = currentModelData(&mainWindow, &documents)) { const EditingMode mode = action->data().value(); data->tools->setEditMode(mode); checkEditingModeAction(mode); } }); } - QObject::connect(ui.mdiArea, &QMdiArea::subWindowActivated, [ + QObject::connect(mainWindow.mdiArea, &QMdiArea::subWindowActivated, [ &checkEditingModeAction, &documents, - &ui, + &mainWindow, &updateTitle] (QMdiSubWindow* subWindow) { @@ -746,42 +723,42 @@ if (modelSubWindow != nullptr) { if (ModelData* data = documents.findPayload(modelSubWindow->modelId)) { checkEditingModeAction(data->tools->currentEditingMode()); - ui.modelEdit->setDocument(data->model); - ui.modelEdit->setTextCursor(*data->textcursor); + mainWindow.modelEdit->setDocument(data->model); + mainWindow.modelEdit->setTextCursor(*data->textcursor); } } else { checkEditingModeAction(EditingMode::SelectMode); } - ui.modelEdit->setEnabled(modelSubWindow != nullptr); + mainWindow.modelEdit->setEnabled(modelSubWindow != nullptr); updateTitle(); }); - ui.messageLog->setModel(&messageLog); - QObject::connect(ui.actionAboutQt, &QAction::triggered, &app, &QApplication::aboutQt); + mainWindow.messageLog->setModel(&messageLog); + QObject::connect(mainWindow.actionAboutQt, &QAction::triggered, &app, &QApplication::aboutQt); QObject::connect(&documents, &DocumentManager::message, &messageLog, &MessageLog::addMessage); - QObject::connect(&messageLog, &MessageLog::rowsAboutToBeInserted, [&ui]{ - const auto bar = ui.messageLog->verticalScrollBar(); - ui.messageLog->setProperty("shouldAutoScroll", bar->value() == bar->maximum()); + QObject::connect(&messageLog, &MessageLog::rowsAboutToBeInserted, [&mainWindow]{ + const auto bar = mainWindow.messageLog->verticalScrollBar(); + mainWindow.messageLog->setProperty("shouldAutoScroll", bar->value() == bar->maximum()); }); - QObject::connect(&messageLog, &MessageLog::rowsInserted, [&ui]{ - ui.messageLog->resizeRowsToContents(); - if (ui.messageLog->property("shouldAutoScroll").toBool()) { - ui.messageLog->scrollToBottom(); + QObject::connect(&messageLog, &MessageLog::rowsInserted, [&mainWindow]{ + mainWindow.messageLog->resizeRowsToContents(); + if (mainWindow.messageLog->property("shouldAutoScroll").toBool()) { + mainWindow.messageLog->scrollToBottom(); } }); QObject::connect( toolWidgets.circleToolOptions, &CircleToolOptionsWidget::optionsChanged, - [&ui, &documents](const CircleToolOptions& options) { - if (ModelData* data = currentModelData(&ui, &documents)) { + [&mainWindow, &documents](const CircleToolOptions& options) { + if (ModelData* data = currentModelData(&mainWindow, &documents)) { data->tools->setCircleToolOptions(options); } }); QObject::connect( - ui.actionMakeUnofficial, + mainWindow.actionMakeUnofficial, &QAction::triggered, - [&documents, &ui]{ - if (ModelData* data = currentModelData(&ui, &documents)) { + [&documents, &mainWindow]{ + if (ModelData* data = currentModelData(&mainWindow, &documents)) { QTextDocument* const model = data->model; for (const ModelAction& action : ldraw::makeUnofficial(model)) { executeAction(model, action); @@ -789,27 +766,27 @@ } }); QObject::connect( - ui.actionAbout, + mainWindow.actionAbout, &QAction::triggered, - [&mainWindow, &ui]{ + [&mainWindow]{ // Make sure that there's an OpenGL context active, otherwise // we cannot obtain OpenGL information - if (ui.mdiArea->findChildren().empty()) { - ui.actionNew->trigger(); + if (mainWindow.mdiArea->findChildren().empty()) { + mainWindow.actionNew->trigger(); } about(&mainWindow); } ); QObject::connect( - ui.modelEdit, + mainWindow.modelEdit, &QPlainTextEdit::textChanged, - [&documents, &libraries, &ui]{ - if (ModelData* data = currentModelData(&ui, &documents)) { + [&documents, &libraries, &mainWindow]{ + if (ModelData* data = currentModelData(&mainWindow, &documents)) { documents.loadDependenciesForAllModels(libraries); data->canvas->update(); } }); - mainWindow.tabifyDockWidget(ui.messageLogDock, ui.toolOptionsDock); + mainWindow.tabifyDockWidget(mainWindow.messageLogDock, mainWindow.toolOptionsDock); mainWindow.restoreGeometry(setting()); mainWindow.restoreState(setting()); // If a dock is made floating and the app is closed, the dock becomes invisible @@ -818,8 +795,8 @@ dock->setVisible(true); } restoreSettings(); - updateRenderPreferences(&ui, &renderPreferences, &documents); - ui.actionAbout->setText(ui.actionAbout->text().arg(CMAKE_PROJECT_NAME)); + updateRenderPreferences(&mainWindow, &renderPreferences, &documents); + mainWindow.actionAbout->setText(mainWindow.actionAbout->text().arg(CMAKE_PROJECT_NAME)); updateTitle(); mainWindow.show(); const int result = app.exec(); diff -r c229d38f04c6 -r 91053052bb28 src/mainwindow.cpp --- a/src/mainwindow.cpp Sat Apr 08 16:12:12 2023 +0300 +++ b/src/mainwindow.cpp Sat Apr 08 16:41:40 2023 +0300 @@ -1,17 +1,33 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013 - 2020 Teemu Piippo - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +#include "mainwindow.h" + +static constexpr MemberData 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); + }); + } +} + +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); + } +} diff -r c229d38f04c6 -r 91053052bb28 src/mainwindow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mainwindow.h Sat Apr 08 16:41:40 2023 +0300 @@ -0,0 +1,19 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include "ui_mainwindow.h" +#include "src/gl/common.h" + +class MainWindow : public QMainWindow, public Ui_MainWindow +{ + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = nullptr); +Q_SIGNALS: + void renderStyleSelected(gl::RenderStyle newStyle); +public Q_SLOTS: + void setRenderStyle(gl::RenderStyle style); +}; + +#endif // MAINWINDOW_H