Changed: #1302 Added undo command (move, rotate, scale)

--HG--
branch : gsoc2011-worldeditorqt
This commit is contained in:
dnk-88 2011-08-10 23:58:55 +03:00
parent a65eb22feb
commit 89a92f1e4c
9 changed files with 333 additions and 36 deletions

View file

@ -148,6 +148,18 @@ Path PrimitivesTreeModel::pathFromIndex(const QModelIndex &index)
return path;
}
Path PrimitivesTreeModel::pathFromNode(Node *node)
{
Node *iter = node;
Path path;
while(iter != 0)
{
path.prepend(PathItem(iter->row(), 1));
iter = iter->parent();
}
return path;
}
QModelIndex PrimitivesTreeModel::pathToIndex(const Path &path)
{
QModelIndex iter;
@ -158,6 +170,16 @@ QModelIndex PrimitivesTreeModel::pathToIndex(const Path &path)
return iter;
}
Node *PrimitivesTreeModel::pathToNode(const Path &path)
{
Node *node = m_rootNode;
for(int i = 1; i < path.size(); i++)
{
node = node->child(path[i].first);
}
return node;
}
void PrimitivesTreeModel::createWorldEditNode(const QString &fileName)
{
beginResetModel();

View file

@ -68,10 +68,12 @@ public:
/// @Path is a list of [row,column] pairs showing us the way through the model.
Path pathFromIndex(const QModelIndex &index);
//Path pathFromNode(Node *index);
Path pathFromNode(Node *node);
QModelIndex pathToIndex(const Path &path);
Node *pathToNode(const Path &path);
void createWorldEditNode(const QString &fileName);
void deleteWorldEditNode();

View file

@ -134,6 +134,24 @@ void removeGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *mode
}
}
QList<Path> graphicsItemsToPaths(const QList<QGraphicsItem *> &items, PrimitivesTreeModel *model)
{
QList<Path> result;
Q_FOREACH(QGraphicsItem *item, items)
{
Node *node = qvariant_cast<Node *>(item->data(Constants::WORLD_EDITOR_NODE));
result.push_back(model->pathFromNode(node));
}
return result;
}
/*
QList<GraphicsItem *> pathsToGraphicsItems(const QList<Path> &items, PrimitivesTreeModel *model)
{
QList<GraphicsItem *> result;
}
*/
CreateWorldCommand::CreateWorldCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent)
: QUndoCommand(parent),
m_fileName(fileName),
@ -325,4 +343,124 @@ void AddPrimitiveByClassCommand::redo()
m_newPrimIndex = m_model->createPrimitiveNode(newPrimitive, m_parentIndex);
}
MoveWorldItemsCommand::MoveWorldItemsCommand(const QList<QGraphicsItem *> &items, const QPointF &offset,
PrimitivesTreeModel *model, QUndoCommand *parent)
: QUndoCommand(parent),
m_listPaths(graphicsItemsToPaths(items, model)),
m_offset(offset),
m_model(model),
m_firstRun(true)
{
setText("Move item(s)");
}
MoveWorldItemsCommand::~MoveWorldItemsCommand()
{
}
void MoveWorldItemsCommand::undo()
{
for (int i = 0; i < m_listPaths.count(); ++i)
{
Node *node = m_model->pathToNode(m_listPaths.at(i));
QGraphicsItem *item = qvariant_cast<QGraphicsItem *>(node->data(Constants::GRAPHICS_DATA_QT4_2D));
qgraphicsitem_cast<AbstractWorldItem *>(item)->moveOn(-m_offset);
}
}
void MoveWorldItemsCommand::redo()
{
if (!m_firstRun)
{
for (int i = 0; i < m_listPaths.count(); ++i)
{
Node *node = m_model->pathToNode(m_listPaths.at(i));
QGraphicsItem *item = qvariant_cast<QGraphicsItem *>(node->data(Constants::GRAPHICS_DATA_QT4_2D));
qgraphicsitem_cast<AbstractWorldItem *>(item)->moveOn(m_offset);
}
}
m_firstRun = false;
}
RotateWorldItemsCommand::RotateWorldItemsCommand(const QList<QGraphicsItem *> &items, const qreal &angle,
const QPointF &pivot, PrimitivesTreeModel *model, QUndoCommand *parent)
: QUndoCommand(parent),
m_listPaths(graphicsItemsToPaths(items, model)),
m_angle(angle),
m_pivot(pivot),
m_model(model),
m_firstRun(true)
{
setText("Rotate item(s)");
}
RotateWorldItemsCommand::~RotateWorldItemsCommand()
{
}
void RotateWorldItemsCommand::undo()
{
for (int i = 0; i < m_listPaths.count(); ++i)
{
Node *node = m_model->pathToNode(m_listPaths.at(i));
QGraphicsItem *item = qvariant_cast<QGraphicsItem *>(node->data(Constants::GRAPHICS_DATA_QT4_2D));
qgraphicsitem_cast<AbstractWorldItem *>(item)->rotateOn(m_pivot, -m_angle);
}
}
void RotateWorldItemsCommand::redo()
{
if (!m_firstRun)
{
for (int i = 0; i < m_listPaths.count(); ++i)
{
Node *node = m_model->pathToNode(m_listPaths.at(i));
QGraphicsItem *item = qvariant_cast<QGraphicsItem *>(node->data(Constants::GRAPHICS_DATA_QT4_2D));
qgraphicsitem_cast<AbstractWorldItem *>(item)->rotateOn(m_pivot, m_angle);
}
}
m_firstRun = false;
}
ScaleWorldItemsCommand::ScaleWorldItemsCommand(const QList<QGraphicsItem *> &items, const QPointF &factor,
const QPointF &pivot, PrimitivesTreeModel *model, QUndoCommand *parent)
: QUndoCommand(parent),
m_listPaths(graphicsItemsToPaths(items, model)),
m_factor(factor),
m_pivot(pivot),
m_model(model),
m_firstRun(true)
{
setText("Scale item(s)");
}
ScaleWorldItemsCommand::~ScaleWorldItemsCommand()
{
}
void ScaleWorldItemsCommand::undo()
{
QPointF m_invertFactor(1 / m_factor.x(), 1 / m_factor.y());
for (int i = 0; i < m_listPaths.count(); ++i)
{
Node *node = m_model->pathToNode(m_listPaths.at(i));
QGraphicsItem *item = qvariant_cast<QGraphicsItem *>(node->data(Constants::GRAPHICS_DATA_QT4_2D));
qgraphicsitem_cast<AbstractWorldItem *>(item)->scaleOn(m_pivot, m_invertFactor);
}
}
void ScaleWorldItemsCommand::redo()
{
if (!m_firstRun)
{
for (int i = 0; i < m_listPaths.count(); ++i)
{
Node *node = m_model->pathToNode(m_listPaths.at(i));
QGraphicsItem *item = qvariant_cast<QGraphicsItem *>(node->data(Constants::GRAPHICS_DATA_QT4_2D));
qgraphicsitem_cast<AbstractWorldItem *>(item)->scaleOn(m_pivot, m_factor);
}
}
m_firstRun = false;
}
} /* namespace WorldEditor */

