Add collision events and fix a few bugs when objects are renamed/deleted

This commit is contained in:
2023-12-29 17:48:21 +01:00
parent 95d1936a5f
commit 42575e5d5a
14 changed files with 416 additions and 97 deletions

View File

@@ -2,9 +2,13 @@
#include "ui_addeventdialog.h" #include "ui_addeventdialog.h"
#include <QMessageBox> #include <QMessageBox>
#include <QMenu>
AddEventDialog::AddEventDialog(QWidget *parent) : #include "models/projecttreemodel.h"
AddEventDialog::AddEventDialog(ProjectTreeModel &projectModel, QWidget *parent) :
QDialog{parent}, QDialog{parent},
m_projectModel{projectModel},
m_ui{std::make_unique<Ui::AddEventDialog>()} m_ui{std::make_unique<Ui::AddEventDialog>()}
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@@ -27,6 +31,29 @@ AddEventDialog::AddEventDialog(QWidget *parent) :
this, [this](){ m_eventType = Object::EventType::Draw; accept(); }); this, [this](){ m_eventType = Object::EventType::Draw; accept(); });
connect(m_ui->pushButtonStep, &QAbstractButton::clicked, connect(m_ui->pushButtonStep, &QAbstractButton::clicked,
this, [this](){ m_eventType = Object::EventType::Step; accept(); }); this, [this](){ m_eventType = Object::EventType::Step; accept(); });
auto menu = new QMenu;
connect(menu, &QMenu::aboutToShow, menu, [this,menu](){
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();
}
}
menu->addAction(icon, object.name, this, [this,&object](){
m_eventType = object.name; accept();
});
}
}, Qt::SingleShotConnection);
m_ui->pushButtonCollision->setMenu(menu);
} }
AddEventDialog::~AddEventDialog() = default; AddEventDialog::~AddEventDialog() = default;

View File

@@ -3,26 +3,31 @@
#include <QDialog> #include <QDialog>
#include <optional> #include <optional>
#include <variant>
#include "projectcontainer.h" #include "projectcontainer.h"
namespace Ui { class AddEventDialog; } namespace Ui { class AddEventDialog; }
class ProjectTreeModel;
class AddEventDialog : public QDialog class AddEventDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit AddEventDialog(QWidget *parent = nullptr); explicit AddEventDialog(ProjectTreeModel &projectModel, QWidget *parent = nullptr);
~AddEventDialog(); ~AddEventDialog();
Object::EventType eventType() const { return *m_eventType; } const std::optional<std::variant<Object::EventType, QString>> &eventType() const { return m_eventType; }
void accept() override; void accept() override;
void reject() override; void reject() override;
private: private:
ProjectTreeModel &m_projectModel;
const std::unique_ptr<Ui::AddEventDialog> m_ui; const std::unique_ptr<Ui::AddEventDialog> m_ui;
std::optional<Object::EventType> m_eventType; std::optional<std::variant<Object::EventType, QString>> m_eventType;
}; };

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>265</width> <width>265</width>
<height>221</height> <height>238</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -82,6 +82,10 @@
<property name="text"> <property name="text">
<string>C&amp;ollision</string> <string>C&amp;ollision</string>
</property> </property>
<property name="icon">
<iconset resource="../resources_editor.qrc">
<normaloff>:/qtgameengine/icons/event-collision.png</normaloff>:/qtgameengine/icons/event-collision.png</iconset>
</property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">

View File

