Merge branch 'move'

move
Marc Zinnschlag 9 years ago
commit d5067201d0

@ -26,7 +26,7 @@ opencs_units_noqt (model/world
universalid record commands columnbase columnimp scriptcontext cell refidcollection universalid record commands columnbase columnimp scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
idcompletionmanager metadata defaultgmsts infoselectwrapper idcompletionmanager metadata defaultgmsts infoselectwrapper commandmacro
) )
opencs_hdrs_noqt (model/world opencs_hdrs_noqt (model/world
@ -85,7 +85,7 @@ opencs_units (view/widget
opencs_units (view/render opencs_units (view/render
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
previewwidget editmode instancemode instanceselectionmode previewwidget editmode instancemode instanceselectionmode instancemovemode
) )
opencs_units_noqt (view/render opencs_units_noqt (view/render

@ -1,5 +1,7 @@
#include "cellcoordinates.hpp" #include "cellcoordinates.hpp"
#include <cmath>
#include <ostream> #include <ostream>
#include <sstream> #include <sstream>
@ -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 (int x, int y) : mX (x), mY (y) {}
CSMWorld::CellCoordinates::CellCoordinates (const std::pair<int, int>& coordinates)
: mX (coordinates.first), mY (coordinates.second) {}
int CSMWorld::CellCoordinates::getX() const int CSMWorld::CellCoordinates::getX() const
{ {
return mX; return mX;
@ -49,6 +54,13 @@ std::pair<CSMWorld::CellCoordinates, bool> CSMWorld::CellCoordinates::fromId (
return std::make_pair (CellCoordinates(), false); return std::make_pair (CellCoordinates(), false);
} }
std::pair<int, int> 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) bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right)
{ {
return left.getX()==right.getX() && left.getY()==right.getY(); return left.getX()==right.getX() && left.getY()==right.getY();

@ -3,6 +3,7 @@
#include <iosfwd> #include <iosfwd>
#include <string> #include <string>
#include <utility>
#include <QMetaType> #include <QMetaType>
@ -19,6 +20,8 @@ namespace CSMWorld
CellCoordinates (int x, int y); CellCoordinates (int x, int y);
CellCoordinates (const std::pair<int, int>& coordinates);
int getX() const; int getX() const;
int getY() const; int getY() const;
@ -34,6 +37,8 @@ namespace CSMWorld
/// ///
/// \note The worldspace part of \a id is ignored /// \note The worldspace part of \a id is ignored
static std::pair<CellCoordinates, bool> fromId (const std::string& id); static std::pair<CellCoordinates, bool> fromId (const std::string& id);
static std::pair<int, int> coordinatesToCellIndex (float x, float y);
}; };
bool operator== (const CellCoordinates& left, const CellCoordinates& right); bool operator== (const CellCoordinates& left, const CellCoordinates& right);

@ -11,6 +11,7 @@
#include "record.hpp" #include "record.hpp"
#include "commands.hpp" #include "commands.hpp"
#include "idtableproxymodel.hpp" #include "idtableproxymodel.hpp"
#include "commandmacro.hpp"
std::vector<std::string> CSMWorld::CommandDispatcher::getDeletableRecords() const std::vector<std::string> CSMWorld::CommandDispatcher::getDeletableRecords() const
{ {
@ -171,10 +172,9 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons
if (modifyCell.get()) if (modifyCell.get())
{ {
mDocument.getUndoStack().beginMacro (modifyData->text()); CommandMacro macro (mDocument.getUndoStack());
mDocument.getUndoStack().push (modifyData.release()); macro.push (modifyData.release());
mDocument.getUndoStack().push (modifyCell.release()); macro.push (modifyCell.release());
mDocument.getUndoStack().endMacro();
} }
else else
mDocument.getUndoStack().push (modifyData.release()); mDocument.getUndoStack().push (modifyData.release());
@ -194,9 +194,7 @@ void CSMWorld::CommandDispatcher::executeDelete()
int columnIndex = model.findColumnIndex (Columns::ColumnId_Id); int columnIndex = model.findColumnIndex (Columns::ColumnId_Id);
if (rows.size()>1) CommandMacro macro (mDocument.getUndoStack(), rows.size()>1 ? "Delete multiple records" : "");
mDocument.getUndoStack().beginMacro (tr ("Delete multiple records"));
for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter) for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
{ {
std::string id = model.data (model.getModelIndex (*iter, columnIndex)). std::string id = model.data (model.getModelIndex (*iter, columnIndex)).
@ -204,7 +202,7 @@ void CSMWorld::CommandDispatcher::executeDelete()
if (mId.getType() == UniversalId::Type_Referenceables) if (mId.getType() == UniversalId::Type_Referenceables)
{ {
mDocument.getUndoStack().push ( new CSMWorld::DeleteCommand (model, id, macro.push (new CSMWorld::DeleteCommand (model, id,
static_cast<CSMWorld::UniversalId::Type>(model.data (model.index ( static_cast<CSMWorld::UniversalId::Type>(model.data (model.index (
model.getModelIndex (id, columnIndex).row(), model.getModelIndex (id, columnIndex).row(),
model.findColumnIndex (CSMWorld::Columns::ColumnId_RecordType))).toInt()))); model.findColumnIndex (CSMWorld::Columns::ColumnId_RecordType))).toInt())));
@ -212,9 +210,6 @@ void CSMWorld::CommandDispatcher::executeDelete()
else else
mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id)); mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id));
} }
if (rows.size()>1)
mDocument.getUndoStack().endMacro();
} }
void CSMWorld::CommandDispatcher::executeRevert() void CSMWorld::CommandDispatcher::executeRevert()
@ -231,25 +226,19 @@ void CSMWorld::CommandDispatcher::executeRevert()
int columnIndex = model.findColumnIndex (Columns::ColumnId_Id); int columnIndex = model.findColumnIndex (Columns::ColumnId_Id);
if (rows.size()>1) CommandMacro macro (mDocument.getUndoStack(), rows.size()>1 ? "Revert multiple records" : "");
mDocument.getUndoStack().beginMacro (tr ("Revert multiple records"));
for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter) for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
{ {
std::string id = model.data (model.getModelIndex (*iter, columnIndex)). std::string id = model.data (model.getModelIndex (*iter, columnIndex)).
toString().toUtf8().constData(); 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() void CSMWorld::CommandDispatcher::executeExtendedDelete()
{ {
if (mExtendedTypes.size()>1) CommandMacro macro (mDocument.getUndoStack(), mExtendedTypes.size()>1 ? tr ("Extended delete of multiple records") : "");
mDocument.getUndoStack().beginMacro (tr ("Extended delete of multiple records"));
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin()); for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
iter!=mExtendedTypes.end(); ++iter) iter!=mExtendedTypes.end(); ++iter)
@ -276,20 +265,15 @@ void CSMWorld::CommandDispatcher::executeExtendedDelete()
Misc::StringUtils::lowerCase (record.get().mCell))) Misc::StringUtils::lowerCase (record.get().mCell)))
continue; continue;
mDocument.getUndoStack().push ( macro.push (new CSMWorld::DeleteCommand (model, record.get().mId));
new CSMWorld::DeleteCommand (model, record.get().mId));
} }
} }
} }
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().endMacro();
} }
void CSMWorld::CommandDispatcher::executeExtendedRevert() void CSMWorld::CommandDispatcher::executeExtendedRevert()
{ {
if (mExtendedTypes.size()>1) CommandMacro macro (mDocument.getUndoStack(), mExtendedTypes.size()>1 ? tr ("Extended revert of multiple records") : "");
mDocument.getUndoStack().beginMacro (tr ("Extended revert of multiple records"));
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin()); for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
iter!=mExtendedTypes.end(); ++iter) iter!=mExtendedTypes.end(); ++iter)
@ -313,12 +297,8 @@ void CSMWorld::CommandDispatcher::executeExtendedRevert()
Misc::StringUtils::lowerCase (record.get().mCell))) Misc::StringUtils::lowerCase (record.get().mCell)))
continue; continue;
mDocument.getUndoStack().push ( macro.push (new CSMWorld::RevertCommand (model, record.get().mId));
new CSMWorld::RevertCommand (model, record.get().mId));
} }
} }
} }
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().endMacro();
} }

