Add collision events and fix a few bugs when objects are renamed/deleted
This commit is contained in:
@@ -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;
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
@@ -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&ollision</string>
|
<string>C&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">
|
||||||
|
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
BIN
src/editor/icons/event-collision.png
Normal file
BIN
src/editor/icons/event-collision.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -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>
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user