#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include "projecttreemodel.h" #include "dialogs/spritepropertiesdialog.h" #include "dialogs/soundpropertiesdialog.h" #include "dialogs/backgroundpropertiesdialog.h" #include "dialogs/pathpropertiesdialog.h" #include "dialogs/scriptpropertiesdialog.h" #include "dialogs/fontpropertiesdialog.h" #include "dialogs/preferencesdialog.h" #include "dialogs/gameinformationdialog.h" #include "dialogs/globalgamesettingsdialog.h" #include "dialogs/extensionpackagesdialog.h" #include "dialogs/objectinformationdialog.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent}, m_ui{std::make_unique()}, m_projectTreeModel{std::make_unique(m_project, this)} { m_ui->setupUi(this); { QList sizes; sizes.append(0.5 * m_ui->splitter->width()); sizes.append(0.5 * m_ui->splitter->width()); m_ui->splitter->setSizes(sizes); } m_ui->actionNew->setShortcut(QKeySequence::New); m_ui->actionOpen->setShortcut(QKeySequence::Open); m_ui->actionSave->setShortcut(QKeySequence::Save); m_ui->actionSaveAs->setShortcut(QKeySequence::SaveAs); m_ui->actionExit->setShortcut(QKeySequence::Quit); m_ui->actionFindResource->setShortcut(QKeySequence::Find); m_ui->actionPrevious->setShortcut(QKeySequence::PreviousChild); m_ui->actionNext->setShortcut(QKeySequence::NextChild); m_ui->actionContents->setShortcut(QKeySequence::HelpContents); { const auto updateViewActions = [this](){ m_ui->actionSubWindowedView->setChecked(m_ui->mdiArea->viewMode() == QMdiArea::SubWindowView); m_ui->actionTabbedView->setChecked(m_ui->mdiArea->viewMode() == QMdiArea::TabbedView); }; updateViewActions(); connect(m_ui->actionSubWindowedView, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,updateViewActions](){ mdiArea->setViewMode(QMdiArea::SubWindowView); updateViewActions(); }); connect(m_ui->actionTabbedView, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,updateViewActions](){ mdiArea->setViewMode(QMdiArea::TabbedView); updateViewActions(); }); } connect(m_ui->actionNew, &QAction::triggered, this, &MainWindow::newFile); connect(m_ui->actionOpen, &QAction::triggered, this, &MainWindow::openFile); connect(m_ui->actionSave, &QAction::triggered, this, &MainWindow::saveFile); connect(m_ui->actionSaveAs, &QAction::triggered, this, &MainWindow::saveFileAs); connect(m_ui->actionCreateExecutable, &QAction::triggered, this, &MainWindow::createExecutable); connect(m_ui->actionPublishGame, &QAction::triggered, this, &MainWindow::publishGame); connect(m_ui->actionImportResources, &QAction::triggered, this, &MainWindow::importResources); connect(m_ui->actionExportResources, &QAction::triggered, this, &MainWindow::exportResources); connect(m_ui->actionPreferences, &QAction::triggered, this, &MainWindow::preferences); connect(m_ui->actionCreate, &QAction::triggered, this, &MainWindow::create); connect(m_ui->actionDuplicate, &QAction::triggered, this, &MainWindow::duplicate); connect(m_ui->actionCreateGroup, &QAction::triggered, this, &MainWindow::createGroup); connect(m_ui->actionSortByName, &QAction::triggered, this, &MainWindow::sortByName); connect(m_ui->actionDelete, &QAction::triggered, this, &MainWindow::delete_); connect(m_ui->actionRename, &QAction::triggered, this, &MainWindow::rename); connect(m_ui->actionProperties, &QAction::triggered, this, &MainWindow::showProperties); connect(m_ui->actionFindResource, &QAction::triggered, this, &MainWindow::findResource); connect(m_ui->actionShowObjectInformation, &QAction::triggered, this, &MainWindow::showObjectInformation); connect(m_ui->actionCreateSprite, &QAction::triggered, this, &MainWindow::createSprite); connect(m_ui->actionCreateSound, &QAction::triggered, this, &MainWindow::createSound); connect(m_ui->actionCreateBackground, &QAction::triggered, this, &MainWindow::createBackground); connect(m_ui->actionCreatePath, &QAction::triggered, this, &MainWindow::createPath); connect(m_ui->actionCreateScript, &QAction::triggered, this, &MainWindow::createScript); connect(m_ui->actionCreateFont, &QAction::triggered, this, &MainWindow::createFont); connect(m_ui->actionGameInformation, &QAction::triggered, this, &MainWindow::showGameInformation); connect(m_ui->actionGlobalGameSettings, &QAction::triggered, this, &MainWindow::showGlobalGameSettings); connect(m_ui->actionExtensionPackages, &QAction::triggered, this, &MainWindow::showExtensionPackages); connect(m_ui->actionAbout, &QAction::triggered, this, &MainWindow::about); connect(m_ui->actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt); m_ui->treeView->setModel(m_projectTreeModel.get()); connect(m_projectTreeModel.get(), &ProjectTreeModel::errorOccured, this, &MainWindow::modelErrorOccured); connect(m_ui->treeView, &QTreeView::customContextMenuRequested, this, &MainWindow::contextMenuRequested); connect(m_ui->treeView, &QTreeView::doubleClicked, this, &MainWindow::doubleClicked); connect(m_ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::selectionChanged); connect(m_projectTreeModel.get(), &ProjectTreeModel::rowsInserted, this, &MainWindow::rowsInserted); connect(m_projectTreeModel.get(), &ProjectTreeModel::rowsAboutToBeRemoved, this, &MainWindow::rowsAboutToBeRemoved); connect(m_projectTreeModel.get(), &ProjectTreeModel::modelAboutToBeReset, this, &MainWindow::modelAboutToBeReset); updateTitle(); } void MainWindow::closeEvent(QCloseEvent *event) { m_ui->mdiArea->closeAllSubWindows(); if (!m_ui->mdiArea->subWindowList().empty()) { event->ignore(); return; } if (m_unsavedChanges) { const auto result = QMessageBox::warning( this, tr("The Game has been modified."), tr("Do you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save ); switch (result) { case QMessageBox::Save: saveFile(); if (m_unsavedChanges) { event->ignore(); return; } else break; case QMessageBox::Discard: break; case QMessageBox::Cancel: event->ignore(); return; default: qWarning() << "unexpected dialog result" << result; event->ignore(); return; } } QMainWindow::closeEvent(event); } MainWindow::~MainWindow() = default; void MainWindow::contextMenuRequested(const QPoint &pos) { QMenu menu{this}; menu.addAction(m_ui->actionCreate); menu.addAction(m_ui->actionDuplicate); menu.addSeparator(); menu.addAction(m_ui->actionCreateGroup); menu.addSeparator(); menu.addAction(m_ui->actionSortByName); menu.addSeparator(); menu.addAction(m_ui->actionDelete); menu.addSeparator(); menu.addAction(m_ui->actionRename); menu.addSeparator(); menu.addAction(m_ui->actionProperties); menu.exec(m_ui->treeView->viewport()->mapToGlobal(pos)); } void MainWindow::doubleClicked(const QModelIndex &index) { switch (m_projectTreeModel->nodeType(index)) { case ProjectTreeModel::NodeType::Root: if (index == m_projectTreeModel->gameInformationRoot()) showGameInformation(); else if (index == m_projectTreeModel->globalGameSettingsRoot()) showGlobalGameSettings(); else if (index == m_projectTreeModel->extensionPackagesRoot()) showExtensionPackages(); break; case ProjectTreeModel::NodeType::Sprite: { auto sprite = m_projectTreeModel->getSprite(index); if (!sprite) break; if (const auto iter = m_spritePropertiesWindows.find(sprite); iter != std::cend(m_spritePropertiesWindows)) { m_ui->mdiArea->setActiveSubWindow(iter->second); } else { auto dialog = new SpritePropertiesDialog{*sprite}; auto subwindow = m_ui->mdiArea->addSubWindow(dialog); auto action = m_ui->menuWindow->addAction(dialog->windowTitle()); action->setCheckable(true); connect(action, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,subwindow,action](){ mdiArea->setActiveSubWindow(subwindow); action->setChecked(subwindow->windowState().testFlag(Qt::WindowActive)); }); connect(subwindow, &QMdiSubWindow::windowStateChanged, action, [action](Qt::WindowStates oldState, Qt::WindowStates newState){ action->setChecked(newState.testFlag(Qt::WindowActive)); }); connect(dialog, &QWidget::windowTitleChanged, action, &QAction::setText); connect(dialog, &QDialog::finished, this, [&spritePropertiesDialogs=m_spritePropertiesWindows,subwindow](){ for (auto iter = std::begin(spritePropertiesDialogs); iter != std::end(spritePropertiesDialogs); ) { if (iter->second == subwindow) iter = spritePropertiesDialogs.erase(iter); else iter++; } }); connect(dialog, &QDialog::finished, subwindow, &QObject::deleteLater); connect(dialog, &QDialog::finished, action, &QObject::deleteLater); m_spritePropertiesWindows[sprite] = subwindow; dialog->show(); } break; } case ProjectTreeModel::NodeType::Sound: { auto sound = m_projectTreeModel->getSound(index); if (!sound) break; if (const auto iter = m_soundPropertiesWindows.find(sound); iter != std::cend(m_soundPropertiesWindows)) { m_ui->mdiArea->setActiveSubWindow(iter->second); } else { auto dialog = new SoundPropertiesDialog{*sound}; auto subwindow = m_ui->mdiArea->addSubWindow(dialog); auto action = m_ui->menuWindow->addAction(dialog->windowTitle()); action->setCheckable(true); connect(action, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,subwindow,action](){ mdiArea->setActiveSubWindow(subwindow); action->setChecked(subwindow->windowState().testFlag(Qt::WindowActive)); }); connect(subwindow, &QMdiSubWindow::windowStateChanged, action, [action](Qt::WindowStates oldState, Qt::WindowStates newState){ action->setChecked(newState.testFlag(Qt::WindowActive)); }); connect(dialog, &QWidget::windowTitleChanged, action, &QAction::setText); connect(dialog, &QDialog::finished, this, [&soundPropertiesDialogs=m_soundPropertiesWindows,subwindow](){ for (auto iter = std::begin(soundPropertiesDialogs); iter != std::end(soundPropertiesDialogs); ) { if (iter->second == subwindow) iter = soundPropertiesDialogs.erase(iter); else iter++; } }); connect(dialog, &QDialog::finished, subwindow, &QObject::deleteLater); connect(dialog, &QDialog::finished, action, &QObject::deleteLater); m_soundPropertiesWindows[sound] = subwindow; dialog->show(); } break; } case ProjectTreeModel::NodeType::Background: { auto background = m_projectTreeModel->getBackground(index); if (!background) break; if (const auto iter = m_backgroundPropertiesWindows.find(background); iter != std::cend(m_backgroundPropertiesWindows)) { m_ui->mdiArea->setActiveSubWindow(iter->second); } else { auto dialog = new BackgroundPropertiesDialog{*background}; auto subwindow = m_ui->mdiArea->addSubWindow(dialog); auto action = m_ui->menuWindow->addAction(dialog->windowTitle()); action->setCheckable(true); connect(action, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,subwindow,action](){ mdiArea->setActiveSubWindow(subwindow); action->setChecked(subwindow->windowState().testFlag(Qt::WindowActive)); }); connect(subwindow, &QMdiSubWindow::windowStateChanged, action, [action](Qt::WindowStates oldState, Qt::WindowStates newState){ action->setChecked(newState.testFlag(Qt::WindowActive)); }); connect(dialog, &QWidget::windowTitleChanged, action, &QAction::setText); connect(dialog, &QDialog::finished, this, [&backgroundPropertiesDialogs=m_backgroundPropertiesWindows,subwindow](){ for (auto iter = std::begin(backgroundPropertiesDialogs); iter != std::end(backgroundPropertiesDialogs); ) { if (iter->second == subwindow) iter = backgroundPropertiesDialogs.erase(iter); else iter++; } }); connect(dialog, &QDialog::finished, subwindow, &QObject::deleteLater); connect(dialog, &QDialog::finished, action, &QObject::deleteLater); m_backgroundPropertiesWindows[background] = subwindow; dialog->show(); } break; } case ProjectTreeModel::NodeType::Path: { auto path = m_projectTreeModel->getPath(index); if (!path) break; if (const auto iter = m_pathPropertiesWindows.find(path); iter != std::cend(m_pathPropertiesWindows)) { m_ui->mdiArea->setActiveSubWindow(iter->second); } else { auto dialog = new PathPropertiesDialog{*path}; auto subwindow = m_ui->mdiArea->addSubWindow(dialog); auto action = m_ui->menuWindow->addAction(dialog->windowTitle()); action->setCheckable(true); connect(action, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,subwindow,action](){ mdiArea->setActiveSubWindow(subwindow); action->setChecked(subwindow->windowState().testFlag(Qt::WindowActive)); }); connect(subwindow, &QMdiSubWindow::windowStateChanged, action, [action](Qt::WindowStates oldState, Qt::WindowStates newState){ action->setChecked(newState.testFlag(Qt::WindowActive)); }); connect(dialog, &QWidget::windowTitleChanged, action, &QAction::setText); connect(dialog, &QDialog::finished, this, [&pathPropertiesDialogs=m_pathPropertiesWindows,subwindow](){ for (auto iter = std::begin(pathPropertiesDialogs); iter != std::end(pathPropertiesDialogs); ) { if (iter->second == subwindow) iter = pathPropertiesDialogs.erase(iter); else iter++; } }); connect(dialog, &QDialog::finished, subwindow, &QObject::deleteLater); connect(dialog, &QDialog::finished, action, &QObject::deleteLater); m_pathPropertiesWindows[path] = subwindow; dialog->show(); } break; } case ProjectTreeModel::NodeType::Script: { auto script = m_projectTreeModel->getScript(index); if (!script) break; if (const auto iter = m_scriptPropertiesWindows.find(script); iter != std::cend(m_scriptPropertiesWindows)) { m_ui->mdiArea->setActiveSubWindow(iter->second); } else { auto dialog = new ScriptPropertiesDialog{*script}; auto subwindow = m_ui->mdiArea->addSubWindow(dialog); auto action = m_ui->menuWindow->addAction(dialog->windowTitle()); action->setCheckable(true); connect(action, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,subwindow,action](){ mdiArea->setActiveSubWindow(subwindow); action->setChecked(subwindow->windowState().testFlag(Qt::WindowActive)); }); connect(subwindow, &QMdiSubWindow::windowStateChanged, action, [action](Qt::WindowStates oldState, Qt::WindowStates newState){ action->setChecked(newState.testFlag(Qt::WindowActive)); }); connect(dialog, &QWidget::windowTitleChanged, action, &QAction::setText); connect(dialog, &QDialog::finished, this, [&scriptPropertiesDialogs=m_scriptPropertiesWindows,subwindow](){ for (auto iter = std::begin(scriptPropertiesDialogs); iter != std::end(scriptPropertiesDialogs); ) { if (iter->second == subwindow) iter = scriptPropertiesDialogs.erase(iter); else iter++; } }); connect(dialog, &QDialog::finished, subwindow, &QObject::deleteLater); connect(dialog, &QDialog::finished, action, &QObject::deleteLater); m_scriptPropertiesWindows[script] = subwindow; dialog->show(); } break; } case ProjectTreeModel::NodeType::Font: { auto font = m_projectTreeModel->getFont(index); if (!font) break; if (const auto iter = m_fontPropertiesWindows.find(font); iter != std::cend(m_fontPropertiesWindows)) { m_ui->mdiArea->setActiveSubWindow(iter->second); } else { auto dialog = new FontPropertiesDialog{*font}; auto subwindow = m_ui->mdiArea->addSubWindow(dialog); auto action = m_ui->menuWindow->addAction(dialog->windowTitle()); action->setCheckable(true); connect(action, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,subwindow,action](){ mdiArea->setActiveSubWindow(subwindow); action->setChecked(subwindow->windowState().testFlag(Qt::WindowActive)); }); connect(subwindow, &QMdiSubWindow::windowStateChanged, action, [action](Qt::WindowStates oldState, Qt::WindowStates newState){ action->setChecked(newState.testFlag(Qt::WindowActive)); }); connect(dialog, &QWidget::windowTitleChanged, action, &QAction::setText); connect(dialog, &QDialog::finished, this, [&fontPropertiesDialogs=m_fontPropertiesWindows,subwindow](){ for (auto iter = std::begin(fontPropertiesDialogs); iter != std::end(fontPropertiesDialogs); ) { if (iter->second == subwindow) iter = fontPropertiesDialogs.erase(iter); else iter++; } }); connect(dialog, &QDialog::finished, subwindow, &QObject::deleteLater); connect(dialog, &QDialog::finished, action, &QObject::deleteLater); m_fontPropertiesWindows[font] = subwindow; dialog->show(); } break; } } } void MainWindow::selectionChanged(const QModelIndex &index) { switch (const auto nodeType = m_projectTreeModel->nodeType(index)) { case ProjectTreeModel::NodeType::Root: if (index == m_projectTreeModel->spritesRoot() || index == m_projectTreeModel->soundsRoot() || index == m_projectTreeModel->backgroundsRoot() || index == m_projectTreeModel->pathsRoot() || index == m_projectTreeModel->scriptsRoot() || index == m_projectTreeModel->fontsRoot()) { m_ui->actionCreate->setEnabled(true); m_ui->actionCreateGroup->setText(tr("Cr&eate Group")); m_ui->actionCreateGroup->setEnabled(true); m_ui->actionSortByName->setEnabled(true); if (index == m_projectTreeModel->spritesRoot()) m_ui->actionCreate->setText(tr("&Create Sprite")); else if (index == m_projectTreeModel->soundsRoot()) m_ui->actionCreate->setText(tr("&Create Sound")); else if (index == m_projectTreeModel->backgroundsRoot()) m_ui->actionCreate->setText(tr("&Create Background")); else if (index == m_projectTreeModel->pathsRoot()) m_ui->actionCreate->setText(tr("&Create Path")); else if (index == m_projectTreeModel->scriptsRoot()) m_ui->actionCreate->setText(tr("&Create Script")); else if (index == m_projectTreeModel->fontsRoot()) m_ui->actionCreate->setText(tr("&Create Font")); } else { m_ui->actionCreate->setEnabled(false); m_ui->actionCreate->setText(tr("&Create")); m_ui->actionCreateGroup->setText(tr("Cr&eate Group")); m_ui->actionCreateGroup->setEnabled(false); m_ui->actionSortByName->setEnabled(false); } m_ui->actionDuplicate->setEnabled(false); m_ui->actionDelete->setEnabled(false); m_ui->actionRename->setEnabled(false); m_ui->actionProperties->setEnabled( index == m_projectTreeModel->gameInformationRoot() || index == m_projectTreeModel->globalGameSettingsRoot() || index == m_projectTreeModel->extensionPackagesRoot()); break; case ProjectTreeModel::NodeType::Sprite: case ProjectTreeModel::NodeType::Sound: case ProjectTreeModel::NodeType::Background: case ProjectTreeModel::NodeType::Path: case ProjectTreeModel::NodeType::Script: case ProjectTreeModel::NodeType::Font: m_ui->actionCreate->setEnabled(true); switch (nodeType) { case ProjectTreeModel::NodeType::Sprite: m_ui->actionCreate->setText(tr("&Insert Sprite")); break; case ProjectTreeModel::NodeType::Sound: m_ui->actionCreate->setText(tr("&Insert Sound")); break; case ProjectTreeModel::NodeType::Background: m_ui->actionCreate->setText(tr("&Insert Background")); break; case ProjectTreeModel::NodeType::Path: m_ui->actionCreate->setText(tr("&Insert Path")); break; case ProjectTreeModel::NodeType::Script: m_ui->actionCreate->setText(tr("&Insert Script")); break; case ProjectTreeModel::NodeType::Font: m_ui->actionCreate->setText(tr("&Insert Font")); break; default: __builtin_unreachable(); } m_ui->actionDuplicate->setEnabled(true); m_ui->actionCreateGroup->setText(tr("I&nsert Group")); m_ui->actionCreateGroup->setEnabled(true); m_ui->actionSortByName->setEnabled(false); m_ui->actionDelete->setEnabled(true); m_ui->actionRename->setEnabled(true); m_ui->actionProperties->setEnabled(true); break; default: m_ui->actionCreate->setEnabled(false); m_ui->actionCreate->setText(tr("&Create")); m_ui->actionDuplicate->setEnabled(false); m_ui->actionCreateGroup->setText(tr("Cr&eate Group")); m_ui->actionCreateGroup->setEnabled(false); m_ui->actionSortByName->setEnabled(false); m_ui->actionDelete->setEnabled(false); m_ui->actionRename->setEnabled(false); m_ui->actionProperties->setEnabled(false); } } void MainWindow::modelErrorOccured(const QString &message) { QMessageBox::warning(this, tr("Error occured!"), tr("Error occured!") + "\n\n" + message); } void MainWindow::newFile() { m_ui->mdiArea->closeAllSubWindows(); if (!m_ui->mdiArea->subWindowList().empty()) return; if (m_unsavedChanges) { const auto result = QMessageBox::warning( this, tr("The Game has been modified."), tr("Do you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save ); switch (result) { case QMessageBox::Save: saveFile(); if (m_unsavedChanges) return; else break; case QMessageBox::Discard: break; case QMessageBox::Cancel: return; default: qWarning() << "unexpected dialog result" << result; return; } } m_project = {}; m_projectTreeModel->setProject(&m_project); m_filePath = {}; m_unsavedChanges = false; updateTitle(); } void MainWindow::openFile() { auto path = QFileDialog::getOpenFileName(this, tr("Load a game"), {}, tr("GMK Files (*.gmk)")); if (path.isEmpty()) return; ProjectContainer project; { QFile file{path}; if (!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(this, tr("Could not load game!"), tr("Could not load game!") + "\n\n" + file.errorString()); return; } QDataStream dataStream{&file}; dataStream >> project; } m_ui->mdiArea->closeAllSubWindows(); if (!m_ui->mdiArea->subWindowList().empty()) return; if (m_unsavedChanges) { const auto result = QMessageBox::warning( this, tr("The Game has been modified."), tr("Do you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save ); switch (result) { case QMessageBox::Save: saveFile(); if (m_unsavedChanges) return; else break; case QMessageBox::Discard: break; case QMessageBox::Cancel: return; default: qWarning() << "unexpected dialog result" << result; return; } } m_project = std::move(project); m_projectTreeModel->setProject(&m_project); m_filePath = path; m_unsavedChanges = false; updateTitle(); } void MainWindow::saveFile() { if (m_filePath.isEmpty()) { saveFileAs(); return; } { QFile file{m_filePath}; if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QMessageBox::warning(this, tr("Could not save game!"), tr("Could not save game!") + "\n\n" + file.errorString()); saveFileAs(); return; } QDataStream dataStream{&file}; dataStream << m_project; } m_unsavedChanges = false; updateTitle(); } void MainWindow::saveFileAs() { auto path = QFileDialog::getSaveFileName(this, tr("Save the game"), "mygame.gmk", tr("GMK Files (*.gmk)")); if (path.isEmpty()) return; { QFile file{path}; if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QMessageBox::warning(this, tr("Could not save game!"), tr("Could not save game!") + "\n\n" + file.errorString()); return; } QDataStream dataStream{&file}; dataStream << m_project; } m_filePath = path; m_unsavedChanges = false; updateTitle(); } void MainWindow::createExecutable() { QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); } void MainWindow::publishGame() { QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); } void MainWindow::importResources() { QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); } void MainWindow::exportResources() { QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); } void MainWindow::preferences() { PreferencesDialog{this}.exec(); } void MainWindow::create() { const auto index = m_ui->treeView->currentIndex(); if (!index.isValid()) return; if (index == m_projectTreeModel->spritesRoot()) createSprite(); else if (index == m_projectTreeModel->soundsRoot()) createSound(); else if (index == m_projectTreeModel->backgroundsRoot()) createBackground(); else if (index == m_projectTreeModel->pathsRoot()) createPath(); else if (index == m_projectTreeModel->scriptsRoot()) createScript(); else if (index == m_projectTreeModel->fontsRoot()) createFont(); else { switch (m_projectTreeModel->nodeType(index)) { case ProjectTreeModel::NodeType::Sprite: case ProjectTreeModel::NodeType::Sound: case ProjectTreeModel::NodeType::Background: case ProjectTreeModel::NodeType::Path: case ProjectTreeModel::NodeType::Script: case ProjectTreeModel::NodeType::Font: if (!m_projectTreeModel->insertRows(index.row(), 1, index.parent())) QMessageBox::warning(this, tr("Inserting failed!"), tr("Inserting failed!")); break; } } } void MainWindow::duplicate() { QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); } void MainWindow::createGroup() { QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); } void MainWindow::sortByName() { QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); } void MainWindow::delete_() { const auto index = m_ui->treeView->currentIndex(); if (!index.isValid()) return; if (!m_projectTreeModel->removeRow(index.row(), index.parent())) QMessageBox::warning(this, tr("Deleting failed!"), tr("Deleting failed!")); } void MainWindow::rename() { m_ui->treeView->edit(m_ui->treeView->currentIndex()); } void MainWindow::showProperties() { const auto index = m_ui->treeView->currentIndex(); if (!index.isValid()) { qWarning() << "unexpected invalid index"; return; } doubleClicked(index); } void MainWindow::findResource() { bool ok; const auto filter = QInputDialog::getText(this, tr("Finding a resource"), tr("Resource name:"), QLineEdit::Normal, {}, &ok); if (!ok) return; QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); } void MainWindow::showObjectInformation() { if (m_objectInformationWindow) m_ui->mdiArea->setActiveSubWindow(m_objectInformationWindow); else { auto dialog = new ObjectInformationDialog; auto subwindow = m_ui->mdiArea->addSubWindow(dialog); auto action = m_ui->menuWindow->addAction(dialog->windowTitle()); action->setCheckable(true); connect(action, &QAction::triggered, m_ui->mdiArea, [mdiArea=m_ui->mdiArea,subwindow,action](){ mdiArea->setActiveSubWindow(subwindow); action->setChecked(subwindow->windowState().testFlag(Qt::WindowActive)); }); connect(subwindow, &QMdiSubWindow::windowStateChanged, action, [action](Qt::WindowStates oldState, Qt::WindowStates newState){ action->setChecked(newState.testFlag(Qt::WindowActive)); }); connect(dialog, &QWidget::windowTitleChanged, action, &QAction::setText); connect(dialog, &QDialog::finished, this, [&objectInformationWindow=m_objectInformationWindow](){ objectInformationWindow = nullptr; }); connect(dialog, &QDialog::finished, subwindow, &QObject::deleteLater); connect(dialog, &QDialog::finished, action, &QObject::deleteLater); m_objectInformationWindow = subwindow; dialog->show(); } } void MainWindow::createSprite() { if (!m_projectTreeModel->insertRows(m_project.sprites.size(), 1, m_projectTreeModel->spritesRoot())) QMessageBox::warning(this, tr("Creating Sprite failed!"), tr("Creating Sprite failed!")); } void MainWindow::createSound() { if (!m_projectTreeModel->insertRows(m_project.sounds.size(), 1, m_projectTreeModel->soundsRoot())) QMessageBox::warning(this, tr("Creating Sound failed!"), tr("Creating Sound failed!")); } void MainWindow::createBackground() { if (!m_projectTreeModel->insertRows(m_project.backgrounds.size(), 1, m_projectTreeModel->backgroundsRoot())) QMessageBox::warning(this, tr("Creating Background failed!"), tr("Creating Background failed!")); } void MainWindow::createPath() { if (!m_projectTreeModel->insertRows(m_project.paths.size(), 1, m_projectTreeModel->pathsRoot())) QMessageBox::warning(this, tr("Creating Path failed!"), tr("Creating Path failed!")); } void MainWindow::createScript() { if (!m_projectTreeModel->insertRows(m_project.scripts.size(), 1, m_projectTreeModel->scriptsRoot())) QMessageBox::warning(this, tr("Creating Script failed!"), tr("Creating Script failed!")); } void MainWindow::createFont() { if (!m_projectTreeModel->insertRows(m_project.fonts.size(), 1, m_projectTreeModel->fontsRoot())) QMessageBox::warning(this, tr("Creating Font failed!"), tr("Creating Font failed!")); } void MainWindow::showGameInformation() { GameInformationDialog{this}.exec(); } void MainWindow::showGlobalGameSettings() { GlobalGameSettingsDialog{this}.exec(); } void MainWindow::showExtensionPackages() { ExtensionPackagesDialog{this}.exec(); } void MainWindow::about() { QMessageBox::about(this, tr("About Qt Game Maker"), tr("This About-Dialog is not finished.")); } void MainWindow::rowsInserted(const QModelIndex &parent, int first, int last) { m_ui->treeView->expand(parent); const auto index = m_projectTreeModel->index(first, 0, parent); m_ui->treeView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); doubleClicked(index); } void MainWindow::rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last) { if (parent == m_projectTreeModel->spritesRoot()) { for (int row = first; row <= last; row++) { if (const auto sprite = m_projectTreeModel->getSprite(m_projectTreeModel->index(row, 0, parent))) { if (const auto iter = m_spritePropertiesWindows.find(sprite); iter != std::end(m_spritePropertiesWindows)) { delete iter->second; m_spritePropertiesWindows.erase(iter); } } } } else if (parent == m_projectTreeModel->soundsRoot()) { for (int row = first; row <= last; row++) { if (const auto sound = m_projectTreeModel->getSound(m_projectTreeModel->index(row, 0, parent))) { if (const auto iter = m_soundPropertiesWindows.find(sound); iter != std::end(m_soundPropertiesWindows)) { delete iter->second; m_soundPropertiesWindows.erase(iter); } } } } else if (parent == m_projectTreeModel->backgroundsRoot()) { for (int row = first; row <= last; row++) { if (const auto background = m_projectTreeModel->getBackground(m_projectTreeModel->index(row, 0, parent))) { if (const auto iter = m_backgroundPropertiesWindows.find(background); iter != std::end(m_backgroundPropertiesWindows)) { delete iter->second; m_backgroundPropertiesWindows.erase(iter); } } } } else if (parent == m_projectTreeModel->pathsRoot()) { for (int row = first; row <= last; row++) { if (const auto path = m_projectTreeModel->getPath(m_projectTreeModel->index(row, 0, parent))) { if (const auto iter = m_pathPropertiesWindows.find(path); iter != std::end(m_pathPropertiesWindows)) { delete iter->second; m_pathPropertiesWindows.erase(iter); } } } } else if (parent == m_projectTreeModel->scriptsRoot()) { for (int row = first; row <= last; row++) { if (const auto script = m_projectTreeModel->getScript(m_projectTreeModel->index(row, 0, parent))) { if (const auto iter = m_scriptPropertiesWindows.find(script); iter != std::end(m_scriptPropertiesWindows)) { delete iter->second; m_scriptPropertiesWindows.erase(iter); } } } } else if (parent == m_projectTreeModel->fontsRoot()) { for (int row = first; row <= last; row++) { if (const auto font = m_projectTreeModel->getFont(m_projectTreeModel->index(row, 0, parent))) { if (const auto iter = m_fontPropertiesWindows.find(font); iter != std::end(m_fontPropertiesWindows)) { delete iter->second; m_fontPropertiesWindows.erase(iter); } } } } } void MainWindow::modelAboutToBeReset() { for (const auto &pair : m_spritePropertiesWindows) delete pair.second; m_spritePropertiesWindows.clear(); for (const auto &pair : m_soundPropertiesWindows) delete pair.second; m_soundPropertiesWindows.clear(); for (const auto &pair : m_backgroundPropertiesWindows) delete pair.second; m_backgroundPropertiesWindows.clear(); for (const auto &pair : m_pathPropertiesWindows) delete pair.second; m_pathPropertiesWindows.clear(); for (const auto &pair : m_scriptPropertiesWindows) delete pair.second; m_scriptPropertiesWindows.clear(); for (const auto &pair : m_fontPropertiesWindows) delete pair.second; m_fontPropertiesWindows.clear(); } void MainWindow::updateTitle() { setWindowTitle(tr("%0 - Qt Gamemaker 1.0 Ultimate%1") .arg(m_filePath.isEmpty() ? "" : QFileInfo{m_filePath}.fileName()) .arg(m_unsavedChanges ? tr("*") : QString{})); }