@ -0,0 +1,26 @@
#include "commandmacro.hpp"
#include <QUndoStack>
#include <QUndoCommand>
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);
}

@ -0,0 +1,34 @@
#ifndef CSM_WOLRD_COMMANDMACRO_H
#define CSM_WOLRD_COMMANDMACRO_H
class QUndoStack;
class QUndoCommand;
#include <QString>
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

@ -2,6 +2,10 @@
#include <cmath> #include <cmath>
#include <sstream>
#include "cellcoordinates.hpp"
CSMWorld::CellRef::CellRef() CSMWorld::CellRef::CellRef()
{ {
mRefNum.mIndex = 0; mRefNum.mIndex = 0;
@ -10,8 +14,5 @@ CSMWorld::CellRef::CellRef()
std::pair<int, int> CSMWorld::CellRef::getCellIndex() const std::pair<int, int> CSMWorld::CellRef::getCellIndex() const
{ {
const int cellSize = 8192; return CellCoordinates::coordinatesToCellIndex (mPos.pos[0], mPos.pos[1]);
return std::make_pair (
std::floor (mPos.pos[0]/cellSize), std::floor (mPos.pos[1]/cellSize));
} }

@ -51,7 +51,12 @@ bool CSVRender::Cell::addObjects (int start, int end)
{ {
std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); 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> object (new Object (mData, mCellNode, id, false));
if (mSubModeElementMask & Mask_Reference)
object->setSubMode (mSubMode);
mObjects.insert (std::make_pair (id, object.release()));
modified = true; 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, CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id,
bool deleted) 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<CSMWorld::CellCoordinates, bool> result = CSMWorld::CellCoordinates::fromId (id); std::pair<CSMWorld::CellCoordinates, bool> result = CSMWorld::CellCoordinates::fromId (id);
@ -349,3 +355,35 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getSelection (un
return result; return result;
} }
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getEdited (unsigned int elementMask) const
{
std::vector<osg::ref_ptr<TagBase> > result;
if (elementMask & Mask_Reference)
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
if (iter->second->isEdited())
result.push_back (iter->second->getTag());
return result;
}
void CSVRender::Cell::setSubMode (int subMode, unsigned int elementMask)
{
mSubMode = subMode;
mSubModeElementMask = elementMask;
if (elementMask & Mask_Reference)
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
iter->second->setSubMode (subMode);
}
void CSVRender::Cell::reset (unsigned int elementMask)
{
if (elementMask & Mask_Reference)
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
iter->second->reset();
}

@ -47,6 +47,8 @@ namespace CSVRender
std::auto_ptr<CellMarker> mCellMarker; std::auto_ptr<CellMarker> mCellMarker;
std::auto_ptr<CellBorder> mCellBorder; std::auto_ptr<CellBorder> mCellBorder;
bool mDeleted; bool mDeleted;
int mSubMode;
unsigned int mSubModeElementMask;
/// Ignored if cell does not have an object with the given ID. /// Ignored if cell does not have an object with the given ID.
/// ///
@ -118,6 +120,14 @@ namespace CSVRender
bool isDeleted() const; bool isDeleted() const;
std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask) const; std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask) const;
std::vector<osg::ref_ptr<TagBase> > 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);
}; };
} }