View file

@ -38,6 +38,8 @@ class WorldEditorScene;
void addNewGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *model, WorldEditorScene *scene);
void removeGraphicsItems(const QModelIndex &primIndex, PrimitivesTreeModel *model, WorldEditorScene *scene);
QList<Path> graphicsItemsToPaths(const QList<QGraphicsItem *> &items, PrimitivesTreeModel *model);
//QList<GraphicsItem *> pathsToGraphicsItems(const QList<Path> &items, PrimitivesTreeModel *model);
/**
@class CreateWorldCommand
@ -84,7 +86,8 @@ private:
class CreateRootPrimitiveCommand: public QUndoCommand
{
public:
CreateRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0);
CreateRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model,
QUndoCommand *parent = 0);
virtual ~CreateRootPrimitiveCommand();
virtual void undo();
@ -139,6 +142,74 @@ private:
PrimitivesTreeModel *m_model;
};
/**
@class MoveWorldItemsCommand
@brief
@details
*/
class MoveWorldItemsCommand: public QUndoCommand
{
public:
MoveWorldItemsCommand(const QList<QGraphicsItem *> &items, const QPointF &offset,
PrimitivesTreeModel *model, QUndoCommand *parent = 0);
virtual ~MoveWorldItemsCommand();
virtual void undo();
virtual void redo();
private:
const QList<Path> m_listPaths;
const QPointF m_offset;
PrimitivesTreeModel *const m_model;
bool m_firstRun;
};
/**
@class RotateWorldItemsCommand
@brief
@details
*/
class RotateWorldItemsCommand: public QUndoCommand
{
public:
RotateWorldItemsCommand(const QList<QGraphicsItem *> &items, const qreal &angle,
const QPointF &pivot, PrimitivesTreeModel *model, QUndoCommand *parent = 0);
virtual ~RotateWorldItemsCommand();
virtual void undo();
virtual void redo();
private:
const QList<Path> m_listPaths;
const qreal m_angle;
const QPointF m_pivot;
PrimitivesTreeModel *const m_model;
bool m_firstRun;
};
/**
@class ScaleWorldItemsCommand
@brief
@details
*/
class ScaleWorldItemsCommand: public QUndoCommand
{
public:
ScaleWorldItemsCommand(const QList<QGraphicsItem *> &items, const QPointF &factor,
const QPointF &pivot, PrimitivesTreeModel *model, QUndoCommand *parent = 0);
virtual ~ScaleWorldItemsCommand();
virtual void undo();
virtual void redo();
private:
const QList<Path> m_listPaths;
const QPointF m_factor;
const QPointF m_pivot;
PrimitivesTreeModel *const m_model;
bool m_firstRun;
};
} /* namespace WorldEditor */
#endif // WORLD_EDITOR_ACTIONS_H