@@ -19,7 +19,8 @@ ObjectPropertiesDialog::ObjectPropertiesDialog(Object &object, ProjectTreeModel
m_projectModel{projectModel}, m_projectModel{projectModel},
m_mainWindow{mainWindow}, m_mainWindow{mainWindow},
m_events{m_object.events}, m_events{m_object.events},
m_eventsModel{std::make_unique<ObjectEventsModel>(m_events)}, m_collisionEvents{m_object.collisionEvents},
m_eventsModel{std::make_unique<ObjectEventsModel>(m_events, m_collisionEvents)},
m_menuSprites{new QMenu{this}}, m_menuSprites{new QMenu{this}},
m_spriteName{object.spriteName} m_spriteName{object.spriteName}
{ {
@@ -132,6 +133,7 @@ void ObjectPropertiesDialog::accept()
m_object.depth = m_ui->spinBoxDepth->value(); m_object.depth = m_ui->spinBoxDepth->value();
m_object.persistent = m_ui->checkBoxPersistent->isChecked(); m_object.persistent = m_ui->checkBoxPersistent->isChecked();
m_object.events = std::move(m_events); m_object.events = std::move(m_events);
m_object.collisionEvents = std::move(m_collisionEvents);
QDialog::accept(); QDialog::accept();
} }
@@ -204,12 +206,11 @@ void ObjectPropertiesDialog::showInformation()
void ObjectPropertiesDialog::addEvent() void ObjectPropertiesDialog::addEvent()
{ {
AddEventDialog dialog{this}; AddEventDialog dialog{m_projectModel, this};
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ if (const auto &eventType = dialog.eventType())
if (!m_eventsModel->addEvent(dialog.eventType())) if (!m_eventsModel->addEvent(*eventType))
QMessageBox::warning(this, tr("Could not add Event!"), tr("Could not add Event!")); QMessageBox::warning(this, tr("Could not add Event!"), tr("Could not add Event!"));
}
} }
void ObjectPropertiesDialog::deleteEvent() void ObjectPropertiesDialog::deleteEvent()
@@ -235,12 +236,13 @@ void ObjectPropertiesDialog::replaceEvent()
if (!event) if (!event)
return; return;
AddEventDialog dialog{this}; std::variant<Object::EventType, QString> x = event->first;
AddEventDialog dialog{m_projectModel, this};
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ if (const auto &eventType = dialog.eventType())
if (!m_eventsModel->changeEvent(event->first, dialog.eventType())) if (!m_eventsModel->changeEvent(event->first, *eventType))
QMessageBox::warning(this, tr("Could not change Event!"), tr("Could not change Event!")); QMessageBox::warning(this, tr("Could not change Event!"), tr("Could not change Event!"));
}
} }
void ObjectPropertiesDialog::duplicateEvent() void ObjectPropertiesDialog::duplicateEvent()
@@ -329,7 +331,7 @@ void ObjectPropertiesDialog::currentEventChanged(const QModelIndex &index)
if (index.isValid()) if (index.isValid())
{ {
if (auto event = m_eventsModel->getEvent(index)) if (auto event = m_eventsModel->getEvent(index))
m_ui->actionsWidget->setActionsContainer(&event->second); m_ui->actionsWidget->setActionsContainer(&event->second.get());
else else
goto none; goto none;
} }
@@ -343,13 +345,13 @@ none:
void ObjectPropertiesDialog::eventsContextMenuRequested(const QPoint &pos) void ObjectPropertiesDialog::eventsContextMenuRequested(const QPoint &pos)
{ {
const auto index = m_ui->listViewEvents->indexAt(pos); const auto index = m_ui->listViewEvents->indexAt(pos);
auto event = index.isValid() ? m_eventsModel->getEvent(index) : nullptr; auto event = index.isValid() ? m_eventsModel->getEvent(index) : std::nullopt;
QMenu menu{this}; QMenu menu{this};
menu.addAction(tr("&Add Event"), this, &ObjectPropertiesDialog::addEvent); menu.addAction(tr("&Add Event"), this, &ObjectPropertiesDialog::addEvent);
menu.addAction(tr("&Change Event"), this, &ObjectPropertiesDialog::replaceEvent)->setEnabled(event); menu.addAction(tr("&Change Event"), this, &ObjectPropertiesDialog::replaceEvent)->setEnabled(event.has_value());
menu.addAction(tr("&Duplicate Event"), this, &ObjectPropertiesDialog::duplicateEvent)->setEnabled(event); menu.addAction(tr("&Duplicate Event"), this, &ObjectPropertiesDialog::duplicateEvent)->setEnabled(event.has_value());
menu.addAction(tr("D&elete Event"), this, &ObjectPropertiesDialog::deleteEvent)->setEnabled(event); menu.addAction(tr("D&elete Event"), this, &ObjectPropertiesDialog::deleteEvent)->setEnabled(event.has_value());
menu.exec(m_ui->listViewEvents->viewport()->mapToGlobal(pos)); menu.exec(m_ui->listViewEvents->viewport()->mapToGlobal(pos));
} }

