From 8d45958d45087652d67ab58e40bb95dd9a29f0c1 Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Thu, 13 Jan 2022 14:41:17 +0100 Subject: [PATCH] Added dialog to add events to object --- QtGameMaker.pro | 3 + dialogs/addeventdialog.cpp | 48 ++++++ dialogs/addeventdialog.h | 28 ++++ dialogs/addeventdialog.ui | 166 ++++++++++++++++++++ dialogs/backgroundpropertiesdialog.ui | 2 +- dialogs/fontpropertiesdialog.ui | 2 +- dialogs/objectpropertiesdialog.cpp | 18 ++- dialogs/objectpropertiesdialog.h | 7 +- dialogs/objectpropertiesdialog.ui | 2 +- dialogs/pathpropertiesdialog.ui | 26 ++-- dialogs/scriptpropertiesdialog.cpp | 2 +- dialogs/soundpropertiesdialog.ui | 2 +- dialogs/spritepropertiesdialog.ui | 6 +- dialogs/timelinepropertiesdialog.ui | 2 +- icons/event-create.png | Bin 0 -> 3258 bytes icons/event-destroy.png | Bin 0 -> 10117 bytes icons/event-step.png | Bin 0 -> 13745 bytes objecteventsmodel.cpp | 47 +++++- objecteventsmodel.h | 12 +- projectcontainer.cpp | 215 +++++++++++++++----------- projectcontainer.h | 7 + resources.qrc | 3 + 22 files changed, 474 insertions(+), 124 deletions(-) create mode 100644 dialogs/addeventdialog.cpp create mode 100644 dialogs/addeventdialog.h create mode 100644 dialogs/addeventdialog.ui create mode 100644 icons/event-create.png create mode 100644 icons/event-destroy.png create mode 100644 icons/event-step.png diff --git a/QtGameMaker.pro b/QtGameMaker.pro index d0e57ec..c09b8ec 100644 --- a/QtGameMaker.pro +++ b/QtGameMaker.pro @@ -11,6 +11,7 @@ DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 HEADERS += \ codeeditorwidget.h \ constantsmodel.h \ + dialogs/addeventdialog.h \ dialogs/codeeditordialog.h \ dialogs/createspritedialog.h \ dialogs/fontpropertiesdialog.h \ @@ -54,6 +55,7 @@ HEADERS += \ SOURCES += main.cpp \ codeeditorwidget.cpp \ constantsmodel.cpp \ + dialogs/addeventdialog.cpp \ dialogs/codeeditordialog.cpp \ dialogs/createspritedialog.cpp \ dialogs/fontpropertiesdialog.cpp \ @@ -94,6 +96,7 @@ SOURCES += main.cpp \ triggersmodel.cpp FORMS += \ + dialogs/addeventdialog.ui \ dialogs/codeeditordialog.ui \ dialogs/createspritedialog.ui \ dialogs/fontpropertiesdialog.ui \ diff --git a/dialogs/addeventdialog.cpp b/dialogs/addeventdialog.cpp new file mode 100644 index 0000000..b0c51b3 --- /dev/null +++ b/dialogs/addeventdialog.cpp @@ -0,0 +1,48 @@ +#include "addeventdialog.h" +#include "ui_addeventdialog.h" + +#include + +AddEventDialog::AddEventDialog(QWidget *parent) : + QDialog{parent}, + m_ui{std::make_unique()} +{ + m_ui->setupUi(this); + +#ifdef Q_OS_LINUX + setWindowFlags((windowFlags() & ~Qt::Dialog) | Qt::Window); +#endif + setWindowFlag(Qt::WindowCloseButtonHint); + + if (auto button = m_ui->buttonBox->button(QDialogButtonBox::Ok)) + button->setIcon(QIcon{":/qtgameengine/icons/ok.png"}); + if (auto button = m_ui->buttonBox->button(QDialogButtonBox::Cancel)) + button->setIcon(QIcon{":/qtgameengine/icons/delete.png"}); + + connect(m_ui->pushButtonCreate, &QAbstractButton::clicked, + this, [this](){ m_eventType = Object::EventType::Create; accept(); }); + connect(m_ui->pushButtonStep, &QAbstractButton::clicked, + this, [this](){ m_eventType = Object::EventType::Step; accept(); }); + connect(m_ui->pushButtonDestroy, &QAbstractButton::clicked, + this, [this](){ m_eventType = Object::EventType::Destroy; accept(); }); +} + +AddEventDialog::~AddEventDialog() = default; + +void AddEventDialog::accept() +{ + if (!m_eventType) + { + QMessageBox::warning(this, tr("No Event selected!"), tr("No Event selected!")); + return; + } + + QDialog::accept(); +} + +void AddEventDialog::reject() +{ + m_eventType = std::nullopt; + + QDialog::reject(); +} diff --git a/dialogs/addeventdialog.h b/dialogs/addeventdialog.h new file mode 100644 index 0000000..3b88fd6 --- /dev/null +++ b/dialogs/addeventdialog.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include + +#include "projectcontainer.h" + +namespace Ui { class AddEventDialog; } + +class AddEventDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AddEventDialog(QWidget *parent = nullptr); + ~AddEventDialog(); + + Object::EventType eventType() const { return *m_eventType; } + + void accept() override; + void reject() override; + +private: + const std::unique_ptr m_ui; + + std::optional m_eventType; +}; diff --git a/dialogs/addeventdialog.ui b/dialogs/addeventdialog.ui new file mode 100644 index 0000000..aa5b6f4 --- /dev/null +++ b/dialogs/addeventdialog.ui @@ -0,0 +1,166 @@ + + + AddEventDialog + + + + 0 + 0 + 265 + 220 + + + + Choose the Event to Add + + + + + + + + Dra&w + + + + + + + &Mouse + + + + + + + Ke&y Release + + + + + + + &Alarm + + + + + + + &Step + + + + :/qtgameengine/icons/event-step.png:/qtgameengine/icons/event-step.png + + + + + + + C&reate + + + + :/qtgameengine/icons/event-create.png:/qtgameengine/icons/event-create.png + + + + + + + O&ther + + + + + + + C&ollision + + + + + + + &Destroy + + + + :/qtgameengine/icons/event-destroy.png:/qtgameengine/icons/event-destroy.png + + + + + + + Key &Press + + + + + + + &Keyboard + + + + + + + &Trigger + + + + + + + + + QDialogButtonBox::Cancel + + + true + + + + + + + + + + + buttonBox + accepted() + AddEventDialog + accept() + + + 132 + 196 + + + 132 + 108 + + + + + buttonBox + rejected() + AddEventDialog + reject() + + + 132 + 196 + + + 132 + 108 + + + + + diff --git a/dialogs/backgroundpropertiesdialog.ui b/dialogs/backgroundpropertiesdialog.ui index 0aa5732..74f7a03 100644 --- a/dialogs/backgroundpropertiesdialog.ui +++ b/dialogs/backgroundpropertiesdialog.ui @@ -25,7 +25,7 @@ - Name: + &Name: lineEditName diff --git a/dialogs/fontpropertiesdialog.ui b/dialogs/fontpropertiesdialog.ui index c767f61..e6be99c 100644 --- a/dialogs/fontpropertiesdialog.ui +++ b/dialogs/fontpropertiesdialog.ui @@ -23,7 +23,7 @@ - Name: + &Name: lineEditName diff --git a/dialogs/objectpropertiesdialog.cpp b/dialogs/objectpropertiesdialog.cpp index 63ea67e..a02ed97 100644 --- a/dialogs/objectpropertiesdialog.cpp +++ b/dialogs/objectpropertiesdialog.cpp @@ -7,17 +7,18 @@ #include -#include "projectcontainer.h" #include "projecttreemodel.h" #include "objecteventsmodel.h" #include "objectactionsmodel.h" +#include "addeventdialog.h" ObjectPropertiesDialog::ObjectPropertiesDialog(Object &object, ProjectTreeModel &projectModel, QWidget *parent) : QDialog{parent}, m_ui{std::make_unique()}, m_object{object}, m_projectModel{projectModel}, - m_eventsModel{std::make_unique()}, + m_events{m_object.events}, + m_eventsModel{std::make_unique(m_events)}, m_actionsModel{std::make_unique()}, m_spritesMenu{new QMenu{m_ui->toolButtonSprite}}, m_spriteName{object.spriteName} @@ -106,6 +107,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.events = std::move(m_events); QDialog::accept(); } @@ -157,7 +159,17 @@ void ObjectPropertiesDialog::showInformation() void ObjectPropertiesDialog::addEvent() { - QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented")); + AddEventDialog dialog{this}; + if (dialog.exec() == QDialog::Accepted) + { + if (!m_events.contains(dialog.eventType())) + { + m_eventsModel->beginResetModel(); + m_events[dialog.eventType()]; + m_eventsModel->endResetModel(); + m_unsavedChanges = true; + } + } } void ObjectPropertiesDialog::deleteEvent() diff --git a/dialogs/objectpropertiesdialog.h b/dialogs/objectpropertiesdialog.h index 0404614..22dfde4 100644 --- a/dialogs/objectpropertiesdialog.h +++ b/dialogs/objectpropertiesdialog.h @@ -3,14 +3,15 @@ #include #include +#include + +#include "projectcontainer.h" class QMenu; namespace Ui { class ObjectPropertiesDialog; } -struct Object; class ProjectTreeModel; class ObjectEventsModel; class ObjectActionsModel; -class Sprite; class ObjectPropertiesDialog : public QDialog { @@ -48,6 +49,8 @@ private: Object &m_object; ProjectTreeModel &m_projectModel; + std::map m_events; + const std::unique_ptr m_eventsModel; const std::unique_ptr m_actionsModel; diff --git a/dialogs/objectpropertiesdialog.ui b/dialogs/objectpropertiesdialog.ui index 8fc8052..20a6258 100644 --- a/dialogs/objectpropertiesdialog.ui +++ b/dialogs/objectpropertiesdialog.ui @@ -25,7 +25,7 @@ - Name: + &Name: lineEditName diff --git a/dialogs/pathpropertiesdialog.ui b/dialogs/pathpropertiesdialog.ui index 71da15e..ec4acd4 100644 --- a/dialogs/pathpropertiesdialog.ui +++ b/dialogs/pathpropertiesdialog.ui @@ -114,18 +114,18 @@ 10 - - + + - Name: + &Name: lineEditName - + The name of the path @@ -189,7 +189,7 @@ - X: + &X: spinBoxX @@ -209,7 +209,7 @@ - Y: + &Y: spinBoxY @@ -229,7 +229,7 @@ - sp: + s&p: spinBoxSp @@ -269,7 +269,7 @@ Add the point to the path - Add + &Add @@ -279,7 +279,7 @@ Insert the point before the current one - Insert + &Insert @@ -289,7 +289,7 @@ Delete the point from the path - Delete + &Delete @@ -329,14 +329,14 @@ - Straight lines + &Straight lines - Smooth curves + S&mooth curves @@ -348,7 +348,7 @@ - Precision: + P&recision: spinBoxPrecision diff --git a/dialogs/scriptpropertiesdialog.cpp b/dialogs/scriptpropertiesdialog.cpp index 908bd84..041313f 100644 --- a/dialogs/scriptpropertiesdialog.cpp +++ b/dialogs/scriptpropertiesdialog.cpp @@ -16,7 +16,7 @@ ScriptPropertiesDialog::ScriptPropertiesDialog(Script &script, ProjectTreeModel m_lineEditName{new QLineEdit{this}} { { - auto label = new QLabel{tr("Name:"), this}; + auto label = new QLabel{tr("&Name:"), this}; label->setBuddy(m_lineEditName); addToolbarWidget(label); } diff --git a/dialogs/soundpropertiesdialog.ui b/dialogs/soundpropertiesdialog.ui index dd47047..847ba71 100644 --- a/dialogs/soundpropertiesdialog.ui +++ b/dialogs/soundpropertiesdialog.ui @@ -23,7 +23,7 @@ - Name: + &Name: lineEditName diff --git a/dialogs/spritepropertiesdialog.ui b/dialogs/spritepropertiesdialog.ui index cdbf7e0..4f8308f 100644 --- a/dialogs/spritepropertiesdialog.ui +++ b/dialogs/spritepropertiesdialog.ui @@ -25,7 +25,7 @@ - Name: + &Name: lineEditName @@ -153,7 +153,7 @@ - X: + &X: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -173,7 +173,7 @@ - Y: + &Y: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter diff --git a/dialogs/timelinepropertiesdialog.ui b/dialogs/timelinepropertiesdialog.ui index c601bd9..b42bce0 100644 --- a/dialogs/timelinepropertiesdialog.ui +++ b/dialogs/timelinepropertiesdialog.ui @@ -23,7 +23,7 @@ - Name: + &Name: lineEditName diff --git a/icons/event-create.png b/icons/event-create.png new file mode 100644 index 0000000000000000000000000000000000000000..bf82634cd34b121884fc15db2ddc8dc5f6fc7346 GIT binary patch literal 3258 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 literal 0 HcmV?d00001 diff --git a/icons/event-destroy.png b/icons/event-destroy.png new file mode 100644 index 0000000000000000000000000000000000000000..7f3298c75f2057a8a9353680122e4a171950557a GIT binary patch literal 10117 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 D-I&}g literal 0 HcmV?d00001 diff --git a/icons/event-step.png b/icons/event-step.png new file mode 100644 index 0000000000000000000000000000000000000000..216db225d9b3215dee5f992334f4c07ec36840e1 GIT binary patch literal 13745 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 )Kjr`bENB1k{r#dv%8t&?vh};t3_JeW zp8uGub+MD5>C5-@4S&;4GB|B(74ulOsUb_UnBnW{efEMA+x6G2eza((@r!q|59;r~ zWKejWF|T@SYqI*U8Fslw*>=X_F82fXf4X?p_4(6j|4jofP4`Ha;@a(^ufZSD!J%Gt ziJ|@YJ?1Un1w1N#Uj6)W%ZF3Z$JFwY_X<7>8+FEx)EAePWP%$$`Eua`^ezqEXWm6Ql{R1%6-tYuD9fY2_5{WcuCrZDGLqeV^W%8l^Evh5b|Ld66w18`I9Q=eCgiR{wif zW%6FC#sr?5TD+*?j&=FnWr5AR6K9;&IGV8Sz{({VCf!paS^lWGC&hMfoHD34S=Q9C zz@GOH-UbR_rOK(R7TgRD_Ie)qW?N4lpWjKCSWHz_oDlO@#Y3zOt zLHciR)||eb%Wq2&N-pNjEH%lU>#63ly0b0UWl!Kzt@EFG7%qo+2)--` zJ>fp{{*wz2&De_cPHp)2&Zc8g(aATOf)0Z3_1C)D*Vr_2=eX=I>?w7x6saXB(ZDssHtM*BKL) zN1r1(4mn)Ym2^;hypRPwZXC=1?WuNt&mFZ; zwiBt`Z*G)oJ zEti%vl104}a)q||-m|Od`M2iwLZ17v>8rCvI31oASBm>{EAIZHb@toL9rKQTG-*ol z7f#(5B=}`>&OwpO=~CZ%G6Q4$Ps~f?bWvv9wQI6W&P(T+&tj|R#mL)7GaOaB9s9G% zI5vBs(F^s-`np0lw)Oj1RcHO;uRZbi{Y|sW#h>Qy%Xz1wH_Nv5=H}%OzDF)$n|oQ^ z)={4A(Czng4_tlqbFY8yjY7Ri^8%M}Z~u1ea)*P;6aAm62OIjY9Pljkkj$^GxLzK{ zUspzixSF3$yCp1x7Cp z8}L5*D6*hv8PC&S@*7fx51Ab_nw@fN;Zkeoa3k+?l6snL%wo$J-^;yZxT0Nco}cl@ zgF&O>>}4mViHkNZTC+slX9dTCtrxCNW?5QS{N(8Gx%V|UiTSM3bmvat){APnBB|tS z@j`ieaR>hs!Hd`R_B~#nAN%*|^VR3<87^0GE?8{bmnr45R!h#w^+f-*SrO^>2iE&f zPho8~Q|hVWTflJp+vaz_PR|I5Y*UzcclI^4bJh*dWcjx&ymIgREbEUpiLZ_ne0;tC z%=rTjY{!MC1nsu}k@It}^%N&oUS~z66B>rwbmtxYYO*t?@mz}7(w_M>A=M0AUnl?b z>6}y7{iZLRbuH_Wvz-ny$ogOLz;^zYL#Rkt6PILtASST`aLVros zgum{)0#8-E`l^0ydwmK+((U*D8cXM8z3jLw?r*qp*PaziJhm+G|Fx}PmrIar&TCnR z7D3ewuRa9)sC_(FEMV1ngIa!Lwy;@RIWz9FPPHm9Xk#dT?RLL`dtG}_){E=0$K~cF zt%z4)D^mH*uK9WP@>sU1it>!}4?bM{R_49u;whE)U;E#a`G11(NLk%p@umNEtu=S8 zt~L*ys33e;S^l30mt5U#dz1e!ULIENd4JsDTf*fFmsaV0-(Rn@>`K5R;Vrtitbg73 zooDSOX@6^X>fx|sC%o+IjhOluUs+eno+R>#Rm$ySQ_j7E@4wHF;d^)He(k>JonK>5 z8SKA(X(Fh!(YdT3wQ;7vww1js96x-bqIXyR?3M76)SuaSVQ^69Q z(MYwE`NTfI=I8t{?&O^3C6QIndjJ1O%02S$uxhus!29zTZ(Ost;gRZE`dR(*)tiT3 z|DGMl<>H|EIC`V_|3~@t+y91s&(;4v=U}#@Z_ud>v$qG|VK1_Wp+-5^v|c z<2YJoSK*}jc;c~Vesi1}GcR6Veq!%QN1n?m|NgMOacFpXc~Qd^rE5iYY1ZGpgY5p> z^FO)s?p$Bqp@j!B`Aw`RM;5V8pI6aVQ8b~zl{M8)_~O0N$MOxY&$wSKeG*|l?|ERf zsLVWGE*Xnk-o@!%_a;B*x;V=~!P_p6;dzPon#8xuv|=S{&gM%#+p<#lgN?66%3_Im zpXYhC2S>8&IvGeX{7Uc5=Fh16cbZdV|0bX2m8HP~OJBT@l_<#vbMwvER| z@DnS$%bn!&cXc02IlTE<9lNw=zof*Oi+8Vj8$4LN>d%=|g&GNpQ6A|<3oMNOEoMlV z68=|YX`J1iJAP)<)uTj}9vGirAb4xXyk*vQ3@d8ISsE5c=ZmLCY~MN0&(v(&g00K+ zq~zEZD!oun`2FIo_k&8QrB~`>1sMFYSPfHW#J}-R|N8K-ZU;x{MFU|irYS#tR~AM9ya@N4S*Xzg3oQcE^1+cYP^z+vHo3s-ORuh7zkB2yzaI6o<;H*JcpeEgg{W44 P&^(x@tDnm{r-UW|-w&*{ literal 0 HcmV?d00001 diff --git a/objecteventsmodel.cpp b/objecteventsmodel.cpp index 9e2883a..a683562 100644 --- a/objecteventsmodel.cpp +++ b/objecteventsmodel.cpp @@ -1,19 +1,58 @@ #include "objecteventsmodel.h" -ObjectEventsModel::ObjectEventsModel(QObject *parent) : - QAbstractListModel{parent} +#include +#include + +#include "futurecpp.h" + +ObjectEventsModel::ObjectEventsModel(std::map &events, QObject *parent) : + QAbstractListModel{parent}, + m_events{events} { } int ObjectEventsModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) - return 0; + return m_events.size(); } QVariant ObjectEventsModel::data(const QModelIndex &index, int role) const { Q_UNUSED(index) - Q_UNUSED(role) + + if (index.row() < 0 || index.row() >= m_events.size()) + { + qWarning() << "row out of bounds" << index.row(); + return {}; + } + + const auto &pair = *std::next(std::cbegin(m_events), index.row()); + + switch (role) + { + case Qt::DisplayRole: + case Qt::EditRole: + switch (pair.first) + { + case Object::EventType::Create: return tr("Create"); + case Object::EventType::Step: return tr("Step"); + case Object::EventType::Destroy: return tr("Destroy"); + 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::Step: return QIcon{":/qtgameengine/icons/event-step.png"}; + case Object::EventType::Destroy: return QIcon{":/qtgameengine/icons/event-destroy.png"}; + default: + qWarning() << "unknown event type" << std::to_underlying(pair.first); + return {}; + } + } + return {}; } diff --git a/objecteventsmodel.h b/objecteventsmodel.h index 1b44325..55cc1e4 100644 --- a/objecteventsmodel.h +++ b/objecteventsmodel.h @@ -2,13 +2,23 @@ #include +#include + +#include "projectcontainer.h" + class ObjectEventsModel : public QAbstractListModel { Q_OBJECT public: - explicit ObjectEventsModel(QObject *parent = nullptr); + explicit ObjectEventsModel(std::map &events, QObject *parent = nullptr); int rowCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; + + using QAbstractListModel::beginResetModel; + using QAbstractListModel::endResetModel; + +private: + std::map &m_events; }; diff --git a/projectcontainer.cpp b/projectcontainer.cpp index f75ed9a..1eb12aa 100644 --- a/projectcontainer.cpp +++ b/projectcontainer.cpp @@ -73,135 +73,164 @@ QDataStream &operator>>(QDataStream &ds, std::vector &list) return ds; } +template +QDataStream &operator<<(QDataStream &ds, const std::map &map) +{ + { + int entries = map.size(); + ds << entries; + } + for (auto iter = std::cbegin(map); iter != std::cend(map); iter++) + ds << iter->first << iter->second; + return ds; +} + +template +QDataStream &operator>>(QDataStream &ds, std::map &map) +{ + int entries; + ds >> entries; + + for (int i = 0; i < entries; i++) + { + Tkey key; + Tvalue value; + ds >> key + >> value; + map[std::move(key)] = std::move(value); + } + return ds; +} + QDataStream &operator<<(QDataStream &ds, const Sprite &sprite) { - ds << sprite.name; - ds << sprite.pixmaps; - ds << sprite.origin.x; - ds << sprite.origin.y; - ds << sprite.preciseCollisionChecking; - ds << sprite.separateCollisionMasks; + ds << sprite.name + << sprite.pixmaps + << sprite.origin.x + << sprite.origin.y + << sprite.preciseCollisionChecking + << sprite.separateCollisionMasks; return ds; } QDataStream &operator>>(QDataStream &ds, Sprite &sprite) { - ds >> sprite.name; - ds >> sprite.pixmaps; - ds >> sprite.origin.x; - ds >> sprite.origin.y; - ds >> sprite.preciseCollisionChecking; - ds >> sprite.separateCollisionMasks; + ds >> sprite.name + >> sprite.pixmaps + >> sprite.origin.x + >> sprite.origin.y + >> sprite.preciseCollisionChecking + >> sprite.separateCollisionMasks; return ds; } QDataStream &operator<<(QDataStream &ds, const Sound &sound) { - ds << sound.name; - ds << sound.type; - ds << sound.path; - ds << sound.effects.chorus; - ds << sound.effects.flanger; - ds << sound.effects.gargle; - ds << sound.effects.echo; - ds << sound.effects.reverb; - ds << sound.volume; - ds << sound.pan; - ds << sound.preload; + ds << sound.name + << sound.type + << sound.path + << sound.effects.chorus + << sound.effects.flanger + << sound.effects.gargle + << sound.effects.echo + << sound.effects.reverb + << sound.volume + << sound.pan + << sound.preload; return ds; } QDataStream &operator>>(QDataStream &ds, Sound &sound) { - ds >> sound.name; - ds >> sound.type; - ds >> sound.path; - ds >> sound.effects.chorus; - ds >> sound.effects.flanger; - ds >> sound.effects.gargle; - ds >> sound.effects.echo; - ds >> sound.effects.reverb; - ds >> sound.volume; - ds >> sound.pan; - ds >> sound.preload; + ds >> sound.name + >> sound.type + >> sound.path + >> sound.effects.chorus + >> sound.effects.flanger + >> sound.effects.gargle + >> sound.effects.echo + >> sound.effects.reverb + >> sound.volume + >> sound.pan + >> sound.preload; return ds; } QDataStream &operator<<(QDataStream &ds, const Background &background) { - ds << background.name; - ds << background.pixmap; - ds << background.tileset; + ds << background.name + << background.pixmap + << background.tileset; return ds; } QDataStream &operator>>(QDataStream &ds, Background &background) { - ds >> background.name; - ds >> background.pixmap; - ds >> background.tileset; + ds >> background.name + >> background.pixmap + >> background.tileset; return ds; } QDataStream &operator<<(QDataStream &ds, const Path::Point &point) { - ds << point.point; - ds << point.sp; + ds << point.point + << point.sp; return ds; } QDataStream &operator>>(QDataStream &ds, Path::Point &point) { - ds >> point.point; - ds >> point.sp; + ds >> point.point + >> point.sp; return ds; } QDataStream &operator<<(QDataStream &ds, const Path &path) { - ds << path.name; - ds << path.points; - ds << path.type; - ds << path.closed; - ds << path.precision; + ds << path.name + << path.points + << path.type + << path.closed + << path.precision; return ds; } QDataStream &operator>>(QDataStream &ds, Path &path) { - ds >> path.name; - ds >> path.points; - ds >> path.type; - ds >> path.closed; - ds >> path.precision; + ds >> path.name + >> path.points + >> path.type + >> path.closed + >> path.precision; return ds; } QDataStream &operator<<(QDataStream &ds, const Script &script) { - ds << script.name; - ds << script.script; + ds << script.name + << script.script; return ds; } QDataStream &operator>>(QDataStream &ds, Script &script) { - ds >> script.name; - ds >> script.script; + ds >> script.name + >> script.script; return ds; } QDataStream &operator<<(QDataStream &ds, const Font &font) { - ds << font.name; - ds << font.font; + ds << font.name + << font.font; return ds; } QDataStream &operator>>(QDataStream &ds, Font &font) { - ds >> font.name; - ds >> font.font; + ds >> font.name + >> font.font; return ds; } @@ -219,23 +248,25 @@ QDataStream &operator>>(QDataStream &ds, TimeLine &timeLine) QDataStream &operator<<(QDataStream &ds, const Object &object) { - ds << object.name; - ds << object.spriteName; - ds << object.visible; - ds << object.solid; - ds << object.depth; - ds << object.persistent; + ds << object.name + << object.spriteName + << object.visible + << object.solid + << object.depth + << object.persistent + << object.events; return ds; } QDataStream &operator>>(QDataStream &ds, Object &object) { - ds >> object.name; - ds >> object.spriteName; - ds >> object.visible; - ds >> object.solid; - ds >> object.depth; - ds >> object.persistent; + ds >> object.name + >> object.spriteName + >> object.visible + >> object.solid + >> object.depth + >> object.persistent + >> object.events; return ds; } @@ -253,29 +284,29 @@ QDataStream &operator>>(QDataStream &ds, Room &room) QDataStream &operator<<(QDataStream &ds, const ProjectContainer &project) { - ds << project.sprites; - ds << project.sounds; - ds << project.backgrounds; - ds << project.paths; - ds << project.scripts; - ds << project.fonts; - ds << project.timeLines; - ds << project.objects; - ds << project.rooms; + ds << project.sprites + << project.sounds + << project.backgrounds + << project.paths + << project.scripts + << project.fonts + << project.timeLines + << project.objects + << project.rooms; return ds; } QDataStream &operator>>(QDataStream &ds, ProjectContainer &project) { - ds >> project.sprites; - ds >> project.sounds; - ds >> project.backgrounds; - ds >> project.paths; - ds >> project.scripts; - ds >> project.fonts; - ds >> project.timeLines; - ds >> project.objects; - ds >> project.rooms; + ds >> project.sprites + >> project.sounds + >> project.backgrounds + >> project.paths + >> project.scripts + >> project.fonts + >> project.timeLines + >> project.objects + >> project.rooms; return ds; } diff --git a/projectcontainer.h b/projectcontainer.h index 13dcd62..d5df0e7 100644 --- a/projectcontainer.h +++ b/projectcontainer.h @@ -84,12 +84,19 @@ struct TimeLine struct Object { + enum class EventType { + Create, + Step, + Destroy + }; + QString name; QString spriteName; bool visible{true}; bool solid{}; int depth{}; bool persistent{}; + std::map events; }; struct Room diff --git a/resources.qrc b/resources.qrc index a9bb71d..ae337a1 100644 --- a/resources.qrc +++ b/resources.qrc @@ -76,5 +76,8 @@ icons/info.png icons/merge.png icons/sort.png + icons/event-create.png + icons/event-destroy.png + icons/event-step.png