From d213cd784034285337e137b6575166088ef7a803 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 17:10:15 -0700 Subject: [PATCH] More work on Undo/Redo --- examples/editVoxels.js | 1 - interface/src/Application.cpp | 1 + interface/src/Menu.cpp | 11 +-- libraries/voxels/src/VoxelTree.h | 7 +- libraries/voxels/src/VoxelTreeCommands.cpp | 64 +++++++++++++++ libraries/voxels/src/VoxelTreeCommands.h | 46 +++++++++++ .../voxels/src/VoxelsScriptingInterface.cpp | 77 +++++++++++++++---- .../voxels/src/VoxelsScriptingInterface.h | 4 +- 8 files changed, 190 insertions(+), 21 deletions(-) create mode 100644 libraries/voxels/src/VoxelTreeCommands.cpp create mode 100644 libraries/voxels/src/VoxelTreeCommands.h diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 4922caf0d8..0f9ed25d2c 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -911,7 +911,6 @@ function mousePressEvent(event) { } voxelDetails = calculateVoxelFromIntersection(intersection,"add"); - Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, newColor.red, newColor.green, newColor.blue); lastVoxelPosition = { x: voxelDetails.x, y: voxelDetails.y, z: voxelDetails.z }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d54cceb245..68b2ae9a24 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3274,6 +3274,7 @@ void Application::loadScript(const QString& scriptName) { // we can use the same ones from the application. scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender); scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree()); + scriptEngine->getVoxelsScriptingInterface()->setUndoStack(&_undoStack); scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender); scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e090f4d046..b9aa0ea91c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -161,14 +161,15 @@ Menu::Menu() : QMenu* editMenu = addMenu("Edit"); + QUndoStack* undoStack = Application::getInstance()->getUndoStack(); QAction* undoAction = undoStack->createUndoAction(editMenu); + undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, undoAction); + QAction* redoAction = undoStack->createRedoAction(editMenu); - - addActionToQMenuAndActionHash(editMenu, - undoAction); - addActionToQMenuAndActionHash(editMenu, - redoAction); + redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, redoAction); addActionToQMenuAndActionHash(editMenu, MenuOption::Preferences, diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 2079ab91b2..3d1b699a45 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -1,4 +1,4 @@ -// + // // VoxelTree.h // hifi // @@ -14,6 +14,7 @@ #include "VoxelTreeElement.h" #include "VoxelEditPacketSender.h" +class QUndoStack; class ReadCodeColorBufferToTreeArgs; class VoxelTree : public Octree { @@ -44,6 +45,8 @@ public: virtual bool handlesEditPacketType(PacketType packetType) const; virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength, const unsigned char* editData, int maxLength, const SharedNodePointer& node); + + void setUndoStack(QUndoStack* undoStack) { _undoStack = undoStack; } private: // helper functions for nudgeSubTree @@ -52,6 +55,8 @@ private: void nudgeLeaf(VoxelTreeElement* element, void* extraData); void chunkifyLeaf(VoxelTreeElement* element); void readCodeColorBufferToTreeRecursion(VoxelTreeElement* node, ReadCodeColorBufferToTreeArgs& args); + + QUndoStack* _undoStack; }; #endif /* defined(__hifi__VoxelTree__) */ diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp new file mode 100644 index 0000000000..a557137367 --- /dev/null +++ b/libraries/voxels/src/VoxelTreeCommands.cpp @@ -0,0 +1,64 @@ +// +// VoxelTreeCommands.cpp +// hifi +// +// Created by Clement on 4/4/14. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// + +#include "VoxelTree.h" + +#include "VoxelTreeCommands.h" + +AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : +QUndoCommand("Add Voxel", parent), +_tree(tree), +_packetSender(packetSender), +_voxel(voxel) +{ +} + +void AddVoxelCommand::redo() { + if (_tree) { + _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); + } +} + +void AddVoxelCommand::undo() { + if (_tree) { + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); + } +} + +DeleteVoxelCommand::DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : +QUndoCommand("Delete Voxel", parent), +_tree(tree), +_packetSender(packetSender), +_voxel(voxel) +{ +} + +void DeleteVoxelCommand::redo() { + if (_tree) { + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); + } +} + +void DeleteVoxelCommand::undo() { + if (_tree) { + _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); + } +} \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTreeCommands.h b/libraries/voxels/src/VoxelTreeCommands.h new file mode 100644 index 0000000000..ca7700417c --- /dev/null +++ b/libraries/voxels/src/VoxelTreeCommands.h @@ -0,0 +1,46 @@ +// +// VoxelTreeCommands.h +// hifi +// +// Created by Clement on 4/4/14. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__VoxelTreeCommands__ +#define __hifi__VoxelTreeCommands__ + +#include +#include + +#include "VoxelDetail.h" +#include "VoxelEditPacketSender.h" + +class VoxelTree; + +class AddVoxelCommand : public QUndoCommand { +public: + AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); + + virtual void redo(); + virtual void undo(); + +private: + VoxelTree* _tree; + VoxelEditPacketSender* _packetSender; + VoxelDetail _voxel; +}; + +class DeleteVoxelCommand : public QUndoCommand { +public: + DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); + + virtual void redo(); + virtual void undo(); + +private: + VoxelTree* _tree; + VoxelEditPacketSender* _packetSender; + VoxelDetail _voxel; +}; + +#endif /* defined(__hifi__VoxelTreeCommands__) */ diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index 2aecb2d457..59e4662bed 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -6,6 +6,8 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include "VoxelTreeCommands.h" + #include "VoxelsScriptingInterface.h" void VoxelsScriptingInterface::queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails) { @@ -37,17 +39,24 @@ VoxelDetail VoxelsScriptingInterface::getVoxelAt(float x, float y, float z, floa } void VoxelsScriptingInterface::setVoxelNonDestructive(float x, float y, float z, float scale, - uchar red, uchar green, uchar blue) { + uchar red, uchar green, uchar blue) { // setup a VoxelDetail struct with the data - VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, + VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, scale / (float)TREE_SCALE, red, green, blue}; - // queue the add packet - queueVoxelAdd(PacketTypeVoxelSet, addVoxelDetail); // handle the local tree also... if (_tree) { - _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, false); + if (_undoStack) { + AddVoxelCommand* command = new AddVoxelCommand(_tree, + addVoxelDetail, + getVoxelPacketSender()); + _undoStack->push(command); + } else { + // queue the add packet + queueVoxelAdd(PacketTypeVoxelSet, addVoxelDetail); + _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, false); + } } } @@ -57,26 +66,68 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, scale / (float)TREE_SCALE, red, green, blue}; - // queue the destructive add - queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail); // handle the local tree also... if (_tree) { - _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, true); + if (_undoStack) { + AddVoxelCommand* addCommand = new AddVoxelCommand(_tree, + addVoxelDetail, + getVoxelPacketSender()); + + VoxelTreeElement* deleteVoxelElement = _tree->getVoxelAt(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s); + if (deleteVoxelElement) { + nodeColor color; + memcpy(&color, &deleteVoxelElement->getColor(), sizeof(nodeColor)); + VoxelDetail deleteVoxelDetail = {addVoxelDetail.x, + addVoxelDetail.y, + addVoxelDetail.z, + addVoxelDetail.s, + color[0], + color[1], + color[2]}; + DeleteVoxelCommand* delCommand = new DeleteVoxelCommand(_tree, + deleteVoxelDetail, + getVoxelPacketSender()); + _undoStack->beginMacro(addCommand->text()); + qDebug() << "Macro"; + _undoStack->push(delCommand); + _undoStack->push(addCommand); + _undoStack->endMacro(); + } else { + _undoStack->push(addCommand); + } + } else { + // queue the destructive add + queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail); + _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, true); + } } } void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale) { - // setup a VoxelDetail struct with data - VoxelDetail deleteVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, - scale / (float)TREE_SCALE, 0, 0, 0}; + VoxelDetail deleteVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, + scale / (float)TREE_SCALE}; - getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); // handle the local tree also... if (_tree) { - _tree->deleteVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); + VoxelTreeElement* deleteVoxelElement = _tree->getVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); + if (deleteVoxelElement) { + deleteVoxelDetail.red = deleteVoxelElement->getColor()[0]; + deleteVoxelDetail.green = deleteVoxelElement->getColor()[1]; + deleteVoxelDetail.blue = deleteVoxelElement->getColor()[2]; + } + + if (_undoStack) { + DeleteVoxelCommand* command = new DeleteVoxelCommand(_tree, + deleteVoxelDetail, + getVoxelPacketSender()); + _undoStack->push(command); + } else { + getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); + _tree->deleteVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); + } } } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index d07d2a785c..339e527ebc 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -22,12 +22,13 @@ class VoxelsScriptingInterface : public OctreeScriptingInterface { Q_OBJECT public: - VoxelsScriptingInterface() : _tree(NULL) {}; + VoxelsScriptingInterface() : _tree(NULL), _undoStack(NULL) {}; VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); } virtual NodeType_t getServerNodeType() const { return NodeType::VoxelServer; } virtual OctreeEditPacketSender* createPacketSender() { return new VoxelEditPacketSender(); } void setVoxelTree(VoxelTree* tree) { _tree = tree; } + void setUndoStack(QUndoStack* undoStack) { _undoStack = undoStack; } public slots: @@ -79,6 +80,7 @@ public slots: private: void queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails); VoxelTree* _tree; + QUndoStack* _undoStack; }; #endif /* defined(__hifi__VoxelsScriptingInterface__) */