View File

@@ -60,6 +60,7 @@ private:
MainWindow * const m_mainWindow; MainWindow * const m_mainWindow;
Object::events_container_t m_events; Object::events_container_t m_events;
Object::collision_events_container_t m_collisionEvents;
const std::unique_ptr<ObjectEventsModel> m_eventsModel; const std::unique_ptr<ObjectEventsModel> m_eventsModel;

View File

@@ -343,29 +343,35 @@ void RoomPropertiesDialog::spritePixmapsChanged(const Sprite &sprite)
m_ui->labelObjectPreview->setPixmap(std::move(pixmap)); m_ui->labelObjectPreview->setPixmap(std::move(pixmap));
} }
void RoomPropertiesDialog::objectNameChanged(const Object &object) void RoomPropertiesDialog::objectNameChanged(const Object &object, const QString &oldName)
{ {
if (!m_selectedObject) if (m_selectedObject && &object == m_selectedObject)
return; m_ui->lineEditObject->setText(object.name);
if (&object != m_selectedObject) for (auto &obj : m_objects)
return; {
if (obj.objectName != oldName)
continue;
m_ui->lineEditObject->setText(object.name); obj.objectName = object.name;
}
} }
void RoomPropertiesDialog::objectAboutToBeRemoved(const Object &object) void RoomPropertiesDialog::objectAboutToBeRemoved(const Object &object)
{ {
if (!m_selectedObject) if (m_selectedObject && &object == m_selectedObject)
return; {
m_selectedObject = nullptr;
m_ui->lineEditObject->clear();
m_ui->labelObjectPreview->setPixmap({});
m_ui->roomEditWidget->setSelectedObject(nullptr);
}
if (&object != m_selectedObject) for (auto iter = std::begin(m_objects); iter != std::end(m_objects);)
return; if (iter->objectName == object.name)
iter = m_objects.erase(iter);
m_selectedObject = nullptr; else
m_ui->lineEditObject->clear(); iter++;
m_ui->labelObjectPreview->setPixmap({});
m_ui->roomEditWidget->setSelectedObject(nullptr);
} }
void RoomPropertiesDialog::objectSpriteNameChanged(const Object &object) void RoomPropertiesDialog::objectSpriteNameChanged(const Object &object)

View File

