src/main.cpp

changeset 362
e1d646a4cbd8
parent 361
c5e8b68e34f8
child 363
16f5dcfa7c9f
equal deleted inserted replaced
361:c5e8b68e34f8 362:e1d646a4cbd8
21 #include "src/version.h" 21 #include "src/version.h"
22 #include "src/widgets/colorselectdialog.h" 22 #include "src/widgets/colorselectdialog.h"
23 #include "src/parser.h" 23 #include "src/parser.h"
24 #include "src/ldrawsyntaxhighlighter.h" 24 #include "src/ldrawsyntaxhighlighter.h"
25 #include <GL/glew.h> 25 #include <GL/glew.h>
26 #include "src/main.h"
26 27
27 static const QDir LOCALE_DIR {":/locale"}; 28 static const QDir LOCALE_DIR {":/locale"};
28 29
29 class ModelData : public QObject 30 class ModelData : public QObject
30 { 31 {
141 return activeSubWindow->modelId; 142 return activeSubWindow->modelId;
142 } 143 }
143 else { 144 else {
144 return {}; 145 return {};
145 } 146 }
146 }
147
148 static QString title(MainWindow* ui)
149 {
150 QMdiSubWindow* subWindow = ui->mdiArea->activeSubWindow();
151 QString titlestring;
152 const QString versionString = fullVersionString(QLocale::ShortFormat);
153 if (subWindow != nullptr) {
154 titlestring = QObject::tr("%1 - %2").arg(subWindow->windowTitle(), versionString);
155 }
156 else {
157 titlestring = versionString;
158 }
159 if (/* DISABLES CODE */ (true)
160 and std::strcmp(CMAKE_BUILD_TYPE, "Release") != 0
161 and std::strcmp(CMAKE_BUILD_TYPE, "MinSizeRel") != 0
162 ) {
163 titlestring += QObject::tr(" [%1]").arg(CMAKE_BUILD_TYPE);
164 }
165 return titlestring;
166 } 147 }
167 148
168 static ColorTable loadColors(const LibrariesModel* libraries) 149 static ColorTable loadColors(const LibrariesModel* libraries)
169 { 150 {
170 QTextStream errors; 151 QTextStream errors;
326 font.setPointSize(setting<Setting::CodeEditorFontSize>()); 307 font.setPointSize(setting<Setting::CodeEditorFontSize>());
327 } 308 }
328 return font; 309 return font;
329 } 310 }
330 311
331 constexpr glm::mat4 DEFAULT_GRID_MATRIX = {{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}}; 312 struct MainState
332 313 {
333 int main(int argc, char *argv[])
334 {
335 doQtRegistrations();
336 QApplication app{argc, argv};
337 QApplication::setWindowIcon(QIcon{":/icons/appicon.png"});
338 MainWindow mainWindow; 314 MainWindow mainWindow;
339 DocumentManager documents; 315 DocumentManager documents;
340 QString currentLanguage = "en"; 316 QString currentLanguage = "en";
341 QTranslator translator{&mainWindow}; 317 QTranslator translator{&mainWindow};
342 LibrariesModel libraries{&mainWindow}; 318 LibrariesModel libraries{&mainWindow};
343 QStringList recentlyOpenedFiles; 319 QStringList recentlyOpenedFiles;
344 ColorTable colorTable; 320 ColorTable colorTable;
345 gl::RenderPreferences renderPreferences; 321 gl::RenderPreferences renderPreferences;
346 MessageLog messageLog; 322 MessageLog messageLog;
347 Signal settingsChanged;
348 ToolWidgets toolWidgets{ 323 ToolWidgets toolWidgets{
349 .circleToolOptions = new CircleToolOptionsWidget{&mainWindow}, 324 .circleToolOptions = new CircleToolOptionsWidget{&mainWindow},
350 }; 325 };
351 const auto updateTitle = [&mainWindow]{ 326 };
352 mainWindow.setWindowTitle(title(&mainWindow)); 327
353 }; 328 static void openModelForEditing(MainState* state, const ModelId modelId)
354 const uiutilities::KeySequenceMap defaultKeyboardShortcuts = 329 {
355 uiutilities::makeKeySequenceMap(uiutilities::collectActions(&mainWindow)); 330 QTextDocument* model = state->documents.getModelById(modelId);
356 const auto saveSettings = [ 331 if (model != nullptr) {
357 &libraries, 332 ModelData* data = new ModelData(&state->documents);
358 &mainWindow, 333 data->tools = std::make_unique<EditTools>();
359 &recentlyOpenedFiles, 334 data->canvas = std::make_unique<PartRenderer>(model, &state->documents, state->colorTable);
360 &renderPreferences, 335 data->axesLayer = std::make_unique<AxesLayer>();
361 &settingsChanged] 336 data->gridLayer = std::make_unique<GridLayer>();
362 { 337 data->gridLayer->setGridMatrix(DEFAULT_GRID_MATRIX);
363 setSetting<Setting::MainWindowGeometry>(mainWindow.saveGeometry()); 338 data->tools->setGridMatrix(DEFAULT_GRID_MATRIX);
364 setSetting<Setting::MainWindowState>(mainWindow.saveState()); 339 data->model = model;
365 setSetting<Setting::RecentFiles>(recentlyOpenedFiles); 340 data->canvas->addRenderLayer(data->axesLayer.get());
366 setSetting<Setting::RenderStyle>(renderPreferences.style); 341 data->canvas->setLayerEnabled(data->axesLayer.get(), setting<Setting::DrawAxes>());
367 setSetting<Setting::DrawAxes>(renderPreferences.drawAxes); 342 data->canvas->addRenderLayer(data->gridLayer.get());
368 setSetting<Setting::Wireframe>(renderPreferences.wireframe); 343 data->canvas->addRenderLayer(data->tools.get());
369 libraries.storeToSettings(); 344 new LDrawSyntaxHighlighter{model};
370 settingsChanged.emit(); 345 data->textcursor = std::make_unique<QTextCursor>(model);
371 }; 346 state->documents.setModelPayload(modelId, data);
372 const auto openModelForEditing = [ 347 QObject::connect(
373 &colorTable, 348 data->tools.get(),
374 &documents, 349 &EditTools::modelAction,
375 &mainWindow, 350 std::bind(executeAction, model, std::placeholders::_1));
376 &messageLog, 351 data->canvas->setRenderPreferences(state->renderPreferences);
377 &renderPreferences, 352 QObject::connect(
378 &settingsChanged] 353 data->tools.get(),
379 (const ModelId modelId) 354 &EditTools::newStatusText,
380 { 355 [&state](const QString& newStatusText) {
381 QTextDocument* model = documents.getModelById(modelId); 356 state->mainWindow.statusBar()->showMessage(newStatusText);
382 if (model != nullptr) { 357 });
383 ModelData* data = new ModelData(&documents);
384 data->tools = std::make_unique<EditTools>();
385 data->canvas = std::make_unique<PartRenderer>(model, &documents, colorTable);
386 data->axesLayer = std::make_unique<AxesLayer>();
387 data->gridLayer = std::make_unique<GridLayer>();
388 data->gridLayer->setGridMatrix(DEFAULT_GRID_MATRIX);
389 data->tools->setGridMatrix(DEFAULT_GRID_MATRIX);
390 data->model = model;
391 data->canvas->addRenderLayer(data->axesLayer.get());
392 data->canvas->setLayerEnabled(data->axesLayer.get(), setting<Setting::DrawAxes>());
393 data->canvas->addRenderLayer(data->gridLayer.get());
394 data->canvas->addRenderLayer(data->tools.get());
395 new LDrawSyntaxHighlighter{model};
396 data->textcursor = std::make_unique<QTextCursor>(model);
397 documents.setModelPayload(modelId, data);
398 QObject::connect(
399 data->tools.get(),
400 &EditTools::modelAction,
401 std::bind(executeAction, model, std::placeholders::_1));
402 data->canvas->setRenderPreferences(renderPreferences);
403 QObject::connect(
404 data->tools.get(),
405 &EditTools::newStatusText,
406 [&mainWindow](const QString& newStatusText) {
407 mainWindow.statusBar()->showMessage(newStatusText);
408 });
409 #if 0 358 #if 0
410 QObject::connect( 359 QObject::connect(
411 data->tools.get(), 360 data->tools.get(),
412 &EditTools::select, 361 &EditTools::select,
413 [modelId, &documents](const QSet<ElementId>& indices, bool retain) { 362 [modelId, &documents](const QSet<ElementId>& indices, bool retain) {
414 ModelData* data = findModelData(&documents, modelId); 363 ModelData* data = findModelData(&documents, modelId);
415 if (data != nullptr) { 364 if (data != nullptr) {
416 if (not retain) { 365 if (not retain) {
417 data->textcursor->clearSelection(); 366 data->textcursor->clearSelection();
418 } 367 }
419 for (const ElementId id : indices) { 368 for (const ElementId id : indices) {
420 opt<int> index = data->model->find(id); 369 opt<int> index = data->model->find(id);
421 if (index.has_value()) { 370 if (index.has_value()) {
422 const QModelIndex qindex = data->model->index(*index); 371 const QModelIndex qindex = data->model->index(*index);
423 data->itemSelectionModel->select(qindex, QItemSelectionModel::Select); 372 data->itemSelectionModel->select(qindex, QItemSelectionModel::Select);
424 }
425 } 373 }
426 } 374 }
427 });
428 #endif
429 QObject::connect(&settingsChanged, &Signal::triggered, [modelId, &documents]{
430 ModelData* data = findModelData(&documents, modelId);
431 if (data != nullptr) {
432 data->gridLayer->settingsChanged();
433 } 375 }
434 }); 376 });
435 QObject::connect(data->canvas.get(), &PartRenderer::message, &messageLog, &MessageLog::addMessage); 377 #endif
436 QObject::connect( 378 #if 0
437 data->tools.get(), 379 QObject::connect(this, &Main::settingsChanged, [modelId, this]{
438 &EditTools::suggestCursor, 380 ModelData* data = findModelData(&state.documents, modelId);
439 data->canvas.get(), 381 if (data != nullptr) {
440 &QWidget::setCursor); 382 data->gridLayer->settingsChanged();
441 data->tools->setEditMode(SelectMode); 383 }
442 const QFileInfo fileInfo{*documents.modelPath(modelId)}; 384 });
443 auto* const subWindow = createSubWindow<ModelSubWindow>(mainWindow.mdiArea, modelId); 385 #endif
444 subWindow->setMinimumSize({96, 96}); 386 QObject::connect(data->canvas.get(), &PartRenderer::message, &state->messageLog, &MessageLog::addMessage);
445 subWindow->resize({320, 200}); 387 QObject::connect(
446 subWindow->setWidget(data->canvas.get()); 388 data->tools.get(),
447 subWindow->setWindowTitle(tabName(fileInfo)); 389 &EditTools::suggestCursor,
448 subWindow->show(); 390 data->canvas.get(),
449 } 391 &QWidget::setCursor);
450 }; 392 data->tools->setEditMode(SelectMode);
451 const auto updateRecentlyOpenedDocumentsMenu = [ 393 const QFileInfo fileInfo{*state->documents.modelPath(modelId)};
452 &mainWindow, 394 auto* const subWindow = createSubWindow<ModelSubWindow>(state->mainWindow.mdiArea, modelId);
453 &recentlyOpenedFiles] 395 subWindow->setMinimumSize({96, 96});
454 { 396 subWindow->resize({320, 200});
455 mainWindow.rebuildRecentFilesMenu(recentlyOpenedFiles); 397 subWindow->setWidget(data->canvas.get());
456 }; 398 subWindow->setWindowTitle(tabName(fileInfo));
457 const auto restoreSettings = [ 399 subWindow->show();
458 &colorTable, 400 }
459 &documents, 401 }
460 &libraries, 402
461 &mainWindow, 403 static void updateRecentlyOpenedDocumentsMenu(MainState* state)
462 &recentlyOpenedFiles, 404 {
463 &renderPreferences, 405 state->mainWindow.rebuildRecentFilesMenu(state->recentlyOpenedFiles);
464 &settingsChanged, 406 }
465 &updateRecentlyOpenedDocumentsMenu] 407
466 { 408 static void restoreSettings(MainState* state)
467 recentlyOpenedFiles = setting<Setting::RecentFiles>(); 409 {
468 renderPreferences = loadRenderPreferences(); 410 state->recentlyOpenedFiles = setting<Setting::RecentFiles>();
469 libraries.restoreFromSettings(); 411 state->renderPreferences = loadRenderPreferences();
470 updateRecentlyOpenedDocumentsMenu(); 412 state->libraries.restoreFromSettings();
471 colorTable = loadColors(&libraries); 413 updateRecentlyOpenedDocumentsMenu(state);
472 updateRenderPreferences(&mainWindow, &renderPreferences, &documents); 414 state->colorTable = loadColors(&state->libraries);
473 mainWindow.mdiArea->setViewMode(setting<Setting::ViewMode>()); 415 updateRenderPreferences(&state->mainWindow, &state->renderPreferences, &state->documents);
474 mainWindow.retranslateUi(&mainWindow); 416 state->mainWindow.mdiArea->setViewMode(setting<Setting::ViewMode>());
475 mainWindow.setToolButtonStyle(setting<Setting::ToolButtonStyle>()); 417 state->mainWindow.retranslateUi(&state->mainWindow);
476 settingsChanged.emit(); 418 state->mainWindow.setToolButtonStyle(setting<Setting::ToolButtonStyle>());
477 }; 419 }
478 const auto addRecentlyOpenedFile = [ 420
479 &recentlyOpenedFiles, 421 static void saveSettings(MainState* state)
480 &saveSettings, 422 {
481 &updateRecentlyOpenedDocumentsMenu] 423 setSetting<Setting::MainWindowGeometry>(state->mainWindow.saveGeometry());
482 (const QString& path) 424 setSetting<Setting::MainWindowState>(state->mainWindow.saveState());
483 { 425 setSetting<Setting::RecentFiles>(state->recentlyOpenedFiles);
484 constexpr int maxRecentlyOpenedFiles = 10; 426 setSetting<Setting::RenderStyle>(state->renderPreferences.style);
485 recentlyOpenedFiles.removeAll(path); 427 setSetting<Setting::DrawAxes>(state->renderPreferences.drawAxes);
486 recentlyOpenedFiles.insert(0, path); 428 setSetting<Setting::Wireframe>(state->renderPreferences.wireframe);
487 while (recentlyOpenedFiles.size() > maxRecentlyOpenedFiles) 429 state->libraries.storeToSettings();
488 { 430 }
489 recentlyOpenedFiles.removeLast(); 431
490 } 432 static void addRecentlyOpenedFile(MainState* state, const QString& path)
491 saveSettings(); 433 {
492 updateRecentlyOpenedDocumentsMenu(); 434 constexpr int maxRecentlyOpenedFiles = 10;
493 }; 435 state->recentlyOpenedFiles.removeAll(path);
436 state->recentlyOpenedFiles.insert(0, path);
437 while (state->recentlyOpenedFiles.size() > maxRecentlyOpenedFiles)
438 {
439 state->recentlyOpenedFiles.removeLast();
440 }
441 saveSettings(state);
442 updateRecentlyOpenedDocumentsMenu(state);
443 }
444
445 static void saveCurrentModel(MainState* state, ModelId modelId)
446 {
447 QString error;
448 QTextStream errorStream{&error};
449 const bool succeeded = state->documents.saveModel(modelId, errorStream);
450 if (not succeeded)
451 {
452 QMessageBox::critical(&state->mainWindow, QObject::tr("Save error"), error);
453 }
454 else
455 {
456 const QString* pathPtr = state->documents.modelPath(modelId);
457 if (pathPtr != nullptr) {
458 addRecentlyOpenedFile(state, *pathPtr);
459 }
460 }
461 }
462
463 static void saveCurrentModelAs(MainState* state)
464 {
465 const std::optional<ModelId> modelId = findCurrentModelId(&state->mainWindow);
466 if (modelId.has_value())
467 {
468 const QString* pathPtr = state->documents.modelPath(*modelId);
469 QString defaultPath = (pathPtr != nullptr) ? *pathPtr : "";
470 const QString newPath = QFileDialog::getSaveFileName(
471 &state->mainWindow,
472 QObject::tr("Save as…"),
473 QFileInfo{defaultPath}.absoluteDir().path(),
474 QObject::tr("LDraw files (*.ldr *dat);;All files (*)")
475 );
476 if (not newPath.isEmpty()) {
477 QString error;
478 QTextStream errorStream{&error};
479 state->documents.setModelPath(*modelId, newPath, state->libraries, errorStream);
480 QMdiSubWindow* const subWindow = state->mainWindow.mdiArea->currentSubWindow();
481 if (subWindow != nullptr) {
482 subWindow->setWindowTitle(tabName(QFileInfo{newPath}));
483 }
484 saveCurrentModel(state, *modelId);
485 }
486 }
487 }
488
489 static void checkEditingModeAction(MainState* state, const EditingMode mode)
490 {
491 const bool hasDocument = currentModelData(&state->mainWindow, &state->documents) != nullptr;
492 for (QAction* action : state->mainWindow.editingModesToolBar->actions())
493 {
494 action->setEnabled(hasDocument);
495 action->setChecked(hasDocument and action->data().value<EditingMode>() == mode);
496 }
497 }
498
499 int main(int argc, char *argv[])
500 {
501 doQtRegistrations();
502 QApplication app{argc, argv};
503 QApplication::setWindowIcon(QIcon{":/icons/appicon.png"});
504 MainState state;
494 QObject::connect( 505 QObject::connect(
495 &mainWindow, 506 &state.mainWindow,
496 &MainWindow::recentFileSelected, 507 &MainWindow::recentFileSelected,
497 [&libraries, &documents, &mainWindow, &openModelForEditing, &addRecentlyOpenedFile](const QString& path) { 508 [&state](const QString& path) {
498 const auto id = openModelFromPath(path, &libraries, &documents, &mainWindow); 509 const auto id = openModelFromPath(path, &state.libraries, &state.documents, &state.mainWindow);
499 if (id.has_value()) 510 if (id.has_value())
500 { 511 {
501 openModelForEditing(id.value()); 512 openModelForEditing(&state, id.value());
502 addRecentlyOpenedFile(path); 513 addRecentlyOpenedFile(&state, path);
503 } 514 }
504 } 515 }
505 ); 516 );
506 QObject::connect(mainWindow.actionNew, &QAction::triggered, 517 QObject::connect(state.mainWindow.actionNew, &QAction::triggered,
507 [&documents, &openModelForEditing]{ 518 [&state]{
508 openModelForEditing(documents.newModel()); 519 openModelForEditing(&state, state.documents.newModel());
509 } 520 }
510 ); 521 );
511 QObject::connect(mainWindow.actionOpen, &QAction::triggered, 522 QObject::connect(state.mainWindow.actionOpen, &QAction::triggered,
512 [&addRecentlyOpenedFile, &documents, &libraries, &mainWindow, &openModelForEditing] 523 [&state]
513 { 524 {
514 const QString path = getOpenModelPath(&mainWindow); 525 const QString path = getOpenModelPath(&state.mainWindow);
515 if (not path.isEmpty()) 526 if (not path.isEmpty())
516 { 527 {
517 const std::optional<ModelId> id = openModelFromPath(path, &libraries, &documents, &mainWindow); 528 const std::optional<ModelId> id = openModelFromPath(path, &state.libraries, &state.documents, &state.mainWindow);
518 if (id.has_value()) { 529 if (id.has_value()) {
519 openModelForEditing(id.value()); 530 openModelForEditing(&state, id.value());
520 addRecentlyOpenedFile(path); 531 addRecentlyOpenedFile(&state, path);
521 } 532 }
522 } 533 }
523 } 534 }
524 ); 535 );
525 QObject::connect(mainWindow.actionSettingsEditor, &QAction::triggered, [&defaultKeyboardShortcuts, &restoreSettings, &settingsChanged, &mainWindow]{ 536 QObject::connect(state.mainWindow.actionSettingsEditor, &QAction::triggered, [
526 if (mainWindow.mdiArea->findChildren<SettingsEditor*>().isEmpty()) { 537 &state,
527 auto* const settingsEditor = createSubWindow<SettingsEditor>(mainWindow.mdiArea, defaultKeyboardShortcuts); 538 defaultKeyboardShortcuts = uiutilities::makeKeySequenceMap(uiutilities::collectActions(&state.mainWindow))]
528 QObject::connect(&settingsChanged, &Signal::triggered, settingsEditor, &SettingsEditor::loadSettings); 539 {
529 QObject::connect(settingsEditor, &SettingsEditor::settingsChanged, restoreSettings); 540 if (state.mainWindow.mdiArea->findChildren<SettingsEditor*>().isEmpty())
541 {
542 auto* const settingsEditor = createSubWindow<SettingsEditor>(state.mainWindow.mdiArea, defaultKeyboardShortcuts);
543 QObject::connect(settingsEditor, &SettingsEditor::settingsChanged, [&]{
544 restoreSettings(&state);
545 });
530 settingsEditor->setAttribute(Qt::WA_DeleteOnClose); 546 settingsEditor->setAttribute(Qt::WA_DeleteOnClose);
531 settingsEditor->show(); 547 settingsEditor->show();
532 } 548 }
533 }); 549 });
534 QObject::connect(mainWindow.actionQuit, &QAction::triggered, &mainWindow, &QMainWindow::close); 550 QObject::connect(state.mainWindow.actionQuit, &QAction::triggered, &state.mainWindow, &QMainWindow::close);
535 #if 0 551 #if 0
536 QObject::connect(ui.actionAdjustGridToView, &QAction::triggered, [&]{ 552 QObject::connect(ui.actionAdjustGridToView, &QAction::triggered, [&]{
537 if (ModelData* data = currentModelData(&ui, &documents)) { 553 if (ModelData* data = currentModelData(&ui, &documents)) {
538 adjustGridToView(data->canvas.get()); 554 adjustGridToView(data->canvas.get());
539 } 555 }
540 }); 556 });
541 #endif 557 #endif
542 QObject::connect(mainWindow.actionClose, &QAction::triggered, [&mainWindow, &documents]{ 558 QObject::connect(state.mainWindow.actionClose, &QAction::triggered, [&state]{
543 if (ModelData* data = currentModelData(&mainWindow, &documents)) { 559 if (ModelData* data = currentModelData(&state.mainWindow, &state.documents)) {
544 // TODO 560 // TODO
545 } 561 }
546 }); 562 });
547 const auto save = [&addRecentlyOpenedFile, &mainWindow](DocumentManager* documents, ModelId modelId){ 563 QObject::connect(state.mainWindow.actionSaveAs, &QAction::triggered, [&state]{
548 QString error; 564 saveCurrentModelAs(&state);
549 QTextStream errorStream{&error}; 565 });
550 const bool succeeded = documents->saveModel(modelId, errorStream); 566 QObject::connect(state.mainWindow.actionSave, &QAction::triggered, [&state]
551 if (not succeeded) 567 {
552 { 568 const std::optional<ModelId> modelId = findCurrentModelId(&state.mainWindow);
553 QMessageBox::critical(&mainWindow, QObject::tr("Save error"), error);
554 }
555 else
556 {
557 const QString* pathPtr = documents->modelPath(modelId);
558 if (pathPtr != nullptr) {
559 addRecentlyOpenedFile(*pathPtr);
560 }
561 }
562 };
563 const auto actionSaveAs = [&documents, &libraries, &mainWindow, &save]{
564 const std::optional<ModelId> modelId = findCurrentModelId(&mainWindow);
565 if (modelId.has_value())
566 {
567 const QString* pathPtr = documents.modelPath(*modelId);
568 QString defaultPath = (pathPtr != nullptr) ? *pathPtr : "";
569 const QString newPath = QFileDialog::getSaveFileName(
570 &mainWindow,
571 QObject::tr("Save as…"),
572 QFileInfo{defaultPath}.absoluteDir().path(),
573 QObject::tr("LDraw files (*.ldr *dat);;All files (*)")
574 );
575 if (not newPath.isEmpty()) {
576 QString error;
577 QTextStream errorStream{&error};
578 documents.setModelPath(*modelId, newPath, libraries, errorStream);
579 QMdiSubWindow* const subWindow = mainWindow.mdiArea->currentSubWindow();
580 if (subWindow != nullptr) {
581 subWindow->setWindowTitle(tabName(QFileInfo{newPath}));
582 }
583 save(&documents, *modelId);
584 }
585 }
586 };
587 QObject::connect(mainWindow.actionSaveAs, &QAction::triggered, actionSaveAs);
588 QObject::connect(mainWindow.actionSave, &QAction::triggered, [
589 &actionSaveAs,
590 &documents,
591 &save,
592 &mainWindow]
593 {
594 const std::optional<ModelId> modelId = findCurrentModelId(&mainWindow);
595 if (modelId.has_value()) { 569 if (modelId.has_value()) {
596 const QString* path = documents.modelPath(*modelId); 570 const QString* path = state.documents.modelPath(*modelId);
597 if (path == nullptr or path->isEmpty()) { 571 if (path == nullptr or path->isEmpty()) {
598 actionSaveAs(); 572 saveCurrentModelAs(&state);
599 } 573 }
600 else { 574 else {
601 save(&documents, *modelId); 575 saveCurrentModel(&state, *modelId);
602 } 576 }
603 } 577 }
604 }); 578 });
605 QObject::connect(mainWindow.actionDrawAxes, &QAction::triggered, [ 579 QObject::connect(state.mainWindow.actionDrawAxes, &QAction::triggered, [&state]
606 &documents,
607 &renderPreferences,
608 &saveSettings,
609 &mainWindow]
610 (bool drawAxes) 580 (bool drawAxes)
611 { 581 {
612 renderPreferences.drawAxes = drawAxes; 582 state.renderPreferences.drawAxes = drawAxes;
613 saveSettings(); 583 saveSettings(&state);
614 updateRenderPreferences(&mainWindow, &renderPreferences, &documents); 584 updateRenderPreferences(&state.mainWindow, &state.renderPreferences, &state.documents);
615 }); 585 });
616 QObject::connect(mainWindow.actionWireframe, &QAction::triggered, [ 586 QObject::connect(state.mainWindow.actionWireframe, &QAction::triggered, [&state]
617 &documents,
618 &renderPreferences,
619 &saveSettings,
620 &mainWindow]
621 (bool enabled) 587 (bool enabled)
622 { 588 {
623 renderPreferences.wireframe = enabled; 589 state.renderPreferences.wireframe = enabled;
624 saveSettings(); 590 saveSettings(&state);
625 updateRenderPreferences(&mainWindow, &renderPreferences, &documents); 591 updateRenderPreferences(&state.mainWindow, &state.renderPreferences, &state.documents);
626 }); 592 });
627 QObject::connect(&mainWindow, &MainWindow::renderStyleSelected, [ 593 QObject::connect(&state.mainWindow, &MainWindow::renderStyleSelected, [&state]
628 &documents,
629 &mainWindow,
630 &renderPreferences,
631 &saveSettings]
632 (gl::RenderStyle newStyle) 594 (gl::RenderStyle newStyle)
633 { 595 {
634 renderPreferences.style = newStyle; 596 state.renderPreferences.style = newStyle;
635 saveSettings(); 597 saveSettings(&state);
636 updateRenderPreferences(&mainWindow, &renderPreferences, &documents); 598 updateRenderPreferences(&state.mainWindow, &state.renderPreferences, &state.documents);
637 }); 599 });
638 const auto checkEditingModeAction = [&mainWindow, &documents](EditingMode mode) { 600 initializeTools(&state.mainWindow, &state.toolWidgets, &state.mainWindow);
639 const bool hasDocument = currentModelData(&mainWindow, &documents) != nullptr; 601 for (QAction* action : state.mainWindow.editingModesToolBar->actions()) {
640 for (QAction* action : mainWindow.editingModesToolBar->actions()) { 602 QObject::connect(action, &QAction::triggered, [action, &state]
641 action->setEnabled(hasDocument); 603 {
642 action->setChecked(hasDocument and action->data().value<EditingMode>() == mode); 604 if (ModelData* data = currentModelData(&state.mainWindow, &state.documents))
643 } 605 {
644 };
645 initializeTools(&mainWindow, &toolWidgets, &mainWindow);
646 for (QAction* action : mainWindow.editingModesToolBar->actions()) {
647 QObject::connect(action, &QAction::triggered, [
648 action,
649 &checkEditingModeAction,
650 &documents,
651 &mainWindow]
652 {
653 if (ModelData* data = currentModelData(&mainWindow, &documents)) {
654 const EditingMode mode = action->data().value<EditingMode>(); 606 const EditingMode mode = action->data().value<EditingMode>();
655 data->tools->setEditMode(mode); 607 data->tools->setEditMode(mode);
656 checkEditingModeAction(mode); 608 checkEditingModeAction(&state, mode);
657 } 609 }
658 }); 610 });
659 } 611 }
660 QObject::connect(mainWindow.mdiArea, &QMdiArea::subWindowActivated, [ 612 QObject::connect(state.mainWindow.mdiArea, &QMdiArea::subWindowActivated,
661 &checkEditingModeAction, 613 [&state](QMdiSubWindow* subWindow)
662 &documents,
663 &mainWindow,
664 &updateTitle]
665 (QMdiSubWindow* subWindow)
666 { 614 {
667 ModelSubWindow* modelSubWindow = qobject_cast<ModelSubWindow*>(subWindow); 615 ModelSubWindow* modelSubWindow = qobject_cast<ModelSubWindow*>(subWindow);
668 if (modelSubWindow != nullptr) { 616 if (modelSubWindow != nullptr)
669 if (ModelData* data = documents.findPayload<ModelData>(modelSubWindow->modelId)) { 617 {
670 checkEditingModeAction(data->tools->currentEditingMode()); 618 if (ModelData* data = state.documents.findPayload<ModelData>(modelSubWindow->modelId))
671 mainWindow.modelEdit->setDocument(data->model); 619 {
672 mainWindow.modelEdit->setTextCursor(*data->textcursor); 620 checkEditingModeAction(&state, data->tools->currentEditingMode());
673 mainWindow.modelEdit->setFont(codeEditorFontFromSettings()); 621 state.mainWindow.modelEdit->setDocument(data->model);
674 } 622 state.mainWindow.modelEdit->setTextCursor(*data->textcursor);
675 } 623 state.mainWindow.modelEdit->setFont(codeEditorFontFromSettings());
676 else { 624 }
677 checkEditingModeAction(EditingMode::SelectMode); 625 }
678 } 626 else
679 mainWindow.modelEdit->setEnabled(modelSubWindow != nullptr); 627 {
680 updateTitle(); 628 checkEditingModeAction(&state, EditingMode::SelectMode);
681 }); 629 }
682 mainWindow.messageLog->setModel(&messageLog); 630 state.mainWindow.modelEdit->setEnabled(modelSubWindow != nullptr);
683 QObject::connect(&documents, &DocumentManager::message, &messageLog, &MessageLog::addMessage); 631 });
684 QObject::connect(&messageLog, &MessageLog::rowsAboutToBeInserted, [&mainWindow]{ 632 state.mainWindow.messageLog->setModel(&state.messageLog);
685 const auto bar = mainWindow.messageLog->verticalScrollBar(); 633 QObject::connect(&state.documents, &DocumentManager::message, &state.messageLog, &MessageLog::addMessage);
686 mainWindow.messageLog->setProperty("shouldAutoScroll", bar->value() == bar->maximum()); 634 QObject::connect(&state.messageLog, &MessageLog::rowsAboutToBeInserted, [&state]{
687 }); 635 const auto bar = state.mainWindow.messageLog->verticalScrollBar();
688 QObject::connect(&messageLog, &MessageLog::rowsInserted, [&mainWindow]{ 636 state.mainWindow.messageLog->setProperty("shouldAutoScroll", bar->value() == bar->maximum());
689 mainWindow.messageLog->resizeRowsToContents(); 637 });
690 if (mainWindow.messageLog->property("shouldAutoScroll").toBool()) { 638 QObject::connect(&state.messageLog, &MessageLog::rowsInserted, [&state]{
691 mainWindow.messageLog->scrollToBottom(); 639 state.mainWindow.messageLog->resizeRowsToContents();
640 if (state.mainWindow.messageLog->property("shouldAutoScroll").toBool()) {
641 state.mainWindow.messageLog->scrollToBottom();
692 } 642 }
693 }); 643 });
694 QObject::connect( 644 QObject::connect(
695 toolWidgets.circleToolOptions, 645 state.toolWidgets.circleToolOptions,
696 &CircleToolOptionsWidget::optionsChanged, 646 &CircleToolOptionsWidget::optionsChanged,
697 [&mainWindow, &documents](const CircleToolOptions& options) { 647 [&state](const CircleToolOptions& options) {
698 if (ModelData* data = currentModelData(&mainWindow, &documents)) { 648 if (ModelData* data = currentModelData(&state.mainWindow, &state.documents)) {
699 data->tools->setCircleToolOptions(options); 649 data->tools->setCircleToolOptions(options);
700 } 650 }
701 }); 651 });
702 QObject::connect( 652 QObject::connect(
703 mainWindow.actionMakeUnofficial, 653 state.mainWindow.actionMakeUnofficial,
704 &QAction::triggered, 654 &QAction::triggered,
705 [&documents, &mainWindow]{ 655 [&state]{
706 if (ModelData* data = currentModelData(&mainWindow, &documents)) { 656 if (ModelData* data = currentModelData(&state.mainWindow, &state.documents)) {
707 QTextDocument* const model = data->model; 657 QTextDocument* const model = data->model;
708 for (const ModelAction& action : ldraw::makeUnofficial(model)) { 658 for (const ModelAction& action : ldraw::makeUnofficial(model)) {
709 executeAction(model, action); 659 executeAction(model, action);
710 } 660 }
711 } 661 }
712 }); 662 });
713 QObject::connect(mainWindow.actionAboutQt, &QAction::triggered, &app, &QApplication::aboutQt); 663 QObject::connect(state.mainWindow.actionAboutQt, &QAction::triggered, &QApplication::aboutQt);
714 QObject::connect( 664 QObject::connect(
715 mainWindow.modelEdit, 665 state.mainWindow.modelEdit,
716 &QPlainTextEdit::textChanged, 666 &QPlainTextEdit::textChanged,
717 [&documents, &libraries, &mainWindow]{ 667 [&state]{
718 if (ModelData* data = currentModelData(&mainWindow, &documents)) { 668 if (ModelData* data = currentModelData(&state.mainWindow, &state.documents)) {
719 documents.loadDependenciesForAllModels(libraries); 669 state.documents.loadDependenciesForAllModels(state.libraries);
720 data->canvas->update(); 670 data->canvas->update();
721 } 671 }
722 }); 672 });
723 QObject::connect( 673 QObject::connect(
724 mainWindow.gridMatrix, 674 state.mainWindow.gridMatrix,
725 &MatrixEditor::valueChanged, 675 &MatrixEditor::valueChanged,
726 [&](const glm::mat4& newGridMatrix) 676 [&](const glm::mat4& newGridMatrix)
727 { 677 {
728 forEachModel(&documents, [&](const void*, const ModelData* data) 678 forEachModel(&state.documents, [&](const void*, const ModelData* data)
729 { 679 {
730 if (data->gridLayer != nullptr and data->tools != nullptr and data->canvas != nullptr) 680 if (data->gridLayer != nullptr and data->tools != nullptr and data->canvas != nullptr)
731 { 681 {
732 data->gridLayer->setGridMatrix(newGridMatrix); 682 data->gridLayer->setGridMatrix(newGridMatrix);
733 data->tools->setGridMatrix(newGridMatrix); 683 data->tools->setGridMatrix(newGridMatrix);
735 data->canvas->update(); 685 data->canvas->update();
736 } 686 }
737 }); 687 });
738 } 688 }
739 ); 689 );
740 mainWindow.gridMatrix->setValue(DEFAULT_GRID_MATRIX); 690 restoreSettings(&state);
741 mainWindow.tabifyDockWidget(mainWindow.messageLogDock, mainWindow.toolOptionsDock); 691 updateRenderPreferences(&state.mainWindow, &state.renderPreferences, &state.documents);
742 mainWindow.restoreGeometry(setting<Setting::MainWindowGeometry>());
743 mainWindow.restoreState(setting<Setting::MainWindowState>());
744 // If a dock is made floating and the app is closed, the dock becomes invisible
745 // after the restoreState call. So we make them visible again here.
746 for (QDockWidget* dock : mainWindow.findChildren<QDockWidget*>()) {
747 dock->setVisible(true);
748 }
749 restoreSettings();
750 updateRenderPreferences(&mainWindow, &renderPreferences, &documents);
751 mainWindow.actionAbout->setText(mainWindow.actionAbout->text().arg(CMAKE_PROJECT_NAME));
752 updateTitle();
753 mainWindow.show();
754 const int result = app.exec(); 692 const int result = app.exec();
755 saveSettings(); 693 saveSettings(&state);
756 return result; 694 return result;
757 } 695 }

mercurial