View file

@ -16,6 +16,8 @@
// Project includes
#include "world_editor_scene.h"
#include "world_editor_scene_item.h"
#include "world_editor_actions.h"
// NeL includes
#include <nel/misc/debug.h>
@ -29,12 +31,14 @@
namespace WorldEditor
{
WorldEditorScene::WorldEditorScene(int sizeCell, QObject *parent)
WorldEditorScene::WorldEditorScene(int sizeCell, PrimitivesTreeModel *model, QUndoStack *undoStack, QObject *parent)
: LandscapeEditor::LandscapeSceneBase(sizeCell, parent),
m_editedSelectedItems(false),
m_lastPickedPrimitive(0),
m_mode(SelectMode),
m_editMode(false)
m_editMode(false),
m_undoStack(undoStack),
m_model(model)
{
setItemIndexMethod(NoIndex);
@ -134,7 +138,7 @@ void WorldEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
// if ((!m_editedSelectedItems) && (m_mode != WorldEditorScene::SelectMode))
if ((!m_editedSelectedItems && m_selectedItems.isEmpty()) ||
(!calcBoundingShape(m_selectedItems).contains(mouseEvent->scenePos())))
(!calcBoundingRect(m_selectedItems).contains(mouseEvent->scenePos())))
{
updatePickSelection(mouseEvent->scenePos());
m_firstSelection = true;
@ -190,29 +194,38 @@ void WorldEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
}
case WorldEditorScene::RotateMode:
{
QRectF pivot = calcBoundingRect(m_selectedItems);
QPointF pivot = calcBoundingRect(m_selectedItems).center();
// Caluculate angle between two line
QLineF firstLine(pivot.center(), mouseEvent->lastScenePos());
QLineF secondLine(pivot.center(), mouseEvent->scenePos());
QLineF firstLine(pivot, mouseEvent->lastScenePos());
QLineF secondLine(pivot, mouseEvent->scenePos());
qreal angle = secondLine.angleTo(firstLine);
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
{
qgraphicsitem_cast<AbstractWorldItem *>(item)->rotateOn(pivot.center(), angle);
qgraphicsitem_cast<AbstractWorldItem *>(item)->rotateOn(pivot, angle);
}
break;
}
case WorldEditorScene::ScaleMode:
{
// float scale = (_SelectionMin.x - _SelectionMax.x + _SelectionMax.y - _SelectionMin.y) * SCALE_PER_PIXEL + 1.f;
// moveAction->setScale (std::max (0.001f, scale), _MainFrame->getTransformMode ()==CMainFrame::Scale, radius);
// TODO: perfomance
QRectF pivot = calcBoundingRect(m_selectedItems);
QPointF pivot = calcBoundingRect(m_selectedItems).center();
// Calculate scale factor
if (offset.x() > 0)
offset.setX(1.0 + (offset.x() / 5000));
else
offset.setX(1.0 / (1.0 + (-offset.x() / 5000)));
if (offset.y() < 0)
offset.setY(1.0 + (-offset.y() / 5000));
else
offset.setY(1.0 / (1.0 + (offset.y() / 5000)));
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
{
qgraphicsitem_cast<AbstractWorldItem *>(item)->scaleOn(pivot.center(), offset);
qgraphicsitem_cast<AbstractWorldItem *>(item)->scaleOn(pivot, offset);
}
break;
}
@ -240,6 +253,51 @@ void WorldEditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
if (mouseEvent->button() != Qt::LeftButton)
return;
if (m_editedSelectedItems)
{
switch (m_mode)
{
case WorldEditorScene::SelectMode:
break;
case WorldEditorScene::MoveMode:
{
QPointF offset = mouseEvent->scenePos() - m_firstPick;
m_undoStack->push(new MoveWorldItemsCommand(m_selectedItems, offset, m_model));
break;
}
case WorldEditorScene::RotateMode:
{
QPointF pivot = calcBoundingRect(m_selectedItems).center();
// Caluculate angle between two line
QLineF firstLine(pivot, m_firstPick);
QLineF secondLine(pivot, mouseEvent->scenePos());
qreal angle = secondLine.angleTo(firstLine);
m_undoStack->push(new RotateWorldItemsCommand(m_selectedItems, angle, pivot, m_model));
break;
}
case WorldEditorScene::ScaleMode:
{
QPointF pivot = calcBoundingRect(m_selectedItems).center();
QPointF offset = mouseEvent->scenePos() - m_firstPick;
// Calculate scale factor
offset.setX(1.0 + (offset.x() / 5000));
offset.setY(1.0 + (-offset.y() / 5000));
m_undoStack->push(new ScaleWorldItemsCommand(m_selectedItems, offset, pivot, m_model));
break;
}
case WorldEditorScene::TurnMode:
break;
case WorldEditorScene::RadiusMode:
break;
};
}
if ((m_selectionArea.left() != 0) && (m_selectionArea.right() != 0))
{
QList<QGraphicsItem *> listItems;

View file

@ -19,16 +19,17 @@
// Project includes
#include "world_editor_global.h"
#include "world_editor_scene_item.h"
#include "../landscape_editor/landscape_scene_base.h"
// NeL includes
// Qt includes
#include <QtGui/QUndoStack>
namespace WorldEditor
{
class PrimitivesTreeModel;
/*
@class WorldEditorScene
@ -50,7 +51,8 @@ public:
RadiusMode
};
WorldEditorScene(int sizeCell = 160, QObject *parent = 0);
WorldEditorScene(int sizeCell, PrimitivesTreeModel *model,
QUndoStack *undoStack, QObject *parent = 0);
virtual ~WorldEditorScene();
QGraphicsItem *addWorldItemPoint(const QPointF &point, const float angle);
@ -91,6 +93,8 @@ private:
uint m_lastPickedPrimitive;
ModeEdit m_mode;
bool m_editMode;
QUndoStack *m_undoStack;
PrimitivesTreeModel *m_model;
};
} /* namespace WorldEditor */

View file

@ -378,7 +378,7 @@ void WorldItemPoint::rotateOn(const QPointF &pivot, const qreal deltaAngle)
setPos(rotatedPolygon.boundingRect().center());
}
void WorldItemPoint::scaleOn(const QPointF &pivot, const QPointF &offset)
void WorldItemPoint::scaleOn(const QPointF &pivot, const QPointF &factor)
{
prepareGeometryChange();
@ -389,7 +389,7 @@ void WorldItemPoint::scaleOn(const QPointF &pivot, const QPointF &offset)
scaledPolygon.translate(-pivot);
QTransform trans;
trans = trans.scale(1.0 + (offset.x() / 5000), 1.0 + (-offset.y() / 5000));
trans = trans.scale(factor.x(), factor.y());
scaledPolygon = trans.map(scaledPolygon);
scaledPolygon.translate(pivot);
@ -485,7 +485,7 @@ void WorldItemPath::rotateOn(const QPointF &pivot, const qreal deltaAngle)
m_polygon.translate(pivot);
}
void WorldItemPath::scaleOn(const QPointF &pivot, const QPointF &offset)
void WorldItemPath::scaleOn(const QPointF &pivot, const QPointF &factor)
{
prepareGeometryChange();
@ -493,7 +493,7 @@ void WorldItemPath::scaleOn(const QPointF &pivot, const QPointF &offset)
scaledPolygon.translate(-pivot);
QTransform trans;
trans = trans.scale(1.0 + (offset.x() / 5000), 1.0 + (-offset.y() / 5000));
trans = trans.scale(factor.x(), factor.y());
m_polygon = trans.map(scaledPolygon);
m_polygon.translate(pivot);
@ -590,7 +590,7 @@ void WorldItemZone::rotateOn(const QPointF &pivot, const qreal deltaAngle)
m_polygon.translate(pivot);
}
void WorldItemZone::scaleOn(const QPointF &pivot, const QPointF &offset)
void WorldItemZone::scaleOn(const QPointF &pivot, const QPointF &factor)
{
prepareGeometryChange();
@ -598,7 +598,7 @@ void WorldItemZone::scaleOn(const QPointF &pivot, const QPointF &offset)
scaledPolygon.translate(-pivot);
QTransform trans;
trans = trans.scale(1.0 + (offset.x() / 5000), 1.0 + (-offset.y() / 5000));
trans = trans.scale(factor.x(), factor.y());
m_polygon = trans.map(scaledPolygon);
m_polygon.translate(pivot);

View file

@ -131,7 +131,7 @@ public:
virtual void moveOn(const QPointF &offset) = 0;
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle) = 0;
// TODO: add modes: IgnoreAspectRatio, KeepAspectRatio
virtual void scaleOn(const QPointF &pivot, const QPointF &offset) = 0;
virtual void scaleOn(const QPointF &pivot, const QPointF &factor) = 0;
virtual void turnOn(const QPointF &offset) = 0;
virtual void radiusOn(const qreal radius) = 0;
@ -152,7 +152,7 @@ public:
virtual void moveOn(const QPointF &offset);
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle);
virtual void scaleOn(const QPointF &pivot, const QPointF &offset);
virtual void scaleOn(const QPointF &pivot, const QPointF &factor);
virtual void turnOn(const QPointF &offset);
virtual void radiusOn(const qreal radius);
@ -188,7 +188,7 @@ public:
virtual void moveOn(const QPointF &offset);
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle);
virtual void scaleOn(const QPointF &pivot, const QPointF &offset);
virtual void scaleOn(const QPointF &pivot, const QPointF &factor);
virtual void turnOn(const QPointF &offset);
virtual void radiusOn(const qreal radius);
@ -216,7 +216,7 @@ public:
virtual void moveOn(const QPointF &offset);
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle);
virtual void scaleOn(const QPointF &pivot, const QPointF &offset);
virtual void scaleOn(const QPointF &pivot, const QPointF &factor);
virtual void turnOn(const QPointF &offset);
virtual void radiusOn(const qreal radius);
@ -234,4 +234,6 @@ protected:
} /* namespace WorldEditor */
Q_DECLARE_METATYPE(WorldEditor::AbstractWorldItem *)
#endif // WORLD_EDITOR_SCENE_ITEM_H