@ -70,3 +70,8 @@ void CSVRender::EditMode::dragEnterEvent (QDragEnterEvent *event) {}
void CSVRender::EditMode::dropEvent (QDropEvent* event) {} void CSVRender::EditMode::dropEvent (QDropEvent* event) {}
void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {} void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {}
int CSVRender::EditMode::getSubMode() const
{
return -1;
}

@ -92,6 +92,9 @@ namespace CSVRender
/// Default-implementation: ignored /// Default-implementation: ignored
virtual void dragMoveEvent (QDragMoveEvent *event); virtual void dragMoveEvent (QDragMoveEvent *event);
/// Default: return -1
virtual int getSubMode() const;
}; };
} }

@ -8,6 +8,7 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idtree.hpp" #include "../../model/world/idtree.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/commandmacro.hpp"
#include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolbar.hpp"
#include "../widget/scenetoolmode.hpp" #include "../widget/scenetoolmode.hpp"
@ -18,10 +19,17 @@
#include "worldspacewidget.hpp" #include "worldspacewidget.hpp"
#include "pagedworldspacewidget.hpp" #include "pagedworldspacewidget.hpp"
#include "instanceselectionmode.hpp" #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) CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
: EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing",
parent), mSubMode (0), mSelectionMode (0) parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
mDragAxis (-1), mLocked (false)
{ {
} }
@ -30,12 +38,7 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
if (!mSubMode) if (!mSubMode)
{ {
mSubMode = new CSVWidget::SceneToolMode (toolbar, "Edit Sub-Mode"); mSubMode = new CSVWidget::SceneToolMode (toolbar, "Edit Sub-Mode");
mSubMode->addButton (":placeholder", "move", mSubMode->addButton (new InstanceMoveMode (this), "move");
"Move selected instances"
"<ul><li>Use primary edit to move instances around freely</li>"
"<li>Use secondary edit to move instances around within the grid</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");
mSubMode->addButton (":placeholder", "rotate", mSubMode->addButton (":placeholder", "rotate",
"Rotate selected instances" "Rotate selected instances"
"<ul><li>Use primary edit to rotate instances freely</li>" "<ul><li>Use primary edit to rotate instances freely</li>"
@ -48,19 +51,33 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
"<li>Use secondary edit to scale instances along the grid</li>" "<li>Use secondary edit to scale instances along the grid</li>"
"</ul>" "</ul>"
"<font color=Red>Not implemented yet</font color>"); "<font color=Red>Not implemented yet</font color>");
mSubMode->setButton (mSubModeId);
connect (mSubMode, SIGNAL (modeChanged (const std::string&)),
this, SLOT (subModeChanged (const std::string&)));
} }
if (!mSelectionMode) if (!mSelectionMode)
mSelectionMode = new InstanceSelectionMode (toolbar, getWorldspaceWidget()); mSelectionMode = new InstanceSelectionMode (toolbar, getWorldspaceWidget());
mDragMode = DragMode_None;
EditMode::activate (toolbar); EditMode::activate (toolbar);
toolbar->addTool (mSubMode); toolbar->addTool (mSubMode);
toolbar->addTool (mSelectionMode); toolbar->addTool (mSelectionMode);
std::string subMode = mSubMode->getCurrentId();
getWorldspaceWidget().setSubMode (getSubModeFromId (subMode), Mask_Reference);
} }
void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar)
{ {
mDragMode = DragMode_None;
getWorldspaceWidget().reset (Mask_Reference);
if (mSelectionMode) if (mSelectionMode)
{ {
toolbar->removeTool (mSelectionMode); toolbar->removeTool (mSelectionMode);
@ -78,6 +95,14 @@ void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar)
EditMode::deactivate (toolbar); EditMode::deactivate (toolbar);
} }
void CSVRender::InstanceMode::setEditLock (bool locked)
{
mLocked = locked;
if (mLocked)
getWorldspaceWidget().abortDrag();
}
void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr<TagBase> tag) void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr<TagBase> tag)
{ {
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
@ -120,6 +145,173 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr<TagBase> tag)
} }
} }
bool CSVRender::InstanceMode::primaryEditStartDrag (osg::ref_ptr<TagBase> tag)
{
if (mDragMode!=DragMode_None || mLocked)
return false;
if (tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
{
getWorldspaceWidget().clearSelection (Mask_Reference);
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
{
CSVRender::Object* object = objectTag->mObject;
object->setSelected (true);
}
}
std::vector<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getSelection (Mask_Reference);
if (selection.empty())
return false;
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
{
objectTag->mObject->setEdited (Object::Override_Position);
}
}
// \todo check for sub-mode
if (CSVRender::ObjectMarkerTag *objectTag = dynamic_cast<CSVRender::ObjectMarkerTag *> (tag.get()))
{
mDragAxis = objectTag->mAxis;
}
else
mDragAxis = -1;
mDragMode = DragMode_Move;
return true;
}
bool CSVRender::InstanceMode::secondaryEditStartDrag (osg::ref_ptr<TagBase> tag)
{
if (mLocked)
return false;
return false;
}
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:
{
if (mDragAxis!=-1)
for (int i=0; i<3; ++i)
if (i!=mDragAxis)
offset[i] = 0;
std::vector<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getEdited (Mask_Reference);
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (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<osg::ref_ptr<TagBase> > 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;
}
CSMWorld::CommandMacro macro (undoStack, description);
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
{
objectTag->mObject->apply (macro);
}
}
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)
{
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<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getEdited (Mask_Reference);
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (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) void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event)
{ {
if (const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData())) if (const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData()))
@ -243,11 +435,10 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event)
new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); new CSMWorld::ModifyCommand (cellTable, countIndex, count+1));
} }
document.getUndoStack().beginMacro (createCommand->text()); CSMWorld::CommandMacro macro (document.getUndoStack());
document.getUndoStack().push (createCommand.release()); macro.push (createCommand.release());
if (incrementCommand.get()) if (incrementCommand.get())
document.getUndoStack().push (incrementCommand.release()); macro.push (incrementCommand.release());
document.getUndoStack().endMacro();
dropped = true; dropped = true;
} }
@ -256,3 +447,15 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event)
event->accept(); event->accept();
} }
} }
int CSVRender::InstanceMode::getSubMode() const
{
return mSubMode ? getSubModeFromId (mSubMode->getCurrentId()) : 0;
}
void CSVRender::InstanceMode::subModeChanged (const std::string& id)
{
mSubModeId = id;
getWorldspaceWidget().abortDrag();
getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference);
}