@@ -41,7 +41,7 @@ private slots:
void roomNameChanged(const Room &room); void roomNameChanged(const Room &room);
void spritePixmapsChanged(const Sprite &sprite); void spritePixmapsChanged(const Sprite &sprite);
void objectNameChanged(const Object &object); void objectNameChanged(const Object &object, const QString &oldName);
void objectAboutToBeRemoved(const Object &object); void objectAboutToBeRemoved(const Object &object);
void objectSpriteNameChanged(const Object &object); void objectSpriteNameChanged(const Object &object);

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -5,56 +5,78 @@
#include "futurecpp.h" #include "futurecpp.h"
ObjectEventsModel::ObjectEventsModel(Object::events_container_t &events, QObject *parent) : ObjectEventsModel::ObjectEventsModel(Object::events_container_t &events, Object::collision_events_container_t &collisionEvents,
QObject *parent) :
QAbstractListModel{parent}, QAbstractListModel{parent},
m_events{events} m_events{events},
m_collisionEvents{collisionEvents}
{ {
} }
int ObjectEventsModel::rowCount(const QModelIndex &parent) const int ObjectEventsModel::rowCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent) Q_UNUSED(parent)
return m_events.size(); return m_events.size() + m_collisionEvents.size();
} }
QVariant ObjectEventsModel::data(const QModelIndex &index, int role) const QVariant ObjectEventsModel::data(const QModelIndex &index, int role) const
{ {
Q_UNUSED(index) Q_UNUSED(index)
if (index.row() < 0 || std::size_t(index.row()) >= m_events.size()) if (index.row() < 0)
{ {
qWarning() << "row out of bounds" << index.row(); qWarning() << "row out of bounds" << index.row();
return {}; return {};
} }
else if (std::size_t(index.row()) < m_events.size())
const auto &pair = *std::next(std::cbegin(m_events), index.row());
switch (role)
{ {
case Qt::DisplayRole: const auto &pair = *std::next(std::cbegin(m_events), index.row());
case Qt::EditRole:
switch (pair.first) switch (role)
{ {
case Object::EventType::Create: return tr("Create"); case Qt::DisplayRole:
case Object::EventType::Destroy: return tr("Destroy"); case Qt::EditRole:
case Object::EventType::Step: return tr("Step"); switch (pair.first)
case Object::EventType::Draw: return tr("Draw"); {
default: case Object::EventType::Create: return tr("Create");
qWarning() << "unknown event type" << std::to_underlying(pair.first); case Object::EventType::Destroy: return tr("Destroy");
return QString::number(std::to_underlying(pair.first)); case Object::EventType::Step: return tr("Step");
case Object::EventType::Draw: return tr("Draw");
default:
qWarning() << "unknown event type" << std::to_underlying(pair.first);
return QString::number(std::to_underlying(pair.first));
}
case Qt::DecorationRole:
switch (pair.first)
{
case Object::EventType::Create: return QIcon{":/qtgameengine/icons/event-create.png"};
case Object::EventType::Destroy: return QIcon{":/qtgameengine/icons/event-destroy.png"};
case Object::EventType::Step: return QIcon{":/qtgameengine/icons/event-step.png"};
case Object::EventType::Draw: return QIcon{":/qtgameengine/icons/event-draw.png"};
default:
qWarning() << "unknown event type" << std::to_underlying(pair.first);
return {};
}
} }
case Qt::DecorationRole: }
switch (pair.first) else if (std::size_t(index.row()) < m_collisionEvents.size() + m_events.size())
{
const auto &pair = *std::next(std::cbegin(m_collisionEvents), index.row() - m_events.size());
switch (role)
{ {
case Object::EventType::Create: return QIcon{":/qtgameengine/icons/event-create.png"}; case Qt::DisplayRole:
case Object::EventType::Destroy: return QIcon{":/qtgameengine/icons/event-destroy.png"}; case Qt::EditRole:
case Object::EventType::Step: return QIcon{":/qtgameengine/icons/event-step.png"}; return pair.first;
case Object::EventType::Draw: return QIcon{":/qtgameengine/icons/event-draw.png"}; case Qt::DecorationRole:
default: return QIcon{":/qtgameengine/icons/event-collision.png"};
qWarning() << "unknown event type" << std::to_underlying(pair.first);
return {};
} }
} }
else
{
qWarning() << "row out of bounds" << index.row();
return {};
}
return {}; return {};
} }
@@ -63,27 +85,62 @@ bool ObjectEventsModel::removeRows(int row, int count, const QModelIndex &parent
{ {
Q_UNUSED(parent) Q_UNUSED(parent)
if (row < 0 || std::size_t(row) >= m_events.size()) if (row < 0 || std::size_t(row) >= m_events.size() + m_collisionEvents.size())
{ {
qWarning() << "unexpected row" << row; qWarning() << "unexpected row" << row;
return false; return false;
} }
if (count < 0 || std::size_t(count) > m_events.size() - row) if (count < 0 || std::size_t(count) > m_events.size() + m_collisionEvents.size() - row)
{ {
qWarning() << "unexpected row+count" << count << row; qWarning() << "unexpected row+count" << count << row;
return false; return false;
} }
beginRemoveRows({}, row, row + count - 1); beginRemoveRows({}, row, row + count - 1);
auto begin = std::next(std::begin(m_events), row);
auto end = std::next(begin, count); if (std::size_t(row) < m_events.size())
m_events.erase(begin, end); {
const auto remaining = m_events.size() - row;
const auto begin = std::next(std::begin(m_events), row);
const auto end = std::next(begin, std::min<std::size_t>(count, remaining));
m_events.erase(begin, end);
if (std::size_t(count) > remaining)
{
count -= remaining;
const auto begin = std::begin(m_collisionEvents);
const auto end = std::next(begin, count);
m_collisionEvents.erase(begin, end);
}
}
else if (std::size_t(row) < m_events.size() + m_collisionEvents.size())
{
qDebug() << row - m_events.size();
qDebug() << count;
qDebug() << m_collisionEvents.size();
const auto begin = std::next(std::begin(m_collisionEvents), row - m_events.size());
const auto end = std::next(begin, count);
m_collisionEvents.erase(begin, end);
}
endRemoveRows(); endRemoveRows();
return true; return true;
} }
bool ObjectEventsModel::addEvent(std::variant<Object::EventType, QString> eventType)
{
if (const auto &type = std::get_if<Object::EventType>(&eventType))
return addEvent(*type);
if (const auto &object = std::get_if<QString>(&eventType))
return addEvent(*object);
qCritical() << "not implemented";
return false;
}
bool ObjectEventsModel::addEvent(Object::EventType eventType) bool ObjectEventsModel::addEvent(Object::EventType eventType)
{ {
if (m_events.contains(eventType)) if (m_events.contains(eventType))
@@ -122,6 +179,72 @@ bool ObjectEventsModel::addEvent(Object::EventType eventType)
return true; return true;
} }
bool ObjectEventsModel::addEvent(const QString &object)
{
if (m_collisionEvents.contains(object))
{
qWarning() << object << "duplicate";
return false;
}
// temporary copy to find row before inserting, as its needed for beginInsertRows()
auto tempevents = m_collisionEvents;
const auto &tempInsertResult = tempevents.insert(std::make_pair(object, ActionsContainer{}));
if (!tempInsertResult.second)
{
qWarning() << "temp inserting failed!";
return false;
}
const auto tempNewRow = std::distance(std::begin(tempevents), tempInsertResult.first);
beginInsertRows({}, tempNewRow + m_events.size(), tempNewRow + m_events.size());
const auto &insertResult = m_collisionEvents.insert(std::make_pair(object, ActionsContainer{}));
if (!insertResult.second)
{
qWarning() << "inserting failed!";
return false;
}
const auto newRow = std::distance(std::begin(m_collisionEvents), insertResult.first);
Q_ASSERT(tempNewRow == newRow);
endInsertRows();
return true;
}
bool ObjectEventsModel::changeEvent(std::variant<Object::EventType, QString> eventType, std::variant<Object::EventType, QString> newEventType)
{
if (const auto &type = std::get_if<Object::EventType>(&eventType))
{
if (const auto &newType = std::get_if<Object::EventType>(&newEventType))
return changeEvent(*type, *newType);
if (const auto &newObject = std::get_if<QString>(&newEventType))
{
//return changeEvent(*type, *newObject);
}
qCritical() << "not implemented";
return false;
}
if (const auto &object = std::get_if<QString>(&eventType))
{
if (const auto &newType = std::get_if<Object::EventType>(&newEventType))
{
//return changeEvent(*object, *newType);
}
if (const auto &newObject = std::get_if<QString>(&newEventType))
return changeEvent(*object, *newObject);
qCritical() << "not implemented";
return false;
}
qCritical() << "not implemented";
return false;
}
bool ObjectEventsModel::changeEvent(Object::EventType eventType, Object::EventType newEventType) bool ObjectEventsModel::changeEvent(Object::EventType eventType, Object::EventType newEventType)
{ {
const auto iter = m_events.find(eventType); const auto iter = m_events.find(eventType);
@@ -137,6 +260,12 @@ bool ObjectEventsModel::changeEvent(Object::EventType eventType, Object::EventTy
return true; return true;
} }
if (m_events.contains(newEventType))
{
qWarning() << std::to_underlying(eventType) << "duplicate";
return false;
}
auto container = std::move(iter->second); auto container = std::move(iter->second);
const auto oldRow = std::distance(std::begin(m_events), iter); const auto oldRow = std::distance(std::begin(m_events), iter);
@@ -175,6 +304,75 @@ bool ObjectEventsModel::changeEvent(Object::EventType eventType, Object::EventTy
return true; return true;
} }
bool ObjectEventsModel::changeEvent(const QString &object, const QString &newObject)
{
const auto iter = m_collisionEvents.find(object);
if (iter == std::cend(m_collisionEvents))
{
qWarning() << object << "not found";
return false;
}
if (object == newObject)
{
qWarning() << "same event again";
return true;
}
if (m_collisionEvents.contains(newObject))
{
qWarning() << newObject << "duplicate";
return false;
}
auto container = std::move(iter->second);
const auto oldRow = std::distance(std::begin(m_collisionEvents), iter);
beginRemoveRows({}, oldRow + m_events.size(), oldRow + m_events.size());
m_collisionEvents.erase(iter);
endRemoveRows();
// temporary copy to find row before inserting, as its needed for beginInsertRows()
auto tempevents = m_collisionEvents;
const auto &tempInsertResult = tempevents.insert(std::make_pair(newObject, ActionsContainer{}));
if (!tempInsertResult.second)
{
qWarning() << "temp inserting failed!";
return false;
}
const auto tempNewRow = std::distance(std::begin(tempevents), tempInsertResult.first);
beginInsertRows({}, tempNewRow + m_events.size(), tempNewRow + m_events.size());
const auto &insertResult = m_collisionEvents.insert(std::make_pair(newObject, std::move(container)));
if (!insertResult.second)
{
qWarning() << "inserting failed!";
return false;
}
const auto newRow = std::distance(std::begin(m_collisionEvents), insertResult.first);
Q_ASSERT(tempNewRow == newRow);
endInsertRows();
return true;
}
bool ObjectEventsModel::removeEvent(std::variant<Object::EventType, QString> eventType)
{
if (const auto &type = std::get_if<Object::EventType>(&eventType))
return removeEvent(*type);
if (const auto &object = std::get_if<QString>(&eventType))
return removeEvent(*object);
qCritical() << "not implemented";
return false;
}
bool ObjectEventsModel::removeEvent(Object::EventType eventType) bool ObjectEventsModel::removeEvent(Object::EventType eventType)
{ {
const auto iter = m_events.find(eventType); const auto iter = m_events.find(eventType);
@@ -193,46 +391,79 @@ bool ObjectEventsModel::removeEvent(Object::EventType eventType)
return true; return true;
} }
std::pair<const Object::EventType, ActionsContainer> *ObjectEventsModel::getEvent(const QModelIndex &index) bool ObjectEventsModel::removeEvent(const QString &object)
{
Q_UNUSED(object);
qCritical() << "not implemented";
return false;
}
auto ObjectEventsModel::getEvent(const QModelIndex &index) -> get_event_result_t
{ {
if (!index.isValid()) if (!index.isValid())
{ {
qWarning() << "unexpected invalid index"; qWarning() << "unexpected invalid index";
return nullptr; return std::nullopt;
} }
return getEvent(index.row()); return getEvent(index.row());
} }
const std::pair<const Object::EventType, ActionsContainer> *ObjectEventsModel::getEvent(const QModelIndex &index) const auto ObjectEventsModel::getEvent(const QModelIndex &index) const -> const_get_event_result_t
{ {
if (!index.isValid()) if (!index.isValid())
{ {
qWarning() << "unexpected invalid index"; qWarning() << "unexpected invalid index";
return nullptr; return std::nullopt;
} }
return getEvent(index.row()); return getEvent(index.row());
} }
std::pair<const Object::EventType, ActionsContainer> *ObjectEventsModel::getEvent(int row) auto ObjectEventsModel::getEvent(int row) -> get_event_result_t
{ {
if (row < 0 || std::size_t(row) >= m_events.size()) if (row < 0)
{ {
qWarning() << "unexpected row" << row; qWarning() << "unexpected row" << row;
return nullptr; return std::nullopt;
} }
else if (std::size_t(row) < m_events.size())
return &*std::next(std::begin(m_events), row); {
} auto iter = std::next(std::begin(m_events), row);
return std::make_pair(iter->first, std::ref(iter->second));
const std::pair<const Object::EventType, ActionsContainer> *ObjectEventsModel::getEvent(int row) const }
{ else if (std::size_t(row) < m_events.size() + m_collisionEvents.size())
if (row < 0 || std::size_t(row) >= m_events.size()) {
auto iter = std::next(std::begin(m_collisionEvents), row - m_events.size());
return std::make_pair(iter->first, std::ref(iter->second));
}
else
{ {
qWarning() << "unexpected row" << row; qWarning() << "unexpected row" << row;
return nullptr; return std::nullopt;
}
}
auto ObjectEventsModel::getEvent(int row) const -> const_get_event_result_t
{
if (row < 0)
{
qWarning() << "unexpected row" << row;
return std::nullopt;
}
else if (std::size_t(row) >= m_events.size())
{
auto iter = std::next(std::cbegin(m_events), row);
return std::make_pair(iter->first, std::cref(iter->second));
}
else if (std::size_t(row) >= m_events.size() + m_collisionEvents.size())
{
auto iter = std::next(std::cbegin(m_collisionEvents), row - m_events.size());
return std::make_pair(iter->first, std::cref(iter->second));
}
else
{
qWarning() << "unexpected row" << row;
return std::nullopt;
} }
return &*std::next(std::cbegin(m_events), row);
} }

View File

@@ -11,21 +11,32 @@ class ObjectEventsModel : public QAbstractListModel
Q_OBJECT Q_OBJECT
public: public:
explicit ObjectEventsModel(Object::events_container_t &events, QObject *parent = nullptr); explicit ObjectEventsModel(Object::events_container_t &events, Object::collision_events_container_t &collisionEvents,
QObject *parent = nullptr);
int rowCount(const QModelIndex &parent) const override; int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override; QVariant data(const QModelIndex &index, int role) const override;
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex{}) override; bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex{}) override;
bool addEvent(std::variant<Object::EventType, QString> eventType);
bool addEvent(Object::EventType eventType); bool addEvent(Object::EventType eventType);
bool addEvent(const QString &object);
bool changeEvent(std::variant<Object::EventType, QString> eventType, std::variant<Object::EventType, QString> newEventType);
bool changeEvent(Object::EventType eventType, Object::EventType newEventType); bool changeEvent(Object::EventType eventType, Object::EventType newEventType);
bool changeEvent(const QString &object, const QString &newObject);
bool removeEvent(std::variant<Object::EventType, QString> eventType);
bool removeEvent(Object::EventType eventType); bool removeEvent(Object::EventType eventType);
bool removeEvent(const QString &object);
std::pair<const Object::EventType, ActionsContainer> *getEvent(const QModelIndex &index); using get_event_result_t = std::optional<std::pair<std::variant<Object::EventType, QString>, std::reference_wrapper<ActionsContainer>>>;
const std::pair<const Object::EventType, ActionsContainer> *getEvent(const QModelIndex &index) const; using const_get_event_result_t = std::optional<std::pair<std::variant<Object::EventType, QString>, std::reference_wrapper<const ActionsContainer>>>;
std::pair<const Object::EventType, ActionsContainer> *getEvent(int row);
const std::pair<const Object::EventType, ActionsContainer> *getEvent(int row) const; get_event_result_t getEvent(const QModelIndex &index);
const_get_event_result_t getEvent(const QModelIndex &index) const;
get_event_result_t getEvent(int row);
const_get_event_result_t getEvent(int row) const;
private: private:
Object::events_container_t &m_events; Object::events_container_t &m_events;
Object::collision_events_container_t &m_collisionEvents;
}; };

