From dececf6c3878d555e94dd548c7a5f5e58c0e4efd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 16 Feb 2016 16:02:29 +0100 Subject: [PATCH 01/19] instance moving via drag in 3D scenes --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/cell.cpp | 13 ++ apps/opencs/view/render/cell.hpp | 2 + apps/opencs/view/render/instancemode.cpp | 160 +++++++++++++++++- apps/opencs/view/render/instancemode.hpp | 19 +++ apps/opencs/view/render/instancemovemode.cpp | 12 ++ apps/opencs/view/render/instancemovemode.hpp | 18 ++ apps/opencs/view/render/object.cpp | 137 ++++++++++++++- apps/opencs/view/render/object.hpp | 40 ++++- .../view/render/pagedworldspacewidget.cpp | 17 ++ .../view/render/pagedworldspacewidget.hpp | 3 + apps/opencs/view/render/scenewidget.cpp | 6 + apps/opencs/view/render/scenewidget.hpp | 3 + .../view/render/unpagedworldspacewidget.cpp | 6 + .../view/render/unpagedworldspacewidget.hpp | 3 + apps/opencs/view/render/worldspacewidget.hpp | 3 + 16 files changed, 428 insertions(+), 16 deletions(-) create mode 100644 apps/opencs/view/render/instancemovemode.cpp create mode 100644 apps/opencs/view/render/instancemovemode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6401e4222..ce0216066 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -85,7 +85,7 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget - previewwidget editmode instancemode instanceselectionmode + previewwidget editmode instancemode instanceselectionmode instancemovemode ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index e7b135891..d666304fa 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -338,3 +338,16 @@ std::vector > CSVRender::Cell::getSelection (un return result; } + +std::vector > CSVRender::Cell::getEdited (unsigned int elementMask) const +{ + std::vector > result; + + if (elementMask & Mask_Reference) + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + if (iter->second->isEdited()) + result.push_back (iter->second->getTag()); + + return result; +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 22f9872e3..6cdafbf36 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -116,6 +116,8 @@ namespace CSVRender bool isDeleted() const; std::vector > getSelection (unsigned int elementMask) const; + + std::vector > getEdited (unsigned int elementMask) const; }; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 4b6b2e41f..f2fb552b0 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -18,10 +18,11 @@ #include "worldspacewidget.hpp" #include "pagedworldspacewidget.hpp" #include "instanceselectionmode.hpp" +#include "instancemovemode.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", - parent), mSubMode (0), mSelectionMode (0) + parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None) { } @@ -30,12 +31,7 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) if (!mSubMode) { mSubMode = new CSVWidget::SceneToolMode (toolbar, "Edit Sub-Mode"); - mSubMode->addButton (":placeholder", "move", - "Move selected instances" - "
  • Use primary edit to move instances around freely
  • " - "
  • Use secondary edit to move instances around within the grid
  • " - "