@ -15,8 +15,21 @@ namespace CSVRender
class InstanceMode : public EditMode class InstanceMode : public EditMode
{ {
Q_OBJECT Q_OBJECT
enum DragMode
{
DragMode_None,
DragMode_Move
};
CSVWidget::SceneToolMode *mSubMode; CSVWidget::SceneToolMode *mSubMode;
std::string mSubModeId;
InstanceSelectionMode *mSelectionMode; InstanceSelectionMode *mSelectionMode;
DragMode mDragMode;
int mDragAxis;
bool mLocked;
int getSubModeFromId (const std::string& id) const;
public: public:
@ -26,6 +39,8 @@ namespace CSVRender
virtual void deactivate (CSVWidget::SceneToolbar *toolbar); virtual void deactivate (CSVWidget::SceneToolbar *toolbar);
virtual void setEditLock (bool locked);
virtual void primaryEditPressed (osg::ref_ptr<TagBase> tag); virtual void primaryEditPressed (osg::ref_ptr<TagBase> tag);
virtual void secondaryEditPressed (osg::ref_ptr<TagBase> tag); virtual void secondaryEditPressed (osg::ref_ptr<TagBase> tag);
@ -34,9 +49,29 @@ namespace CSVRender
virtual void secondarySelectPressed (osg::ref_ptr<TagBase> tag); virtual void secondarySelectPressed (osg::ref_ptr<TagBase> tag);
virtual bool primaryEditStartDrag (osg::ref_ptr<TagBase> tag);
virtual bool secondaryEditStartDrag (osg::ref_ptr<TagBase> tag);
virtual void drag (int diffX, int diffY, double speedFactor);
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); virtual void dragEnterEvent (QDragEnterEvent *event);
virtual void dropEvent (QDropEvent* event); virtual void dropEvent (QDropEvent* event);
virtual int getSubMode() const;
private slots:
void subModeChanged (const std::string& id);
}; };
} }

@ -0,0 +1,12 @@
#include "instancemovemode.hpp"
CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent)
: ModeButton (QIcon (QPixmap (":placeholder")),
"Move selected instances"
"<ul><li>Use primary edit to move instances around freely</li>"
"<li>Use secondary edit to move instances around within the grid</li>"
"</ul>"
"<font color=Red>Grid move not implemented yet</font color>",
parent)
{}

@ -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

