From ac3f9341185a5d3db733858df653969fbd8725ab Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Fri, 29 Dec 2023 22:39:28 +0100 Subject: [PATCH] Implement parent objects --- src/editor/dialogs/objectpropertiesdialog.cpp | 103 ++++++++++++++---- src/editor/dialogs/objectpropertiesdialog.h | 9 +- src/editor/dialogs/objectpropertiesdialog.ui | 14 ++- src/editor/models/projecttreemodel.cpp | 22 ++-- src/projectcontainer.cpp | 2 + src/projectcontainer.h | 1 + 6 files changed, 123 insertions(+), 28 deletions(-) diff --git a/src/editor/dialogs/objectpropertiesdialog.cpp b/src/editor/dialogs/objectpropertiesdialog.cpp index def3293..56da8ef 100644 --- a/src/editor/dialogs/objectpropertiesdialog.cpp +++ b/src/editor/dialogs/objectpropertiesdialog.cpp @@ -22,7 +22,9 @@ ObjectPropertiesDialog::ObjectPropertiesDialog(Object &object, ProjectTreeModel m_collisionEvents{m_object.collisionEvents}, m_eventsModel{std::make_unique(m_events, m_collisionEvents)}, m_menuSprites{new QMenu{this}}, - m_spriteName{object.spriteName} + m_menuParents{new QMenu{this}}, + m_spriteName{object.spriteName}, + m_parentName{object.parentName} { m_ui->setupUi(this); @@ -35,14 +37,17 @@ ObjectPropertiesDialog::ObjectPropertiesDialog(Object &object, ProjectTreeModel m_ui->lineEditName->setText(m_object.name); m_ui->lineEditSprite->setText(m_spriteName.isEmpty() ? tr("") : m_spriteName); + m_ui->lineEditParent->setText(m_parentName.isEmpty() ? tr("") : m_parentName); updateSpritePreview(); m_ui->toolButtonSprite->setMenu(m_menuSprites); + m_ui->toolButtonParent->setMenu(m_menuParents); m_ui->checkBoxVisible->setChecked(m_object.visible); m_ui->checkBoxSolid->setChecked(m_object.solid); m_ui->spinBoxDepth->setValue(m_object.depth); m_ui->checkBoxPersistent->setChecked(m_object.persistent); m_ui->lineEditSprite->setMenu(m_menuSprites); + m_ui->lineEditParent->setMenu(m_menuParents); m_ui->listViewEvents->setModel(m_eventsModel.get()); @@ -50,6 +55,8 @@ ObjectPropertiesDialog::ObjectPropertiesDialog(Object &object, ProjectTreeModel this, &ObjectPropertiesDialog::objectNameChanged); connect(&m_projectModel, &ProjectTreeModel::spriteNameChanged, this, &ObjectPropertiesDialog::spriteNameChanged); + connect(&m_projectModel, &ProjectTreeModel::objectAboutToBeRemoved, + this, &ObjectPropertiesDialog::objectAboutToBeRemoved); connect(&m_projectModel, &ProjectTreeModel::spriteAboutToBeRemoved, this, &ObjectPropertiesDialog::spriteAboutToBeRemoved); connect(&m_projectModel, &ProjectTreeModel::spritePixmapsChanged, @@ -92,6 +99,8 @@ ObjectPropertiesDialog::ObjectPropertiesDialog(Object &object, ProjectTreeModel connect(m_menuSprites, &QMenu::aboutToShow, this, &ObjectPropertiesDialog::spritesMenuAboutToShow); + connect(m_menuParents, &QMenu::aboutToShow, + this, &ObjectPropertiesDialog::parentsMenuAboutToShow); connect(m_ui->listViewEvents->selectionModel(), &QItemSelectionModel::currentChanged, this, &ObjectPropertiesDialog::currentEventChanged); @@ -132,6 +141,7 @@ void ObjectPropertiesDialog::accept() m_object.solid = m_ui->checkBoxSolid->isChecked(); m_object.depth = m_ui->spinBoxDepth->value(); m_object.persistent = m_ui->checkBoxPersistent->isChecked(); + m_object.parentName = m_parentName; m_object.events = std::move(m_events); m_object.collisionEvents = std::move(m_collisionEvents); @@ -259,17 +269,23 @@ void ObjectPropertiesDialog::changed() } } -void ObjectPropertiesDialog::objectNameChanged(const Object &object) +void ObjectPropertiesDialog::objectNameChanged(const Object &object, const QString &oldName) { - if (&object != &m_object) - return; - + if (&object == &m_object) { - QSignalBlocker blocker{m_ui->lineEditName}; - m_ui->lineEditName->setText(object.name); + { + QSignalBlocker blocker{m_ui->lineEditName}; + m_ui->lineEditName->setText(object.name); + } + + updateTitle(); } - updateTitle(); + if (!m_parentName.isEmpty() && m_parentName == oldName) + { + m_parentName = object.name; + m_ui->lineEditParent->setText(object.name); + } } void ObjectPropertiesDialog::spriteNameChanged(const Sprite &sprite, const QString &oldName) @@ -288,20 +304,26 @@ void ObjectPropertiesDialog::spriteNameChanged(const Sprite &sprite, const QStri updateSpritePreview(); } +void ObjectPropertiesDialog::objectAboutToBeRemoved(const Object &object) +{ + if (!m_parentName.isEmpty() && m_parentName == object.name) + { + m_parentName.clear(); + m_ui->lineEditParent->setText(tr("")); + } +} + void ObjectPropertiesDialog::spriteAboutToBeRemoved(const Sprite &sprite) { - if (m_spriteName.isEmpty()) - return; - - if (m_spriteName != sprite.name) - return; - - m_spriteName.clear(); + if (!m_spriteName.isEmpty() && m_spriteName == sprite.name) { - QSignalBlocker blocker{m_ui->lineEditSprite}; - m_ui->lineEditSprite->setText(tr("")); + m_spriteName.clear(); + { + QSignalBlocker blocker{m_ui->lineEditSprite}; + m_ui->lineEditSprite->setText(tr("")); + } + m_ui->labelSpritePreview->setPixmap(QPixmap{}); } - m_ui->labelSpritePreview->setPixmap(QPixmap{}); } void ObjectPropertiesDialog::spritePixmapsChanged(const Sprite &sprite) @@ -326,6 +348,29 @@ void ObjectPropertiesDialog::spritesMenuAboutToShow() [&sprite,this](){ setSprite(sprite); }); } +void ObjectPropertiesDialog::parentsMenuAboutToShow() +{ + m_menuParents->clear(); + m_menuParents->addAction(tr(""), this, &ObjectPropertiesDialog::clearParent); + for (const Object &object : m_projectModel.project()->objects) + { + QIcon icon; + if (!object.spriteName.isEmpty()) + { + const auto &sprites = m_projectModel.project()->sprites; + const auto iter = std::find_if(std::cbegin(sprites), std::cend(sprites), + [&](const Sprite &sprite){ return sprite.name == object.spriteName; }); + if (iter != std::cend(sprites)) + { + if (!iter->pixmaps.empty()) + icon = iter->pixmaps.front(); + } + } + m_menuParents->addAction(icon, object.name, this, + [&object,this](){ setParent(object); }); + } +} + void ObjectPropertiesDialog::currentEventChanged(const QModelIndex &index) { if (index.isValid()) @@ -339,7 +384,7 @@ void ObjectPropertiesDialog::currentEventChanged(const QModelIndex &index) { none: m_ui->actionsWidget->setActionsContainer(nullptr); -} + } } void ObjectPropertiesDialog::eventsContextMenuRequested(const QPoint &pos) @@ -376,6 +421,26 @@ void ObjectPropertiesDialog::setSprite(const Sprite &sprite) changed(); } +void ObjectPropertiesDialog::clearParent() +{ + m_parentName.clear(); + m_ui->lineEditParent->setText(tr("")); + changed(); +} + +void ObjectPropertiesDialog::setParent(const Object &object) +{ + if (&m_object == &object) + { + QMessageBox::warning(m_mainWindow, tr("This will create a loop in parents."), tr("This will create a loop in parents.")); + return; + } + + m_parentName = object.name; + m_ui->lineEditParent->setText(object.name); + changed(); +} + void ObjectPropertiesDialog::updateTitle() { setWindowTitle(tr("Object Properties: %0%1") diff --git a/src/editor/dialogs/objectpropertiesdialog.h b/src/editor/dialogs/objectpropertiesdialog.h index c470629..0c604c4 100644 --- a/src/editor/dialogs/objectpropertiesdialog.h +++ b/src/editor/dialogs/objectpropertiesdialog.h @@ -35,12 +35,14 @@ private slots: void changed(); - void objectNameChanged(const Object &object); + void objectNameChanged(const Object &object, const QString &oldName); void spriteNameChanged(const Sprite &sprite, const QString &oldName); + void objectAboutToBeRemoved(const Object &object); void spriteAboutToBeRemoved(const Sprite &sprite); void spritePixmapsChanged(const Sprite &sprite); void spritesMenuAboutToShow(); + void parentsMenuAboutToShow(); void currentEventChanged(const QModelIndex &index); void eventsContextMenuRequested(const QPoint &pos); void rowsInserted(const QModelIndex &parent, int first); @@ -48,6 +50,9 @@ private slots: void clearSprite(); void setSprite(const Sprite &sprite); + void clearParent(); + void setParent(const Object &object); + private: void updateTitle(); void updateSpritePreview(); @@ -65,8 +70,10 @@ private: const std::unique_ptr m_eventsModel; QMenu * const m_menuSprites; + QMenu * const m_menuParents; QString m_spriteName; + QString m_parentName; bool m_unsavedChanges{}; }; diff --git a/src/editor/dialogs/objectpropertiesdialog.ui b/src/editor/dialogs/objectpropertiesdialog.ui index 8357af7..f9fbffb 100644 --- a/src/editor/dialogs/objectpropertiesdialog.ui +++ b/src/editor/dialogs/objectpropertiesdialog.ui @@ -211,7 +211,7 @@ - + 0 @@ -224,6 +224,9 @@ <no parent> + + true + @@ -231,6 +234,9 @@ ... + + QToolButton::InstantPopup + @@ -251,6 +257,9 @@ <same as sprite> + + true + @@ -258,6 +267,9 @@ ... + + QToolButton::InstantPopup + diff --git a/src/editor/models/projecttreemodel.cpp b/src/editor/models/projecttreemodel.cpp index 4c13853..4898bdf 100644 --- a/src/editor/models/projecttreemodel.cpp +++ b/src/editor/models/projecttreemodel.cpp @@ -961,10 +961,15 @@ template<> void ProjectTreeModel::onBeforeRemove(const Sprite &sprite) template<> void ProjectTreeModel::onBeforeRemove(const Object &object) { - for (auto &object : m_project->objects) - object.collisionEvents.erase(object.name); + for (Object &obj : m_project->objects) + { + if (!obj.parentName.isEmpty() && obj.parentName == object.name) + obj.parentName.clear(); - for (auto &room : m_project->rooms) + obj.collisionEvents.erase(object.name); + } + + for (Room &room : m_project->rooms) for (auto iter = std::begin(room.objects); iter != std::end(room.objects); ) if (iter->objectName == object.name) iter = room.objects.erase(iter); @@ -1004,13 +1009,16 @@ template<> void ProjectTreeModel::onAfterRename(const Sprite &sprite, co template<> void ProjectTreeModel::onBeforeRename(const Object &object, const QString &newName) { - for (auto &object : m_project->objects) + for (Object &obj : m_project->objects) { - if (const auto iter = object.collisionEvents.find(object.name); iter != std::end(object.collisionEvents)) + if (!obj.parentName.isEmpty() && obj.parentName == object.name) + obj.parentName = newName; + + if (const auto iter = obj.collisionEvents.find(object.name); iter != std::end(obj.collisionEvents)) { - auto node = object.collisionEvents.extract(iter); + auto node = obj.collisionEvents.extract(iter); node.key() = newName; - object.collisionEvents.insert(std::move(node)); + obj.collisionEvents.insert(std::move(node)); } } diff --git a/src/projectcontainer.cpp b/src/projectcontainer.cpp index 56346d2..b31b812 100644 --- a/src/projectcontainer.cpp +++ b/src/projectcontainer.cpp @@ -306,6 +306,7 @@ QDataStream &operator<<(QDataStream &ds, const Object &object) << object.solid << object.depth << object.persistent + << object.parentName << object.events << object.collisionEvents; return ds; @@ -319,6 +320,7 @@ QDataStream &operator>>(QDataStream &ds, Object &object) >> object.solid >> object.depth >> object.persistent + >> object.parentName >> object.events >> object.collisionEvents; return ds; diff --git a/src/projectcontainer.h b/src/projectcontainer.h index 8d16478..990afee 100644 --- a/src/projectcontainer.h +++ b/src/projectcontainer.h @@ -126,6 +126,7 @@ struct Object bool solid{}; int depth{}; bool persistent{}; + QString parentName; events_container_t events; collision_events_container_t collisionEvents; };