--- 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 <QStackedWidget> #include <QTranslator> #include <ui_about.h> -#include <ui_mainwindow.h> #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<typename BaseType, typename MemberType, typename DataType> -struct MemberData -{ - std::size_t member; - DataType payload; - constexpr MemberType memberInstance(BaseType* instance) const - { - return *reinterpret_cast<MemberType*>(reinterpret_cast<char*>(instance) + this->member); - } -}; - -static constexpr MemberData<Ui_MainWindow, QAction*, gl::RenderStyle> 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<ModelId> openModelFromPath( const QString& path, const LibrariesModel* libraries, @@ -153,13 +135,13 @@ return documents->findPayload<ModelData>(modelId); } -static ModelSubWindow* currentModelSubWindow(Ui_MainWindow* ui) +static ModelSubWindow* currentModelSubWindow(MainWindow* ui) { auto* w = ui->mdiArea->activeSubWindow(); return qobject_cast<ModelSubWindow*>(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<ModelId> findCurrentModelId(Ui_MainWindow* ui) +static std::optional<ModelId> findCurrentModelId(MainWindow* ui) { ModelSubWindow* activeSubWindow = qobject_cast<ModelSubWindow*>(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<ModelSubWindow>(ui.mdiArea, modelId); + auto* const subWindow = createSubWindow<ModelSubWindow>(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<Setting::RecentFiles>(); @@ -562,9 +536,9 @@ libraries.restoreFromSettings(); updateRecentlyOpenedDocumentsMenu(); colorTable = loadColors(&libraries); - updateRenderPreferences(&ui, &renderPreferences, &documents); - ui.mdiArea->setViewMode(setting<Setting::ViewMode>()); - ui.retranslateUi(&mainWindow); + updateRenderPreferences(&mainWindow, &renderPreferences, &documents); + mainWindow.mdiArea->setViewMode(setting<Setting::ViewMode>()); + mainWindow.retranslateUi(&mainWindow); mainWindow.setToolButtonStyle(setting<Setting::ToolButtonStyle>()); 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<SettingsEditor*>().isEmpty()) { - auto* const settingsEditor = createSubWindow<SettingsEditor>(ui.mdiArea, defaultKeyboardShortcuts); + QObject::connect(mainWindow.actionSettingsEditor, &QAction::triggered, [&defaultKeyboardShortcuts, &restoreSettings, &settingsChanged, &mainWindow]{ + if (mainWindow.mdiArea->findChildren<SettingsEditor*>().isEmpty()) { + auto* const settingsEditor = createSubWindow<SettingsEditor>(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> modelId = findCurrentModelId(&ui); + }; + const auto actionSaveAs = [&documents, &libraries, &mainWindow, &save]{ + const std::optional<ModelId> 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> modelId = findCurrentModelId(&ui); + const std::optional<ModelId> 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<EditingMode>() == 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<EditingMode>(); 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<ModelData>(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<ModelSubWindow*>().empty()) { - ui.actionNew->trigger(); + if (mainWindow.mdiArea->findChildren<ModelSubWindow*>().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<Setting::MainWindowGeometry>()); mainWindow.restoreState(setting<Setting::MainWindowState>()); // 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();