@ -9,12 +9,18 @@
#include <osg/ShapeDrawable> #include <osg/ShapeDrawable>
#include <osg/Shape> #include <osg/Shape>
#include <osg/Geode> #include <osg/Geode>
#include <osg/Geometry>
#include <osg/PrimitiveSet>
#include <osgFX/Scribe> #include <osgFX/Scribe>
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/ref.hpp" #include "../../model/world/ref.hpp"
#include "../../model/world/refidcollection.hpp" #include "../../model/world/refidcollection.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/universalid.hpp"
#include "../../model/world/commandmacro.hpp"
#include "../../model/world/cellcoordinates.hpp"
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/sceneutil/lightutil.hpp> #include <components/sceneutil/lightutil.hpp>
@ -50,6 +56,11 @@ QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const
} }
CSVRender::ObjectMarkerTag::ObjectMarkerTag (Object* object, int axis)
: ObjectTag (object), mAxis (axis)
{}
void CSVRender::Object::clear() void CSVRender::Object::clear()
{ {
} }
@ -130,18 +141,20 @@ void CSVRender::Object::adjustTransform()
if (mReferenceId.empty()) if (mReferenceId.empty())
return; return;
const CSMWorld::CellRef& reference = getReference(); ESM::Position position = getPosition();
// position // position
mBaseNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2])); mRootNode->setPosition(mForceBaseToZero ? osg::Vec3() : osg::Vec3f(position.pos[0], position.pos[1], position.pos[2]));
// orientation // orientation
osg::Quat xr (-reference.mPos.rot[0], osg::Vec3f(1,0,0)); osg::Quat xr (-position.rot[0], osg::Vec3f(1,0,0));
osg::Quat yr (-reference.mPos.rot[1], osg::Vec3f(0,1,0)); osg::Quat yr (-position.rot[1], osg::Vec3f(0,1,0));
osg::Quat zr (-reference.mPos.rot[2], osg::Vec3f(0,0,1)); osg::Quat zr (-position.rot[2], osg::Vec3f(0,0,1));
mBaseNode->setAttitude(zr*yr*xr); 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 const CSMWorld::CellRef& CSVRender::Object::getReference() const
@ -152,10 +165,147 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const
return mData.getReferences().getRecord (mReferenceId).get(); 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<osg::Node>();
}
if (mSelected)
{
if (mSubMode==0)
{
mMarker[i] = makeMarker (i);
mMarker[i]->setUserData(new ObjectMarkerTag (this, i));
mRootNode->addChild (mMarker[i]);
}
}
}
}
osg::ref_ptr<osg::Node> CSVRender::Object::makeMarker (int axis)
{
osg::ref_ptr<osg::Geometry> 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<osg::Geode> 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 2: return osg::Vec3f (x, y, z);
case 0: return osg::Vec3f (z, x, y);
case 1: 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, CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
const std::string& id, bool referenceable, bool forceBaseToZero) 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), mSubMode (-1)
{ {
mRootNode = new osg::PositionAttitudeTransform;
mBaseNode = new osg::PositionAttitudeTransform; mBaseNode = new osg::PositionAttitudeTransform;
mBaseNode->addCullCallback(new SceneUtil::LightListCallback); mBaseNode->addCullCallback(new SceneUtil::LightListCallback);
@ -163,9 +313,11 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
mBaseNode->setUserData(new ObjectTag(this)); mBaseNode->setUserData(new ObjectTag(this));
parentNode->addChild(mBaseNode); mRootNode->addChild (mBaseNode);
mBaseNode->setNodeMask(Mask_Reference); parentNode->addChild (mRootNode);
mRootNode->setNodeMask(Mask_Reference);
if (referenceable) if (referenceable)
{ {
@ -179,14 +331,14 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
adjustTransform(); adjustTransform();
update(); update();
updateMarker();
} }
CSVRender::Object::~Object() CSVRender::Object::~Object()
{ {
clear(); clear();
mParentNode->removeChild(mBaseNode); mParentNode->removeChild (mRootNode);
mParentNode->removeChild(mOutline);
} }
void CSVRender::Object::setSelected(bool selected) void CSVRender::Object::setSelected(bool selected)
@ -194,15 +346,17 @@ void CSVRender::Object::setSelected(bool selected)
mSelected = selected; mSelected = selected;
mOutline->removeChild(mBaseNode); mOutline->removeChild(mBaseNode);
mParentNode->removeChild(mOutline); mRootNode->removeChild(mOutline);
mParentNode->removeChild(mBaseNode); mRootNode->removeChild(mBaseNode);
if (selected) if (selected)
{ {
mOutline->addChild(mBaseNode); mOutline->addChild(mBaseNode);
mParentNode->addChild(mOutline); mRootNode->addChild(mOutline);
} }
else else
mParentNode->addChild(mBaseNode); mRootNode->addChild(mBaseNode);
updateMarker();
} }
bool CSVRender::Object::getSelected() const bool CSVRender::Object::getSelected() const
@ -221,6 +375,7 @@ bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft,
{ {
adjustTransform(); adjustTransform();
update(); update();
updateMarker();
return true; return true;
} }
@ -271,6 +426,7 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft,
references.getData (index, columnIndex).toString().toUtf8().constData(); references.getData (index, columnIndex).toString().toUtf8().constData();
update(); update();
updateMarker();
} }
return true; return true;
@ -293,3 +449,148 @@ osg::ref_ptr<CSVRender::TagBase> CSVRender::Object::getTag() const
{ {
return static_cast<CSVRender::TagBase *> (mBaseNode->getUserData()); return static_cast<CSVRender::TagBase *> (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 (CSMWorld::CommandMacro& commands)
{
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> (
CSMWorld::Columns::ColumnId_PositionXPos+i));
commands.push (new CSMWorld::ModifyCommand (*model,
model->index (recordIndex, column), mPositionOverride.pos[i]));
}
int column = collection.findColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (
CSMWorld::Columns::ColumnId_Cell));
std::pair<int, int> 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)
{
for (int i=0; i<3; ++i)
{
int column = collection.findColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (
CSMWorld::Columns::ColumnId_PositionXRot+i));
commands.push (new CSMWorld::ModifyCommand (*model,
model->index (recordIndex, column), mPositionOverride.rot[i]));
}
}
if (mOverrideFlags & Override_Scale)
{
int column = collection.findColumnIndex (CSMWorld::Columns::ColumnId_Scale);
commands.push (new CSMWorld::ModifyCommand (*model,
model->index (recordIndex, column), mScaleOverride));
}
mOverrideFlags = 0;
}
void CSVRender::Object::setSubMode (int subMode)
{
if (subMode!=mSubMode)
{
mSubMode = subMode;
updateMarker();
}
}
void CSVRender::Object::reset()
{
mOverrideFlags = 0;
adjustTransform();
updateMarker();
}

