diff --git a/QtGameMaker.pro b/QtGameMaker.pro index 5733027..1a3762a 100644 --- a/QtGameMaker.pro +++ b/QtGameMaker.pro @@ -27,6 +27,9 @@ INCLUDEPATH += \ HEADERS += \ src/closeeventfilter.h \ src/editor/dialogs/genericcodeeditordialog.h \ + src/editor/editorguiutils.h \ + src/editor/roomscene.h \ + src/editor/widgets/draggabletreeview.h \ src/editor/widgets/qlineeditwithmenu.h \ src/editor/widgets/qscrollareawithmenu.h \ src/editor/widgets/roomeditwidget.h \ @@ -81,6 +84,9 @@ HEADERS += \ SOURCES += \ src/closeeventfilter.cpp \ src/editor/dialogs/genericcodeeditordialog.cpp \ + src/editor/editorguiutils.cpp \ + src/editor/roomscene.cpp \ + src/editor/widgets/draggabletreeview.cpp \ src/editor/widgets/qlineeditwithmenu.cpp \ src/editor/widgets/qscrollareawithmenu.cpp \ src/editor/widgets/roomeditwidget.cpp \ diff --git a/src/editor/dialogs/roompropertiesdialog.cpp b/src/editor/dialogs/roompropertiesdialog.cpp index 3e01f7a..1f60383 100644 --- a/src/editor/dialogs/roompropertiesdialog.cpp +++ b/src/editor/dialogs/roompropertiesdialog.cpp @@ -10,6 +10,8 @@ #include "projectcontainer.h" #include "models/projecttreemodel.h" +#include "roomscene.h" +#include "editorguiutils.h" #include "genericcodeeditordialog.h" RoomPropertiesDialog::RoomPropertiesDialog(Room &room, ProjectTreeModel &projectModel, QWidget *parent) : @@ -17,6 +19,7 @@ RoomPropertiesDialog::RoomPropertiesDialog(Room &room, ProjectTreeModel &project m_ui{std::make_unique()}, m_room{room}, m_projectModel{projectModel}, + m_scene{std::make_unique(this)}, m_creationCode{m_room.creationCode}, m_spinBoxSnapX{new QSpinBox{this}}, m_spinBoxSnapY{new QSpinBox{this}}, @@ -34,6 +37,10 @@ RoomPropertiesDialog::RoomPropertiesDialog(Room &room, ProjectTreeModel &project m_ui->roomEditWidget->setSnapY(m_room.snapY); m_ui->roomEditWidget->setGridEnabled(m_room.gridEnabled); m_ui->roomEditWidget->setIsometricGrid(m_room.isometricGrid); + m_ui->roomEditWidget->setProjectTreeModel(&m_projectModel); + + m_ui->graphicsView->setScene(m_scene.get()); + m_ui->graphicsView->setBackgroundBrush(makeGridBrush(16, 16, QPen{Qt::black}, Qt::white)); { int index{11}; @@ -352,6 +359,7 @@ void RoomPropertiesDialog::objectAboutToBeRemoved(const Object &object) m_selectedObject = nullptr; m_ui->lineEditObject->clear(); m_ui->labelObjectPreview->setPixmap({}); + m_ui->roomEditWidget->setSelectedObject(nullptr); } void RoomPropertiesDialog::objectSpriteNameChanged(const Object &object) @@ -416,6 +424,7 @@ void RoomPropertiesDialog::setObject(const Object &object) } m_ui->labelObjectPreview->setPixmap(std::move(pixmap)); m_ui->lineEditObject->setText(object.name); + m_ui->roomEditWidget->setSelectedObject(&object); } void RoomPropertiesDialog::updateTitle() diff --git a/src/editor/dialogs/roompropertiesdialog.h b/src/editor/dialogs/roompropertiesdialog.h index 8c452ef..3957548 100644 --- a/src/editor/dialogs/roompropertiesdialog.h +++ b/src/editor/dialogs/roompropertiesdialog.h @@ -12,6 +12,7 @@ struct Room; struct Sprite; struct Object; class ProjectTreeModel; +class RoomScene; class RoomPropertiesDialog : public QDialog { @@ -55,6 +56,8 @@ private: Room &m_room; ProjectTreeModel &m_projectModel; + const std::unique_ptr m_scene; + QString m_creationCode; bool m_unsavedChanges{}; diff --git a/src/editor/dialogs/roompropertiesdialog.ui b/src/editor/dialogs/roompropertiesdialog.ui index 2288602..d3fa9ae 100644 --- a/src/editor/dialogs/roompropertiesdialog.ui +++ b/src/editor/dialogs/roompropertiesdialog.ui @@ -133,7 +133,7 @@ 0 0 - 683 + 419 333 @@ -383,19 +383,35 @@ - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + 0 - - - - 0 - 0 - 0 - 0 - + + + true + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + Custom Widget + + + + + 0 + 0 + 459 + 482 + + + + + + + QGraphicsView + diff --git a/src/editor/editorguiutils.cpp b/src/editor/editorguiutils.cpp new file mode 100644 index 0000000..1d0832a --- /dev/null +++ b/src/editor/editorguiutils.cpp @@ -0,0 +1,37 @@ +#include "editorguiutils.h" + +#include +#include +#include +#include +#include + +QBrush makeGridBrush(int snapX, int snapY, const QPen &gridPen, const QColor &backgroundColor) +{ + QPixmap pixmap{snapX, snapY}; + pixmap.fill(backgroundColor); + + { + QPainter painter{&pixmap}; + painter.setPen(gridPen); + painter.drawLine(0, 0, snapX, 0); + painter.drawLine(0, 0, 0, snapY); + } + + return QBrush{std::move(pixmap)}; +} + +QBrush makeGridBrush(int snapX, int snapY, const QColor &gridColor, const QColor &backgroundColor) +{ + QPixmap pixmap{snapX, snapY}; + pixmap.fill(backgroundColor); + + { + QPainter painter{&pixmap}; + painter.setPen(gridColor); + painter.drawLine(0, 0, snapX, 0); + painter.drawLine(0, 0, 0, snapY); + } + + return QBrush{std::move(pixmap)}; +} diff --git a/src/editor/editorguiutils.h b/src/editor/editorguiutils.h new file mode 100644 index 0000000..294c264 --- /dev/null +++ b/src/editor/editorguiutils.h @@ -0,0 +1,8 @@ +#pragma once + +class QBrush; +class QPen; +class QColor; + +QBrush makeGridBrush(int snapX, int snapY, const QPen &gridPen, const QColor &backgroundColor); +QBrush makeGridBrush(int snapX, int snapY, const QColor &gridColor, const QColor &backgroundColor); diff --git a/src/editor/mainwindow.ui b/src/editor/mainwindow.ui index 94224f1..84c59bf 100644 --- a/src/editor/mainwindow.ui +++ b/src/editor/mainwindow.ui @@ -17,13 +17,19 @@ Qt::Horizontal - + Qt::CustomContextMenu QAbstractItemView::EditKeyPressed + + true + + + QAbstractItemView::DragDrop + 16 @@ -264,7 +270,7 @@ - + :/qtgameengine/icons/new.png:/qtgameengine/icons/new.png @@ -273,7 +279,7 @@ - + :/qtgameengine/icons/open.png:/qtgameengine/icons/open.png @@ -282,7 +288,7 @@ - + :/qtgameengine/icons/save.png:/qtgameengine/icons/save.png @@ -291,7 +297,7 @@ - + :/qtgameengine/icons/save-as.png:/qtgameengine/icons/save-as.png @@ -300,7 +306,7 @@ - + :/qtgameengine/icons/create-executable.png:/qtgameengine/icons/create-executable.png @@ -309,7 +315,7 @@ - + :/qtgameengine/icons/publish-game.png:/qtgameengine/icons/publish-game.png @@ -318,7 +324,7 @@ - + :/qtgameengine/icons/import-resources.png:/qtgameengine/icons/import-resources.png @@ -327,7 +333,7 @@ - + :/qtgameengine/icons/export-resources.png:/qtgameengine/icons/export-resources.png @@ -347,7 +353,7 @@ - + :/qtgameengine/icons/preferences.png:/qtgameengine/icons/preferences.png @@ -359,7 +365,7 @@ - + :/qtgameengine/icons/exit.png:/qtgameengine/icons/exit.png @@ -379,7 +385,7 @@ - + :/qtgameengine/icons/create.png:/qtgameengine/icons/create.png @@ -388,7 +394,7 @@ - + :/qtgameengine/icons/duplicate.png:/qtgameengine/icons/duplicate.png @@ -400,7 +406,7 @@ - + :/qtgameengine/icons/create-group.png:/qtgameengine/icons/create-group.png @@ -414,7 +420,7 @@ - + :/qtgameengine/icons/delete.png:/qtgameengine/icons/delete.png @@ -423,7 +429,7 @@ - + :/qtgameengine/icons/rename.png:/qtgameengine/icons/rename.png @@ -432,7 +438,7 @@ - + :/qtgameengine/icons/properties.png:/qtgameengine/icons/properties.png @@ -444,7 +450,7 @@ - + :/qtgameengine/icons/find.png:/qtgameengine/icons/find.png @@ -463,7 +469,7 @@ - + :/qtgameengine/icons/object-file.png:/qtgameengine/icons/object-file.png @@ -472,7 +478,7 @@ - + :/qtgameengine/icons/sprite.png:/qtgameengine/icons/sprite.png @@ -484,7 +490,7 @@ - + :/qtgameengine/icons/sound.png:/qtgameengine/icons/sound.png @@ -496,7 +502,7 @@ - + :/qtgameengine/icons/background.png:/qtgameengine/icons/background.png @@ -508,7 +514,7 @@ - + :/qtgameengine/icons/path.png:/qtgameengine/icons/path.png @@ -520,7 +526,7 @@ - + :/qtgameengine/icons/script.png:/qtgameengine/icons/script.png @@ -532,7 +538,7 @@ - + :/qtgameengine/icons/font.png:/qtgameengine/icons/font.png @@ -544,7 +550,7 @@ - + :/qtgameengine/icons/timeline.png:/qtgameengine/icons/timeline.png @@ -556,7 +562,7 @@ - + :/qtgameengine/icons/object.png:/qtgameengine/icons/object.png @@ -568,7 +574,7 @@ - + :/qtgameengine/icons/room.png:/qtgameengine/icons/room.png @@ -580,7 +586,7 @@ - + :/qtgameengine/icons/game-information.png:/qtgameengine/icons/game-information.png @@ -592,7 +598,7 @@ - + :/qtgameengine/icons/global-game-settings.png:/qtgameengine/icons/global-game-settings.png @@ -604,7 +610,7 @@ - + :/qtgameengine/icons/extension-packages.png:/qtgameengine/icons/extension-packages.png @@ -616,7 +622,7 @@ - + :/qtgameengine/icons/constants.png:/qtgameengine/icons/constants.png @@ -644,7 +650,7 @@ - + :/qtgameengine/icons/run.png:/qtgameengine/icons/run.png @@ -656,7 +662,7 @@ - + :/qtgameengine/icons/debug.png:/qtgameengine/icons/debug.png @@ -673,7 +679,7 @@ - + :/qtgameengine/icons/help.png:/qtgameengine/icons/help.png @@ -783,7 +789,7 @@ - + :/qtgameengine/icons/tile.png:/qtgameengine/icons/tile.png @@ -792,7 +798,7 @@ - + :/qtgameengine/icons/cascade.png:/qtgameengine/icons/cascade.png @@ -826,8 +832,15 @@ + + + DraggableTreeView + QTreeView +
widgets/draggabletreeview.h
+
+
- + diff --git a/src/editor/models/projecttreemodel.cpp b/src/editor/models/projecttreemodel.cpp index ff7eda9..d4cf477 100644 --- a/src/editor/models/projecttreemodel.cpp +++ b/src/editor/models/projecttreemodel.cpp @@ -273,12 +273,17 @@ Qt::ItemFlags ProjectTreeModel::flags(const QModelIndex &index) const case NodeType::TimeLine: case NodeType::Object: case NodeType::Room: - flags |= Qt::ItemIsEditable; + flags |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return flags; } +Qt::DropActions ProjectTreeModel::supportedDropActions() const +{ + return QAbstractItemModel::supportedDropActions() | Qt::MoveAction; +} + bool ProjectTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { switch (const auto nodeType = this->nodeType(index)) @@ -314,6 +319,12 @@ bool ProjectTreeModel::insertRows(int row, int count, const QModelIndex &parent) return false; } +bool ProjectTreeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) +{ + qDebug() << "called" << sourceParent << sourceRow << count << destinationParent << destinationChild; + return false; +} + bool ProjectTreeModel::removeRows(int row, int count, const QModelIndex &parent) { if (auto result = removeRowsFor(row, count, parent)) return *result; diff --git a/src/editor/models/projecttreemodel.h b/src/editor/models/projecttreemodel.h index 56c0f6a..ae156d5 100644 --- a/src/editor/models/projecttreemodel.h +++ b/src/editor/models/projecttreemodel.h @@ -42,8 +42,10 @@ public: int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; + Qt::DropActions supportedDropActions() const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; bool insertRows(int row, int count, const QModelIndex &parent) override; + bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override; bool removeRows(int row, int count, const QModelIndex &parent) override; ProjectContainer *project() { return m_project; } diff --git a/src/editor/roomscene.cpp b/src/editor/roomscene.cpp new file mode 100644 index 0000000..7e8a5f2 --- /dev/null +++ b/src/editor/roomscene.cpp @@ -0,0 +1,7 @@ +#include "roomscene.h" + +RoomScene::RoomScene(QObject *parent) : + QGraphicsScene{parent} +{ + setSceneRect(QRectF{0, 0, 640, 480}); +} diff --git a/src/editor/roomscene.h b/src/editor/roomscene.h new file mode 100644 index 0000000..c8a9573 --- /dev/null +++ b/src/editor/roomscene.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +class RoomScene : public QGraphicsScene +{ + Q_OBJECT + +public: + explicit RoomScene(QObject *parent = nullptr); +}; diff --git a/src/editor/widgets/draggabletreeview.cpp b/src/editor/widgets/draggabletreeview.cpp new file mode 100644 index 0000000..38148dd --- /dev/null +++ b/src/editor/widgets/draggabletreeview.cpp @@ -0,0 +1,51 @@ +#include "draggabletreeview.h" + +DraggableTreeView::DraggableTreeView(QWidget *parent) : + QTreeView{parent} +{ +} + +void DraggableTreeView::dragMoveEvent(QDragMoveEvent *event) +{ + setDropIndicatorShown(true); + //qDebug() << QStringList{"OnItem","AboveItem","BelowItem","OnViewport"}[dropIndicatorPosition()]; + QTreeView::dragMoveEvent(event); +} + +void DraggableTreeView::dropEvent(QDropEvent *event) +{ + bool dropOK = false; + DropIndicatorPosition dropIndicator = dropIndicatorPosition(); + + switch (dropIndicator) + { + case QAbstractItemView::AboveItem: + dropOK = true; + break; + case QAbstractItemView::BelowItem: + dropOK = true; + break; + case QAbstractItemView::OnItem: + dropOK = false; + break; + case QAbstractItemView::OnViewport: + dropOK = false; + break; + } + if(dropOK) + { + // Here, you need to manage yourself the case of dropping an item + } + setDropIndicatorShown(false); // hide the drop indicator once the drop is done + QTreeView::dropEvent(event); +} + +void DraggableTreeView::paintEvent(QPaintEvent *event) +{ + DropIndicatorPosition position = dropIndicatorPosition(); + setDropIndicatorShown( position == QAbstractItemView::BelowItem || position == QAbstractItemView::AboveItem ); + + QTreeView::paintEvent(event); + + setDropIndicatorShown( true ); +} diff --git a/src/editor/widgets/draggabletreeview.h b/src/editor/widgets/draggabletreeview.h new file mode 100644 index 0000000..fcb8f15 --- /dev/null +++ b/src/editor/widgets/draggabletreeview.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +class DraggableTreeView : public QTreeView +{ + Q_OBJECT + +public: + explicit DraggableTreeView(QWidget *parent = nullptr); + + void dragMoveEvent(QDragMoveEvent *event) override; + void dropEvent(QDropEvent *event) override; + void paintEvent(QPaintEvent *event) override; +}; diff --git a/src/editor/widgets/pathpointswidget.cpp b/src/editor/widgets/pathpointswidget.cpp index 92568fe..3cb75de 100644 --- a/src/editor/widgets/pathpointswidget.cpp +++ b/src/editor/widgets/pathpointswidget.cpp @@ -7,6 +7,8 @@ #include +#include "editorguiutils.h" + PathPointsWidget::PathPointsWidget(QWidget *parent) : QWidget{parent} { @@ -81,21 +83,10 @@ void PathPointsWidget::paintEvent(QPaintEvent *event) { if (!m_gridBrush || m_gridBrush->snapX != m_snapX || m_gridBrush->snapY != m_snapY) { - QPixmap pixmap{m_snapX, m_snapY}; - - { - QPainter painter{&pixmap}; - painter.setPen(palette().color(m_gridRole)); - painter.drawLine(0, 0, m_snapX, 0); - painter.drawLine(0, 0, 0, m_snapY); - - painter.fillRect(1, 1, m_snapX - 1, m_snapY - 1, palette().color(backgroundRole())); - } - m_gridBrush = GridBrush { .snapX = m_snapX, .snapY = m_snapY, - .brush = QBrush{std:: move(pixmap)} + .brush = makeGridBrush(m_snapX, m_snapY, palette().color(m_gridRole), palette().color(backgroundRole())) }; } } diff --git a/src/editor/widgets/roomeditwidget.cpp b/src/editor/widgets/roomeditwidget.cpp index cae259a..2bbdd2f 100644 --- a/src/editor/widgets/roomeditwidget.cpp +++ b/src/editor/widgets/roomeditwidget.cpp @@ -5,6 +5,10 @@ #include #include +#include "editorguiutils.h" +#include "models/projecttreemodel.h" +#include "projectcontainer.h" + RoomEditWidget::RoomEditWidget(QWidget *parent) : QWidget{parent} { @@ -18,7 +22,8 @@ void RoomEditWidget::setSnapX(int snapX) if (m_snapX == snapX) return; emit snapXChanged(m_snapX = snapX); - update(); + if (m_gridEnabled) + update(); } void RoomEditWidget::setSnapY(int snapY) @@ -26,7 +31,8 @@ void RoomEditWidget::setSnapY(int snapY) if (m_snapY == snapY) return; emit snapYChanged(m_snapY = snapY); - update(); + if (m_gridEnabled) + update(); } void RoomEditWidget::setGridEnabled(bool gridEnabled) @@ -50,6 +56,17 @@ void RoomEditWidget::setGridRole(QPalette::ColorRole gridRole) if (gridRole == m_gridRole) return; m_gridRole = gridRole; + if (m_gridEnabled) + update(); +} + +void RoomEditWidget::setSelectedObject(const Object *selectedObject) +{ + if (m_selectedObject == selectedObject) + return; + if (m_draggedObject && &m_draggedObject->object.get() == m_selectedObject) + m_draggedObject = std::nullopt; + m_selectedObject = selectedObject; update(); } @@ -57,25 +74,16 @@ void RoomEditWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event) + QWidget::paintEvent(event); + if (m_gridEnabled) { if (!m_gridBrush || m_gridBrush->snapX != m_snapX || m_gridBrush->snapY != m_snapY) { - QPixmap pixmap{m_snapX, m_snapY}; - - { - QPainter painter{&pixmap}; - painter.setPen(palette().color(m_gridRole)); - painter.drawLine(0, 0, m_snapX, 0); - painter.drawLine(0, 0, 0, m_snapY); - - painter.fillRect(1, 1, m_snapX - 1, m_snapY - 1, palette().color(backgroundRole())); - } - m_gridBrush = GridBrush { .snapX = m_snapX, .snapY = m_snapY, - .brush = QBrush{std:: move(pixmap)} + .brush = makeGridBrush(m_snapX, m_snapY, palette().color(m_gridRole), Qt::transparent) }; } } @@ -83,17 +91,62 @@ void RoomEditWidget::paintEvent(QPaintEvent *event) m_gridBrush = std::nullopt; QPainter painter{this}; - painter.fillRect(rect(), m_gridBrush ? m_gridBrush->brush : palette().color(backgroundRole())); + + if (m_draggedObject) + { + if (m_projectTreeModel) + { + QPixmap pixmap; + const auto &object = m_draggedObject->object.get(); + if (!object.spriteName.isEmpty()) + { + const auto iter = std::find_if(std::cbegin(m_projectTreeModel->project()->sprites), std::cend(m_projectTreeModel->project()->sprites), + [&object](const auto &sprite){ return object.spriteName == sprite.name; }); + if (iter == std::cend(m_projectTreeModel->project()->sprites)) + qWarning() << "invalid sprite" << object.spriteName; + else if (!iter->pixmaps.empty() && !iter->pixmaps.front().isNull()) + pixmap = iter->pixmaps.front(); + } + + if (pixmap.isNull()) + goto noPixmap; + + painter.drawPixmap(m_draggedObject->pos, std::move(pixmap)); + } + else + { +noPixmap: + painter.drawRect(QRect{m_draggedObject->pos, QSize{64, 64}}); + } + } + + if (m_gridBrush) + painter.fillRect(rect(), m_gridBrush->brush); } void RoomEditWidget::mousePressEvent(QMouseEvent *event) { QWidget::mousePressEvent(event); + + if (m_selectedObject) + { + m_draggedObject = DraggedObject { + .object = *m_selectedObject, + .pos = event->pos() + }; + update(); + } } void RoomEditWidget::mouseReleaseEvent(QMouseEvent *event) { QWidget::mouseReleaseEvent(event); + + if (m_draggedObject) + { + m_draggedObject = std::nullopt; + update(); + } } void RoomEditWidget::mouseMoveEvent(QMouseEvent *event) @@ -101,6 +154,16 @@ void RoomEditWidget::mouseMoveEvent(QMouseEvent *event) QWidget::mouseMoveEvent(event); emit cursorMoved(snapPoint(event->pos())); + + if (m_draggedObject) + { + const auto newPos = snapPoint(event->pos()); + if (newPos != m_draggedObject->pos) + { + m_draggedObject->pos = newPos; + update(); + } + } } QPoint RoomEditWidget::snapPoint(const QPoint &point) const diff --git a/src/editor/widgets/roomeditwidget.h b/src/editor/widgets/roomeditwidget.h index 4e3896e..6550166 100644 --- a/src/editor/widgets/roomeditwidget.h +++ b/src/editor/widgets/roomeditwidget.h @@ -6,6 +6,7 @@ #include struct Object; +class ProjectTreeModel; class RoomEditWidget : public QWidget { @@ -33,8 +34,12 @@ public: QPalette::ColorRole gridRole() const { return m_gridRole; } void setGridRole(QPalette::ColorRole gridRole); + ProjectTreeModel *projectTreeModel() { return m_projectTreeModel; } + const ProjectTreeModel *projectTreeModel() const { return m_projectTreeModel; } + void setProjectTreeModel(ProjectTreeModel *projectTreeModel) { m_projectTreeModel = projectTreeModel; update(); } + const Object *selectedObject() const { return m_selectedObject; } - void setSelectedObject(const Object *object) { m_selectedObject = object; update(); } + void setSelectedObject(const Object *selectedObject); signals: void snapXChanged(int snapX); @@ -69,4 +74,12 @@ private: std::optional m_gridBrush; QPalette::ColorRole m_gridRole{QPalette::Dark}; + + ProjectTreeModel *m_projectTreeModel{}; + + struct DraggedObject { + std::reference_wrapper object; + QPoint pos; + }; + std::optional m_draggedObject; };