View File

@@ -959,6 +959,16 @@ template<> void ProjectTreeModel::onBeforeRemove<Sprite>(const Sprite &sprite)
} }
} }
template<> void ProjectTreeModel::onBeforeRemove<Object>(const Object &object)
{
for (auto &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);
else
iter++;
}
template<typename T> void ProjectTreeModel::onBeforeRename(const T &entry, const QString &newName) template<typename T> void ProjectTreeModel::onBeforeRename(const T &entry, const QString &newName)
{ {
Q_UNUSED(entry) Q_UNUSED(entry)
@@ -973,22 +983,38 @@ template<typename T> void ProjectTreeModel::onAfterRename(const T &entry, const
template<> void ProjectTreeModel::onAfterRename<Sprite>(const Sprite &sprite, const QString &oldName) template<> void ProjectTreeModel::onAfterRename<Sprite>(const Sprite &sprite, const QString &oldName)
{ {
for (auto iter = std::begin(m_project->objects); iter != std::end(m_project->objects); iter++) for (auto &object : m_project->objects)
{ {
if (iter->spriteName != oldName) if (object.spriteName != oldName)
continue; continue;
auto oldSpriteName = std::move(iter->spriteName); auto oldSpriteName = std::move(object.spriteName);
iter->spriteName = sprite.name; object.spriteName = sprite.name;
// const auto index = this->index(std::distance(std::begin(m_project->objects), iter), 0, rootFor<Object>()); // const auto index = this->index(std::distance(std::begin(m_project->objects), iter), 0, rootFor<Object>());
// emit dataChanged(index, index, {Qt::DecorationRole}); // emit dataChanged(index, index, {Qt::DecorationRole});
emit objectSpriteNameChanged(*iter, std::move(oldSpriteName)); emit objectSpriteNameChanged(object, std::move(oldSpriteName));
} }
} }
template<> void ProjectTreeModel::onAfterRename<Object>(const Object &object, const QString &oldName)
{
for (auto &room : m_project->rooms)
{
for (auto &obj : room.objects)
{
if (obj.objectName != oldName)
continue;
obj.objectName = object.name;
}
}
// TODO object collision events
}
template<typename T> template<typename T>
QString ProjectTreeModel::getFreeNameFor(const std::list<T> &container) QString ProjectTreeModel::getFreeNameFor(const std::list<T> &container)
{ {

View File

@@ -76,6 +76,7 @@
<file>icons/info.png</file> <file>icons/info.png</file>
<file>icons/merge.png</file> <file>icons/merge.png</file>
<file>icons/sort.png</file> <file>icons/sort.png</file>
<file>icons/event-collision.png</file>
<file>icons/event-create.png</file> <file>icons/event-create.png</file>
<file>icons/event-destroy.png</file> <file>icons/event-destroy.png</file>
<file>icons/event-step.png</file> <file>icons/event-step.png</file>

View File

@@ -306,7 +306,8 @@ QDataStream &operator<<(QDataStream &ds, const Object &object)
<< object.solid << object.solid
<< object.depth << object.depth
<< object.persistent << object.persistent
<< object.events; << object.events
<< object.collisionEvents;
return ds; return ds;
} }
@@ -318,7 +319,8 @@ QDataStream &operator>>(QDataStream &ds, Object &object)
>> object.solid >> object.solid
>> object.depth >> object.depth
>> object.persistent >> object.persistent
>> object.events; >> object.events
>> object.collisionEvents;
return ds; return ds;
} }

View File

@@ -2,6 +2,7 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <map>
#include <QString> #include <QString>
#include <QPixmap> #include <QPixmap>
@@ -117,6 +118,7 @@ struct Object
}; };
using events_container_t = std::map<EventType, ActionsContainer>; using events_container_t = std::map<EventType, ActionsContainer>;
using collision_events_container_t = std::map<QString, ActionsContainer>;
QString name; QString name;
QString spriteName; QString spriteName;
@@ -125,6 +127,7 @@ struct Object
int depth{}; int depth{};
bool persistent{}; bool persistent{};
events_container_t events; events_container_t events;
collision_events_container_t collisionEvents;
}; };
struct Room struct Room