@ -8,14 +8,19 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Referenced> #include <osg/Referenced>
#include <components/esm/defs.hpp>
#include "tagbase.hpp" #include "tagbase.hpp"
class QModelIndex; class QModelIndex;
class QUndoStack;
namespace osg namespace osg
{ {
class PositionAttitudeTransform; class PositionAttitudeTransform;
class Group; class Group;
class Node;
class Geode;
} }
namespace osgFX namespace osgFX
@ -32,6 +37,7 @@ namespace CSMWorld
{ {
class Data; class Data;
struct CellRef; struct CellRef;
class CommandMacro;
} }
namespace CSVRender namespace CSVRender
@ -50,18 +56,43 @@ namespace CSVRender
virtual QString getToolTip (bool hideBasics) const; virtual QString getToolTip (bool hideBasics) const;
}; };
class ObjectMarkerTag : public ObjectTag
{
public:
ObjectMarkerTag (Object* object, int axis);
int mAxis;
};
class Object 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 mReferenceId;
std::string mReferenceableId; std::string mReferenceableId;
osg::ref_ptr<osg::PositionAttitudeTransform> mRootNode;
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode; osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
osg::ref_ptr<osgFX::Scribe> mOutline; osg::ref_ptr<osgFX::Scribe> mOutline;
bool mSelected; bool mSelected;
osg::Group* mParentNode; osg::Group* mParentNode;
Resource::ResourceSystem* mResourceSystem; Resource::ResourceSystem* mResourceSystem;
bool mForceBaseToZero; bool mForceBaseToZero;
ESM::Position mPositionOverride;
int mScaleOverride;
int mOverrideFlags;
osg::ref_ptr<osg::Node> mMarker[3];
int mSubMode;
/// Not implemented /// Not implemented
Object (const Object&); Object (const Object&);
@ -82,6 +113,12 @@ namespace CSVRender
/// Throws an exception if *this was constructed with referenceable /// Throws an exception if *this was constructed with referenceable
const CSMWorld::CellRef& getReference() const; const CSMWorld::CellRef& getReference() const;
void updateMarker();
osg::ref_ptr<osg::Node> makeMarker (int axis);
osg::Vec3f getMarkerPosition (float x, float y, float z, int axis);
public: public:
Object (CSMWorld::Data& data, osg::Group *cellNode, Object (CSMWorld::Data& data, osg::Group *cellNode,
@ -116,6 +153,33 @@ namespace CSVRender
std::string getReferenceableId() const; std::string getReferenceableId() const;
osg::ref_ptr<TagBase> getTag() const; osg::ref_ptr<TagBase> 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 (CSMWorld::CommandMacro& commands);
void setSubMode (int subMode);
/// Erase all overrides and restore the visual representation of the object to its
/// true state.
void reset();
}; };
} }

@ -309,10 +309,13 @@ void CSVRender::PagedWorldspaceWidget::addCellToScene (
bool deleted = index==-1 || bool deleted = index==-1 ||
cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted;
Cell *cell = new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), std::auto_ptr<Cell> cell (
deleted); 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 ( void CSVRender::PagedWorldspaceWidget::removeCellFromScene (
@ -555,6 +558,37 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::PagedWorldspaceWidget:
return result; return result;
} }
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::PagedWorldspaceWidget::getEdited (
unsigned int elementMask) const
{
std::vector<osg::ref_ptr<CSVRender::TagBase> > result;
for (std::map<CSMWorld::CellCoordinates, Cell *>::const_iterator iter = mCells.begin();
iter!=mCells.end(); ++iter)
{
std::vector<osg::ref_ptr<CSVRender::TagBase> > cellResult =
iter->second->getEdited (elementMask);
result.insert (result.end(), cellResult.begin(), cellResult.end());
}
return result;
}
void CSVRender::PagedWorldspaceWidget::setSubMode (int subMode, unsigned int elementMask)
{
for (std::map<CSMWorld::CellCoordinates, Cell *>::const_iterator iter = mCells.begin();
iter!=mCells.end(); ++iter)
iter->second->setSubMode (subMode, elementMask);
}
void CSVRender::PagedWorldspaceWidget::reset (unsigned int elementMask)
{
for (std::map<CSMWorld::CellCoordinates, Cell *>::const_iterator iter = mCells.begin();
iter!=mCells.end(); ++iter)
iter->second->reset (elementMask);
}
CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector (
CSVWidget::SceneToolbar *parent) CSVWidget::SceneToolbar *parent)
{ {

@ -112,6 +112,14 @@ namespace CSVRender
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask) virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
const; const;
virtual std::vector<osg::ref_ptr<TagBase> > getEdited (unsigned int elementMask)
const;
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: protected:
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);

@ -120,6 +120,12 @@ bool RenderWidget::eventFilter(QObject* obj, QEvent* event)
return QObject::eventFilter(obj, event); return QObject::eventFilter(obj, event);
} }
osg::Camera *RenderWidget::getCamera()
{
return mView->getCamera();
}
// -------------------------------------------------- // --------------------------------------------------
CompositeViewer::CompositeViewer() CompositeViewer::CompositeViewer()

@ -21,6 +21,7 @@ namespace Resource
namespace osg namespace osg
{ {
class Group; class Group;
class Camera;
} }
namespace CSVWidget namespace CSVWidget
@ -47,6 +48,8 @@ namespace CSVRender
bool eventFilter(QObject *, QEvent *); bool eventFilter(QObject *, QEvent *);
osg::Camera *getCamera();
protected: protected:
osg::ref_ptr<osgViewer::View> mView; osg::ref_ptr<osgViewer::View> mView;

