| 601 addRecentlyOpenedFile(path); |
575 addRecentlyOpenedFile(path); |
| 602 } |
576 } |
| 603 } |
577 } |
| 604 } |
578 } |
| 605 ); |
579 ); |
| 606 QObject::connect(ui.actionSettingsEditor, &QAction::triggered, [&defaultKeyboardShortcuts, &restoreSettings, &settingsChanged, &ui]{ |
580 QObject::connect(mainWindow.actionSettingsEditor, &QAction::triggered, [&defaultKeyboardShortcuts, &restoreSettings, &settingsChanged, &mainWindow]{ |
| 607 if (ui.mdiArea->findChildren<SettingsEditor*>().isEmpty()) { |
581 if (mainWindow.mdiArea->findChildren<SettingsEditor*>().isEmpty()) { |
| 608 auto* const settingsEditor = createSubWindow<SettingsEditor>(ui.mdiArea, defaultKeyboardShortcuts); |
582 auto* const settingsEditor = createSubWindow<SettingsEditor>(mainWindow.mdiArea, defaultKeyboardShortcuts); |
| 609 QObject::connect(&settingsChanged, &Signal::triggered, settingsEditor, &SettingsEditor::loadSettings); |
583 QObject::connect(&settingsChanged, &Signal::triggered, settingsEditor, &SettingsEditor::loadSettings); |
| 610 QObject::connect(settingsEditor, &SettingsEditor::settingsChanged, restoreSettings); |
584 QObject::connect(settingsEditor, &SettingsEditor::settingsChanged, restoreSettings); |
| 611 settingsEditor->setAttribute(Qt::WA_DeleteOnClose); |
585 settingsEditor->setAttribute(Qt::WA_DeleteOnClose); |
| 612 settingsEditor->show(); |
586 settingsEditor->show(); |
| 613 } |
587 } |
| 614 }); |
588 }); |
| 615 QObject::connect(ui.actionQuit, &QAction::triggered, &mainWindow, &QMainWindow::close); |
589 QObject::connect(mainWindow.actionQuit, &QAction::triggered, &mainWindow, &QMainWindow::close); |
| 616 #if 0 |
590 #if 0 |
| 617 QObject::connect(ui.actionAdjustGridToView, &QAction::triggered, [&]{ |
591 QObject::connect(ui.actionAdjustGridToView, &QAction::triggered, [&]{ |
| 618 if (ModelData* data = currentModelData(&ui, &documents)) { |
592 if (ModelData* data = currentModelData(&ui, &documents)) { |
| 619 adjustGridToView(data->canvas.get()); |
593 adjustGridToView(data->canvas.get()); |
| 620 } |
594 } |
| 621 }); |
595 }); |
| 622 #endif |
596 #endif |
| 623 QObject::connect(ui.actionClose, &QAction::triggered, [&ui, &documents]{ |
597 QObject::connect(mainWindow.actionClose, &QAction::triggered, [&mainWindow, &documents]{ |
| 624 if (ModelData* data = currentModelData(&ui, &documents)) { |
598 if (ModelData* data = currentModelData(&mainWindow, &documents)) { |
| 625 // TODO |
599 // TODO |
| 626 } |
600 } |
| 627 }); |
601 }); |
| 628 const auto save = [&addRecentlyOpenedFile, &documents, &mainWindow](ModelId modelId){ |
602 const auto save = [&addRecentlyOpenedFile, &mainWindow](DocumentManager* documents, ModelId modelId){ |
| 629 QString error; |
603 QString error; |
| 630 QTextStream errorStream{&error}; |
604 QTextStream errorStream{&error}; |
| 631 const bool succeeded = documents.saveModel(modelId, errorStream); |
605 const bool succeeded = documents->saveModel(modelId, errorStream); |
| 632 if (not succeeded) |
606 if (not succeeded) |
| 633 { |
607 { |
| 634 QMessageBox::critical(&mainWindow, QObject::tr("Save error"), error); |
608 QMessageBox::critical(&mainWindow, QObject::tr("Save error"), error); |
| 635 } |
609 } |
| 636 else |
610 else |
| 637 { |
611 { |
| 638 const QString* pathPtr = documents.modelPath(modelId); |
612 const QString* pathPtr = documents->modelPath(modelId); |
| 639 if (pathPtr != nullptr) { |
613 if (pathPtr != nullptr) { |
| 640 addRecentlyOpenedFile(*pathPtr); |
614 addRecentlyOpenedFile(*pathPtr); |
| 641 } |
615 } |
| 642 } |
616 } |
| 643 };; |
617 }; |
| 644 const auto actionSaveAs = [&documents, &libraries, &mainWindow, &save, &ui]{ |
618 const auto actionSaveAs = [&documents, &libraries, &mainWindow, &save]{ |
| 645 const std::optional<ModelId> modelId = findCurrentModelId(&ui); |
619 const std::optional<ModelId> modelId = findCurrentModelId(&mainWindow); |
| 646 if (modelId.has_value()) |
620 if (modelId.has_value()) |
| 647 { |
621 { |
| 648 const QString* pathPtr = documents.modelPath(*modelId); |
622 const QString* pathPtr = documents.modelPath(*modelId); |
| 649 QString defaultPath = (pathPtr != nullptr) ? *pathPtr : ""; |
623 QString defaultPath = (pathPtr != nullptr) ? *pathPtr : ""; |
| 650 const QString newPath = QFileDialog::getSaveFileName( |
624 const QString newPath = QFileDialog::getSaveFileName( |
| 655 ); |
629 ); |
| 656 if (not newPath.isEmpty()) { |
630 if (not newPath.isEmpty()) { |
| 657 QString error; |
631 QString error; |
| 658 QTextStream errorStream{&error}; |
632 QTextStream errorStream{&error}; |
| 659 documents.setModelPath(*modelId, newPath, libraries, errorStream); |
633 documents.setModelPath(*modelId, newPath, libraries, errorStream); |
| 660 QMdiSubWindow* const subWindow = ui.mdiArea->currentSubWindow(); |
634 QMdiSubWindow* const subWindow = mainWindow.mdiArea->currentSubWindow(); |
| 661 if (subWindow != nullptr) { |
635 if (subWindow != nullptr) { |
| 662 subWindow->setWindowTitle(tabName(QFileInfo{newPath})); |
636 subWindow->setWindowTitle(tabName(QFileInfo{newPath})); |
| 663 } |
637 } |
| 664 save(*modelId); |
638 save(&documents, *modelId); |
| 665 } |
639 } |
| 666 } |
640 } |
| 667 }; |
641 }; |
| 668 QObject::connect(ui.actionSaveAs, &QAction::triggered, actionSaveAs); |
642 QObject::connect(mainWindow.actionSaveAs, &QAction::triggered, actionSaveAs); |
| 669 QObject::connect(ui.actionSave, &QAction::triggered, [ |
643 QObject::connect(mainWindow.actionSave, &QAction::triggered, [ |
| 670 &actionSaveAs, |
644 &actionSaveAs, |
| 671 &documents, |
645 &documents, |
| 672 &save, |
646 &save, |
| 673 &ui] |
647 &mainWindow] |
| 674 { |
648 { |
| 675 const std::optional<ModelId> modelId = findCurrentModelId(&ui); |
649 const std::optional<ModelId> modelId = findCurrentModelId(&mainWindow); |
| 676 if (modelId.has_value()) { |
650 if (modelId.has_value()) { |
| 677 const QString* path = documents.modelPath(*modelId); |
651 const QString* path = documents.modelPath(*modelId); |
| 678 if (path == nullptr or path->isEmpty()) { |
652 if (path == nullptr or path->isEmpty()) { |
| 679 actionSaveAs(); |
653 actionSaveAs(); |
| 680 } |
654 } |
| 681 else { |
655 else { |
| 682 save(*modelId); |
656 save(&documents, *modelId); |
| 683 } |
657 } |
| 684 } |
658 } |
| 685 }); |
659 }); |
| 686 QObject::connect(ui.actionDrawAxes, &QAction::triggered, [ |
660 QObject::connect(mainWindow.actionDrawAxes, &QAction::triggered, [ |
| 687 &documents, |
661 &documents, |
| 688 &renderPreferences, |
662 &renderPreferences, |
| 689 &saveSettings, |
663 &saveSettings, |
| 690 &ui] |
664 &mainWindow] |
| 691 (bool drawAxes) |
665 (bool drawAxes) |
| 692 { |
666 { |
| 693 renderPreferences.drawAxes = drawAxes; |
667 renderPreferences.drawAxes = drawAxes; |
| 694 saveSettings(); |
668 saveSettings(); |
| 695 updateRenderPreferences(&ui, &renderPreferences, &documents); |
669 updateRenderPreferences(&mainWindow, &renderPreferences, &documents); |
| 696 }); |
670 }); |
| 697 QObject::connect(ui.actionWireframe, &QAction::triggered, [ |
671 QObject::connect(mainWindow.actionWireframe, &QAction::triggered, [ |
| 698 &documents, |
672 &documents, |
| 699 &renderPreferences, |
673 &renderPreferences, |
| 700 &saveSettings, |
674 &saveSettings, |
| 701 &ui] |
675 &mainWindow] |
| 702 (bool enabled) |
676 (bool enabled) |
| 703 { |
677 { |
| 704 renderPreferences.wireframe = enabled; |
678 renderPreferences.wireframe = enabled; |
| 705 saveSettings(); |
679 saveSettings(); |
| 706 updateRenderPreferences(&ui, &renderPreferences, &documents); |
680 updateRenderPreferences(&mainWindow, &renderPreferences, &documents); |
| 707 }); |
681 }); |
| 708 for (auto data : ::renderStyleButtons) { |
682 QObject::connect(&mainWindow, &MainWindow::renderStyleSelected, [ |
| 709 QAction* action = data.memberInstance(&ui); |
683 &documents, |
| 710 QObject::connect(action, &QAction::triggered, [&, data]{ |
684 &mainWindow, |
| 711 renderPreferences.style = data.payload; |
685 &renderPreferences, |
| 712 saveSettings(); |
686 &saveSettings] |
| 713 updateRenderPreferences(&ui, &renderPreferences, &documents); |
687 (gl::RenderStyle newStyle) |
| 714 }); |
688 { |
| 715 } |
689 renderPreferences.style = newStyle; |
| 716 const auto checkEditingModeAction = [&ui, &documents](EditingMode mode) { |
690 saveSettings(); |
| 717 const bool hasDocument = currentModelData(&ui, &documents) != nullptr; |
691 updateRenderPreferences(&mainWindow, &renderPreferences, &documents); |
| 718 for (QAction* action : ui.editingModesToolBar->actions()) { |
692 }); |
| |
693 const auto checkEditingModeAction = [&mainWindow, &documents](EditingMode mode) { |
| |
694 const bool hasDocument = currentModelData(&mainWindow, &documents) != nullptr; |
| |
695 for (QAction* action : mainWindow.editingModesToolBar->actions()) { |
| 719 action->setEnabled(hasDocument); |
696 action->setEnabled(hasDocument); |
| 720 action->setChecked(hasDocument and action->data().value<EditingMode>() == mode); |
697 action->setChecked(hasDocument and action->data().value<EditingMode>() == mode); |
| 721 } |
698 } |
| 722 }; |
699 }; |
| 723 initializeTools(&ui, &toolWidgets, &mainWindow); |
700 initializeTools(&mainWindow, &toolWidgets, &mainWindow); |
| 724 for (QAction* action : ui.editingModesToolBar->actions()) { |
701 for (QAction* action : mainWindow.editingModesToolBar->actions()) { |
| 725 QObject::connect(action, &QAction::triggered, [ |
702 QObject::connect(action, &QAction::triggered, [ |
| 726 action, |
703 action, |
| 727 &checkEditingModeAction, |
704 &checkEditingModeAction, |
| 728 &documents, |
705 &documents, |
| 729 &ui] |
706 &mainWindow] |
| 730 { |
707 { |
| 731 if (ModelData* data = currentModelData(&ui, &documents)) { |
708 if (ModelData* data = currentModelData(&mainWindow, &documents)) { |
| 732 const EditingMode mode = action->data().value<EditingMode>(); |
709 const EditingMode mode = action->data().value<EditingMode>(); |
| 733 data->tools->setEditMode(mode); |
710 data->tools->setEditMode(mode); |
| 734 checkEditingModeAction(mode); |
711 checkEditingModeAction(mode); |
| 735 } |
712 } |
| 736 }); |
713 }); |
| 737 } |
714 } |
| 738 QObject::connect(ui.mdiArea, &QMdiArea::subWindowActivated, [ |
715 QObject::connect(mainWindow.mdiArea, &QMdiArea::subWindowActivated, [ |
| 739 &checkEditingModeAction, |
716 &checkEditingModeAction, |
| 740 &documents, |
717 &documents, |
| 741 &ui, |
718 &mainWindow, |
| 742 &updateTitle] |
719 &updateTitle] |
| 743 (QMdiSubWindow* subWindow) |
720 (QMdiSubWindow* subWindow) |
| 744 { |
721 { |
| 745 ModelSubWindow* modelSubWindow = qobject_cast<ModelSubWindow*>(subWindow); |
722 ModelSubWindow* modelSubWindow = qobject_cast<ModelSubWindow*>(subWindow); |
| 746 if (modelSubWindow != nullptr) { |
723 if (modelSubWindow != nullptr) { |
| 747 if (ModelData* data = documents.findPayload<ModelData>(modelSubWindow->modelId)) { |
724 if (ModelData* data = documents.findPayload<ModelData>(modelSubWindow->modelId)) { |
| 748 checkEditingModeAction(data->tools->currentEditingMode()); |
725 checkEditingModeAction(data->tools->currentEditingMode()); |
| 749 ui.modelEdit->setDocument(data->model); |
726 mainWindow.modelEdit->setDocument(data->model); |
| 750 ui.modelEdit->setTextCursor(*data->textcursor); |
727 mainWindow.modelEdit->setTextCursor(*data->textcursor); |
| 751 } |
728 } |
| 752 } |
729 } |
| 753 else { |
730 else { |
| 754 checkEditingModeAction(EditingMode::SelectMode); |
731 checkEditingModeAction(EditingMode::SelectMode); |
| 755 } |
732 } |
| 756 ui.modelEdit->setEnabled(modelSubWindow != nullptr); |
733 mainWindow.modelEdit->setEnabled(modelSubWindow != nullptr); |
| 757 updateTitle(); |
734 updateTitle(); |
| 758 }); |
735 }); |
| 759 ui.messageLog->setModel(&messageLog); |
736 mainWindow.messageLog->setModel(&messageLog); |
| 760 QObject::connect(ui.actionAboutQt, &QAction::triggered, &app, &QApplication::aboutQt); |
737 QObject::connect(mainWindow.actionAboutQt, &QAction::triggered, &app, &QApplication::aboutQt); |
| 761 QObject::connect(&documents, &DocumentManager::message, &messageLog, &MessageLog::addMessage); |
738 QObject::connect(&documents, &DocumentManager::message, &messageLog, &MessageLog::addMessage); |
| 762 QObject::connect(&messageLog, &MessageLog::rowsAboutToBeInserted, [&ui]{ |
739 QObject::connect(&messageLog, &MessageLog::rowsAboutToBeInserted, [&mainWindow]{ |
| 763 const auto bar = ui.messageLog->verticalScrollBar(); |
740 const auto bar = mainWindow.messageLog->verticalScrollBar(); |
| 764 ui.messageLog->setProperty("shouldAutoScroll", bar->value() == bar->maximum()); |
741 mainWindow.messageLog->setProperty("shouldAutoScroll", bar->value() == bar->maximum()); |
| 765 }); |
742 }); |
| 766 QObject::connect(&messageLog, &MessageLog::rowsInserted, [&ui]{ |
743 QObject::connect(&messageLog, &MessageLog::rowsInserted, [&mainWindow]{ |
| 767 ui.messageLog->resizeRowsToContents(); |
744 mainWindow.messageLog->resizeRowsToContents(); |
| 768 if (ui.messageLog->property("shouldAutoScroll").toBool()) { |
745 if (mainWindow.messageLog->property("shouldAutoScroll").toBool()) { |
| 769 ui.messageLog->scrollToBottom(); |
746 mainWindow.messageLog->scrollToBottom(); |
| 770 } |
747 } |
| 771 }); |
748 }); |
| 772 QObject::connect( |
749 QObject::connect( |
| 773 toolWidgets.circleToolOptions, |
750 toolWidgets.circleToolOptions, |
| 774 &CircleToolOptionsWidget::optionsChanged, |
751 &CircleToolOptionsWidget::optionsChanged, |
| 775 [&ui, &documents](const CircleToolOptions& options) { |
752 [&mainWindow, &documents](const CircleToolOptions& options) { |
| 776 if (ModelData* data = currentModelData(&ui, &documents)) { |
753 if (ModelData* data = currentModelData(&mainWindow, &documents)) { |
| 777 data->tools->setCircleToolOptions(options); |
754 data->tools->setCircleToolOptions(options); |
| 778 } |
755 } |
| 779 }); |
756 }); |
| 780 QObject::connect( |
757 QObject::connect( |
| 781 ui.actionMakeUnofficial, |
758 mainWindow.actionMakeUnofficial, |
| 782 &QAction::triggered, |
759 &QAction::triggered, |
| 783 [&documents, &ui]{ |
760 [&documents, &mainWindow]{ |
| 784 if (ModelData* data = currentModelData(&ui, &documents)) { |
761 if (ModelData* data = currentModelData(&mainWindow, &documents)) { |
| 785 QTextDocument* const model = data->model; |
762 QTextDocument* const model = data->model; |
| 786 for (const ModelAction& action : ldraw::makeUnofficial(model)) { |
763 for (const ModelAction& action : ldraw::makeUnofficial(model)) { |
| 787 executeAction(model, action); |
764 executeAction(model, action); |
| 788 } |
765 } |
| 789 } |
766 } |
| 790 }); |
767 }); |
| 791 QObject::connect( |
768 QObject::connect( |
| 792 ui.actionAbout, |
769 mainWindow.actionAbout, |
| 793 &QAction::triggered, |
770 &QAction::triggered, |
| 794 [&mainWindow, &ui]{ |
771 [&mainWindow]{ |
| 795 // Make sure that there's an OpenGL context active, otherwise |
772 // Make sure that there's an OpenGL context active, otherwise |
| 796 // we cannot obtain OpenGL information |
773 // we cannot obtain OpenGL information |
| 797 if (ui.mdiArea->findChildren<ModelSubWindow*>().empty()) { |
774 if (mainWindow.mdiArea->findChildren<ModelSubWindow*>().empty()) { |
| 798 ui.actionNew->trigger(); |
775 mainWindow.actionNew->trigger(); |
| 799 } |
776 } |
| 800 about(&mainWindow); |
777 about(&mainWindow); |
| 801 } |
778 } |
| 802 ); |
779 ); |
| 803 QObject::connect( |
780 QObject::connect( |
| 804 ui.modelEdit, |
781 mainWindow.modelEdit, |
| 805 &QPlainTextEdit::textChanged, |
782 &QPlainTextEdit::textChanged, |
| 806 [&documents, &libraries, &ui]{ |
783 [&documents, &libraries, &mainWindow]{ |
| 807 if (ModelData* data = currentModelData(&ui, &documents)) { |
784 if (ModelData* data = currentModelData(&mainWindow, &documents)) { |
| 808 documents.loadDependenciesForAllModels(libraries); |
785 documents.loadDependenciesForAllModels(libraries); |
| 809 data->canvas->update(); |
786 data->canvas->update(); |
| 810 } |
787 } |
| 811 }); |
788 }); |
| 812 mainWindow.tabifyDockWidget(ui.messageLogDock, ui.toolOptionsDock); |
789 mainWindow.tabifyDockWidget(mainWindow.messageLogDock, mainWindow.toolOptionsDock); |
| 813 mainWindow.restoreGeometry(setting<Setting::MainWindowGeometry>()); |
790 mainWindow.restoreGeometry(setting<Setting::MainWindowGeometry>()); |
| 814 mainWindow.restoreState(setting<Setting::MainWindowState>()); |
791 mainWindow.restoreState(setting<Setting::MainWindowState>()); |
| 815 // If a dock is made floating and the app is closed, the dock becomes invisible |
792 // If a dock is made floating and the app is closed, the dock becomes invisible |
| 816 // after the restoreState call. So we make them visible again here. |
793 // after the restoreState call. So we make them visible again here. |
| 817 for (QDockWidget* dock : mainWindow.findChildren<QDockWidget*>()) { |
794 for (QDockWidget* dock : mainWindow.findChildren<QDockWidget*>()) { |
| 818 dock->setVisible(true); |
795 dock->setVisible(true); |
| 819 } |
796 } |
| 820 restoreSettings(); |
797 restoreSettings(); |
| 821 updateRenderPreferences(&ui, &renderPreferences, &documents); |
798 updateRenderPreferences(&mainWindow, &renderPreferences, &documents); |
| 822 ui.actionAbout->setText(ui.actionAbout->text().arg(CMAKE_PROJECT_NAME)); |
799 mainWindow.actionAbout->setText(mainWindow.actionAbout->text().arg(CMAKE_PROJECT_NAME)); |
| 823 updateTitle(); |
800 updateTitle(); |
| 824 mainWindow.show(); |
801 mainWindow.show(); |
| 825 const int result = app.exec(); |
802 const int result = app.exec(); |
| 826 saveSettings(); |
803 saveSettings(); |
| 827 return result; |
804 return result; |