" - "Not implemented yet"); + mSubMode->addButton (new InstanceMoveMode (this), "move"); mSubMode->addButton (":placeholder", "rotate", "Rotate selected instances" "
  • Use primary edit to rotate instances freely
  • " @@ -53,6 +49,8 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) if (!mSelectionMode) mSelectionMode = new InstanceSelectionMode (toolbar, getWorldspaceWidget()); + mDragMode = DragMode_None; + EditMode::activate (toolbar); toolbar->addTool (mSubMode); @@ -120,6 +118,154 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) } } +bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr tag) +{ + if (mDragMode!=DragMode_None) + return false; + + if (tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) + { + getWorldspaceWidget().clearSelection (Mask_Reference); + if (CSVRender::ObjectTag *objectTag = dynamic_cast (tag.get())) + { + CSVRender::Object* object = objectTag->mObject; + object->setSelected (true); + } + } + + std::vector > selection = + getWorldspaceWidget().getSelection (Mask_Reference); + + if (selection.empty()) + return false; + + // \todo check for sub-mode + + for (std::vector >::iterator iter (selection.begin()); + iter!=selection.end(); ++iter) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (iter->get())) + { + objectTag->mObject->setEdited (Object::Override_Position); + } + } + + mDragMode = DragMode_Move; + + return true; +} + +bool CSVRender::InstanceMode::secondaryEditStartDrag (osg::ref_ptr tag) +{ + + return false; +} + +void CSVRender::InstanceMode::drag (int diffX, int diffY, double speedFactor) +{ + switch (mDragMode) + { + case DragMode_Move: + { + osg::Vec3f eye; + osg::Vec3f centre; + osg::Vec3f up; + + getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up); + + osg::Vec3f offset; + + if (diffY) + offset += up * diffY * speedFactor; + + if (diffX) + offset += ((centre-eye) ^ up) * diffX * speedFactor; + + std::vector > selection = + getWorldspaceWidget().getEdited (Mask_Reference); + + for (std::vector >::iterator iter (selection.begin()); + iter!=selection.end(); ++iter) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (iter->get())) + { + ESM::Position position = objectTag->mObject->getPosition(); + for (int i=0; i<3; ++i) + position.pos[i] += offset[i]; + objectTag->mObject->setPosition (position.pos); + } + } + + break; + } + + case DragMode_None: break; + } +} + +void CSVRender::InstanceMode::dragCompleted() +{ + std::vector > selection = + getWorldspaceWidget().getEdited (Mask_Reference); + + QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); + + QString description; + + switch (mDragMode) + { + case DragMode_Move: description = "Move Instances"; break; + + case DragMode_None: break; + } + + undoStack.beginMacro (description); + + for (std::vector >::iterator iter (selection.begin()); + iter!=selection.end(); ++iter) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (iter->get())) + { + objectTag->mObject->apply (undoStack); + } + } + + undoStack.endMacro(); + + mDragMode = DragMode_None; +} + +void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor) +{ + if (mDragMode==DragMode_Move) + { + osg::Vec3f eye; + osg::Vec3f centre; + osg::Vec3f up; + + getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up); + + osg::Vec3f offset = centre - eye; + offset.normalize(); + offset *= diff * speedFactor; + + std::vector > selection = + getWorldspaceWidget().getEdited (Mask_Reference); + + for (std::vector >::iterator iter (selection.begin()); + iter!=selection.end(); ++iter) + { + if (CSVRender::ObjectTag *objectTag = dynamic_cast (iter->get())) + { + ESM::Position position = objectTag->mObject->getPosition(); + for (int i=0; i<3; ++i) + position.pos[i] += offset[i]; + objectTag->mObject->setPosition (position.pos); + } + } + } +} + void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event) { if (const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData())) diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 78836878a..7662a0cdc 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -15,8 +15,17 @@ namespace CSVRender class InstanceMode : public EditMode { Q_OBJECT + + enum DragMode + { + DragMode_None, + DragMode_Move + + }; + CSVWidget::SceneToolMode *mSubMode; InstanceSelectionMode *mSelectionMode; + DragMode mDragMode; public: @@ -34,6 +43,16 @@ namespace CSVRender virtual void secondarySelectPressed (osg::ref_ptr tag); + virtual bool primaryEditStartDrag (osg::ref_ptr tag); + + virtual bool secondaryEditStartDrag (osg::ref_ptr tag); + + virtual void drag (int diffX, int diffY, double speedFactor); + + virtual void dragCompleted(); + + virtual void dragWheel (int diff, double speedFactor); + virtual void dragEnterEvent (QDragEnterEvent *event); virtual void dropEvent (QDropEvent* event); diff --git a/apps/opencs/view/render/instancemovemode.cpp b/apps/opencs/view/render/instancemovemode.cpp new file mode 100644 index 000000000..fd42b9f69 --- /dev/null +++ b/apps/opencs/view/render/instancemovemode.cpp @@ -0,0 +1,12 @@ + +#include "instancemovemode.hpp" + +CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent) +: ModeButton (QIcon (QPixmap (":placeholder")), + "Move selected instances" + "
    • Use primary edit to move instances around freely
    • " + "
    • Use secondary edit to move instances around within the grid
    • " + "
    " + "Not implemented yet", + parent) +{} diff --git a/apps/opencs/view/render/instancemovemode.hpp b/apps/opencs/view/render/instancemovemode.hpp new file mode 100644 index 000000000..bd0e28dac --- /dev/null +++ b/apps/opencs/view/render/instancemovemode.hpp @@ -0,0 +1,18 @@ +#ifndef CSV_RENDER_INSTANCEMOVEMODE_H +#define CSV_RENDER_INSTANCEMOVEMODE_H + +#include "../widget/modebutton.hpp" + +namespace CSVRender +{ + class InstanceMoveMode : public CSVWidget::ModeButton + { + Q_OBJECT + + public: + + InstanceMoveMode (QWidget *parent = 0); + }; +} + +#endif diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 33939625d..1e2fd2640 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -15,6 +15,8 @@ #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/universalid.hpp" #include #include @@ -130,18 +132,20 @@ void CSVRender::Object::adjustTransform() if (mReferenceId.empty()) return; - const CSMWorld::CellRef& reference = getReference(); + ESM::Position position = getPosition(); // position - mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2])); + mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(position.pos[0], position.pos[1], position.pos[2])); // orientation - osg::Quat xr (-reference.mPos.rot[0], osg::Vec3f(1,0,0)); - osg::Quat yr (-reference.mPos.rot[1], osg::Vec3f(0,1,0)); - osg::Quat zr (-reference.mPos.rot[2], osg::Vec3f(0,0,1)); + osg::Quat xr (-position.rot[0], osg::Vec3f(1,0,0)); + osg::Quat yr (-position.rot[1], osg::Vec3f(0,1,0)); + osg::Quat zr (-position.rot[2], osg::Vec3f(0,0,1)); mBaseNode->setAttitude(zr*yr*xr); - mBaseNode->setScale(osg::Vec3(reference.mScale, reference.mScale, reference.mScale)); + float scale = getScale(); + + mBaseNode->setScale(osg::Vec3(scale, scale, scale)); } const CSMWorld::CellRef& CSVRender::Object::getReference() const @@ -154,7 +158,8 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero), + mScaleOverride (1), mOverrideFlags (0) { mBaseNode = new osg::PositionAttitudeTransform; mBaseNode->addCullCallback(new SceneUtil::LightListCallback); @@ -290,3 +295,121 @@ osg::ref_ptr CSVRender::Object::getTag() const { return static_cast (mBaseNode->getUserData()); } + +bool CSVRender::Object::isEdited() const +{ + return mOverrideFlags; +} + +void CSVRender::Object::setEdited (int flags) +{ + bool discard = mOverrideFlags & ~flags; + int added = flags & ~mOverrideFlags; + + mOverrideFlags = flags; + + if (added & Override_Position) + for (int i=0; i<3; ++i) + mPositionOverride.pos[i] = getReference().mPos.pos[i]; + + if (added & Override_Rotation) + for (int i=0; i<3; ++i) + mPositionOverride.rot[i] = getReference().mPos.rot[i]; + + if (added & Override_Scale) + mScaleOverride = getReference().mScale; + + if (discard) + adjustTransform(); +} + +ESM::Position CSVRender::Object::getPosition() const +{ + ESM::Position position = getReference().mPos; + + if (mOverrideFlags & Override_Position) + for (int i=0; i<3; ++i) + position.pos[i] = mPositionOverride.pos[i]; + + if (mOverrideFlags & Override_Rotation) + for (int i=0; i<3; ++i) + position.rot[i] = mPositionOverride.rot[i]; + + return position; +} + +float CSVRender::Object::getScale() const +{ + return mOverrideFlags & Override_Scale ? mScaleOverride : getReference().mScale; +} + +void CSVRender::Object::setPosition (const float position[3]) +{ + mOverrideFlags |= Override_Position; + + for (int i=0; i<3; ++i) + mPositionOverride.pos[i] = position[i]; + + adjustTransform(); +} + +void CSVRender::Object::setRotation (const float rotation[3]) +{ + mOverrideFlags |= Override_Rotation; + + for (int i=0; i<3; ++i) + mPositionOverride.rot[i] = rotation[i]; + + adjustTransform(); +} + +void CSVRender::Object::setScale (float scale) +{ + mOverrideFlags |= Override_Scale; + + mScaleOverride = scale; + + adjustTransform(); +} + +void CSVRender::Object::apply (QUndoStack& undoStack) +{ + const CSMWorld::RefCollection& collection = mData.getReferences(); + QAbstractItemModel *model = mData.getTableModel (CSMWorld::UniversalId::Type_References); + + int recordIndex = collection.getIndex (mReferenceId); + + if (mOverrideFlags & Override_Position) + { + for (int i=0; i<3; ++i) + { + int column = collection.findColumnIndex (static_cast ( + CSMWorld::Columns::ColumnId_PositionXPos+i)); + + undoStack.push (new CSMWorld::ModifyCommand (*model, + model->index (recordIndex, column), mPositionOverride.pos[i])); + } + } + + if (mOverrideFlags & Override_Rotation) + { + for (int i=0; i<3; ++i) + { + int column = collection.findColumnIndex (static_cast ( + CSMWorld::Columns::ColumnId_PositionXRot+i)); + + undoStack.push (new CSMWorld::ModifyCommand (*model, + model->index (recordIndex, column), mPositionOverride.rot[i])); + } + } + + if (mOverrideFlags & Override_Scale) + { + int column = collection.findColumnIndex (CSMWorld::Columns::ColumnId_Scale); + + undoStack.push (new CSMWorld::ModifyCommand (*model, + model->index (recordIndex, column), mScaleOverride)); + } + + mOverrideFlags = 0; +} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 4a89fe201..accdb93e0 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -8,9 +8,12 @@ #include #include +#include + #include "tagbase.hpp" class QModelIndex; +class QUndoStack; namespace osg { @@ -53,7 +56,18 @@ namespace CSVRender class Object { - const CSMWorld::Data& mData; + public: + + enum OverrideFlags + { + Override_Position = 1, + Override_Rotation = 2, + Override_Scale = 4 + }; + + private: + + CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; osg::ref_ptr mBaseNode; @@ -62,6 +76,9 @@ namespace CSVRender osg::Group* mParentNode; Resource::ResourceSystem* mResourceSystem; bool mForceBaseToZero; + ESM::Position mPositionOverride; + int mScaleOverride; + int mOverrideFlags; /// Not implemented Object (const Object&); @@ -116,6 +133,27 @@ namespace CSVRender std::string getReferenceableId() const; osg::ref_ptr getTag() const; + + /// Is there currently an editing operation running on this object? + bool isEdited() const; + + void setEdited (int flags); + + ESM::Position getPosition() const; + + float getScale() const; + + /// Set override position. + void setPosition (const float position[3]); + + /// Set override rotation + void setRotation (const float rotation[3]); + + /// Set override scale + void setScale (float scale); + + /// Apply override changes via command and end edit mode + void apply (QUndoStack& undoStack); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index d71446d0b..cbba9ef5d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -555,6 +555,23 @@ std::vector > CSVRender::PagedWorldspaceWidget: return result; } +std::vector > CSVRender::PagedWorldspaceWidget::getEdited ( + unsigned int elementMask) const +{ + std::vector > result; + + for (std::map::const_iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + { + std::vector > cellResult = + iter->second->getEdited (elementMask); + + result.insert (result.end(), cellResult.begin(), cellResult.end()); + } + + return result; +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 419a2a46a..baec96b03 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -112,6 +112,9 @@ namespace CSVRender virtual std::vector > getSelection (unsigned int elementMask) const; + virtual std::vector > getEdited (unsigned int elementMask) + const; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index ba31c9b8b..55d9c8195 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -120,6 +120,12 @@ bool RenderWidget::eventFilter(QObject* obj, QEvent* event) return QObject::eventFilter(obj, event); } +osg::Camera *RenderWidget::getCamera() +{ + return mView->getCamera(); +} + + // -------------------------------------------------- CompositeViewer::CompositeViewer() diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 63da01a45..07a7d7600 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -21,6 +21,7 @@ namespace Resource namespace osg { class Group; + class Camera; } namespace CSVWidget @@ -47,6 +48,8 @@ namespace CSVRender bool eventFilter(QObject *, QEvent *); + osg::Camera *getCamera(); + protected: osg::ref_ptr mView; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 8d65c3694..4a7723d2f 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -131,6 +131,12 @@ std::vector > CSVRender::UnpagedWorldspaceWidge return mCell->getSelection (elementMask); } +std::vector > CSVRender::UnpagedWorldspaceWidget::getEdited ( + unsigned int elementMask) const +{ + return mCell->getEdited (elementMask); +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index a4c517948..f7b583f3d 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -60,6 +60,9 @@ namespace CSVRender virtual std::vector > getSelection (unsigned int elementMask) const; + virtual std::vector > getEdited (unsigned int elementMask) + const; + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index ac6426b42..67f585e03 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -152,6 +152,9 @@ namespace CSVRender virtual std::vector > getSelection (unsigned int elementMask) const = 0; + virtual std::vector > getEdited (unsigned int elementMask) + const = 0; + protected: /// Visual elements in a scene From 22e717161a3d4e9ebb1cf556ba2b4154237f7532 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 21 Feb 2016 15:19:31 +0100 Subject: [PATCH 02/19] split object base node into two node (one for position, one for everything else) --- apps/opencs/view/render/object.cpp | 21 ++++++++++++--------- apps/opencs/view/render/object.hpp | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 1e2fd2640..1833d7340 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -135,7 +135,7 @@ void CSVRender::Object::adjustTransform() ESM::Position position = getPosition(); // position - mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(position.pos[0], position.pos[1], position.pos[2])); + mRootNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(position.pos[0], position.pos[1], position.pos[2])); // orientation osg::Quat xr (-position.rot[0], osg::Vec3f(1,0,0)); @@ -161,6 +161,8 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, : mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero), mScaleOverride (1), mOverrideFlags (0) { + mRootNode = new osg::PositionAttitudeTransform; + mBaseNode = new osg::PositionAttitudeTransform; mBaseNode->addCullCallback(new SceneUtil::LightListCallback); @@ -169,9 +171,11 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, mBaseNode->setUserData(new ObjectTag(this)); - parentNode->addChild(mBaseNode); + mRootNode->addChild (mBaseNode); + + parentNode->addChild (mRootNode); - mBaseNode->setNodeMask(Mask_Reference); + mRootNode->setNodeMask(Mask_Reference); if (referenceable) { @@ -191,20 +195,19 @@ CSVRender::Object::~Object() { clear(); - mParentNode->removeChild(mBaseNode); - mParentNode->removeChild(mOutline); + mParentNode->removeChild (mRootNode); } void CSVRender::Object::setSelected(bool selected) { mSelected = selected; - mParentNode->removeChild(mOutline); - mParentNode->removeChild(mBaseNode); + mRootNode->removeChild(mOutline); + mRootNode->removeChild(mBaseNode); if (selected) - mParentNode->addChild(mOutline); + mRootNode->addChild(mOutline); else - mParentNode->addChild(mBaseNode); + mRootNode->addChild(mBaseNode); } bool CSVRender::Object::getSelected() const diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index accdb93e0..4b528b59f 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -70,6 +70,7 @@ namespace CSVRender CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; + osg::ref_ptr mRootNode; osg::ref_ptr mBaseNode; osg::ref_ptr mOutline; bool mSelected; From 1c24cba46a266499b136e55ce5c351f0eb7c0acd Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Feb 2016 15:13:31 +0100 Subject: [PATCH 03/19] Don't use multiple parental node paths. --- apps/opencs/view/render/object.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 1833d7340..0f135459b 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -167,7 +167,6 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, mBaseNode->addCullCallback(new SceneUtil::LightListCallback); mOutline = new osgFX::Scribe; - mOutline->addChild(mBaseNode); mBaseNode->setUserData(new ObjectTag(this)); @@ -202,10 +201,14 @@ void CSVRender::Object::setSelected(bool selected) { mSelected = selected; + mOutline->removeChild(mBaseNode); mRootNode->removeChild(mOutline); mRootNode->removeChild(mBaseNode); if (selected) + { + mOutline->addChild(mBaseNode); mRootNode->addChild(mOutline); + } else mRootNode->addChild(mBaseNode); } From a19ac722151b18bef3199a30180a2bba33e226e3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 1 Mar 2016 15:48:34 +0100 Subject: [PATCH 04/19] render marker --- apps/opencs/view/render/cell.cpp | 21 ++- apps/opencs/view/render/cell.hpp | 4 + apps/opencs/view/render/editmode.cpp | 5 + apps/opencs/view/render/editmode.hpp | 3 + apps/opencs/view/render/instancemode.cpp | 22 +++ apps/opencs/view/render/instancemode.hpp | 8 + apps/opencs/view/render/object.cpp | 157 +++++++++++++++++- apps/opencs/view/render/object.hpp | 21 +++ .../view/render/pagedworldspacewidget.cpp | 16 +- .../view/render/pagedworldspacewidget.hpp | 2 + .../view/render/unpagedworldspacewidget.cpp | 5 + .../view/render/unpagedworldspacewidget.hpp | 2 + apps/opencs/view/render/worldspacewidget.cpp | 5 + apps/opencs/view/render/worldspacewidget.hpp | 5 + apps/opencs/view/widget/scenetoolmode.cpp | 5 + apps/opencs/view/widget/scenetoolmode.hpp | 3 + 16 files changed, 278 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index f82ef3150..6e47d3594 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -51,7 +51,12 @@ bool CSVRender::Cell::addObjects (int start, int end) { std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); - mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false))); + std::auto_ptr object (new Object (mData, mCellNode, id, false)); + + if (mSubModeElementMask & Mask_Reference) + object->setSubMode (mSubMode); + + mObjects.insert (std::make_pair (id, object.release())); modified = true; } } @@ -61,7 +66,8 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), + mSubModeElementMask (0) { std::pair result = CSMWorld::CellCoordinates::fromId (id); @@ -359,3 +365,14 @@ std::vector > CSVRender::Cell::getEdited (unsig return result; } + +void CSVRender::Cell::setSubMode (int subMode, unsigned int elementMask) +{ + mSubMode = subMode; + mSubModeElementMask = elementMask; + + if (elementMask & Mask_Reference) + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + iter->second->setSubMode (subMode); +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 6cdafbf36..21949992d 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -45,6 +45,8 @@ namespace CSVRender std::auto_ptr mCellArrows[4]; std::auto_ptr mCellMarker; bool mDeleted; + int mSubMode; + unsigned int mSubModeElementMask; /// Ignored if cell does not have an object with the given ID. /// @@ -118,6 +120,8 @@ namespace CSVRender std::vector > getSelection (unsigned int elementMask) const; std::vector > getEdited (unsigned int elementMask) const; + + void setSubMode (int subMode, unsigned int elementMask); }; } diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index b325e31fb..be264afc7 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -70,3 +70,8 @@ void CSVRender::EditMode::dragEnterEvent (QDragEnterEvent *event) {} void CSVRender::EditMode::dropEvent (QDropEvent* event) {} void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {} + +int CSVRender::EditMode::getSubMode() const +{ + return -1; +} diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 3ba97cf00..f5cef1be2 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -92,6 +92,9 @@ namespace CSVRender /// Default-implementation: ignored virtual void dragMoveEvent (QDragMoveEvent *event); + + /// Default: return -1 + virtual int getSubMode() const; }; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index f2fb552b0..24e307dc5 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -20,6 +20,11 @@ #include "instanceselectionmode.hpp" #include "instancemovemode.hpp" +int CSVRender::InstanceMode::getSubModeFromId (const std::string& id) const +{ + return id=="move" ? 0 : (id=="rotate" ? 1 : 2); +} + CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None) @@ -44,6 +49,9 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) "
  • Use secondary edit to scale instances along the grid
  • " "" "Not implemented yet"); + + connect (mSubMode, SIGNAL (modeChanged (const std::string&)), + this, SLOT (subModeChanged (const std::string&))); } if (!mSelectionMode) @@ -55,6 +63,10 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) toolbar->addTool (mSubMode); toolbar->addTool (mSelectionMode); + + std::string subMode = mSubMode->getCurrentId(); + + getWorldspaceWidget().setSubMode (getSubModeFromId (subMode), Mask_Reference); } void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) @@ -402,3 +414,13 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) event->accept(); } } + +int CSVRender::InstanceMode::getSubMode() const +{ + return mSubMode ? getSubModeFromId (mSubMode->getCurrentId()) : 0; +} + +void CSVRender::InstanceMode::subModeChanged (const std::string& id) +{ + getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference); +} diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 7662a0cdc..5beec5643 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -27,6 +27,8 @@ namespace CSVRender InstanceSelectionMode *mSelectionMode; DragMode mDragMode; + int getSubModeFromId (const std::string& id) const; + public: InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); @@ -56,6 +58,12 @@ namespace CSVRender virtual void dragEnterEvent (QDragEnterEvent *event); virtual void dropEvent (QDropEvent* event); + + virtual int getSubMode() const; + + private slots: + + void subModeChanged (const std::string& id); }; } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 0f135459b..b7efa5058 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include @@ -52,6 +54,11 @@ QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const } +CSVRender::ObjectMarkerTag::ObjectMarkerTag (Object* object, int axis) +: TagBase (Mask_Reference), mObject (object), mAxis (axis) +{} + + void CSVRender::Object::clear() { } @@ -156,10 +163,144 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord (mReferenceId).get(); } +void CSVRender::Object::updateMarker() +{ + for (int i=0; i<3; ++i) + { + if (mMarker[i]) + { + mRootNode->removeChild (mMarker[i]); + mMarker[i] = osg::ref_ptr(); + } + + if (mSelected) + { + if (mSubMode==0) + { + mMarker[i] = makeMarker (i); + mMarker[i]->setUserData(new ObjectMarkerTag (this, i)); + + mRootNode->addChild (mMarker[i]); + } + } + } +} + +osg::ref_ptr CSVRender::Object::makeMarker (int axis) +{ + osg::ref_ptr geometry (new osg::Geometry); + + const float shaftWidth = 10; + const float shaftBaseLength = 50; + const float headWidth = 30; + const float headLength = 30; + + float shaftLength = shaftBaseLength + mBaseNode->getBound().radius(); + + // shaft + osg::Vec3Array *vertices = new osg::Vec3Array; + + for (int i=0; i<2; ++i) + { + float length = i ? shaftLength : 0; + + vertices->push_back (getMarkerPosition (-shaftWidth/2, -shaftWidth/2, length, axis)); + vertices->push_back (getMarkerPosition (-shaftWidth/2, shaftWidth/2, length, axis)); + vertices->push_back (getMarkerPosition (shaftWidth/2, shaftWidth/2, length, axis)); + vertices->push_back (getMarkerPosition (shaftWidth/2, -shaftWidth/2, length, axis)); + } + + // head backside + vertices->push_back (getMarkerPosition (-headWidth/2, -headWidth/2, shaftLength, axis)); + vertices->push_back (getMarkerPosition (-headWidth/2, headWidth/2, shaftLength, axis)); + vertices->push_back (getMarkerPosition (headWidth/2, headWidth/2, shaftLength, axis)); + vertices->push_back (getMarkerPosition (headWidth/2, -headWidth/2, shaftLength, axis)); + + // head + vertices->push_back (getMarkerPosition (0, 0, shaftLength+headLength, axis)); + + geometry->setVertexArray (vertices); + + osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + + // shaft + for (int i=0; i<4; ++i) + { + int i2 = i==3 ? 0 : i+1; + primitives->push_back (i); + primitives->push_back (4+i); + primitives->push_back (i2); + + primitives->push_back (4+i); + primitives->push_back (4+i2); + primitives->push_back (i2); + } + + // cap + primitives->push_back (0); + primitives->push_back (1); + primitives->push_back (2); + + primitives->push_back (2); + primitives->push_back (3); + primitives->push_back (0); + + // head, backside + primitives->push_back (0+8); + primitives->push_back (1+8); + primitives->push_back (2+8); + + primitives->push_back (2+8); + primitives->push_back (3+8); + primitives->push_back (0+8); + + for (int i=0; i<4; ++i) + { + primitives->push_back (12); + primitives->push_back (8+(i==3 ? 0 : i+1)); + primitives->push_back (8+i); + } + + geometry->addPrimitiveSet (primitives); + + osg::Vec4Array *colours = new osg::Vec4Array; + + for (int i=0; i<8; ++i) + colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, + axis==2 ? 1.0f : 0.2f, 1.0f)); + + for (int i=8; i<8+4+1; ++i) + colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.0f, axis==1 ? 1.0f : 0.0f, + axis==2 ? 1.0f : 0.0f, 1.0f)); + + geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX); + + geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable (geometry); + + return geode; +} + +osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis) +{ + switch (axis) + { + case 0: return osg::Vec3f (x, y, z); + case 1: return osg::Vec3f (z, x, y); + case 2: return osg::Vec3f (y, z, x); + + default: + + throw std::logic_error ("invalid axis for marker geometry"); + } +} + CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) : mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero), - mScaleOverride (1), mOverrideFlags (0) + mScaleOverride (1), mOverrideFlags (0), mSubMode (-1) { mRootNode = new osg::PositionAttitudeTransform; @@ -188,6 +329,7 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, adjustTransform(); update(); + updateMarker(); } CSVRender::Object::~Object() @@ -211,6 +353,8 @@ void CSVRender::Object::setSelected(bool selected) } else mRootNode->addChild(mBaseNode); + + updateMarker(); } bool CSVRender::Object::getSelected() const @@ -229,6 +373,7 @@ bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, { adjustTransform(); update(); + updateMarker(); return true; } @@ -279,6 +424,7 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, references.getData (index, columnIndex).toString().toUtf8().constData(); update(); + updateMarker(); } return true; @@ -419,3 +565,12 @@ void CSVRender::Object::apply (QUndoStack& undoStack) mOverrideFlags = 0; } + +void CSVRender::Object::setSubMode (int subMode) +{ + if (subMode!=mSubMode) + { + mSubMode = subMode; + updateMarker(); + } +} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 4b528b59f..9cd0a8d67 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -19,6 +19,8 @@ namespace osg { class PositionAttitudeTransform; class Group; + class Node; + class Geode; } namespace osgFX @@ -53,6 +55,15 @@ namespace CSVRender virtual QString getToolTip (bool hideBasics) const; }; + class ObjectMarkerTag : public TagBase + { + public: + + ObjectMarkerTag (Object* object, int axis); + + Object* mObject; + int mAxis; + }; class Object { @@ -80,6 +91,8 @@ namespace CSVRender ESM::Position mPositionOverride; int mScaleOverride; int mOverrideFlags; + osg::ref_ptr mMarker[3]; + int mSubMode; /// Not implemented Object (const Object&); @@ -100,6 +113,12 @@ namespace CSVRender /// Throws an exception if *this was constructed with referenceable const CSMWorld::CellRef& getReference() const; + void updateMarker(); + + osg::ref_ptr makeMarker (int axis); + + osg::Vec3f getMarkerPosition (float x, float y, float z, int axis); + public: Object (CSMWorld::Data& data, osg::Group *cellNode, @@ -155,6 +174,8 @@ namespace CSVRender /// Apply override changes via command and end edit mode void apply (QUndoStack& undoStack); + + void setSubMode (int subMode); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index cbba9ef5d..68c8949f3 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -309,10 +309,13 @@ void CSVRender::PagedWorldspaceWidget::addCellToScene ( bool deleted = index==-1 || cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; - Cell *cell = new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), - deleted); + std::auto_ptr cell ( + new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), + deleted)); + EditMode *editMode = getEditMode(); + cell->setSubMode (editMode->getSubMode(), editMode->getInteractionMask()); - mCells.insert (std::make_pair (coordinates, cell)); + mCells.insert (std::make_pair (coordinates, cell.release())); } void CSVRender::PagedWorldspaceWidget::removeCellFromScene ( @@ -572,6 +575,13 @@ std::vector > CSVRender::PagedWorldspaceWidget: return result; } +void CSVRender::PagedWorldspaceWidget::setSubMode (int subMode, unsigned int elementMask) +{ + for (std::map::const_iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + iter->second->setSubMode (subMode, elementMask); +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index baec96b03..c77c3ebd2 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -115,6 +115,8 @@ namespace CSVRender virtual std::vector > getEdited (unsigned int elementMask) const; + virtual void setSubMode (int subMode, unsigned int elementMask); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 4a7723d2f..60aeeb4d8 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -137,6 +137,11 @@ std::vector > CSVRender::UnpagedWorldspaceWidge return mCell->getEdited (elementMask); } +void CSVRender::UnpagedWorldspaceWidget::setSubMode (int subMode, unsigned int elementMask) +{ + mCell->setSubMode (subMode, elementMask); +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index f7b583f3d..a3718d9f3 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -63,6 +63,8 @@ namespace CSVRender virtual std::vector > getEdited (unsigned int elementMask) const; + virtual void setSubMode (int subMode, unsigned int elementMask); + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 6ba6e9543..83feb0be3 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -761,3 +761,8 @@ void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, c else if (button=="s-select") editMode.secondarySelectPressed (tag); } + +CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode() +{ + return dynamic_cast (mEditMode->getCurrent()); +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 67f585e03..eee618ed1 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -35,6 +35,7 @@ namespace CSVRender { class TagBase; class CellArrow; + class EditMode; class WorldspaceWidget : public SceneWidget { @@ -155,6 +156,8 @@ namespace CSVRender virtual std::vector > getEdited (unsigned int elementMask) const = 0; + virtual void setSubMode (int subMode, unsigned int elementMask) = 0; + protected: /// Visual elements in a scene @@ -184,6 +187,8 @@ namespace CSVRender virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button, bool shift); + EditMode *getEditMode(); + private: void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 125f4ac79..08e8ad5a4 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -96,6 +96,11 @@ CSVWidget::ModeButton *CSVWidget::SceneToolMode::getCurrent() return mCurrent; } +std::string CSVWidget::SceneToolMode::getCurrentId() const +{ + return mButtons.find (mCurrent)->second; +} + void CSVWidget::SceneToolMode::selected() { std::map::const_iterator iter = diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 3aa8e6799..c274d84ab 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -56,6 +56,9 @@ namespace CSVWidget /// Will return a 0-pointer only if the mode does not have any buttons yet. ModeButton *getCurrent(); + /// Must not be called if there aren't any buttons yet. + std::string getCurrentId() const; + signals: void modeChanged (const std::string& id); From c2a8be9048fb7982bed7c90b23369e0d33e0e0c7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Mar 2016 12:00:05 +0100 Subject: [PATCH 05/19] confine move marker drags to a single axis --- apps/opencs/view/render/instancemode.cpp | 53 ++++++++++++++++-------- apps/opencs/view/render/instancemode.hpp | 4 +- apps/opencs/view/render/object.cpp | 8 ++-- apps/opencs/view/render/object.hpp | 3 +- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 24e307dc5..f4f38dd34 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -27,7 +27,7 @@ int CSVRender::InstanceMode::getSubModeFromId (const std::string& id) const CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", - parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None) + parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None), mDragAxis (0) { } @@ -151,8 +151,6 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr tag) if (selection.empty()) return false; - // \todo check for sub-mode - for (std::vector >::iterator iter (selection.begin()); iter!=selection.end(); ++iter) { @@ -162,7 +160,15 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr tag) } } - mDragMode = DragMode_Move; + // \todo check for sub-mode + + if (CSVRender::ObjectMarkerTag *objectTag = dynamic_cast (tag.get())) + { + mDragAxis = objectTag->mAxis; + mDragMode = DragMode_MoveAxis; + } + else + mDragMode = DragMode_Move; return true; } @@ -175,23 +181,33 @@ bool CSVRender::InstanceMode::secondaryEditStartDrag (osg::ref_ptr tag) void CSVRender::InstanceMode::drag (int diffX, int diffY, double speedFactor) { + osg::Vec3f eye; + osg::Vec3f centre; + osg::Vec3f up; + + getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up); + + osg::Vec3f offset; + + if (diffY) + offset += up * diffY * speedFactor; + + if (diffX) + offset += ((centre-eye) ^ up) * diffX * speedFactor; + switch (mDragMode) { - case DragMode_Move: + case DragMode_MoveAxis: { - osg::Vec3f eye; - osg::Vec3f centre; - osg::Vec3f up; - - getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up); + for (int i=0; i<3; ++i) + if (i!=mDragAxis) + offset[i] = 0; - osg::Vec3f offset; - - if (diffY) - offset += up * diffY * speedFactor; + // Fall through + } - if (diffX) - offset += ((centre-eye) ^ up) * diffX * speedFactor; + case DragMode_Move: + { std::vector > selection = getWorldspaceWidget().getEdited (Mask_Reference); @@ -226,7 +242,10 @@ void CSVRender::InstanceMode::dragCompleted() switch (mDragMode) { - case DragMode_Move: description = "Move Instances"; break; + case DragMode_Move: + case DragMode_MoveAxis: + + description = "Move Instances"; break; case DragMode_None: break; } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 5beec5643..e65d8146c 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -19,13 +19,15 @@ namespace CSVRender enum DragMode { DragMode_None, - DragMode_Move + DragMode_Move, + DragMode_MoveAxis }; CSVWidget::SceneToolMode *mSubMode; InstanceSelectionMode *mSelectionMode; DragMode mDragMode; + int mDragAxis; int getSubModeFromId (const std::string& id) const; diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index b7efa5058..1771acdf9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -55,7 +55,7 @@ QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const CSVRender::ObjectMarkerTag::ObjectMarkerTag (Object* object, int axis) -: TagBase (Mask_Reference), mObject (object), mAxis (axis) +: ObjectTag (object), mAxis (axis) {} @@ -287,9 +287,9 @@ osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int { switch (axis) { - case 0: return osg::Vec3f (x, y, z); - case 1: return osg::Vec3f (z, x, y); - case 2: return osg::Vec3f (y, z, x); + case 2: return osg::Vec3f (x, y, z); + case 0: return osg::Vec3f (z, x, y); + case 1: return osg::Vec3f (y, z, x); default: diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 9cd0a8d67..12cb0c78b 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -55,13 +55,12 @@ namespace CSVRender virtual QString getToolTip (bool hideBasics) const; }; - class ObjectMarkerTag : public TagBase + class ObjectMarkerTag : public ObjectTag { public: ObjectMarkerTag (Object* object, int axis); - Object* mObject; int mAxis; }; From d57021b23c682598f71a6922ca9bebe0ea6d56a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Mar 2016 12:02:45 +0100 Subject: [PATCH 06/19] some code simplification --- apps/opencs/view/render/instancemode.cpp | 25 +++++++++--------------- apps/opencs/view/render/instancemode.hpp | 4 +--- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index f4f38dd34..91923e004 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -27,7 +27,7 @@ int CSVRender::InstanceMode::getSubModeFromId (const std::string& id) const CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", - parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None), mDragAxis (0) + parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None), mDragAxis (-1) { } @@ -165,10 +165,11 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr tag) if (CSVRender::ObjectMarkerTag *objectTag = dynamic_cast (tag.get())) { mDragAxis = objectTag->mAxis; - mDragMode = DragMode_MoveAxis; } else - mDragMode = DragMode_Move; + mDragAxis = -1; + + mDragMode = DragMode_Move; return true; } @@ -197,17 +198,12 @@ void CSVRender::InstanceMode::drag (int diffX, int diffY, double speedFactor) switch (mDragMode) { - case DragMode_MoveAxis: - { - for (int i=0; i<3; ++i) - if (i!=mDragAxis) - offset[i] = 0; - - // Fall through - } - case DragMode_Move: { + if (mDragAxis!=-1) + for (int i=0; i<3; ++i) + if (i!=mDragAxis) + offset[i] = 0; std::vector > selection = getWorldspaceWidget().getEdited (Mask_Reference); @@ -242,10 +238,7 @@ void CSVRender::InstanceMode::dragCompleted() switch (mDragMode) { - case DragMode_Move: - case DragMode_MoveAxis: - - description = "Move Instances"; break; + case DragMode_Move: description = "Move Instances"; break; case DragMode_None: break; } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index e65d8146c..5a744ea88 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -19,9 +19,7 @@ namespace CSVRender enum DragMode { DragMode_None, - DragMode_Move, - DragMode_MoveAxis - + DragMode_Move }; CSVWidget::SceneToolMode *mSubMode; From 1240e0c716fee64a072affaabaad3a42c84037e8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Mar 2016 15:19:26 +0100 Subject: [PATCH 07/19] cancel instance move on drag abort --- apps/opencs/view/render/cell.cpp | 8 ++++++++ apps/opencs/view/render/cell.hpp | 4 ++++ apps/opencs/view/render/instancemode.cpp | 6 ++++++ apps/opencs/view/render/instancemode.hpp | 4 ++++ apps/opencs/view/render/object.cpp | 7 +++++++ apps/opencs/view/render/object.hpp | 4 ++++ apps/opencs/view/render/pagedworldspacewidget.cpp | 7 +++++++ apps/opencs/view/render/pagedworldspacewidget.hpp | 3 +++ apps/opencs/view/render/unpagedworldspacewidget.cpp | 5 +++++ apps/opencs/view/render/unpagedworldspacewidget.hpp | 3 +++ apps/opencs/view/render/worldspacewidget.hpp | 3 +++ 11 files changed, 54 insertions(+) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 6e47d3594..782a37796 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -376,3 +376,11 @@ void CSVRender::Cell::setSubMode (int subMode, unsigned int elementMask) iter!=mObjects.end(); ++iter) iter->second->setSubMode (subMode); } + +void CSVRender::Cell::reset (unsigned int elementMask) +{ + if (elementMask & Mask_Reference) + for (std::map::const_iterator iter (mObjects.begin()); + iter!=mObjects.end(); ++iter) + iter->second->reset(); +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 21949992d..4af5e4a25 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -122,6 +122,10 @@ namespace CSVRender std::vector > getEdited (unsigned int elementMask) const; void setSubMode (int subMode, unsigned int elementMask); + + /// Erase all overrides and restore the visual representation of the cell to its + /// true state. + void reset (unsigned int elementMask); }; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 91923e004..332753811 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -259,6 +259,12 @@ void CSVRender::InstanceMode::dragCompleted() mDragMode = DragMode_None; } +void CSVRender::InstanceMode::dragAborted() +{ + getWorldspaceWidget().reset (Mask_Reference); + mDragMode = DragMode_None; +} + void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor) { if (mDragMode==DragMode_Move) diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 5a744ea88..94bdbb08f 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -53,6 +53,10 @@ namespace CSVRender virtual void dragCompleted(); + /// \note dragAborted will not be called, if the drag is aborted via changing + /// editing mode + virtual void dragAborted(); + virtual void dragWheel (int diff, double speedFactor); virtual void dragEnterEvent (QDragEnterEvent *event); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 1771acdf9..6ca751ba5 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -574,3 +574,10 @@ void CSVRender::Object::setSubMode (int subMode) updateMarker(); } } + +void CSVRender::Object::reset() +{ + mOverrideFlags = 0; + adjustTransform(); + updateMarker(); +} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 12cb0c78b..a5cc141a0 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -175,6 +175,10 @@ namespace CSVRender void apply (QUndoStack& undoStack); void setSubMode (int subMode); + + /// Erase all overrides and restore the visual representation of the object to its + /// true state. + void reset(); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 68c8949f3..0ca3ff706 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -582,6 +582,13 @@ void CSVRender::PagedWorldspaceWidget::setSubMode (int subMode, unsigned int ele iter->second->setSubMode (subMode, elementMask); } +void CSVRender::PagedWorldspaceWidget::reset (unsigned int elementMask) +{ + for (std::map::const_iterator iter = mCells.begin(); + iter!=mCells.end(); ++iter) + iter->second->reset (elementMask); +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index c77c3ebd2..fe533be2d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -117,6 +117,9 @@ namespace CSVRender virtual void setSubMode (int subMode, unsigned int elementMask); + /// Erase all overrides and restore the visual representation to its true state. + virtual void reset (unsigned int elementMask); + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 60aeeb4d8..16c28cf93 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -142,6 +142,11 @@ void CSVRender::UnpagedWorldspaceWidget::setSubMode (int subMode, unsigned int mCell->setSubMode (subMode, elementMask); } +void CSVRender::UnpagedWorldspaceWidget::reset (unsigned int elementMask) +{ + mCell->reset (elementMask); +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index a3718d9f3..c5bfd22e6 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -65,6 +65,9 @@ namespace CSVRender virtual void setSubMode (int subMode, unsigned int elementMask); + /// Erase all overrides and restore the visual representation to its true state. + virtual void reset (unsigned int elementMask); + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index eee618ed1..55b0f1f55 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -158,6 +158,9 @@ namespace CSVRender virtual void setSubMode (int subMode, unsigned int elementMask) = 0; + /// Erase all overrides and restore the visual representation to its true state. + virtual void reset (unsigned int elementMask) = 0; + protected: /// Visual elements in a scene From 25effc4222e0b050abc3b95d16479faef77d06b5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Mar 2016 15:30:28 +0100 Subject: [PATCH 08/19] cancel instance move on sub mode change --- apps/opencs/view/render/instancemode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 332753811..bfc233d29 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -440,5 +440,6 @@ int CSVRender::InstanceMode::getSubMode() const void CSVRender::InstanceMode::subModeChanged (const std::string& id) { + getWorldspaceWidget().reset (Mask_Reference); getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference); } From 1726393963fc4bff781eb6a43460647bae2a3fe2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Mar 2016 15:31:50 +0100 Subject: [PATCH 09/19] cancel instance move on edit mode change --- apps/opencs/view/render/instancemode.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index bfc233d29..d31327137 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -71,6 +71,8 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) { + getWorldspaceWidget().reset (Mask_Reference); + if (mSelectionMode) { toolbar->removeTool (mSelectionMode); From dd564daba05f6cd7595630be5661e2198b88bb82 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Mar 2016 16:24:02 +0100 Subject: [PATCH 10/19] do not start move drags while the document is locked for editing --- apps/opencs/view/render/instancemode.cpp | 13 +++++++++++-- apps/opencs/view/render/instancemode.hpp | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index d31327137..e8a7d95d7 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -27,7 +27,8 @@ int CSVRender::InstanceMode::getSubModeFromId (const std::string& id) const CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", - parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None), mDragAxis (-1) + parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None), mDragAxis (-1), + mLocked (false) { } @@ -90,6 +91,12 @@ void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) EditMode::deactivate (toolbar); } +void CSVRender::InstanceMode::setEditLock (bool locked) +{ + mLocked = locked; + +} + void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) { if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) @@ -134,7 +141,7 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr tag) { - if (mDragMode!=DragMode_None) + if (mDragMode!=DragMode_None || mLocked) return false; if (tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) @@ -178,6 +185,8 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr tag) bool CSVRender::InstanceMode::secondaryEditStartDrag (osg::ref_ptr tag) { + if (mLocked) + return false; return false; } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 94bdbb08f..20b685916 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -26,6 +26,7 @@ namespace CSVRender InstanceSelectionMode *mSelectionMode; DragMode mDragMode; int mDragAxis; + bool mLocked; int getSubModeFromId (const std::string& id) const; @@ -37,6 +38,8 @@ namespace CSVRender virtual void deactivate (CSVWidget::SceneToolbar *toolbar); + virtual void setEditLock (bool locked); + virtual void primaryEditPressed (osg::ref_ptr tag); virtual void secondaryEditPressed (osg::ref_ptr tag); From b1fb64bf685cf74c5548fb5d18b7c260de1d4a5a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Mar 2016 16:25:30 +0100 Subject: [PATCH 11/19] added missing drag mode resets --- apps/opencs/view/render/instancemode.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index e8a7d95d7..74df6740e 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -72,6 +72,7 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) { + mDragMode = DragMode_None; getWorldspaceWidget().reset (Mask_Reference); if (mSelectionMode) @@ -451,6 +452,7 @@ int CSVRender::InstanceMode::getSubMode() const void CSVRender::InstanceMode::subModeChanged (const std::string& id) { + mDragMode = DragMode_None; getWorldspaceWidget().reset (Mask_Reference); getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference); } From 70745487f388851ac41204d81f5238e54979bfa2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Mar 2016 10:44:46 +0100 Subject: [PATCH 12/19] cancel instance move on editing lock becoming active --- apps/opencs/view/render/instancemode.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 74df6740e..0c4da4963 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -96,6 +96,11 @@ void CSVRender::InstanceMode::setEditLock (bool locked) { mLocked = locked; + if (mLocked) + { + mDragMode = DragMode_None; + getWorldspaceWidget().reset (Mask_Reference); + } } void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) From 51a4e3fa7d980349516100184e455d4449e59435 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Mar 2016 10:56:54 +0100 Subject: [PATCH 13/19] properly abort drags from outside the worldspace widget (code was leaving unclean dragging flags behind) --- apps/opencs/view/render/instancemode.cpp | 8 ++------ apps/opencs/view/render/worldspacewidget.cpp | 19 ++++++++++++------- apps/opencs/view/render/worldspacewidget.hpp | 6 ++++++ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 0c4da4963..80529d80d 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -97,10 +97,7 @@ void CSVRender::InstanceMode::setEditLock (bool locked) mLocked = locked; if (mLocked) - { - mDragMode = DragMode_None; - getWorldspaceWidget().reset (Mask_Reference); - } + getWorldspaceWidget().abortDrag(); } void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr tag) @@ -457,7 +454,6 @@ int CSVRender::InstanceMode::getSubMode() const void CSVRender::InstanceMode::subModeChanged (const std::string& id) { - mDragMode = DragMode_None; - getWorldspaceWidget().reset (Mask_Reference); + getWorldspaceWidget().abortDrag(); getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference); } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 83feb0be3..aea23ba7e 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -364,6 +364,17 @@ osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& loca return start + direction * CSMPrefs::get()["Scene Drops"]["distance"].toInt(); } +void CSVRender::WorldspaceWidget::abortDrag() +{ + if (mDragging) + { + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + editMode.dragAborted(); + mDragging = false; + } +} + void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); @@ -736,13 +747,7 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) { if(event->key() == Qt::Key_Escape) { - if (mDragging) - { - EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - - editMode.dragAborted(); - mDragging = false; - } + abortDrag(); } else RenderWidget::keyPressEvent(event); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 55b0f1f55..4c9c0c31e 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -161,6 +161,12 @@ namespace CSVRender /// Erase all overrides and restore the visual representation to its true state. virtual void reset (unsigned int elementMask) = 0; + /// \note Drags will be automatically aborted when the aborting is triggered + /// (either explicitly or implicitly) from within this class. This function only + /// needs to be called, when the drag abort is triggered externally (e.g. from + /// an edit mode). + void abortDrag(); + protected: /// Visual elements in a scene From a63453846b78bde8a7a7f5f82f77ce6b192eb221 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Mar 2016 11:14:08 +0100 Subject: [PATCH 14/19] properly clear drag mode at the end of a drag --- apps/opencs/view/render/worldspacewidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index aea23ba7e..df5790473 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -372,6 +372,7 @@ void CSVRender::WorldspaceWidget::abortDrag() editMode.dragAborted(); mDragging = false; + mDragMode.clear(); } } @@ -584,6 +585,7 @@ void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) { dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); mDragging = false; + mDragMode.clear(); } void CSVRender::WorldspaceWidget::showToolTip() From b5005f7812bd61e1d36b04afae625b74619d36b7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Mar 2016 11:41:42 +0100 Subject: [PATCH 15/19] keep sub mode over mode changes --- apps/opencs/view/render/instancemode.cpp | 7 ++- apps/opencs/view/render/instancemode.hpp | 1 + apps/opencs/view/widget/scenetoolmode.cpp | 52 +++++++++++++++-------- apps/opencs/view/widget/scenetoolmode.hpp | 5 +++ 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 80529d80d..6fa8ddaa8 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -27,8 +27,8 @@ int CSVRender::InstanceMode::getSubModeFromId (const std::string& id) const CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", - parent), mSubMode (0), mSelectionMode (0), mDragMode (DragMode_None), mDragAxis (-1), - mLocked (false) + parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None), + mDragAxis (-1), mLocked (false) { } @@ -51,6 +51,8 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) "" "Not implemented yet"); + mSubMode->setButton (mSubModeId); + connect (mSubMode, SIGNAL (modeChanged (const std::string&)), this, SLOT (subModeChanged (const std::string&))); } @@ -454,6 +456,7 @@ int CSVRender::InstanceMode::getSubMode() const void CSVRender::InstanceMode::subModeChanged (const std::string& id) { + mSubModeId = id; getWorldspaceWidget().abortDrag(); getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference); } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 20b685916..db7fdaa96 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -23,6 +23,7 @@ namespace CSVRender }; CSVWidget::SceneToolMode *mSubMode; + std::string mSubModeId; InstanceSelectionMode *mSelectionMode; DragMode mDragMode; int mDragAxis; diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 08e8ad5a4..c91890c69 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -38,6 +38,27 @@ void CSVWidget::SceneToolMode::adjustToolTip (const ModeButton *activeMode) setToolTip (toolTip); } +void CSVWidget::SceneToolMode::setButton (std::map::iterator iter) +{ + for (std::map::const_iterator iter2 = mButtons.begin(); + iter2!=mButtons.end(); ++iter2) + iter2->first->setChecked (iter2==iter); + + setIcon (iter->first->icon()); + adjustToolTip (iter->first); + + if (mCurrent!=iter->first) + { + if (mCurrent) + mCurrent->deactivate (mToolbar); + + mCurrent = iter->first; + mCurrent->activate (mToolbar); + } + + emit modeChanged (iter->second); +} + CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent, const QString& toolTip) : SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()), mToolTip (toolTip), mFirst (0), mCurrent (0), mToolbar (parent) @@ -101,9 +122,20 @@ std::string CSVWidget::SceneToolMode::getCurrentId() const return mButtons.find (mCurrent)->second; } +void CSVWidget::SceneToolMode::setButton (const std::string& id) +{ + for (std::map::iterator iter = mButtons.begin(); + iter!=mButtons.end(); ++iter) + if (iter->second==id) + { + setButton (iter); + break; + } +} + void CSVWidget::SceneToolMode::selected() { - std::map::const_iterator iter = + std::map::iterator iter = mButtons.find (dynamic_cast (sender())); if (iter!=mButtons.end()) @@ -111,22 +143,6 @@ void CSVWidget::SceneToolMode::selected() if (!iter->first->hasKeepOpen()) mPanel->hide(); - for (std::map::const_iterator iter2 = mButtons.begin(); - iter2!=mButtons.end(); ++iter2) - iter2->first->setChecked (iter2==iter); - - setIcon (iter->first->icon()); - adjustToolTip (iter->first); - - if (mCurrent!=iter->first) - { - if (mCurrent) - mCurrent->deactivate (mToolbar); - - mCurrent = iter->first; - mCurrent->activate (mToolbar); - } - - emit modeChanged (iter->second); + setButton (iter); } } diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index c274d84ab..192b3ee78 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -41,6 +41,8 @@ namespace CSVWidget /// items to be added, the function must return true anyway. virtual bool createContextMenu (QMenu *menu); + void setButton (std::map::iterator iter); + public: SceneToolMode (SceneToolbar *parent, const QString& toolTip); @@ -59,6 +61,9 @@ namespace CSVWidget /// Must not be called if there aren't any buttons yet. std::string getCurrentId() const; + /// Manually change the current mode + void setButton (const std::string& id); + signals: void modeChanged (const std::string& id); From b2181fae208c1d86987806628b77f0c3d964b9f3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Mar 2016 10:48:44 +0100 Subject: [PATCH 16/19] safer handling of command macros --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/commanddispatcher.cpp | 44 +++++-------------- apps/opencs/model/world/commandmacro.cpp | 26 +++++++++++ apps/opencs/model/world/commandmacro.hpp | 34 ++++++++++++++ apps/opencs/view/render/instancemode.cpp | 13 +++--- apps/opencs/view/world/referencecreator.cpp | 12 ++--- apps/opencs/view/world/regionmap.cpp | 18 +++----- apps/opencs/view/world/vartypedelegate.cpp | 10 ++--- 8 files changed, 94 insertions(+), 65 deletions(-) create mode 100644 apps/opencs/model/world/commandmacro.cpp create mode 100644 apps/opencs/model/world/commandmacro.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4caf76090..ee6a47db0 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,7 +26,7 @@ opencs_units_noqt (model/world universalid record commands columnbase columnimp scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection - idcompletionmanager metadata defaultgmsts infoselectwrapper + idcompletionmanager metadata defaultgmsts infoselectwrapper commandmacro ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index a1fc980eb..ffbaa3dec 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -11,6 +11,7 @@ #include "record.hpp" #include "commands.hpp" #include "idtableproxymodel.hpp" +#include "commandmacro.hpp" std::vector CSMWorld::CommandDispatcher::getDeletableRecords() const { @@ -171,10 +172,9 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons if (modifyCell.get()) { - mDocument.getUndoStack().beginMacro (modifyData->text()); - mDocument.getUndoStack().push (modifyData.release()); - mDocument.getUndoStack().push (modifyCell.release()); - mDocument.getUndoStack().endMacro(); + CommandMacro macro (mDocument.getUndoStack()); + macro.push (modifyData.release()); + macro.push (modifyCell.release()); } else mDocument.getUndoStack().push (modifyData.release()); @@ -194,9 +194,7 @@ void CSMWorld::CommandDispatcher::executeDelete() int columnIndex = model.findColumnIndex (Columns::ColumnId_Id); - if (rows.size()>1) - mDocument.getUndoStack().beginMacro (tr ("Delete multiple records")); - + CommandMacro macro (mDocument.getUndoStack(), rows.size()>1 ? "Delete multiple records" : ""); for (std::vector::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter) { std::string id = model.data (model.getModelIndex (*iter, columnIndex)). @@ -204,7 +202,7 @@ void CSMWorld::CommandDispatcher::executeDelete() if (mId.getType() == UniversalId::Type_Referenceables) { - mDocument.getUndoStack().push ( new CSMWorld::DeleteCommand (model, id, + macro.push (new CSMWorld::DeleteCommand (model, id, static_cast(model.data (model.index ( model.getModelIndex (id, columnIndex).row(), model.findColumnIndex (CSMWorld::Columns::ColumnId_RecordType))).toInt()))); @@ -212,9 +210,6 @@ void CSMWorld::CommandDispatcher::executeDelete() else mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id)); } - - if (rows.size()>1) - mDocument.getUndoStack().endMacro(); } void CSMWorld::CommandDispatcher::executeRevert() @@ -231,25 +226,19 @@ void CSMWorld::CommandDispatcher::executeRevert() int columnIndex = model.findColumnIndex (Columns::ColumnId_Id); - if (rows.size()>1) - mDocument.getUndoStack().beginMacro (tr ("Revert multiple records")); - + CommandMacro macro (mDocument.getUndoStack(), rows.size()>1 ? "Revert multiple records" : ""); for (std::vector::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter) { std::string id = model.data (model.getModelIndex (*iter, columnIndex)). toString().toUtf8().constData(); - mDocument.getUndoStack().push (new CSMWorld::RevertCommand (model, id)); + macro.push (new CSMWorld::RevertCommand (model, id)); } - - if (rows.size()>1) - mDocument.getUndoStack().endMacro(); } void CSMWorld::CommandDispatcher::executeExtendedDelete() { - if (mExtendedTypes.size()>1) - mDocument.getUndoStack().beginMacro (tr ("Extended delete of multiple records")); + CommandMacro macro (mDocument.getUndoStack(), mExtendedTypes.size()>1 ? tr ("Extended delete of multiple records") : ""); for (std::vector::const_iterator iter (mExtendedTypes.begin()); iter!=mExtendedTypes.end(); ++iter) @@ -276,20 +265,15 @@ void CSMWorld::CommandDispatcher::executeExtendedDelete() Misc::StringUtils::lowerCase (record.get().mCell))) continue; - mDocument.getUndoStack().push ( - new CSMWorld::DeleteCommand (model, record.get().mId)); + macro.push (new CSMWorld::DeleteCommand (model, record.get().mId)); } } } - - if (mExtendedTypes.size()>1) - mDocument.getUndoStack().endMacro(); } void CSMWorld::CommandDispatcher::executeExtendedRevert() { - if (mExtendedTypes.size()>1) - mDocument.getUndoStack().beginMacro (tr ("Extended revert of multiple records")); + CommandMacro macro (mDocument.getUndoStack(), mExtendedTypes.size()>1 ? tr ("Extended revert of multiple records") : ""); for (std::vector::const_iterator iter (mExtendedTypes.begin()); iter!=mExtendedTypes.end(); ++iter) @@ -313,12 +297,8 @@ void CSMWorld::CommandDispatcher::executeExtendedRevert() Misc::StringUtils::lowerCase (record.get().mCell))) continue; - mDocument.getUndoStack().push ( - new CSMWorld::RevertCommand (model, record.get().mId)); + macro.push (new CSMWorld::RevertCommand (model, record.get().mId)); } } } - - if (mExtendedTypes.size()>1) - mDocument.getUndoStack().endMacro(); } diff --git a/apps/opencs/model/world/commandmacro.cpp b/apps/opencs/model/world/commandmacro.cpp new file mode 100644 index 000000000..0bd74cbe2 --- /dev/null +++ b/apps/opencs/model/world/commandmacro.cpp @@ -0,0 +1,26 @@ + +#include "commandmacro.hpp" + +#include +#include + +CSMWorld::CommandMacro::CommandMacro (QUndoStack& undoStack, const QString& description) +: mUndoStack (undoStack), mDescription (description), mStarted (false) +{} + +CSMWorld::CommandMacro::~CommandMacro() +{ + if (mStarted) + mUndoStack.endMacro(); +} + +void CSMWorld::CommandMacro::push (QUndoCommand *command) +{ + if (!mStarted) + { + mUndoStack.beginMacro (mDescription.isEmpty() ? command->text() : mDescription); + mStarted = true; + } + + mUndoStack.push (command); +} diff --git a/apps/opencs/model/world/commandmacro.hpp b/apps/opencs/model/world/commandmacro.hpp new file mode 100644 index 000000000..b1f6301d9 --- /dev/null +++ b/apps/opencs/model/world/commandmacro.hpp @@ -0,0 +1,34 @@ +#ifndef CSM_WOLRD_COMMANDMACRO_H +#define CSM_WOLRD_COMMANDMACRO_H + +class QUndoStack; +class QUndoCommand; + +#include + +namespace CSMWorld +{ + class CommandMacro + { + QUndoStack& mUndoStack; + QString mDescription; + bool mStarted; + + /// not implemented + CommandMacro (const CommandMacro&); + + /// not implemented + CommandMacro& operator= (const CommandMacro&); + + public: + + /// If \a description is empty, the description of the first command is used. + CommandMacro (QUndoStack& undoStack, const QString& description = ""); + + ~CommandMacro(); + + void push (QUndoCommand *command); + }; +} + +#endif diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 6fa8ddaa8..12bc77105 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -8,6 +8,7 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" +#include "../../model/world/commandmacro.hpp" #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" @@ -259,7 +260,8 @@ void CSVRender::InstanceMode::dragCompleted() case DragMode_None: break; } - undoStack.beginMacro (description); + + CSMWorld::CommandMacro macro (undoStack, description); for (std::vector >::iterator iter (selection.begin()); iter!=selection.end(); ++iter) @@ -270,8 +272,6 @@ void CSVRender::InstanceMode::dragCompleted() } } - undoStack.endMacro(); - mDragMode = DragMode_None; } @@ -435,11 +435,10 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); } - document.getUndoStack().beginMacro (createCommand->text()); - document.getUndoStack().push (createCommand.release()); + CSMWorld::CommandMacro macro (document.getUndoStack()); + macro.push (createCommand.release()); if (incrementCommand.get()) - document.getUndoStack().push (incrementCommand.release()); - document.getUndoStack().endMacro(); + macro.push (incrementCommand.release()); dropped = true; } diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 73ca62e02..5428f4e95 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -9,6 +9,7 @@ #include "../../model/world/columns.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/idcompletionmanager.hpp" +#include "../../model/world/commandmacro.hpp" #include "../widget/droplineedit.hpp" @@ -53,10 +54,9 @@ void CSVWorld::ReferenceCreator::pushCommand (std::auto_ptr increment (new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); - getUndoStack().beginMacro (command->text()); + CSMWorld::CommandMacro macro (getUndoStack(), command->text()); GenericCreator::pushCommand (command, id); - getUndoStack().push (increment.release()); - getUndoStack().endMacro(); + macro.push (increment.release()); } int CSVWorld::ReferenceCreator::getRefNumCount() const @@ -147,11 +147,11 @@ void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId, cellChanged(); //otherwise ok button will remain disabled } -CSVWorld::Creator *CSVWorld::ReferenceCreatorFactory::makeCreator (CSMDoc::Document& document, +CSVWorld::Creator *CSVWorld::ReferenceCreatorFactory::makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const { - return new ReferenceCreator(document.getData(), - document.getUndoStack(), + return new ReferenceCreator(document.getData(), + document.getUndoStack(), id, document.getIdCompletionManager()); } diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index 49764bd17..4de470dbc 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -17,6 +17,7 @@ #include "../../model/world/commands.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/tablemimedata.hpp" +#include "../../model/world/commandmacro.hpp" void CSVWorld::RegionMap::contextMenuEvent (QContextMenuEvent *event) { @@ -159,8 +160,7 @@ void CSVWorld::RegionMap::setRegion (const std::string& regionId) QString regionId2 = QString::fromUtf8 (regionId.c_str()); - if (selected.size()>1) - mDocument.getUndoStack().beginMacro (tr ("Set Region")); + CSMWorld::CommandMacro macro (mDocument.getUndoStack(), selected.size()>1 ? tr ("Set Region") : ""); for (QModelIndexList::const_iterator iter (selected.begin()); iter!=selected.end(); ++iter) { @@ -170,12 +170,8 @@ void CSVWorld::RegionMap::setRegion (const std::string& regionId) QModelIndex index = cellsModel->getModelIndex (cellId, cellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Region)); - mDocument.getUndoStack().push ( - new CSMWorld::ModifyCommand (*cellsModel, index, regionId2)); + macro.push (new CSMWorld::ModifyCommand (*cellsModel, index, regionId2)); } - - if (selected.size()>1) - mDocument.getUndoStack().endMacro(); } CSVWorld::RegionMap::RegionMap (const CSMWorld::UniversalId& universalId, @@ -258,19 +254,15 @@ void CSVWorld::RegionMap::createCells() CSMWorld::IdTable *cellsModel = &dynamic_cast (* mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); - if (selected.size()>1) - mDocument.getUndoStack().beginMacro (tr ("Create cells")); + CSMWorld::CommandMacro macro (mDocument.getUndoStack(), selected.size()>1 ? tr ("Create cells"): ""); for (QModelIndexList::const_iterator iter (selected.begin()); iter!=selected.end(); ++iter) { std::string cellId = model()->data (*iter, CSMWorld::RegionMap::Role_CellId). toString().toUtf8().constData(); - mDocument.getUndoStack().push (new CSMWorld::CreateCommand (*cellsModel, cellId)); + macro.push (new CSMWorld::CreateCommand (*cellsModel, cellId)); } - - if (selected.size()>1) - mDocument.getUndoStack().endMacro(); } void CSVWorld::RegionMap::setRegion() diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index a63e6028c..8aa43d15b 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -4,6 +4,7 @@ #include "../../model/world/commands.hpp" #include "../../model/world/columns.hpp" +#include "../../model/world/commandmacro.hpp" void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type) const @@ -36,13 +37,10 @@ void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QM default: break; // ignore the rest } - getUndoStack().beginMacro ( - "Modify " + model->headerData (index.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + CSMWorld::CommandMacro macro (getUndoStack(), "Modify " + model->headerData (index.column(), Qt::Horizontal, Qt::DisplayRole).toString()); - getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); - getUndoStack().push (new CSMWorld::ModifyCommand (*model, next, value)); - - getUndoStack().endMacro(); + macro.push (new CSMWorld::ModifyCommand (*model, index, type)); + macro.push (new CSMWorld::ModifyCommand (*model, next, value)); } CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector >& values, From fa9689c5e7121acbda5e17371191b33f13c9d14f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Mar 2016 14:04:47 +0100 Subject: [PATCH 17/19] delay command execution until call to Object::apply has finished (avoids cutting off the branch we are sitting on) --- apps/opencs/view/render/instancemode.cpp | 2 +- apps/opencs/view/render/object.cpp | 9 +++++---- apps/opencs/view/render/object.hpp | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 12bc77105..32373c395 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -268,7 +268,7 @@ void CSVRender::InstanceMode::dragCompleted() { if (CSVRender::ObjectTag *objectTag = dynamic_cast (iter->get())) { - objectTag->mObject->apply (undoStack); + objectTag->mObject->apply (macro); } } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 6ca751ba5..f7bb338cd 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -19,6 +19,7 @@ #include "../../model/world/refidcollection.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/universalid.hpp" +#include "../../model/world/commandmacro.hpp" #include #include @@ -524,7 +525,7 @@ void CSVRender::Object::setScale (float scale) adjustTransform(); } -void CSVRender::Object::apply (QUndoStack& undoStack) +void CSVRender::Object::apply (CSMWorld::CommandMacro& commands) { const CSMWorld::RefCollection& collection = mData.getReferences(); QAbstractItemModel *model = mData.getTableModel (CSMWorld::UniversalId::Type_References); @@ -538,7 +539,7 @@ void CSVRender::Object::apply (QUndoStack& undoStack) int column = collection.findColumnIndex (static_cast ( CSMWorld::Columns::ColumnId_PositionXPos+i)); - undoStack.push (new CSMWorld::ModifyCommand (*model, + commands.push (new CSMWorld::ModifyCommand (*model, model->index (recordIndex, column), mPositionOverride.pos[i])); } } @@ -550,7 +551,7 @@ void CSVRender::Object::apply (QUndoStack& undoStack) int column = collection.findColumnIndex (static_cast ( CSMWorld::Columns::ColumnId_PositionXRot+i)); - undoStack.push (new CSMWorld::ModifyCommand (*model, + commands.push (new CSMWorld::ModifyCommand (*model, model->index (recordIndex, column), mPositionOverride.rot[i])); } } @@ -559,7 +560,7 @@ void CSVRender::Object::apply (QUndoStack& undoStack) { int column = collection.findColumnIndex (CSMWorld::Columns::ColumnId_Scale); - undoStack.push (new CSMWorld::ModifyCommand (*model, + commands.push (new CSMWorld::ModifyCommand (*model, model->index (recordIndex, column), mScaleOverride)); } diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index a5cc141a0..54a284fa3 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -37,6 +37,7 @@ namespace CSMWorld { class Data; struct CellRef; + class CommandMacro; } namespace CSVRender @@ -172,7 +173,7 @@ namespace CSVRender void setScale (float scale); /// Apply override changes via command and end edit mode - void apply (QUndoStack& undoStack); + void apply (CSMWorld::CommandMacro& commands); void setSubMode (int subMode); From d6b8033b464c5090ea1d42ee0a62d955a362a62d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Mar 2016 13:19:51 +0100 Subject: [PATCH 18/19] handle cell transitions when moving objects --- apps/opencs/model/world/cellcoordinates.cpp | 12 ++++++++++++ apps/opencs/model/world/cellcoordinates.hpp | 5 +++++ apps/opencs/model/world/ref.cpp | 9 +++++---- apps/opencs/view/render/object.cpp | 12 ++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 3ef3e6c69..80ec9dc04 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -1,5 +1,7 @@ #include "cellcoordinates.hpp" +#include + #include #include @@ -7,6 +9,9 @@ CSMWorld::CellCoordinates::CellCoordinates() : mX (0), mY (0) {} CSMWorld::CellCoordinates::CellCoordinates (int x, int y) : mX (x), mY (y) {} +CSMWorld::CellCoordinates::CellCoordinates (const std::pair& coordinates) +: mX (coordinates.first), mY (coordinates.second) {} + int CSMWorld::CellCoordinates::getX() const { return mX; @@ -49,6 +54,13 @@ std::pair CSMWorld::CellCoordinates::fromId ( return std::make_pair (CellCoordinates(), false); } +std::pair CSMWorld::CellCoordinates::coordinatesToCellIndex (float x, float y) +{ + const int cellSize = 8192; + + return std::make_pair (std::floor (x/cellSize), std::floor (y/cellSize)); +} + bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right) { return left.getX()==right.getX() && left.getY()==right.getY(); diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index 63db60c29..f8851a6d9 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -19,6 +20,8 @@ namespace CSMWorld CellCoordinates (int x, int y); + CellCoordinates (const std::pair& coordinates); + int getX() const; int getY() const; @@ -34,6 +37,8 @@ namespace CSMWorld /// /// \note The worldspace part of \a id is ignored static std::pair fromId (const std::string& id); + + static std::pair coordinatesToCellIndex (float x, float y); }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index 638f7ec9c..e6345ce71 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -2,6 +2,10 @@ #include +#include + +#include "cellcoordinates.hpp" + CSMWorld::CellRef::CellRef() { mRefNum.mIndex = 0; @@ -10,8 +14,5 @@ CSMWorld::CellRef::CellRef() std::pair CSMWorld::CellRef::getCellIndex() const { - const int cellSize = 8192; - - return std::make_pair ( - std::floor (mPos.pos[0]/cellSize), std::floor (mPos.pos[1]/cellSize)); + return CellCoordinates::coordinatesToCellIndex (mPos.pos[0], mPos.pos[1]); } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f7bb338cd..cc151ead9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -20,6 +20,7 @@ #include "../../model/world/commands.hpp" #include "../../model/world/universalid.hpp" #include "../../model/world/commandmacro.hpp" +#include "../../model/world/cellcoordinates.hpp" #include #include @@ -542,6 +543,17 @@ void CSVRender::Object::apply (CSMWorld::CommandMacro& commands) commands.push (new CSMWorld::ModifyCommand (*model, model->index (recordIndex, column), mPositionOverride.pos[i])); } + + int column = collection.findColumnIndex (static_cast ( + CSMWorld::Columns::ColumnId_Cell)); + + std::pair cellIndex = collection.getRecord (recordIndex).get().getCellIndex(); + + /// \todo figure out worldspace (not important until multiple worldspaces are supported) + std::string cellId = CSMWorld::CellCoordinates (cellIndex).getId (""); + + commands.push (new CSMWorld::ModifyCommand (*model, + model->index (recordIndex, column), QString::fromUtf8 (cellId.c_str()))); } if (mOverrideFlags & Override_Rotation) From 900378a31e0bdeb43093709fc35568f327736dd7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Mar 2016 13:26:33 +0100 Subject: [PATCH 19/19] changed 'not implemented' warning message for object movement --- apps/opencs/view/render/instancemovemode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/instancemovemode.cpp b/apps/opencs/view/render/instancemovemode.cpp index fd42b9f69..9929f5fcb 100644 --- a/apps/opencs/view/render/instancemovemode.cpp +++ b/apps/opencs/view/render/instancemovemode.cpp @@ -7,6 +7,6 @@ CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent) "
    • Use primary edit to move instances around freely
    • " "
    • Use secondary edit to move instances around within the grid
    • " "
    " - "Not implemented yet", + "Grid move not implemented yet", parent) {}