@ -131,6 +131,22 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::UnpagedWorldspaceWidge
return mCell->getSelection (elementMask); return mCell->getSelection (elementMask);
} }
std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::UnpagedWorldspaceWidget::getEdited (
unsigned int elementMask) const
{
return mCell->getEdited (elementMask);
}
void CSVRender::UnpagedWorldspaceWidget::setSubMode (int subMode, unsigned int elementMask)
{
mCell->setSubMode (subMode, elementMask);
}
void CSVRender::UnpagedWorldspaceWidget::reset (unsigned int elementMask)
{
mCell->reset (elementMask);
}
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight) const QModelIndex& bottomRight)
{ {

@ -60,6 +60,14 @@ namespace CSVRender
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask) virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
const; const;
virtual std::vector<osg::ref_ptr<TagBase> > getEdited (unsigned int elementMask)
const;
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: private:
virtual void referenceableDataChanged (const QModelIndex& topLeft, virtual void referenceableDataChanged (const QModelIndex& topLeft,

@ -364,6 +364,18 @@ osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& loca
return start + direction * CSMPrefs::get()["Scene Drops"]["distance"].toInt(); return start + direction * CSMPrefs::get()["Scene Drops"]["distance"].toInt();
} }
void CSVRender::WorldspaceWidget::abortDrag()
{
if (mDragging)
{
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
editMode.dragAborted();
mDragging = false;
mDragMode.clear();
}
}
void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event)
{ {
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData()); const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
@ -573,6 +585,7 @@ void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id)
{ {
dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).setEditLock (mLocked); dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).setEditLock (mLocked);
mDragging = false; mDragging = false;
mDragMode.clear();
} }
void CSVRender::WorldspaceWidget::showToolTip() void CSVRender::WorldspaceWidget::showToolTip()
@ -736,13 +749,7 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event)
{ {
if(event->key() == Qt::Key_Escape) if(event->key() == Qt::Key_Escape)
{ {
if (mDragging) abortDrag();
{
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
editMode.dragAborted();
mDragging = false;
}
} }
else else
RenderWidget::keyPressEvent(event); RenderWidget::keyPressEvent(event);
@ -761,3 +768,8 @@ void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr<TagBase> tag, c
else if (button=="s-select") else if (button=="s-select")
editMode.secondarySelectPressed (tag); editMode.secondarySelectPressed (tag);
} }
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
{
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
}

@ -35,6 +35,7 @@ namespace CSVRender
{ {
class TagBase; class TagBase;
class CellArrow; class CellArrow;
class EditMode;
class WorldspaceWidget : public SceneWidget class WorldspaceWidget : public SceneWidget
{ {
@ -152,6 +153,20 @@ namespace CSVRender
virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask) virtual std::vector<osg::ref_ptr<TagBase> > getSelection (unsigned int elementMask)
const = 0; const = 0;
virtual std::vector<osg::ref_ptr<TagBase> > getEdited (unsigned int elementMask)
const = 0;
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;
/// \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: protected:
/// Visual elements in a scene /// Visual elements in a scene
@ -181,6 +196,8 @@ namespace CSVRender
virtual void handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button, virtual void handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button,
bool shift); bool shift);
EditMode *getEditMode();
private: private:
void dragEnterEvent(QDragEnterEvent *event); void dragEnterEvent(QDragEnterEvent *event);

@ -38,6 +38,27 @@ void CSVWidget::SceneToolMode::adjustToolTip (const ModeButton *activeMode)
setToolTip (toolTip); setToolTip (toolTip);
} }
void CSVWidget::SceneToolMode::setButton (std::map<ModeButton *, std::string>::iterator iter)
{
for (std::map<ModeButton *, std::string>::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) CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent, const QString& toolTip)
: SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()), : SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()),
mToolTip (toolTip), mFirst (0), mCurrent (0), mToolbar (parent) mToolTip (toolTip), mFirst (0), mCurrent (0), mToolbar (parent)
@ -96,9 +117,25 @@ CSVWidget::ModeButton *CSVWidget::SceneToolMode::getCurrent()
return mCurrent; return mCurrent;
} }
std::string CSVWidget::SceneToolMode::getCurrentId() const
{
return mButtons.find (mCurrent)->second;
}
void CSVWidget::SceneToolMode::setButton (const std::string& id)
{
for (std::map<ModeButton *, std::string>::iterator iter = mButtons.begin();
iter!=mButtons.end(); ++iter)
if (iter->second==id)
{
setButton (iter);
break;
}
}
void CSVWidget::SceneToolMode::selected() void CSVWidget::SceneToolMode::selected()
{ {
std::map<ModeButton *, std::string>::const_iterator iter = std::map<ModeButton *, std::string>::iterator iter =
mButtons.find (dynamic_cast<ModeButton *> (sender())); mButtons.find (dynamic_cast<ModeButton *> (sender()));
if (iter!=mButtons.end()) if (iter!=mButtons.end())
@ -106,22 +143,6 @@ void CSVWidget::SceneToolMode::selected()
if (!iter->first->hasKeepOpen()) if (!iter->first->hasKeepOpen())
mPanel->hide(); mPanel->hide();
for (std::map<ModeButton *, std::string>::const_iterator iter2 = mButtons.begin(); setButton (iter);
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);
} }
} }

