diff -Nuar "a/data/levels/Desert Storm.trk" "b/data/levels/Desert Storm.trk" --- "a/data/levels/Desert Storm.trk" 2017-12-30 16:09:21.000000000 +0300 +++ "b/data/levels/Desert Storm.trk" 2018-02-11 08:22:08.000000000 +0300 @@ -1,993 +1,993 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nuar a/README.md b/README.md --- a/README.md 2017-12-30 16:09:21.000000000 +0300 +++ b/README.md 2018-02-11 08:22:08.000000000 +0300 @@ -11,7 +11,7 @@ -Video of the game +Video of the game Dust Racing (Dustrac) is a tile-based, cross-platform 2D racing game written in Qt (C++) and OpenGL. diff -Nuar a/src/editor/application.cpp b/src/editor/application.cpp --- a/src/editor/application.cpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/application.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -58,7 +58,7 @@ QString lang = ""; const std::vector args(argv, argv + argc); - for (unsigned int i = 0; i < args.size(); i++) + for (unsigned int i = 1; i < args.size(); i++) { if (args[i] == "-h" || args[i] == "--help") { diff -Nuar a/src/editor/CMakeLists.txt b/src/editor/CMakeLists.txt --- a/src/editor/CMakeLists.txt 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/CMakeLists.txt 2018-02-11 08:22:08.000000000 +0300 @@ -10,12 +10,15 @@ set(SRC aboutdlg.cpp application.cpp + draganddropstore.cpp editordata.cpp editorview.cpp - editorscene.cpp + editormode.hpp + floodfill.cpp main.cpp mainwindow.cpp map.cpp + mediator.cpp newtrackdialog.cpp object.cpp objectfactory.cpp diff -Nuar a/src/editor/draganddropstore.cpp b/src/editor/draganddropstore.cpp --- a/src/editor/draganddropstore.cpp 1970-01-01 02:00:00.000000000 +0200 +++ b/src/editor/draganddropstore.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -0,0 +1,69 @@ +// This file is part of Dust Racing 2D. +// Copyright (C) 2018 Jussi Lind +// +// Dust Racing 2D is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// Dust Racing 2D is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Dust Racing 2D. If not, see . + +#include "draganddropstore.hpp" + +DragAndDropStore::DragAndDropStore() +{ +} + +void DragAndDropStore::clear() +{ + m_dragAndDropSourceTile = nullptr; + + m_dragAndDropObject = nullptr; + + m_dragAndDropTargetNode = nullptr; +} + +void DragAndDropStore::setDragAndDropSourceTile(TrackTile * tile) +{ + m_dragAndDropSourceTile = tile; +} + +TrackTile * DragAndDropStore::dragAndDropSourceTile() const +{ + return m_dragAndDropSourceTile; +} + +void DragAndDropStore::setDragAndDropObject(Object * object) +{ + m_dragAndDropObject = object; +} + +Object * DragAndDropStore::dragAndDropObject() const +{ + return m_dragAndDropObject; +} + +void DragAndDropStore::setDragAndDropTargetNode(TargetNode * tnode) +{ + m_dragAndDropTargetNode = tnode; +} + +TargetNode * DragAndDropStore::dragAndDropTargetNode() const +{ + return m_dragAndDropTargetNode; +} + +void DragAndDropStore::setDragAndDropSourcePos(QPointF pos) +{ + m_dragAndDropSourcePos = pos; +} + +QPointF DragAndDropStore::dragAndDropSourcePos() const +{ + return m_dragAndDropSourcePos; +} diff -Nuar a/src/editor/draganddropstore.hpp b/src/editor/draganddropstore.hpp --- a/src/editor/draganddropstore.hpp 1970-01-01 02:00:00.000000000 +0200 +++ b/src/editor/draganddropstore.hpp 2018-02-11 08:22:08.000000000 +0300 @@ -0,0 +1,60 @@ +// This file is part of Dust Racing 2D. +// Copyright (C) 2018 Jussi Lind +// +// Dust Racing 2D is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// Dust Racing 2D is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Dust Racing 2D. If not, see . + +#ifndef DRAGANDDROPSTORE_HPP +#define DRAGANDDROPSTORE_HPP + +#include + +class Object; +class TargetNode; +class TrackTile; + +class DragAndDropStore +{ +public: + + DragAndDropStore(); + + void clear(); + + void setDragAndDropTargetNode(TargetNode * tnode); + + TargetNode * dragAndDropTargetNode() const; + + QPointF dragAndDropSourcePos() const; + + void setDragAndDropSourcePos(QPointF pos); + + void setDragAndDropSourceTile(TrackTile * tile); + + TrackTile * dragAndDropSourceTile() const; + + void setDragAndDropObject(Object * object); + + Object * dragAndDropObject() const; + +private: + + TrackTile * m_dragAndDropSourceTile = nullptr; + + Object * m_dragAndDropObject = nullptr; + + TargetNode * m_dragAndDropTargetNode = nullptr; + + QPointF m_dragAndDropSourcePos; +}; + +#endif // DRAGANDDROPSTORE_HPP diff -Nuar a/src/editor/editordata.cpp b/src/editor/editordata.cpp --- a/src/editor/editordata.cpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/editordata.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -14,9 +14,9 @@ // along with Dust Racing 2D. If not, see . #include "editordata.hpp" -#include "editorscene.hpp" #include "editorview.hpp" #include "mainwindow.hpp" +#include "mediator.hpp" #include "object.hpp" #include "objectmodelloader.hpp" #include "targetnode.hpp" @@ -28,10 +28,8 @@ using std::dynamic_pointer_cast; -EditorData::EditorData(MainWindow * mainWindow) -: m_mode(EditorMode::None) -, m_dragAndDropSourcePos() -, m_mainWindow(mainWindow) +EditorData::EditorData(Mediator & mediator) + : m_mediator(mediator) {} void EditorData::clearScene() @@ -41,6 +39,11 @@ removeTargetNodesFromScene(); } +DragAndDropStore & EditorData::dadStore() +{ + return m_dadStore; +} + bool EditorData::loadTrackData(QString fileName) { m_undoStack.clear(); @@ -60,16 +63,12 @@ { if (m_undoStack.isUndoable()) { - m_dragAndDropSourceTile = nullptr; - - m_dragAndDropObject = nullptr; + m_dadStore.clear(); m_selectedObject = nullptr; m_selectedTargetNode = nullptr; - m_dragAndDropTargetNode = nullptr; - saveRedoPoint(); clearScene(); @@ -87,16 +86,12 @@ { if (m_undoStack.isRedoable()) { - m_dragAndDropSourceTile = nullptr; - - m_dragAndDropObject = nullptr; + m_dadStore.clear(); m_selectedObject = nullptr; m_selectedTargetNode = nullptr; - m_dragAndDropTargetNode = nullptr; - saveUndoPoint(); clearScene(); @@ -116,7 +111,7 @@ assert(m_trackData); m_undoStack.pushUndoPoint(m_trackData); - m_mainWindow->enableUndo(m_undoStack.isUndoable()); + m_mediator.enableUndo(m_undoStack.isUndoable()); } void EditorData::saveRedoPoint() @@ -151,17 +146,11 @@ void EditorData::beginSetRoute() { assert(m_trackData); - setMode(EditorMode::SetRoute); + m_mediator.setMode(EditorMode::SetRoute); removeRouteFromScene(); m_trackData->route().clear(); } -void EditorData::endSetRoute() -{ - // Reset the editing mode. - setMode(EditorMode::None); -} - void EditorData::addExistingRouteToScene() { // Re-push existing (loaded) target nodes so that route lines @@ -204,8 +193,8 @@ auto routeLine = new QGraphicsLineItem; node->setRouteLine(routeLine); - m_mainWindow->editorScene().addItem(node.get()); // The scene wants a raw pointer - m_mainWindow->editorScene().addItem(routeLine); + m_mediator.addItem(node.get()); // The scene wants a raw pointer + m_mediator.addItem(routeLine); const int routeLineZ = 10; node->setZValue(routeLineZ); @@ -214,8 +203,7 @@ // Check if we might have a loop => end if (loopClosed) { - setMode(EditorMode::None); - m_mainWindow->endSetRoute(); + m_mediator.endSetRoute(); auto firstNode = route.get(0); route.get(route.numNodes() - 1)->setLocation(firstNode->location()); @@ -232,13 +220,13 @@ auto node = dynamic_pointer_cast(tnode); assert(node); - m_mainWindow->editorScene().removeItem(node.get()); // The scene wants a raw pointer - m_mainWindow->editorScene().removeItem(node->routeLine()); + m_mediator.removeItem(node.get()); // The scene wants a raw pointer + m_mediator.removeItem(node->routeLine()); delete node->routeLine(); } - m_mainWindow->editorView().update(); + m_mediator.updateView(); } TrackDataPtr EditorData::trackData() @@ -246,36 +234,6 @@ return m_trackData; } -EditorData::EditorMode EditorData::mode() const -{ - return m_mode; -} - -void EditorData::setMode(EditorData::EditorMode newMode) -{ - m_mode = newMode; -} - -void EditorData::setDragAndDropSourceTile(TrackTile * tile) -{ - m_dragAndDropSourceTile = tile; -} - -TrackTile * EditorData::dragAndDropSourceTile() const -{ - return m_dragAndDropSourceTile; -} - -void EditorData::setDragAndDropObject(Object * object) -{ - m_dragAndDropObject = object; -} - -Object * EditorData::dragAndDropObject() const -{ - return m_dragAndDropObject; -} - void EditorData::setSelectedObject(Object * object) { m_selectedObject = object; @@ -296,26 +254,6 @@ return m_selectedTargetNode; } -void EditorData::setDragAndDropTargetNode(TargetNode * tnode) -{ - m_dragAndDropTargetNode = tnode; -} - -TargetNode * EditorData::dragAndDropTargetNode() const -{ - return m_dragAndDropTargetNode; -} - -void EditorData::setDragAndDropSourcePos(QPointF pos) -{ - m_dragAndDropSourcePos = pos; -} - -QPointF EditorData::dragAndDropSourcePos() const -{ - return m_dragAndDropSourcePos; -} - void EditorData::addTilesToScene() { assert(m_trackData); @@ -331,7 +269,7 @@ if (!tile->added()) { - m_mainWindow->editorScene().addItem(tile.get()); // The scene wants a raw pointer + m_mediator.addItem(tile.get()); // The scene wants a raw pointer tile->setAdded(true); } @@ -351,7 +289,7 @@ auto object = dynamic_pointer_cast(m_trackData->objects().object(i)); assert(object); - m_mainWindow->editorScene().addItem(object.get()); // The scene wants a raw pointer + m_mediator.addItem(object.get()); // The scene wants a raw pointer object->setZValue(10); } @@ -364,7 +302,7 @@ auto tile = dynamic_pointer_cast(trackTile); assert(tile); - m_mainWindow->editorScene().removeItem(tile.get()); // The scene wants a raw pointer + m_mediator.removeItem(tile.get()); // The scene wants a raw pointer } void EditorData::removeTilesFromScene() @@ -380,7 +318,7 @@ auto tile = dynamic_pointer_cast(m_trackData->map().getTile(i, j)); assert(tile); - m_mainWindow->editorScene().removeItem(tile.get()); // The scene wants a raw pointer + m_mediator.removeItem(tile.get()); // The scene wants a raw pointer } } } @@ -395,12 +333,13 @@ auto object = dynamic_pointer_cast(m_trackData->objects().object(i)); assert(object); - m_mainWindow->editorScene().removeItem(object.get()); // The scene wants a raw pointer + m_mediator.removeItem(object.get()); // The scene wants a raw pointer } } m_selectedObject = nullptr; - m_dragAndDropObject = nullptr; + + m_dadStore.clear(); } void EditorData::removeTargetNodesFromScene() @@ -412,11 +351,21 @@ auto node = dynamic_pointer_cast(tnode); assert(node); - m_mainWindow->editorScene().removeItem(node.get()); // The scene wants a raw pointer + m_mediator.removeItem(node.get()); // The scene wants a raw pointer } } } +int EditorData::currentScale() const +{ + return m_currentScale; +} + +void EditorData::setCurrentScale(int currentScale) +{ + m_currentScale = currentScale; +} + void EditorData::clearRoute() { assert(m_trackData); @@ -424,7 +373,7 @@ removeRouteFromScene(); m_trackData->route().clear(); - m_mainWindow->console(QString(QObject::tr("Route cleared."))); + m_mediator.console(QString(QObject::tr("Route cleared."))); } void EditorData::setActiveColumn(unsigned int column) diff -Nuar a/src/editor/editordata.hpp b/src/editor/editordata.hpp --- a/src/editor/editordata.hpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/editordata.hpp 2018-02-11 08:22:08.000000000 +0300 @@ -22,11 +22,13 @@ #include #include +#include "draganddropstore.hpp" +#include "editormode.hpp" #include "trackdata.hpp" #include "trackio.hpp" #include "undostack.hpp" -class MainWindow; +class Mediator; class Object; class ObjectModelLoader; class TargetNode; @@ -40,19 +42,10 @@ { public: - //! Editing modes. - enum class EditorMode - { - None, - SetRoute, - SetTileType, - AddObject, - EraseObject - }; - //! Constructor. - //! \param mainWindow Pointer to the main window. - EditorData(MainWindow * mainWindow); + explicit EditorData(Mediator & mediator); + + DragAndDropStore & dadStore(); //! Load track from the given file. bool loadTrackData(QString fileName); @@ -89,10 +82,6 @@ //! setting the route. void beginSetRoute(); - //! This should be called after user ends - //! setting the route. - void endSetRoute(); - //! Adds current target node objects to the scene. void addExistingRouteToScene(); @@ -108,24 +97,6 @@ //! Returns current track data object. Returns NULL if not set. TrackDataPtr trackData(); - //! Returns current editing mode. - EditorMode mode() const; - - //! Sets the current editing mode. - void setMode(EditorMode newMode); - - //! Set tile that is being drag'n'dropped. - void setDragAndDropSourceTile(TrackTile * tile); - - //! Returns the tile being drag'n'dropped or nullptr. - TrackTile * dragAndDropSourceTile() const; - - //! Set object that is being drag'n'dropped. - void setDragAndDropObject(Object * object); - - //! Returns the object being drag'n'dropped or nullptr. - Object * dragAndDropObject() const; - //! Set selected object. void setSelectedObject(Object * object); @@ -138,18 +109,6 @@ //! Returns the selected target node or nullptr. TargetNode * selectedTargetNode() const; - //! Set target node that is being drag'n'dropped. - void setDragAndDropTargetNode(TargetNode * tnode); - - //! Returns the target node being drag'n'dropped or nullptr. - TargetNode * dragAndDropTargetNode() const; - - //! Get source pos of the drag'n'drop. - QPointF dragAndDropSourcePos() const; - - //! Set source pos of the drag'n'drop. - void setDragAndDropSourcePos(QPointF pos); - //! Add tiles in current track data object to the scene. void addTilesToScene(); @@ -167,6 +126,10 @@ unsigned int activeRow() const; + void setCurrentScale(int currentScale); + + int currentScale() const; + private: EditorData(const EditorData & e); @@ -182,33 +145,28 @@ void removeTargetNodesFromScene(); + DragAndDropStore m_dadStore; + TrackIO m_trackIO; TrackDataPtr m_trackData; UndoStack m_undoStack; - EditorMode m_mode; - - TrackTile * m_dragAndDropSourceTile = nullptr; - - Object * m_dragAndDropObject = nullptr; - Object * m_selectedObject = nullptr; TargetNode * m_selectedTargetNode = nullptr; - TargetNode * m_dragAndDropTargetNode = nullptr; - - QPointF m_dragAndDropSourcePos; - - MainWindow * m_mainWindow = nullptr; + Mediator & m_mediator; std::vector m_targetNodes; unsigned int m_activeColumn = 0; unsigned int m_activeRow = 0; + + // Scale percentage + int m_currentScale = 50; }; #endif // EDITORDATA_HPP diff -Nuar a/src/editor/editormode.hpp b/src/editor/editormode.hpp --- a/src/editor/editormode.hpp 1970-01-01 02:00:00.000000000 +0200 +++ b/src/editor/editormode.hpp 2018-02-11 08:22:08.000000000 +0300 @@ -0,0 +1,29 @@ +// This file is part of Dust Racing 2D. +// Copyright (C) 2018 Jussi Lind +// +// Dust Racing 2D is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// Dust Racing 2D is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Dust Racing 2D. If not, see . + +#ifndef EDITORMODE_HPP +#define EDITORMODE_HPP + +//! Editing modes. +enum class EditorMode +{ + None, + SetRoute, + SetTileType, + AddObject, + EraseObject +}; + +#endif // EDITORMODE_HPP diff -Nuar a/src/editor/editor.pro b/src/editor/editor.pro --- a/src/editor/editor.pro 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/editor.pro 2018-02-11 08:22:08.000000000 +0300 @@ -29,11 +29,14 @@ ../common/userexception.hpp \ aboutdlg.hpp \ application.hpp \ + draganddropstore.hpp \ editordata.hpp \ - editorscene.hpp \ editorview.hpp \ + editormode.hpp \ + floodfill.hpp \ mainwindow.hpp \ map.hpp \ + mediator.hpp \ newtrackdialog.hpp \ object.hpp \ objectfactory.hpp \ @@ -60,12 +63,14 @@ ../common/tracktilebase.cpp \ aboutdlg.cpp \ application.cpp \ + draganddropstore.cpp \ editordata.cpp \ - editorscene.cpp \ editorview.cpp \ + floodfill.cpp \ main.cpp \ mainwindow.cpp \ map.cpp \ + mediator.cpp \ newtrackdialog.cpp \ object.cpp \ objectfactory.cpp \ diff -Nuar a/src/editor/editorscene.cpp b/src/editor/editorscene.cpp --- a/src/editor/editorscene.cpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/editorscene.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,20 +0,0 @@ -// This file is part of Dust Racing 2D. -// Copyright (C) 2011 Jussi Lind -// -// Dust Racing 2D is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// Dust Racing 2D is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Dust Racing 2D. If not, see . - -#include "editorscene.hpp" - -EditorScene::EditorScene(QObject * parent) : - QGraphicsScene(parent) -{} diff -Nuar a/src/editor/editorscene.hpp b/src/editor/editorscene.hpp --- a/src/editor/editorscene.hpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/editorscene.hpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,32 +0,0 @@ -// This file is part of Dust Racing 2D. -// Copyright (C) 2011 Jussi Lind -// -// Dust Racing 2D is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// Dust Racing 2D is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Dust Racing 2D. If not, see . - -#ifndef EDITORSCENE_HPP -#define EDITORSCENE_HPP - -#include - -//! Graphics scene of the editor. -class EditorScene : public QGraphicsScene -{ - Q_OBJECT - -public: - - //! Constructor. - explicit EditorScene(QObject * parent = nullptr); -}; - -#endif // EDITORSCENE_HPP diff -Nuar a/src/editor/editorview.cpp b/src/editor/editorview.cpp --- a/src/editor/editorview.cpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/editorview.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -20,9 +20,11 @@ #include #include -#include "editordata.hpp" #include "editorview.hpp" -#include "mainwindow.hpp" + +#include "draganddropstore.hpp" +#include "editormode.hpp" +#include "mediator.hpp" #include "object.hpp" #include "objectfactory.hpp" #include "objectmodelloader.hpp" @@ -35,9 +37,8 @@ #include #include -EditorView::EditorView(EditorData & editorData, QWidget * parent) -: QGraphicsView(parent) -, m_editorData(editorData) +EditorView::EditorView(Mediator & mediator) + : m_mediator(mediator) { createTileContextMenuActions(); createObjectContextMenuActions(); @@ -49,8 +50,8 @@ const QRectF newSceneRect( 0, 0, - m_editorData.trackData()->map().cols() * TrackTile::TILE_W, - m_editorData.trackData()->map().rows() * TrackTile::TILE_H); + m_mediator.cols() * TrackTile::TILE_W, + m_mediator.rows() * TrackTile::TILE_H); setSceneRect(newSceneRect); @@ -69,45 +70,22 @@ } // Tile drag'n'drop active? - if (auto sourceTile = m_editorData.dragAndDropSourceTile()) + if (auto sourceTile = m_mediator.dadStore().dragAndDropSourceTile()) { sourceTile->setPos(mappedPos); } // Object drag'n'drop active? - else if (auto object = m_editorData.dragAndDropObject()) + else if (auto object = m_mediator.dadStore().dragAndDropObject()) { object->setLocation(mappedPos); } // Target node drag'n'drop active? - else if (auto tnode = m_editorData.dragAndDropTargetNode()) + else if (auto tnode = m_mediator.dadStore().dragAndDropTargetNode()) { tnode->setLocation(mappedPos); } - updateCoordinates(mappedPos); - } -} - -void EditorView::updateCoordinates(QPointF mappedPos) -{ - if (m_editorData.trackData()) - { - const int maxCols = static_cast(m_editorData.trackData()->map().cols()); - int column = mappedPos.x() / TrackTile::TILE_W; - column = column >= maxCols ? maxCols - 1 : column; - column = column < 0 ? 0 : column; - - const int maxRows = static_cast(m_editorData.trackData()->map().rows()); - int row = mappedPos.y() / TrackTile::TILE_H; - row = row >= maxRows ? maxRows - 1 : row; - row = row < 0 ? 0 : row; - - m_editorData.setActiveRow(static_cast(row)); - m_editorData.setActiveColumn(static_cast(column)); - - QString coordinates("X: %1 Y: %2 I: %3 J: %4"); - coordinates = coordinates.arg(mappedPos.x()).arg(mappedPos.y()).arg(column).arg(row); - MainWindow::instance()->statusBar()->showMessage(coordinates); + m_mediator.updateCoordinates(mappedPos); } } @@ -121,7 +99,7 @@ if (TrackTile * tile = dynamic_cast(scene()->itemAt(mapToScene(m_clickedPos), QTransform()))) { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); tile->rotate90CW(); } }); @@ -133,28 +111,28 @@ if (auto tile = dynamic_cast(scene()->itemAt(mapToScene(m_clickedPos), QTransform()))) { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); tile->rotate90CCW(); } }); m_clearComputerHint = new QAction(QWidget::tr("Clear computer hint"), &m_tileContextMenu); QObject::connect(m_clearComputerHint, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); setComputerHint(TrackTileBase::CH_NONE); }); m_setComputerHintBrakeHard = new QAction( QWidget::tr("Set computer hint 'brake hard'.."), &m_tileContextMenu); QObject::connect(m_setComputerHintBrakeHard, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); setComputerHint(TrackTileBase::CH_BRAKE_HARD); }); m_setComputerHintBrake = new QAction( QWidget::tr("Set computer hint 'brake'.."), &m_tileContextMenu); QObject::connect(m_setComputerHintBrake, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); setComputerHint(TrackTileBase::CH_BRAKE); }); @@ -164,7 +142,7 @@ QObject::connect(m_excludeFromMinimap, &QAction::changed, [this] () { if (auto tile = dynamic_cast(scene()->itemAt(mapToScene(this->m_clickedPos), QTransform()))) { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); tile->setExcludeFromMinimap(this->m_excludeFromMinimap->isChecked()); } }); @@ -172,9 +150,8 @@ auto insertRowBefore = new QAction( QWidget::tr("Insert row before.."), &m_tileContextMenu); QObject::connect(insertRowBefore, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); - m_editorData.trackData()->insertRow(m_editorData.activeRow(), MapBase::InsertDirection::Before); - m_editorData.addTilesToScene(); + m_mediator.saveUndoPoint(); + m_mediator.insertRowBefore(); updateSceneRect(); update(); }); @@ -182,9 +159,8 @@ auto insertRowAfter = new QAction( QWidget::tr("Insert row after.."), &m_tileContextMenu); QObject::connect(insertRowAfter, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); - m_editorData.trackData()->insertRow(m_editorData.activeRow(), MapBase::InsertDirection::After); - m_editorData.addTilesToScene(); + m_mediator.saveUndoPoint(); + m_mediator.insertRowAfter(); updateSceneRect(); update(); }); @@ -192,11 +168,8 @@ m_deleteRow = new QAction( QWidget::tr("Delete row.."), &m_tileContextMenu); QObject::connect(m_deleteRow, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); - auto deleted = m_editorData.trackData()->deleteRow(m_editorData.activeRow()); - for (auto && tile : deleted) { - m_editorData.removeTileFromScene(tile); - } + m_mediator.saveUndoPoint(); + m_mediator.deleteRow(); updateSceneRect(); update(); }); @@ -204,9 +177,8 @@ auto insertColBefore = new QAction( QWidget::tr("Insert column before.."), &m_tileContextMenu); QObject::connect(insertColBefore, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); - m_editorData.trackData()->insertColumn(m_editorData.activeColumn(), MapBase::InsertDirection::Before); - m_editorData.addTilesToScene(); + m_mediator.saveUndoPoint(); + m_mediator.insertColumnBefore(); updateSceneRect(); update(); }); @@ -214,9 +186,8 @@ auto insertColAfter = new QAction( QWidget::tr("Insert column after.."), &m_tileContextMenu); QObject::connect(insertColAfter, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); - m_editorData.trackData()->insertColumn(m_editorData.activeColumn(), MapBase::InsertDirection::After); - m_editorData.addTilesToScene(); + m_mediator.saveUndoPoint(); + m_mediator.insertColumnAfter(); updateSceneRect(); update(); }); @@ -224,11 +195,8 @@ m_deleteCol = new QAction( QWidget::tr("Delete column.."), &m_tileContextMenu); QObject::connect(m_deleteCol, &QAction::triggered, [this] () { - m_editorData.saveUndoPoint(); - auto deleted = m_editorData.trackData()->deleteColumn(m_editorData.activeColumn()); - for (auto && tile : deleted) { - m_editorData.removeTileFromScene(tile); - } + m_mediator.saveUndoPoint(); + m_mediator.deleteColumn(); updateSceneRect(); update(); }); @@ -260,9 +228,9 @@ RotateDialog dialog; if (dialog.exec() == QDialog::Accepted) { - if (auto object = m_editorData.selectedObject()) + if (auto object = m_mediator.selectedObject()) { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); object->setRotation(static_cast(dialog.angle() + object->rotation()) % 360); } @@ -273,9 +241,9 @@ m_forceStationaryAction = new QAction(dummy2, &m_tileContextMenu); m_forceStationaryAction->setCheckable(true); QObject::connect(m_forceStationaryAction, &QAction::changed, [this] () { - if (auto object = m_editorData.selectedObject()) + if (auto object = m_mediator.selectedObject()) { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); object->setForceStationary(m_forceStationaryAction->isChecked()); } }); @@ -291,12 +259,12 @@ const QString dummy1(QString(QWidget::tr("Set size.."))); auto setSize = new QAction(dummy1, &m_targetNodeContextMenu); QObject::connect(setSize, &QAction::triggered, [this] () { - if (auto tnode = m_editorData.selectedTargetNode()) + if (auto tnode = m_mediator.selectedTargetNode()) { TargetNodeSizeDlg dialog(tnode->size()); if (dialog.exec() == QDialog::Accepted) { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); tnode->setSize(dialog.targetNodeSize()); } @@ -311,12 +279,11 @@ { if (scene()) { - m_clickedPos = event->pos(); + m_clickedPos = event->pos(); m_clickedScenePos = mapToScene(m_clickedPos); // Fetch all items at the location - QList items = scene()->items( - m_clickedScenePos, Qt::IntersectsItemShape, Qt::DescendingOrder); + QList items = scene()->items(m_clickedScenePos, Qt::IntersectsItemShape, Qt::DescendingOrder); if (items.size()) { @@ -351,7 +318,7 @@ void EditorView::eraseObjectAtCurrentClickedPos() { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); // Fetch all items at the location QList items = scene()->items( @@ -363,9 +330,8 @@ { if (auto object = dynamic_cast(item)) { - scene()->removeItem(object); - m_editorData.trackData()->objects().remove(*object); - m_editorData.setSelectedObject(nullptr); + m_mediator.removeObject(*object); + m_mediator.setSelectedObject(nullptr); break; } } @@ -373,26 +339,7 @@ void EditorView::addCurrentToolBarObjectToScene() { - if (QAction * action = MainWindow::instance()->currentToolBarAction()) - { - if (scene()) - { - m_editorData.saveUndoPoint(); - - Object & object = ObjectFactory::createObject(action->data().toString()); - object.setLocation(m_clickedScenePos); - - if (MainWindow::instance()->randomlyRotateObjects()) - { - object.setRotation(std::rand() % 360); - } - - scene()->addItem(&object); - - m_editorData.trackData()->objects().add(ObjectBasePtr(&object)); - m_editorData.setSelectedObject(&object); - } - } + m_mediator.addCurrentToolBarObjectToScene(m_clickedScenePos); } void EditorView::handleMousePressEventOnObject(QMouseEvent & event, Object & object) @@ -404,12 +351,12 @@ else if (event.button() == Qt::LeftButton) { // User is adding an object - if (m_editorData.mode() == EditorData::EditorMode::AddObject) + if (m_mediator.mode() == EditorMode::AddObject) { addCurrentToolBarObjectToScene(); } // User is erasing an object - else if (m_editorData.mode() == EditorData::EditorMode::EraseObject) + else if (m_mediator.mode() == EditorMode::EraseObject) { eraseObjectAtCurrentClickedPos(); } @@ -432,7 +379,7 @@ else if (event.button() == Qt::LeftButton) { // User is adding an object - if (m_editorData.mode() == EditorData::EditorMode::AddObject) + if (m_mediator.mode() == EditorMode::AddObject) { addCurrentToolBarObjectToScene(); } @@ -456,7 +403,7 @@ else if (event.button() == Qt::LeftButton) { // User is adding an object - if (m_editorData.mode() == EditorData::EditorMode::AddObject) + if (m_mediator.mode() == EditorMode::AddObject) { addCurrentToolBarObjectToScene(); } @@ -472,13 +419,13 @@ void EditorView::handleLeftButtonClickOnObject(Object & object) { // User is initiating a drag'n'drop - if (m_editorData.mode() == EditorData::EditorMode::None) + if (m_mediator.mode() == EditorMode::None) { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); object.setZValue(object.zValue() + 1); - m_editorData.setDragAndDropObject(&object); - m_editorData.setSelectedObject(&object); + m_mediator.dadStore().setDragAndDropObject(&object); + m_mediator.setSelectedObject(&object); // Change cursor to the closed hand cursor. QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor)); @@ -488,34 +435,34 @@ void EditorView::handleLeftButtonClickOnTargetNode(TargetNode & tnode) { // User is initiating a drag'n'drop - if (m_editorData.mode() == EditorData::EditorMode::None) + if (m_mediator.mode() == EditorMode::None) { - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); tnode.setZValue(tnode.zValue() + 1); - m_editorData.setDragAndDropTargetNode(&tnode); + m_mediator.dadStore().setDragAndDropTargetNode(&tnode); // Change cursor to the closed hand cursor. QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor)); } // It's not possible to make nodes overlap if not handled also here. - else if (m_editorData.mode() == EditorData::EditorMode::SetRoute) + else if (m_mediator.mode() == EditorMode::SetRoute) { - m_editorData.pushNewTargetNodeToRoute(m_clickedScenePos); + m_mediator.pushNewTargetNodeToRoute(m_clickedScenePos); } } void EditorView::handleLeftButtonClickOnTile(TrackTile & tile) { // User is defining the route - if (m_editorData.mode() == EditorData::EditorMode::SetRoute) + if (m_mediator.mode() == EditorMode::SetRoute) { - m_editorData.pushNewTargetNodeToRoute(m_clickedScenePos); + m_mediator.pushNewTargetNodeToRoute(m_clickedScenePos); } // User is setting the tile type - else if (m_editorData.mode() == EditorData::EditorMode::SetTileType) + else if (m_mediator.mode() == EditorMode::SetTileType) { - if (QAction * action = MainWindow::instance()->currentToolBarAction()) + if (QAction * action = m_mediator.currentToolBarAction()) { Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers(); @@ -525,7 +472,7 @@ if (typeToFill != action->data().toString()) { - doFloodFill(tile, action, typeToFill); + m_mediator.floodFill(tile, action, typeToFill); } } else @@ -535,11 +482,11 @@ } } // User is initiating a drag'n'drop - else if (m_editorData.mode() == EditorData::EditorMode::None) + else if (m_mediator.mode() == EditorMode::None) { tile.setZValue(tile.zValue() + 1); - m_editorData.setDragAndDropSourceTile(&tile); - m_editorData.setDragAndDropSourcePos(tile.pos()); + m_mediator.dadStore().setDragAndDropSourceTile(&tile); + m_mediator.dadStore().setDragAndDropSourcePos(tile.pos()); // Change cursor to the closed hand cursor. QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor)); @@ -570,11 +517,8 @@ m_excludeFromMinimap->setChecked(tile.excludeFromMinimap()); - if (m_editorData.trackData()) - { - m_deleteCol->setEnabled(m_editorData.trackData()->map().cols() > 2); - m_deleteRow->setEnabled(m_editorData.trackData()->map().rows() > 2); - } + m_deleteCol->setEnabled(m_mediator.cols()); + m_deleteRow->setEnabled(m_mediator.rows()); const QPoint globalPos = mapToGlobal(m_clickedPos); m_tileContextMenu.exec(globalPos); @@ -593,7 +537,7 @@ void EditorView::handleRightButtonClickOnObject(Object & object) { - m_editorData.setSelectedObject(&object); + m_mediator.setSelectedObject(&object); m_forceStationaryAction->setChecked(object.forceStationary()); @@ -608,7 +552,7 @@ void EditorView::handleRightButtonClickOnTargetNode(TargetNode & tnode) { - m_editorData.setSelectedTargetNode(&tnode); + m_mediator.setSelectedTargetNode(&tnode); openTargetNodeContextMenu(); } @@ -622,26 +566,26 @@ void EditorView::keyPressEvent(QKeyEvent * event) { - if (auto object = m_editorData.selectedObject()) + if (auto object = m_mediator.selectedObject()) { if (!event->isAutoRepeat()) { switch (event->key()) { case Qt::Key_Left: - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); object->setLocation(QPointF(object->location().x() - 1, object->location().y())); break; case Qt::Key_Right: - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); object->setLocation(QPointF(object->location().x() + 1, object->location().y())); break; case Qt::Key_Up: - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); object->setLocation(QPointF(object->location().x(), object->location().y() - 1)); break; case Qt::Key_Down: - m_editorData.saveUndoPoint(); + m_mediator.saveUndoPoint(); object->setLocation(QPointF(object->location().x(), object->location().y() + 1)); break; default: @@ -653,81 +597,72 @@ void EditorView::handleTileDragRelease(QMouseEvent * event) { - if (scene()) + // Tile drag'n'drop active? + if (auto sourceTile = m_mediator.dadStore().dragAndDropSourceTile()) { - // Tile drag'n'drop active? - if (auto sourceTile = m_editorData.dragAndDropSourceTile()) + // Determine the dest tile + auto destTile = sourceTile; + QList items = scene()->items(mapToScene(event->pos())); + for (QGraphicsItem * item : items) { - // Determine the dest tile - auto destTile = sourceTile; - QList items = scene()->items(mapToScene(event->pos())); - for (QGraphicsItem * item : items) + auto testTile = dynamic_cast(item); + if (testTile && testTile != sourceTile) { - auto testTile = dynamic_cast(item); - if (testTile && testTile != sourceTile) - { - destTile = testTile; - break; - } + destTile = testTile; + break; } + } - // Swap tiles - sourceTile->swap(*destTile); + // Swap tiles + sourceTile->swap(*destTile); - // Restore position - sourceTile->setPos(m_editorData.dragAndDropSourcePos()); - sourceTile->setZValue(sourceTile->zValue() - 1); - destTile->setZValue(sourceTile->zValue()); + // Restore position + sourceTile->setPos(m_mediator.dadStore().dragAndDropSourcePos()); + sourceTile->setZValue(sourceTile->zValue() - 1); + destTile->setZValue(sourceTile->zValue()); - update(); + update(); - m_editorData.setDragAndDropSourceTile(nullptr); + m_mediator.dadStore().clear(); - // Restore the cursor. - QApplication::restoreOverrideCursor(); - } + // Restore the cursor. + QApplication::restoreOverrideCursor(); } } void EditorView::handleObjectDragRelease(QMouseEvent * event) { - if (scene()) + // Object drag'n'drop active? + if (auto object = m_mediator.dadStore().dragAndDropObject()) { - // Object drag'n'drop active? - if (auto object = m_editorData.dragAndDropObject()) - { - // Set the new position position - object->setLocation(mapToScene(event->pos())); - object->setZValue(object->zValue() - 1); + // Set the new position position + object->setLocation(mapToScene(event->pos())); + object->setZValue(object->zValue() - 1); - update(); + update(); - m_editorData.setDragAndDropObject(nullptr); + m_mediator.dadStore().clear(); - // Restore the cursor. - QApplication::restoreOverrideCursor(); - } + // Restore the cursor. + QApplication::restoreOverrideCursor(); } } void EditorView::handleTargetNodeDragRelease(QMouseEvent * event) { - if (scene()) + // Target node drag'n'drop active? + if (auto tnode = m_mediator.dadStore().dragAndDropTargetNode()) { - // Target node drag'n'drop active? - if (auto tnode = m_editorData.dragAndDropTargetNode()) - { - // Set the new position position - tnode->setLocation(mapToScene(event->pos())); - tnode->setZValue(tnode->zValue() - 1); + // Set the new position position + tnode->setLocation(mapToScene(event->pos())); + tnode->setZValue(tnode->zValue() - 1); - update(); + update(); - m_editorData.setDragAndDropTargetNode(nullptr); + m_mediator.dadStore().clear(); - // Restore the cursor. - QApplication::restoreOverrideCursor(); - } + // Restore the cursor. + QApplication::restoreOverrideCursor(); } } @@ -735,58 +670,14 @@ { if (auto tile = dynamic_cast(scene()->itemAt(mapToScene(m_clickedPos), QTransform()))) { - m_editorData.saveUndoPoint(); - + m_mediator.saveUndoPoint(); tile->setComputerHint(hint); } } -void EditorView::doFloodFill(TrackTile & tile, QAction * action, QString typeToFill) -{ - m_editorData.saveUndoPoint(); - - floodFill(tile, action, typeToFill); -} - -void EditorView::floodFill(TrackTile & tile, QAction * action, const QString & typeToFill) -{ - static const int DIRECTION_COUNT = 4; - - // Coordinates of neighbor tiles can be calculated by adding these - // adjustments to tile coordinates. - static const QPoint neighborAdjustments[DIRECTION_COUNT] = - { - QPoint( 1, 0), // right - QPoint( 0, -1), // up - QPoint(-1, 0), // left - QPoint( 0, 1) // down - }; - - setTileType(tile, action); - - MapBase & map = m_editorData.trackData()->map(); - QPoint location = tile.matrixLocation(); - - for (int i = 0; i < DIRECTION_COUNT; ++i) - { - int x = location.x() + neighborAdjustments[i].x(); - int y = location.y() + neighborAdjustments[i].y(); - - if (x >= 0 && y >= 0) - { - auto tile = std::dynamic_pointer_cast(map.getTile(x, y)); - if (tile && tile->tileType() == typeToFill) - { - floodFill(*(tile.get()), action, typeToFill); - } - } - } -} - void EditorView::changeTileType(TrackTile & tile, QAction * action) { - m_editorData.saveUndoPoint(); - + m_mediator.saveUndoPoint(); setTileType(tile, action); } @@ -795,3 +686,15 @@ tile.setTileType(action->data().toString()); tile.setPixmap(action->icon().pixmap(TrackTile::TILE_W, TrackTile::TILE_H)); } + +void EditorView::wheelEvent(QWheelEvent * event) +{ + if (event->modifiers() & Qt::ControlModifier) + { + m_mediator.mouseWheelZoom(event->delta()); + } + else + { + QGraphicsView::wheelEvent(event); + } +} diff -Nuar a/src/editor/editorview.hpp b/src/editor/editorview.hpp --- a/src/editor/editorview.hpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/editorview.hpp 2018-02-11 08:22:08.000000000 +0300 @@ -20,10 +20,10 @@ #include #include "../common/tracktilebase.hpp" +class Mediator; class QAction; class QMouseEvent; class QPaintEvent; -class EditorData; class Object; class ObjectModelLoaderoader; class TargetNode; @@ -35,7 +35,7 @@ public: - explicit EditorView(EditorData & editorData, QWidget * parent = 0); + explicit EditorView(Mediator & mediator); void updateSceneRect(); @@ -49,6 +49,8 @@ void keyPressEvent(QKeyEvent * event) override; + void wheelEvent(QWheelEvent * event) override; + private: void addCurrentToolBarObjectToScene(); @@ -61,12 +63,8 @@ void createTargetNodeContextMenuActions(); - void doFloodFill(TrackTile & tile, QAction * action, QString typeToFill); - void eraseObjectAtCurrentClickedPos(); - void floodFill(TrackTile & tile, QAction * action, const QString & typeToFill); - void handleMousePressEventOnTile(QMouseEvent & event, TrackTile & tile); void handleLeftButtonClickOnTile(TrackTile & tile); @@ -99,8 +97,6 @@ void setComputerHint(TrackTileBase::ComputerHint hint); - void updateCoordinates(QPointF mappedPos); - static void setTileType(TrackTile & tile, QAction * action); QMenu m_tileContextMenu; @@ -127,7 +123,7 @@ QAction * m_forceStationaryAction = nullptr; - EditorData & m_editorData; + Mediator & m_mediator; }; #endif // EDITORVIEW_HPP diff -Nuar a/src/editor/floodfill.cpp b/src/editor/floodfill.cpp --- a/src/editor/floodfill.cpp 1970-01-01 02:00:00.000000000 +0200 +++ b/src/editor/floodfill.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -0,0 +1,62 @@ +// This file is part of Dust Racing 2D. +// Copyright (C) 2018 Jussi Lind +// +// Dust Racing 2D is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// Dust Racing 2D is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Dust Racing 2D. If not, see . + +#include "floodfill.hpp" +#include "map.hpp" +#include "tracktile.hpp" + +#include + +namespace FloodFill { +void setTileType(TrackTile & tile, QAction * action) +{ + tile.setTileType(action->data().toString()); + tile.setPixmap(action->icon().pixmap(TrackTile::TILE_W, TrackTile::TILE_H)); +} +} + +void FloodFill::floodFill(TrackTile & tile, QAction * action, const QString & typeToFill, MapBase & map) +{ + static const int DIRECTION_COUNT = 4; + + // Coordinates of neighbor tiles can be calculated by adding these + // adjustments to tile coordinates. + static const QPoint neighborAdjustments[DIRECTION_COUNT] = + { + QPoint( 1, 0), // right + QPoint( 0, -1), // up + QPoint(-1, 0), // left + QPoint( 0, 1) // down + }; + + setTileType(tile, action); + + QPoint location = tile.matrixLocation(); + + for (int i = 0; i < DIRECTION_COUNT; ++i) + { + int x = location.x() + neighborAdjustments[i].x(); + int y = location.y() + neighborAdjustments[i].y(); + + if (x >= 0 && y >= 0) + { + auto tile = std::dynamic_pointer_cast(map.getTile(x, y)); + if (tile && tile->tileType() == typeToFill) + { + FloodFill::floodFill(*(tile.get()), action, typeToFill, map); + } + } + } +} diff -Nuar a/src/editor/floodfill.hpp b/src/editor/floodfill.hpp --- a/src/editor/floodfill.hpp 1970-01-01 02:00:00.000000000 +0200 +++ b/src/editor/floodfill.hpp 2018-02-11 08:22:08.000000000 +0300 @@ -0,0 +1,28 @@ +// This file is part of Dust Racing 2D. +// Copyright (C) 2018 Jussi Lind +// +// Dust Racing 2D is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// Dust Racing 2D is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Dust Racing 2D. If not, see . + +#ifndef FLOODFILL_HPP +#define FLOODFILL_HPP + +class MapBase; +class QAction; +class QString; +class TrackTile; + +namespace FloodFill { +void floodFill(TrackTile & tile, QAction * action, const QString & typeToFill, MapBase & map); +} + +#endif // FLOODFILL_HPP diff -Nuar a/src/editor/mainwindow.cpp b/src/editor/mainwindow.cpp --- a/src/editor/mainwindow.cpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/mainwindow.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -26,7 +26,7 @@ #include "tracktile.hpp" #include "editordata.hpp" #include "editorview.hpp" -#include "editorscene.hpp" +#include "mediator.hpp" #include "newtrackdialog.hpp" #include @@ -55,26 +55,15 @@ MainWindow * MainWindow::m_instance = nullptr; -namespace -{ - const char * SETTINGS_GROUP = "MainWindow"; - const unsigned int MIN_ZOOM = 0; - const unsigned int MAX_ZOOM = 200; - const unsigned int INI_ZOOM = 100; - const int CONSOLE_HEIGHT = 64; -} - MainWindow::MainWindow(QString trackFile) : m_objectModelLoader(new ObjectModelLoader) , m_aboutDlg(new AboutDlg(this)) -, m_editorData(new EditorData(this)) -, m_editorScene(new EditorScene(this)) -, m_editorView(new EditorView(*m_editorData, this)) , m_console(new QTextEdit(this)) , m_scaleSlider(new QSlider(Qt::Horizontal, this)) , m_toolBar(new QToolBar(this)) , m_randomRotationCheck(new QCheckBox(tr("Randomly rotate objects"), this)) , m_argTrackFile(trackFile) +, m_mediator(new Mediator(*this)) { if (!m_instance) { @@ -122,6 +111,11 @@ } } +void MainWindow::updateScaleSlider(int value) +{ + m_scaleSlider->setValue(value); +} + void MainWindow::showTip() { QMessageBox::information( @@ -138,7 +132,7 @@ QSettings settings; // Read dialog size data - settings.beginGroup(SETTINGS_GROUP); + settings.beginGroup(m_settingsGroup); resize(settings.value("size", QSize(640, 480)).toSize()); settings.endGroup(); @@ -147,15 +141,15 @@ move(geometry.width() / 2 - width() / 2, geometry.height() / 2 - height() / 2); - // Populate menu bar with actions + m_mediator->initScene(); + populateMenuBar(); - // Set scene to the view - m_editorView->setScene(m_editorScene); - m_editorView->setSizePolicy(QSizePolicy::Preferred, - QSizePolicy::Expanding); - m_editorView->setMouseTracking(true); + createWidgets(); +} +void MainWindow::createWidgets() +{ // Create a splitter QSplitter * splitter = new QSplitter(this); splitter->setOrientation(Qt::Vertical); @@ -164,7 +158,7 @@ QVBoxLayout * centralLayout = new QVBoxLayout; QHBoxLayout * viewToolBarLayout = new QHBoxLayout; m_toolBar->setOrientation(Qt::Vertical); - viewToolBarLayout->addWidget(m_editorView); + m_mediator->addViewToLayout(viewToolBarLayout); viewToolBarLayout->addWidget(m_toolBar); centralLayout->addLayout(viewToolBarLayout); @@ -172,8 +166,8 @@ populateToolBar(); // Add zoom slider to the layout - m_scaleSlider->setRange(MIN_ZOOM, MAX_ZOOM); - m_scaleSlider->setValue(INI_ZOOM); + m_scaleSlider->setRange(m_minZoom, m_maxZoom); + m_scaleSlider->setValue(m_initZoom); m_scaleSlider->setTracking(false); m_scaleSlider->setTickInterval(10); m_scaleSlider->setTickPosition(QSlider::TicksBelow); @@ -207,7 +201,7 @@ setCentralWidget(splitter); QList sizes; - sizes << height() - CONSOLE_HEIGHT << CONSOLE_HEIGHT; + sizes << height() - m_consoleHeight << m_consoleHeight; splitter->setSizes(sizes); } @@ -268,21 +262,6 @@ return MainWindow::m_instance; } -EditorView & MainWindow::editorView() const -{ - return *m_editorView; -} - -EditorScene & MainWindow::editorScene() const -{ - return *m_editorScene; -} - -EditorData & MainWindow::editorData() const -{ - return *m_editorData; -} - ObjectModelLoader & MainWindow::objectModelLoader() const { return *m_objectModelLoader; @@ -295,11 +274,7 @@ void MainWindow::updateScale(int value) { - qreal scale = static_cast(value) / 100; - - QTransform transform; - transform.scale(scale, scale); - m_editorView->setTransform(transform); + m_mediator->setScale(value); console(QString(tr("Scale set to %1%")).arg(value)); } @@ -310,7 +285,7 @@ QSettings settings; // Save window size - settings.beginGroup(SETTINGS_GROUP); + settings.beginGroup(m_settingsGroup); settings.setValue("size", size()); settings.endGroup(); @@ -362,12 +337,12 @@ m_undoAction->setShortcut(QKeySequence("Ctrl+Z")); editMenu->addAction(m_undoAction); connect(m_undoAction, &QAction::triggered, [this](){ - m_editorData->undo(); + m_mediator->undo(); setupTrackAfterUndoOrRedo(); - m_undoAction->setEnabled(m_editorData->isUndoable()); - m_redoAction->setEnabled(m_editorData->isRedoable()); + m_undoAction->setEnabled(m_mediator->isUndoable()); + m_redoAction->setEnabled(m_mediator->isRedoable()); }); m_undoAction->setEnabled(false); @@ -376,27 +351,15 @@ m_redoAction->setShortcut(QKeySequence("Ctrl+Shift+Z")); editMenu->addAction(m_redoAction); connect(m_redoAction, &QAction::triggered, [this](){ - m_editorData->redo(); + m_mediator->redo(); setupTrackAfterUndoOrRedo(); - m_undoAction->setEnabled(m_editorData->isUndoable()); - m_redoAction->setEnabled(m_editorData->isRedoable()); + m_undoAction->setEnabled(m_mediator->isUndoable()); + m_redoAction->setEnabled(m_mediator->isRedoable()); }); m_redoAction->setEnabled(false); - // Add "enlarge hor size"-action - m_enlargeHorSize = new QAction(tr("Enlarge hor size"), this); - editMenu->addAction(m_enlargeHorSize); - connect(m_enlargeHorSize, SIGNAL(triggered()), this, SLOT(enlargeHorSize())); - m_enlargeHorSize->setEnabled(false); - - // Add "enlarge ver size"-action - m_enlargeVerSize = new QAction(tr("Enlarge ver size"), this); - editMenu->addAction(m_enlargeVerSize); - connect(m_enlargeVerSize, SIGNAL(triggered()), this, SLOT(enlargeVerSize())); - m_enlargeVerSize->setEnabled(false); - // Add "Set track properties"-action m_setTrackPropertiesAction = new QAction(tr("&Set properties.."), this); editMenu->addAction(m_setTrackPropertiesAction); @@ -460,8 +423,6 @@ { if (action != m_currentToolBarAction) { - assert(m_editorData); - m_currentToolBarAction = action; // Select-action @@ -474,14 +435,14 @@ { QApplication::restoreOverrideCursor(); QApplication::setOverrideCursor(QCursor(action->icon().pixmap(32, 32))); - m_editorData->setMode(EditorData::EditorMode::EraseObject); + m_mediator->setMode(EditorMode::EraseObject); } // The user wants to clear a tile. else if (action->data() == "clear") { QApplication::restoreOverrideCursor(); QApplication::setOverrideCursor(QCursor(action->icon().pixmap(32, 32))); - m_editorData->setMode(EditorData::EditorMode::SetTileType); + m_mediator->setMode(EditorMode::SetTileType); } // The user wants to set a tile type or clear it. else if (m_objectModelLoader->getCategoryByRole( @@ -489,7 +450,7 @@ { QApplication::restoreOverrideCursor(); QApplication::setOverrideCursor(QCursor(action->icon().pixmap(32, 32))); - m_editorData->setMode(EditorData::EditorMode::SetTileType); + m_mediator->setMode(EditorMode::SetTileType); } // The user wants to add an object to the scene. else if (m_objectModelLoader->getCategoryByRole( @@ -497,7 +458,7 @@ { QApplication::restoreOverrideCursor(); QApplication::setOverrideCursor(QCursor(QPixmap(":/cursor2.png"))); - m_editorData->setMode(EditorData::EditorMode::AddObject); + m_mediator->setMode(EditorMode::AddObject); } } else @@ -514,7 +475,7 @@ // Load recent path QSettings settings; - settings.beginGroup(SETTINGS_GROUP); + settings.beginGroup(m_settingsGroup); QString path = settings.value("recentPath", QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).toString(); settings.endGroup(); @@ -539,9 +500,8 @@ void MainWindow::clearRoute() { - assert(m_editorData); - m_editorData->saveUndoPoint(); - m_editorData->clearRoute(); + m_mediator->clearRoute(); + m_clearRouteAction->setEnabled(false); } @@ -553,13 +513,11 @@ return false; } - assert(m_editorData); - // Undo stack will be cleared. m_undoAction->setEnabled(false); m_redoAction->setEnabled(false); - if (m_editorData->loadTrackData(fileName)) + if (m_mediator->openTrack(fileName)) { console(QString(tr("Track '%1' opened.").arg(fileName))); @@ -568,7 +526,7 @@ // Save recent path QSettings settings; - settings.beginGroup(SETTINGS_GROUP); + settings.beginGroup(m_settingsGroup); settings.setValue("recentPath", fileName); settings.endGroup(); @@ -576,21 +534,11 @@ setActionStatesOnNewTrack(); - delete m_editorScene; - m_editorScene = new EditorScene; - - m_editorView->setScene(m_editorScene); - m_editorView->updateSceneRect(); - - m_editorData->addTilesToScene(); - m_editorData->addObjectsToScene(); - m_editorData->addExistingRouteToScene(); - fitScale(); m_saved = true; - m_clearRouteAction->setEnabled(m_editorData->trackData()->route().numNodes()); + m_clearRouteAction->setEnabled(m_mediator->routeHasNodes()); return true; } @@ -603,23 +551,87 @@ return false; } -void MainWindow::setupTrackAfterUndoOrRedo() +void MainWindow::beginSetRoute() { - m_saveAction->setEnabled(true); + if (m_mediator->beginSetRoute()) + { + console(tr("Set route: begin.")); + QMessageBox::information( + this, + tr("Set route, checkpoints and driving lines."), + tr("Setting the route defines checkpoints for the cars so\n" + "that no shortcuts can be taken. It also defines\n" + "driving lines for the computer players.\n\n" + "Click on the tiles one by one and make a closed loop\n" + "with the target nodes. You can adjust the nodes afterwads.\n" + "Start from the first tile after the finish line tile\n" + "to make the lap detection and timing work correctly.\n" + "Click on the first node again to finish.")); + } + else + { + console(tr("Set route: not a valid track.")); + QMessageBox::critical(this, tr("Set route"), tr("Invalid track. Route cannot be set.")); + } +} - setActionStatesOnNewTrack(); +void MainWindow::clearEditMode() +{ + m_mediator->clearEditMode(); +} + +void MainWindow::console(QString text) +{ + QDateTime date = QDateTime::currentDateTime(); + m_console->append(QString("(") + date.toString("hh:mm:ss") + "): " + text); +} + +void MainWindow::enableUndo(bool enable) +{ + m_undoAction->setEnabled(enable); +} + +void MainWindow::endSetRoute() +{ + m_mediator->endSetRoute(); + + m_clearRouteAction->setEnabled(m_mediator->routeHasNodes()); + + console(tr("Set route: route finished.")); +} - delete m_editorScene; - m_editorScene = new EditorScene; +void MainWindow::fitScale() +{ + m_scaleSlider->setValue(m_mediator->fitScale()); +} - m_editorView->setScene(m_editorScene); - m_editorView->updateSceneRect(); +void MainWindow::initializeNewTrack() +{ + QString nameOut; + int colsOut, rowsOut; + if (m_mediator->initializeNewTrack(nameOut, colsOut, rowsOut)) + { + // Undo stack has been cleared. + m_undoAction->setEnabled(false); + m_redoAction->setEnabled(false); - m_editorData->addTilesToScene(); - m_editorData->addObjectsToScene(); - m_editorData->addExistingRouteToScene(); + fitScale(); - m_clearRouteAction->setEnabled(m_editorData->trackData()->route().numNodes()); + setActionStatesOnNewTrack(); + + setTitle(tr("New file")); + + m_clearRouteAction->setEnabled(false); + + m_saved = false; + + console(QString(tr("A new track '%1' created. Columns: %2, Rows: %3.")) + .arg(nameOut) + .arg(colsOut) + .arg(rowsOut)); + } + + QApplication::restoreOverrideCursor(); } void MainWindow::saveTrack() @@ -632,18 +644,15 @@ } else { - assert(m_editorData); - if (m_editorData->saveTrackData()) + if (m_mediator->saveTrackData()) { - console(QString( - tr("Track '")) + m_editorData->trackData()->fileName() + tr("' saved.")); - setTitle(m_editorData->trackData()->fileName()); + console(QString(tr("Track '")) + m_mediator->currentFileName() + tr("' saved.")); + setTitle(m_mediator->currentFileName()); m_saved = true; } else { - console(QString( - tr("Failed to save track '")) + m_editorData->trackData()->fileName() + "'."); + console(QString(tr("Failed to save track '")) + m_mediator->currentFileName() + "'."); } } @@ -665,8 +674,7 @@ fileName += trackFileExtension; } - assert(m_editorData); - if (m_editorData->saveTrackDataAs(fileName)) + if (m_mediator->saveTrackDataAs(fileName)) { console(QString(tr("Track '")) + fileName + tr("' saved.")); setTitle(fileName); @@ -680,51 +688,15 @@ QApplication::restoreOverrideCursor(); } -void MainWindow::initializeNewTrack() +void MainWindow::setupTrackAfterUndoOrRedo() { - QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); - - // Show a dialog asking some questions about the track - NewTrackDialog dialog(this); - if (dialog.exec() == QDialog::Accepted) - { - const unsigned int cols = dialog.cols(); - const unsigned int rows = dialog.rows(); - - assert(m_editorData); - - m_editorData->setTrackData(TrackDataPtr(new TrackData(dialog.name(), dialog.isUserTrack(), cols, rows))); - - delete m_editorScene; - m_editorScene = new EditorScene; - - m_editorView->setScene(m_editorScene); - m_editorView->updateSceneRect(); - - // Undo stack has been cleared. - m_undoAction->setEnabled(false); - m_redoAction->setEnabled(false); - - m_editorData->addTilesToScene(); - m_editorData->addObjectsToScene(); - - fitScale(); - - setActionStatesOnNewTrack(); - - console(QString(tr("A new track '%1' created. Columns: %2, Rows: %3.")) - .arg(m_editorData->trackData()->name()) - .arg(m_editorData->trackData()->map().cols()) - .arg(m_editorData->trackData()->map().rows())); - - setTitle(tr("New file")); + m_saveAction->setEnabled(true); - m_clearRouteAction->setEnabled(false); + setActionStatesOnNewTrack(); - m_saved = false; - } + m_mediator->setupTrackAfterUndoOrRedo(); - QApplication::restoreOverrideCursor(); + m_clearRouteAction->setEnabled(m_mediator->routeHasNodes()); } void MainWindow::setActionStatesOnNewTrack() @@ -732,114 +704,20 @@ m_saveAction->setEnabled(true); m_saveAsAction->setEnabled(true); m_toolBar->setEnabled(true); - m_enlargeHorSize->setEnabled(true); - m_enlargeVerSize->setEnabled(true); m_setRouteAction->setEnabled(true); m_setTrackPropertiesAction->setEnabled(true); } void MainWindow::setTrackProperties() { - // Show a dialog to set some properties e.g. lap count. - assert(m_editorData); - TrackPropertiesDialog dialog(m_editorData->trackData()->name(), m_editorData->trackData()->index(), m_editorData->trackData()->isUserTrack(), this); - if (dialog.exec() == QDialog::Accepted) - { - m_editorData->trackData()->setName(dialog.name()); - m_editorData->trackData()->setIndex(dialog.index()); - m_editorData->trackData()->setUserTrack(dialog.isUserTrack()); - console(QString(tr("Track properties updated."))); - } -} - -void MainWindow::enlargeHorSize() -{ - assert(m_editorData); - if (m_editorData->trackData()) + if (m_mediator->setTrackProperties()) { - m_editorData->trackData()->enlargeHorSize(); - m_editorData->addTilesToScene(); - - m_editorView->updateSceneRect(); - } -} - -void MainWindow::enlargeVerSize() -{ - assert(m_editorData); - if (m_editorData->trackData()) - { - m_editorData->trackData()->enlargeVerSize(); - m_editorData->addTilesToScene(); - - m_editorView->updateSceneRect(); - } -} - -void MainWindow::enableUndo(bool enable) -{ - m_undoAction->setEnabled(enable); -} - -void MainWindow::beginSetRoute() -{ - QApplication::restoreOverrideCursor(); - - assert(m_editorData); - - m_editorData->saveUndoPoint(); - - if (m_editorData->canRouteBeSet()) - { - console(tr("Set route: begin.")); - QMessageBox::information( - this, - tr("Set route, checkpoints and driving lines."), - tr("Setting the route defines checkpoints for the cars so\n" - "that no shortcuts can be taken. It also defines\n" - "driving lines for the computer players.\n\n" - "Click on the tiles one by one and make a closed loop\n" - "with the target nodes. You can adjust the nodes afterwads.\n" - "Start from the first tile after the finish line tile\n" - "to make the lap detection and timing work correctly.\n" - "Click on the first node again to finish.")); - m_editorData->beginSetRoute(); - } - else - { - QMessageBox::critical(this, tr("Set route"), tr("Invalid track. Route cannot be set.")); - console(tr("Set route: not a valid track.")); + console(QString(tr("Track properties updated."))); } } -void MainWindow::endSetRoute() -{ - assert(m_editorData); - m_editorData->endSetRoute(); - m_clearRouteAction->setEnabled(m_editorData->trackData()->route().numNodes()); - console(tr("Set route: route finished.")); -} - -void MainWindow::console(QString text) -{ - QDateTime date = QDateTime::currentDateTime(); - m_console->append(QString("(") + date.toString("hh:mm:ss") + "): " + text); -} - -void MainWindow::clearEditMode() -{ - QApplication::restoreOverrideCursor(); - m_editorData->setMode(EditorData::EditorMode::None); -} - -void MainWindow::fitScale() -{ - m_editorView->centerOn(m_editorView->sceneRect().center()); - m_scaleSlider->setValue(m_editorView->viewport()->height() * 100 / m_editorView->sceneRect().height()); -} - MainWindow::~MainWindow() { - delete m_editorData; + delete m_mediator; delete m_objectModelLoader; } diff -Nuar a/src/editor/mainwindow.hpp b/src/editor/mainwindow.hpp --- a/src/editor/mainwindow.hpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/mainwindow.hpp 2018-02-11 08:22:08.000000000 +0300 @@ -21,15 +21,14 @@ #include class AboutDlg; -class EditorData; -class EditorView; -class EditorScene; class ObjectModelLoader; class QAction; class QCheckBox; class QSlider; class QTextEdit; class QToolBar; + +class Mediator; class TrackData; /*! \class MainWindow @@ -59,15 +58,6 @@ //! Print text to the console. void console(QString text); - //! Get reference to the view. - EditorView & editorView() const; - - //! Get reference to the scene. - EditorScene & editorScene() const; - - //! Get reference to the data. - EditorData & editorData() const; - //! Get reference to the object loaded. ObjectModelLoader & objectModelLoader() const; @@ -89,6 +79,8 @@ void setVisible(bool visible) override; + void updateScaleSlider(int value); + protected: void closeEvent(QCloseEvent * event) override; @@ -99,10 +91,6 @@ bool doOpenTrack(QString fileName); - void enlargeHorSize(); - - void enlargeVerSize(); - void handleToolBarActionClick(QAction * action); void initializeNewTrack(); @@ -133,6 +121,8 @@ void clearEditMode(); + void createWidgets(); + void fitScale(); void init(); @@ -149,12 +139,6 @@ AboutDlg * m_aboutDlg; - EditorData * m_editorData; - - EditorScene * m_editorScene; - - EditorView * m_editorView; - QTextEdit * m_console; QAction * m_saveAction = nullptr; @@ -167,10 +151,6 @@ QAction * m_redoAction = nullptr; - QAction * m_enlargeHorSize = nullptr; - - QAction * m_enlargeVerSize = nullptr; - QAction * m_clearRouteAction = nullptr; QAction * m_setRouteAction = nullptr; @@ -187,6 +167,18 @@ bool m_saved = false; + const char * m_settingsGroup = "MainWindow"; + + const unsigned int m_minZoom = 0; + + const unsigned int m_maxZoom = 200; + + const unsigned int m_initZoom = 100; + + const int m_consoleHeight = 64; + + Mediator * m_mediator = nullptr; + static MainWindow * m_instance; }; diff -Nuar a/src/editor/mediator.cpp b/src/editor/mediator.cpp --- a/src/editor/mediator.cpp 1970-01-01 02:00:00.000000000 +0200 +++ b/src/editor/mediator.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -0,0 +1,475 @@ +// This file is part of Dust Racing 2D. +// Copyright (C) 2018 Jussi Lind +// +// Dust Racing 2D is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// Dust Racing 2D is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Dust Racing 2D. If not, see . + +#include "mediator.hpp" + +#include "draganddropstore.hpp" +#include "editordata.hpp" +#include "editorview.hpp" +#include "floodfill.hpp" +#include "mainwindow.hpp" +#include "newtrackdialog.hpp" +#include "object.hpp" +#include "objectfactory.hpp" +#include "trackdata.hpp" +#include "tracktile.hpp" +#include "trackpropertiesdialog.hpp" + +#include + +#include +#include +#include +#include +#include + +Mediator::Mediator(MainWindow & mainWindow) + : m_editorData(new EditorData(*this)) + , m_editorScene(new QGraphicsScene) + , m_editorView(new EditorView(*this)) + , m_mainWindow(mainWindow) +{ + m_editorView->setParent(&mainWindow); +} + +void Mediator::addCurrentToolBarObjectToScene(QPointF clickedScenePos) +{ + if (QAction * action = MainWindow::instance()->currentToolBarAction()) + { + saveUndoPoint(); + + Object & object = ObjectFactory::createObject(action->data().toString()); + object.setLocation(clickedScenePos); + + if (MainWindow::instance()->randomlyRotateObjects()) + { + object.setRotation(std::rand() % 360); + } + + addObject(object); + setSelectedObject(&object); + } +} + +void Mediator::addItem(QGraphicsItem * item) +{ + m_editorScene->addItem(item); +} + +void Mediator::addObject(Object & object) +{ + m_editorScene->addItem(&object); + m_editorData->trackData()->objects().add(ObjectBasePtr(&object)); +} + +void Mediator::addViewToLayout(QLayout * layout) +{ + layout->addWidget(m_editorView); +} + +bool Mediator::beginSetRoute() +{ + QApplication::restoreOverrideCursor(); + + assert(m_editorData); + + m_editorData->saveUndoPoint(); + + if (m_editorData->canRouteBeSet()) + { + m_editorData->beginSetRoute(); + + return true; + } + + return false; +} + +void Mediator::console(QString message) +{ + m_mainWindow.console(message); +} + +QString Mediator::currentFileName() const +{ + return m_editorData->trackData()->fileName(); +} + +QAction * Mediator::currentToolBarAction() const +{ + return m_mainWindow.currentToolBarAction(); +} + +DragAndDropStore & Mediator::dadStore() +{ + return m_editorData->dadStore(); +} + +void Mediator::deleteColumn() +{ + auto deleted = m_editorData->trackData()->deleteColumn(m_editorData->activeColumn()); + for (auto && tile : deleted) { + m_editorData->removeTileFromScene(tile); + } +} + +void Mediator::deleteRow() +{ + auto deleted = m_editorData->trackData()->deleteRow(m_editorData->activeRow()); + for (auto && tile : deleted) { + m_editorData->removeTileFromScene(tile); + } +} + +void Mediator::floodFill(TrackTile & tile, QAction * action, const QString & typeToFill) +{ + saveUndoPoint(); + + FloodFill::floodFill(tile, action, typeToFill, m_editorData->trackData()->map()); +} + +void Mediator::endSetRoute() +{ + setMode(EditorMode::None); +} + +void Mediator::enableUndo(bool enable) +{ + m_mainWindow.enableUndo(enable); +} + +int Mediator::fitScale() +{ + m_editorView->centerOn(m_editorView->sceneRect().center()); + return m_editorView->viewport()->height() * 100 / m_editorView->sceneRect().height(); +} + +bool Mediator::initializeNewTrack(QString & name, int & cols, int & rows) +{ + assert(m_editorData); + + // Show a dialog asking some questions about the track + NewTrackDialog dialog(&m_mainWindow); + if (dialog.exec() == QDialog::Accepted) + { + cols = dialog.cols(); + rows = dialog.rows(); + name = dialog.name(); + + m_editorData->setTrackData(TrackDataPtr(new TrackData(name, dialog.isUserTrack(), cols, rows))); + + delete m_editorScene; + m_editorScene = new QGraphicsScene; + + m_editorView->setScene(m_editorScene); + m_editorView->updateSceneRect(); + + m_editorData->addTilesToScene(); + m_editorData->addObjectsToScene(); + + return true; + } + + return false; +} + +void Mediator::insertColumnAfter() +{ + m_editorData->trackData()->insertColumn(m_editorData->activeColumn(), MapBase::InsertDirection::After); + m_editorData->addTilesToScene(); +} + +void Mediator::insertColumnBefore() +{ + m_editorData->trackData()->insertColumn(m_editorData->activeColumn(), MapBase::InsertDirection::Before); + m_editorData->addTilesToScene(); +} + +void Mediator::insertRowAfter() +{ + m_editorData->trackData()->insertRow(m_editorData->activeRow(), MapBase::InsertDirection::After); + m_editorData->addTilesToScene(); +} + +void Mediator::insertRowBefore() +{ + m_editorData->trackData()->insertRow(m_editorData->activeRow(), MapBase::InsertDirection::Before); + m_editorData->addTilesToScene(); +} + +void Mediator::initScene() +{ + m_editorView->setScene(m_editorScene); + m_editorView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + m_editorView->setMouseTracking(true); +} + +bool Mediator::isUndoable() const +{ + return m_editorData->isUndoable(); +} + +void Mediator::clearEditMode() +{ + QApplication::restoreOverrideCursor(); + setMode(EditorMode::None); +} + +void Mediator::clearRoute() +{ + assert(m_editorData); + + m_editorData->saveUndoPoint(); + m_editorData->clearRoute(); +} + +int Mediator::cols() +{ + if (m_editorData->trackData()) + { + return m_editorData->trackData()->map().cols(); + } + return 0; +} + +bool Mediator::openTrack(QString fileName) +{ + assert(m_editorData); + + if (m_editorData->loadTrackData(fileName)) + { + delete m_editorScene; + m_editorScene = new QGraphicsScene; + + m_editorView->setScene(m_editorScene); + m_editorView->updateSceneRect(); + + m_editorData->addTilesToScene(); + m_editorData->addObjectsToScene(); + m_editorData->addExistingRouteToScene(); + + return true; + } + + return false; +} + +bool Mediator::isRedoable() const +{ + return m_editorData->isRedoable(); +} + +void Mediator::mouseWheelZoom(int delta) +{ + const int sensitivity = 10; + const int currentScale = m_editorData->currentScale(); + const int maxScale = 200; + + int newScale = currentScale; + + if (delta < 0) + { + if (currentScale > sensitivity) + { + newScale = currentScale - sensitivity; + } + else + { + newScale = 0; + } + } + else if (delta > 0) + { + if (currentScale + sensitivity < maxScale) + { + newScale = currentScale + sensitivity; + } + else + { + newScale = maxScale; + } + } + + if (newScale != currentScale) + { + setScale(newScale); + m_mainWindow.updateScaleSlider(newScale); + } +} + +void Mediator::pushNewTargetNodeToRoute(QPointF pos) +{ + m_editorData->pushNewTargetNodeToRoute(pos); +} + +void Mediator::redo() +{ + m_editorData->redo(); +} + +void Mediator::removeItem(QGraphicsItem * item) +{ + m_editorScene->removeItem(item); +} + +void Mediator::removeObject(Object & object) +{ + m_editorScene->removeItem(&object); + m_editorData->trackData()->objects().remove(object); +} + +bool Mediator::routeHasNodes() const +{ + return m_editorData->trackData()->route().numNodes(); +} + +void Mediator::saveUndoPoint() +{ + m_editorData->saveUndoPoint(); +} + +bool Mediator::saveTrackData() +{ + return m_editorData->saveTrackData(); +} + +bool Mediator::saveTrackDataAs(QString fileName) +{ + return m_editorData->saveTrackDataAs(fileName); +} + +void Mediator::setMode(EditorMode mode) +{ + m_mode = mode; +} + +void Mediator::setSelectedObject(Object * object) +{ + m_editorData->setSelectedObject(object); +} + +Object * Mediator::selectedObject() const +{ + return m_editorData->selectedObject(); +} + +void Mediator::setSelectedTargetNode(TargetNode * tnode) +{ + m_editorData->setSelectedTargetNode(tnode); +} + +TargetNode * Mediator::selectedTargetNode() const +{ + return m_editorData->selectedTargetNode(); +} + +void Mediator::setScale(int value) +{ + const qreal scale = static_cast(value) / 100; + QTransform transform; + transform.scale(scale, scale); + m_editorView->setTransform(transform); + m_editorData->setCurrentScale(value); +} + +EditorMode Mediator::mode() const +{ + return m_mode; +} + +int Mediator::rows() +{ + if (m_editorData->trackData()) + { + return m_editorData->trackData()->map().rows(); + } + return 0; +} + +bool Mediator::setTrackProperties() +{ + assert(m_editorData); + + // Show a dialog to set some properties e.g. lap count. + TrackPropertiesDialog dialog( + m_editorData->trackData()->name(), m_editorData->trackData()->index(), m_editorData->trackData()->isUserTrack(), &m_mainWindow); + if (dialog.exec() == QDialog::Accepted) + { + m_editorData->trackData()->setName(dialog.name()); + m_editorData->trackData()->setIndex(dialog.index()); + m_editorData->trackData()->setUserTrack(dialog.isUserTrack()); + return true; + } + + return false; +} + +void Mediator::showStatusBarMessage(QString message) +{ + m_mainWindow.statusBar()->showMessage(message); +} + +void Mediator::setupTrackAfterUndoOrRedo() +{ + delete m_editorScene; + m_editorScene = new QGraphicsScene; + + m_editorView->setScene(m_editorScene); + m_editorView->updateSceneRect(); + + m_editorData->addTilesToScene(); + m_editorData->addObjectsToScene(); + m_editorData->addExistingRouteToScene(); +} + +void Mediator::undo() +{ + m_editorData->undo(); +} + +void Mediator::updateCoordinates(QPointF mappedPos) +{ + if (m_editorData->trackData()) + { + const int maxCols = static_cast(m_editorData->trackData()->map().cols()); + int column = mappedPos.x() / TrackTile::TILE_W; + column = column >= maxCols ? maxCols - 1 : column; + column = column < 0 ? 0 : column; + + const int maxRows = static_cast(m_editorData->trackData()->map().rows()); + int row = mappedPos.y() / TrackTile::TILE_H; + row = row >= maxRows ? maxRows - 1 : row; + row = row < 0 ? 0 : row; + + m_editorData->setActiveRow(static_cast(row)); + m_editorData->setActiveColumn(static_cast(column)); + + QString coordinates("X: %1 Y: %2 I: %3 J: %4"); + coordinates = coordinates.arg(mappedPos.x()).arg(mappedPos.y()).arg(column).arg(row); + + showStatusBarMessage(coordinates); + } +} + +void Mediator::updateView() +{ + m_editorView->update(); +} + +Mediator::~Mediator() +{ + delete m_editorData; +} + diff -Nuar a/src/editor/mediator.hpp b/src/editor/mediator.hpp --- a/src/editor/mediator.hpp 1970-01-01 02:00:00.000000000 +0200 +++ b/src/editor/mediator.hpp 2018-02-11 08:22:08.000000000 +0300 @@ -0,0 +1,157 @@ +// This file is part of Dust Racing 2D. +// Copyright (C) 2018 Jussi Lind +// +// Dust Racing 2D is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// Dust Racing 2D is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Dust Racing 2D. If not, see . + +#ifndef MEDIATOR_HPP +#define MEDIATOR_HPP + +#include + +#include "editormode.hpp" +#include "targetnode.hpp" + +class DragAndDropStore; +class EditorData; +class EditorView; +class MainWindow; +class TrackTile; +class Object; +class QAction; +class QGraphicsScene; +class QLayout; + +/*! Acts as a communication channel between MainWindow and editor components: + * + * - MainWindow <-> Mediator <-> QGraphicsScene / EditorView / EditorData + * - EditorView <-> Mediator <-> EditorData + */ +class Mediator +{ +public: + + explicit Mediator(MainWindow & mainWindow); + + ~Mediator(); + + void addCurrentToolBarObjectToScene(QPointF clickedScenePos); + + void addItem(QGraphicsItem * item); + + void addObject(Object & object); + + void addViewToLayout(QLayout * layout); + + bool beginSetRoute(); + + void clearEditMode(); + + void clearRoute(); + + int cols(); + + void console(QString message); + + QString currentFileName() const; + + QAction * currentToolBarAction() const; + + DragAndDropStore & dadStore(); + + void deleteColumn(); + + void deleteRow(); + + void endSetRoute(); + + void enableUndo(bool enable); + + void floodFill(TrackTile & tile, QAction * action, const QString & typeToFill); + + int fitScale(); + + void initScene(); + + bool initializeNewTrack(QString & name, int & cols, int & rows); + + void insertColumnAfter(); + + void insertColumnBefore(); + + void insertRowAfter(); + + void insertRowBefore(); + + bool isUndoable() const; + + bool isRedoable() const; + + void mouseWheelZoom(int delta); + + bool openTrack(QString fileName); + + void pushNewTargetNodeToRoute(QPointF pos); + + void redo(); + + void removeItem(QGraphicsItem * item); + + void removeObject(Object & object); + + bool routeHasNodes() const; + + int rows(); + + void saveUndoPoint(); + + bool saveTrackData(); + + bool saveTrackDataAs(QString fileName); + + void setScale(int value); + + void setMode(EditorMode newMode); + EditorMode mode() const; + + void setSelectedObject(Object * object); + Object * selectedObject() const; + + void setSelectedTargetNode(TargetNode * tnode); + TargetNode * selectedTargetNode() const; + + bool setTrackProperties(); + + void showStatusBarMessage(QString message); + + void setupTrackAfterUndoOrRedo(); + + void undo(); + + void updateCoordinates(QPointF mappedPos); + + void updateView(); + +private: + + EditorData * m_editorData; + + QGraphicsScene * m_editorScene; + + EditorView * m_editorView; + + MainWindow & m_mainWindow; + + EditorMode m_mode = EditorMode::None; +}; + +#endif // MEDIATOR_HPP diff -Nuar a/src/editor/trackdata.cpp b/src/editor/trackdata.cpp --- a/src/editor/trackdata.cpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/trackdata.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -104,16 +104,6 @@ return m_objects; } -void TrackData::enlargeHorSize() -{ - m_map.resize(m_map.cols() + 1, m_map.rows()); -} - -void TrackData::enlargeVerSize() -{ - m_map.resize(m_map.cols(), m_map.rows() + 1); -} - void TrackData::insertColumn(unsigned int at, MapBase::InsertDirection insertDirection) { at = m_map.insertColumn(at, insertDirection); diff -Nuar a/src/editor/trackdata.hpp b/src/editor/trackdata.hpp --- a/src/editor/trackdata.hpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/editor/trackdata.hpp 2018-02-11 08:22:08.000000000 +0300 @@ -64,12 +64,6 @@ //! Get objects object. const Objects & objects() const; - //! Enlarge horizontal size. - void enlargeHorSize(); - - //! Enlarge vertical size. - void enlargeVerSize(); - //! Insert tile column at given index and move objects. void insertColumn(unsigned int at, MapBase::InsertDirection insertDirection); diff -Nuar a/src/game/renderer.cpp b/src/game/renderer.cpp --- a/src/game/renderer.cpp 2017-12-30 16:09:21.000000000 +0300 +++ b/src/game/renderer.cpp 2018-02-11 08:22:08.000000000 +0300 @@ -55,7 +55,7 @@ , m_eventHandler(nullptr) , m_viewAngle(22.5f) , m_zNear(10.0f) -, m_zFar(1500.0f) +, m_zFar(10000.0f) // See: https://github.com/juzzlin/DustRacing2D/issues/30 , m_fadeValue(1.0f) , m_enabled(false) , m_hRes(hRes)