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); |