@ -41,6 +41,8 @@ namespace CSVWidget
/// items to be added, the function must return true anyway. /// items to be added, the function must return true anyway.
virtual bool createContextMenu (QMenu *menu); virtual bool createContextMenu (QMenu *menu);
void setButton (std::map<ModeButton *, std::string>::iterator iter);
public: public:
SceneToolMode (SceneToolbar *parent, const QString& toolTip); SceneToolMode (SceneToolbar *parent, const QString& toolTip);
@ -56,6 +58,12 @@ namespace CSVWidget
/// Will return a 0-pointer only if the mode does not have any buttons yet. /// Will return a 0-pointer only if the mode does not have any buttons yet.
ModeButton *getCurrent(); ModeButton *getCurrent();
/// 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: signals:
void modeChanged (const std::string& id); void modeChanged (const std::string& id);

@ -9,6 +9,7 @@
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp" #include "../../model/world/idcompletionmanager.hpp"
#include "../../model/world/commandmacro.hpp"
#include "../widget/droplineedit.hpp" #include "../widget/droplineedit.hpp"
@ -53,10 +54,9 @@ void CSVWorld::ReferenceCreator::pushCommand (std::auto_ptr<CSMWorld::CreateComm
std::auto_ptr<CSMWorld::ModifyCommand> increment (new CSMWorld::ModifyCommand std::auto_ptr<CSMWorld::ModifyCommand> increment (new CSMWorld::ModifyCommand
(cellTable, countIndex, count+1)); (cellTable, countIndex, count+1));
getUndoStack().beginMacro (command->text()); CSMWorld::CommandMacro macro (getUndoStack(), command->text());
GenericCreator::pushCommand (command, id); GenericCreator::pushCommand (command, id);
getUndoStack().push (increment.release()); macro.push (increment.release());
getUndoStack().endMacro();
} }
int CSVWorld::ReferenceCreator::getRefNumCount() const int CSVWorld::ReferenceCreator::getRefNumCount() const
@ -147,11 +147,11 @@ void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId,
cellChanged(); //otherwise ok button will remain disabled 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 const CSMWorld::UniversalId& id) const
{ {
return new ReferenceCreator(document.getData(), return new ReferenceCreator(document.getData(),
document.getUndoStack(), document.getUndoStack(),
id, id,
document.getIdCompletionManager()); document.getIdCompletionManager());
} }

@ -17,6 +17,7 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "../../model/world/commandmacro.hpp"
void CSVWorld::RegionMap::contextMenuEvent (QContextMenuEvent *event) 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()); QString regionId2 = QString::fromUtf8 (regionId.c_str());
if (selected.size()>1) CSMWorld::CommandMacro macro (mDocument.getUndoStack(), selected.size()>1 ? tr ("Set Region") : "");
mDocument.getUndoStack().beginMacro (tr ("Set Region"));
for (QModelIndexList::const_iterator iter (selected.begin()); iter!=selected.end(); ++iter) 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, QModelIndex index = cellsModel->getModelIndex (cellId,
cellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Region)); cellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Region));
mDocument.getUndoStack().push ( macro.push (new CSMWorld::ModifyCommand (*cellsModel, index, regionId2));
new CSMWorld::ModifyCommand (*cellsModel, index, regionId2));
} }
if (selected.size()>1)
mDocument.getUndoStack().endMacro();
} }
CSVWorld::RegionMap::RegionMap (const CSMWorld::UniversalId& universalId, CSVWorld::RegionMap::RegionMap (const CSMWorld::UniversalId& universalId,
@ -258,19 +254,15 @@ void CSVWorld::RegionMap::createCells()
CSMWorld::IdTable *cellsModel = &dynamic_cast<CSMWorld::IdTable&> (* CSMWorld::IdTable *cellsModel = &dynamic_cast<CSMWorld::IdTable&> (*
mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
if (selected.size()>1) CSMWorld::CommandMacro macro (mDocument.getUndoStack(), selected.size()>1 ? tr ("Create cells"): "");
mDocument.getUndoStack().beginMacro (tr ("Create cells"));
for (QModelIndexList::const_iterator iter (selected.begin()); iter!=selected.end(); ++iter) for (QModelIndexList::const_iterator iter (selected.begin()); iter!=selected.end(); ++iter)
{ {
std::string cellId = model()->data (*iter, CSMWorld::RegionMap::Role_CellId). std::string cellId = model()->data (*iter, CSMWorld::RegionMap::Role_CellId).
toString().toUtf8().constData(); 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() void CSVWorld::RegionMap::setRegion()

@ -4,6 +4,7 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/commandmacro.hpp"
void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type) void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type)
const const
@ -36,13 +37,10 @@ void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QM
default: break; // ignore the rest default: break; // ignore the rest
} }
getUndoStack().beginMacro ( CSMWorld::CommandMacro macro (getUndoStack(), "Modify " + model->headerData (index.column(), Qt::Horizontal, Qt::DisplayRole).toString());
"Modify " + model->headerData (index.column(), Qt::Horizontal, Qt::DisplayRole).toString());
getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); macro.push (new CSMWorld::ModifyCommand (*model, index, type));
getUndoStack().push (new CSMWorld::ModifyCommand (*model, next, value)); macro.push (new CSMWorld::ModifyCommand (*model, next, value));
getUndoStack().endMacro();
} }
CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector<std::pair<int, QString> >& values, CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,

Loading…
Cancel
Save