View file

@ -50,12 +50,20 @@ WorldEditorWindow::WorldEditorWindow(QWidget *parent)
m_ui.setupUi(this);
m_undoStack = new QUndoStack(this);
m_worldEditorScene = new WorldEditorScene(NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig->CellSize, this);
m_primitivesModel = new PrimitivesTreeModel(this);
m_worldEditorScene = new WorldEditorScene(Utils::ligoConfig()->CellSize, m_primitivesModel, m_undoStack, this);
m_zoneBuilderBase = new LandscapeEditor::ZoneBuilderBase(m_worldEditorScene);
m_worldEditorScene->setZoneBuilder(m_zoneBuilderBase);
m_ui.graphicsView->setScene(m_worldEditorScene);
//m_ui.graphicsView->setVisibleText(false);
m_ui.graphicsView->setVisibleText(false);
m_ui.treePrimitivesView->setModel(m_primitivesModel);
// TODO: ?
m_ui.treePrimitivesView->setUndoStack(m_undoStack);
m_ui.treePrimitivesView->setZoneBuilder(m_zoneBuilderBase);
m_ui.treePrimitivesView->setWorldScene(m_worldEditorScene);
QActionGroup *sceneModeGroup = new QActionGroup(this);
sceneModeGroup->addAction(m_ui.selectAction);
@ -69,14 +77,6 @@ WorldEditorWindow::WorldEditorWindow(QWidget *parent)
m_ui.newWorldEditAction->setIcon(QIcon(Core::Constants::ICON_NEW));
m_ui.saveWorldEditAction->setIcon(QIcon(Core::Constants::ICON_SAVE));
m_primitivesModel = new PrimitivesTreeModel(this);
m_ui.treePrimitivesView->setModel(m_primitivesModel);
// TODO: ?
m_ui.treePrimitivesView->setUndoStack(m_undoStack);
m_ui.treePrimitivesView->setZoneBuilder(m_zoneBuilderBase);
m_ui.treePrimitivesView->setWorldScene(m_worldEditorScene);
createMenus();
createToolBars();
readSettings();