mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 18:35:20 +00:00
Merge branch 'drop'
This commit is contained in:
commit
e07be2d912
@ -190,6 +190,24 @@ void CSMPrefs::State::declare()
|
|||||||
declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false);
|
declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false);
|
||||||
declareInt ("scene-delay", "Tooltip delay in milliseconds", 500).
|
declareInt ("scene-delay", "Tooltip delay in milliseconds", 500).
|
||||||
setMin (1);
|
setMin (1);
|
||||||
|
|
||||||
|
EnumValue createAndInsert ("Create cell and insert");
|
||||||
|
EnumValue showAndInsert ("Show cell and insert");
|
||||||
|
EnumValue dontInsert ("Discard");
|
||||||
|
EnumValue insertAnyway ("Insert anyway");
|
||||||
|
EnumValues insertOutsideCell;
|
||||||
|
insertOutsideCell.add (createAndInsert).add (dontInsert).add (insertAnyway);
|
||||||
|
EnumValues insertOutsideVisibleCell;
|
||||||
|
insertOutsideVisibleCell.add (showAndInsert).add (dontInsert).add (insertAnyway);
|
||||||
|
|
||||||
|
declareCategory ("Scene Drops");
|
||||||
|
declareInt ("distance", "Drop Distance", 50).
|
||||||
|
setTooltip ("If an instance drop can not be placed against another object at the "
|
||||||
|
"insert point, it will be placed by this distance from the insert point instead");
|
||||||
|
declareEnum ("outside-drop", "Handling drops outside of cells", createAndInsert).
|
||||||
|
addValues (insertOutsideCell);
|
||||||
|
declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert).
|
||||||
|
addValues (insertOutsideVisibleCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::State::declareCategory (const std::string& key)
|
void CSMPrefs::State::declareCategory (const std::string& key)
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
|
|
||||||
#include "instancemode.hpp"
|
#include "instancemode.hpp"
|
||||||
|
|
||||||
|
#include <QDragEnterEvent>
|
||||||
|
|
||||||
#include "../../model/prefs/state.hpp"
|
#include "../../model/prefs/state.hpp"
|
||||||
|
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/idtree.hpp"
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
|
||||||
#include "elements.hpp"
|
#include "elements.hpp"
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
#include "worldspacewidget.hpp"
|
#include "worldspacewidget.hpp"
|
||||||
|
#include "pagedworldspacewidget.hpp"
|
||||||
|
|
||||||
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
||||||
: EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing",
|
: EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing",
|
||||||
@ -55,3 +62,140 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr<TagBase> tag)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event)
|
||||||
|
{
|
||||||
|
if (const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData()))
|
||||||
|
{
|
||||||
|
if (!mime->fromDocument (getWorldspaceWidget().getDocument()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mime->holdsType (CSMWorld::UniversalId::Type_Referenceable))
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::InstanceMode::dropEvent (QDropEvent* event)
|
||||||
|
{
|
||||||
|
if (const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData()))
|
||||||
|
{
|
||||||
|
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||||
|
|
||||||
|
if (!mime->fromDocument (document))
|
||||||
|
return;
|
||||||
|
|
||||||
|
osg::Vec3f insertPoint = getWorldspaceWidget().getIntersectionPoint (event->pos());
|
||||||
|
|
||||||
|
std::string cellId = getWorldspaceWidget().getCellId (insertPoint);
|
||||||
|
|
||||||
|
CSMWorld::IdTree& cellTable = dynamic_cast<CSMWorld::IdTree&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
|
||||||
|
|
||||||
|
bool noCell = document.getData().getCells().searchId (cellId)==-1;
|
||||||
|
|
||||||
|
if (noCell)
|
||||||
|
{
|
||||||
|
std::string mode = CSMPrefs::get()["Scene Drops"]["outside-drop"].toString();
|
||||||
|
|
||||||
|
// target cell does not exist
|
||||||
|
if (mode=="Discard")
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mode=="Create cell and insert")
|
||||||
|
{
|
||||||
|
std::auto_ptr<CSMWorld::CreateCommand> createCommand (
|
||||||
|
new CSMWorld::CreateCommand (cellTable, cellId));
|
||||||
|
|
||||||
|
int parentIndex = cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_Cell);
|
||||||
|
int index = cellTable.findNestedColumnIndex (parentIndex, CSMWorld::Columns::ColumnId_Interior);
|
||||||
|
createCommand->addNestedValue (parentIndex, index, false);
|
||||||
|
|
||||||
|
document.getUndoStack().push (createCommand.release());
|
||||||
|
|
||||||
|
if (CSVRender::PagedWorldspaceWidget *paged =
|
||||||
|
dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
|
||||||
|
{
|
||||||
|
CSMWorld::CellSelection selection = paged->getCellSelection();
|
||||||
|
selection.add (CSMWorld::CellCoordinates::fromId (cellId).first);
|
||||||
|
paged->setCellSelection (selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
noCell = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (CSVRender::PagedWorldspaceWidget *paged =
|
||||||
|
dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
|
||||||
|
{
|
||||||
|
CSMWorld::CellSelection selection = paged->getCellSelection();
|
||||||
|
if (!selection.has (CSMWorld::CellCoordinates::fromId (cellId).first))
|
||||||
|
{
|
||||||
|
// target cell exists, but is not shown
|
||||||
|
std::string mode =
|
||||||
|
CSMPrefs::get()["Scene Drops"]["outside-visible-drop"].toString();
|
||||||
|
|
||||||
|
if (mode=="Discard")
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mode=="Show cell and insert")
|
||||||
|
{
|
||||||
|
selection.add (CSMWorld::CellCoordinates::fromId (cellId).first);
|
||||||
|
paged->setCellSelection (selection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::IdTable& referencesTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_References));
|
||||||
|
|
||||||
|
bool dropped = false;
|
||||||
|
|
||||||
|
std::vector<CSMWorld::UniversalId> ids = mime->getData();
|
||||||
|
|
||||||
|
for (std::vector<CSMWorld::UniversalId>::const_iterator iter (ids.begin());
|
||||||
|
iter!=ids.end(); ++iter)
|
||||||
|
if (mime->isReferencable (iter->getType()))
|
||||||
|
{
|
||||||
|
// create reference
|
||||||
|
std::auto_ptr<CSMWorld::CreateCommand> createCommand (
|
||||||
|
new CSMWorld::CreateCommand (
|
||||||
|
referencesTable, document.getData().getReferences().getNewId()));
|
||||||
|
|
||||||
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
|
CSMWorld::Columns::ColumnId_Cell), QString::fromUtf8 (cellId.c_str()));
|
||||||
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
|
CSMWorld::Columns::ColumnId_PositionXPos), insertPoint.x());
|
||||||
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
|
CSMWorld::Columns::ColumnId_PositionYPos), insertPoint.y());
|
||||||
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
|
CSMWorld::Columns::ColumnId_PositionZPos), insertPoint.z());
|
||||||
|
createCommand->addValue (referencesTable.findColumnIndex (
|
||||||
|
CSMWorld::Columns::ColumnId_ReferenceableId),
|
||||||
|
QString::fromUtf8 (iter->getId().c_str()));
|
||||||
|
|
||||||
|
std::auto_ptr<CSMWorld::ModifyCommand> incrementCommand;
|
||||||
|
|
||||||
|
if (!noCell)
|
||||||
|
{
|
||||||
|
// increase reference count in cell
|
||||||
|
QModelIndex countIndex = cellTable.getModelIndex (cellId,
|
||||||
|
cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter));
|
||||||
|
|
||||||
|
int count = cellTable.data (countIndex).toInt();
|
||||||
|
|
||||||
|
incrementCommand.reset (
|
||||||
|
new CSMWorld::ModifyCommand (cellTable, countIndex, count+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getUndoStack().beginMacro (createCommand->text());
|
||||||
|
document.getUndoStack().push (createCommand.release());
|
||||||
|
if (incrementCommand.get())
|
||||||
|
document.getUndoStack().push (incrementCommand.release());
|
||||||
|
document.getUndoStack().endMacro();
|
||||||
|
|
||||||
|
dropped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dropped)
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,6 +20,10 @@ namespace CSVRender
|
|||||||
virtual void primarySelectPressed (osg::ref_ptr<TagBase> tag);
|
virtual void primarySelectPressed (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
virtual void secondarySelectPressed (osg::ref_ptr<TagBase> tag);
|
virtual void secondarySelectPressed (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
virtual void dragEnterEvent (QDragEnterEvent *event);
|
||||||
|
|
||||||
|
virtual void dropEvent (QDropEvent* event);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,6 +432,11 @@ void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSel
|
|||||||
emit cellSelectionChanged (mSelection);
|
emit cellSelectionChanged (mSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CSMWorld::CellSelection& CSVRender::PagedWorldspaceWidget::getCellSelection() const
|
||||||
|
{
|
||||||
|
return mSelection;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (const std::string& record) const
|
std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (const std::string& record) const
|
||||||
{
|
{
|
||||||
std::istringstream stream (record.c_str());
|
std::istringstream stream (record.c_str());
|
||||||
@ -504,6 +509,17 @@ void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask)
|
|||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const
|
||||||
|
{
|
||||||
|
const int cellSize = 8192;
|
||||||
|
|
||||||
|
CSMWorld::CellCoordinates cellCoordinates (
|
||||||
|
static_cast<int> (std::floor (point.x()/cellSize)),
|
||||||
|
static_cast<int> (std::floor (point.y()/cellSize)));
|
||||||
|
|
||||||
|
return cellCoordinates.getId (mWorldspace);
|
||||||
|
}
|
||||||
|
|
||||||
CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector (
|
CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector (
|
||||||
CSVWidget::SceneToolbar *parent)
|
CSVWidget::SceneToolbar *parent)
|
||||||
{
|
{
|
||||||
|
@ -80,6 +80,8 @@ namespace CSVRender
|
|||||||
|
|
||||||
void setCellSelection(const CSMWorld::CellSelection& selection);
|
void setCellSelection(const CSMWorld::CellSelection& selection);
|
||||||
|
|
||||||
|
const CSMWorld::CellSelection& getCellSelection() const;
|
||||||
|
|
||||||
/// \return Drop handled?
|
/// \return Drop handled?
|
||||||
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
|
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
|
||||||
DropType type);
|
DropType type);
|
||||||
@ -96,6 +98,8 @@ namespace CSVRender
|
|||||||
/// \param elementMask Elements to be affected by the clear operation
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
virtual void clearSelection (int elementMask);
|
virtual void clearSelection (int elementMask);
|
||||||
|
|
||||||
|
virtual std::string getCellId (const osg::Vec3f& point) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
||||||
|
@ -108,6 +108,11 @@ void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask)
|
|||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const
|
||||||
|
{
|
||||||
|
return mCellId;
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
const QModelIndex& bottomRight)
|
const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
|
@ -46,6 +46,8 @@ namespace CSVRender
|
|||||||
/// \param elementMask Elements to be affected by the clear operation
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
virtual void clearSelection (int elementMask);
|
virtual void clearSelection (int elementMask);
|
||||||
|
|
||||||
|
virtual std::string getCellId (const osg::Vec3f& point) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
virtual void referenceableDataChanged (const QModelIndex& topLeft,
|
virtual void referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
|
@ -315,6 +315,54 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
|
|||||||
return mDocument;
|
return mDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& localPos,
|
||||||
|
unsigned int interactionMask, bool ignoreHidden) const
|
||||||
|
{
|
||||||
|
// (0,0) is considered the lower left corner of an OpenGL window
|
||||||
|
int x = localPos.x();
|
||||||
|
int y = height() - localPos.y();
|
||||||
|
|
||||||
|
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (
|
||||||
|
new osgUtil::LineSegmentIntersector (osgUtil::Intersector::WINDOW, x, y));
|
||||||
|
|
||||||
|
intersector->setIntersectionLimit (osgUtil::LineSegmentIntersector::NO_LIMIT);
|
||||||
|
osgUtil::IntersectionVisitor visitor (intersector);
|
||||||
|
|
||||||
|
unsigned int mask = interactionMask;
|
||||||
|
|
||||||
|
if (ignoreHidden)
|
||||||
|
mask &= getVisibilityMask();
|
||||||
|
|
||||||
|
visitor.setTraversalMask (mask << 1);
|
||||||
|
|
||||||
|
mView->getCamera()->accept (visitor);
|
||||||
|
|
||||||
|
for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersector->getIntersections().begin();
|
||||||
|
iter!=intersector->getIntersections().end(); ++iter)
|
||||||
|
{
|
||||||
|
// reject back-facing polygons
|
||||||
|
osg::Vec3f normal = osg::Matrix::transform3x3 (
|
||||||
|
iter->getWorldIntersectNormal(), mView->getCamera()->getViewMatrix());
|
||||||
|
|
||||||
|
if (normal.z()>=0)
|
||||||
|
return iter->getWorldIntersectPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Matrixd matrix;
|
||||||
|
matrix.preMult (mView->getCamera()->getViewport()->computeWindowMatrix());
|
||||||
|
matrix.preMult (mView->getCamera()->getProjectionMatrix());
|
||||||
|
matrix.preMult (mView->getCamera()->getViewMatrix());
|
||||||
|
matrix = osg::Matrixd::inverse (matrix);
|
||||||
|
|
||||||
|
osg::Vec3d start = matrix.preMult (intersector->getStart());
|
||||||
|
osg::Vec3d end = matrix.preMult (intersector->getEnd());
|
||||||
|
|
||||||
|
osg::Vec3d direction = end-start;
|
||||||
|
direction.normalize();
|
||||||
|
|
||||||
|
return start + direction * CSMPrefs::get()["Scene Drops"]["distance"].toInt();
|
||||||
|
}
|
||||||
|
|
||||||
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());
|
||||||
|
@ -127,6 +127,19 @@ namespace CSVRender
|
|||||||
/// \param elementMask Elements to be affected by the clear operation
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
virtual void clearSelection (int elementMask) = 0;
|
virtual void clearSelection (int elementMask) = 0;
|
||||||
|
|
||||||
|
/// Return the next intersection point with scene elements matched by
|
||||||
|
/// \a interactionMask based on \a localPos and the camera vector.
|
||||||
|
/// If there is no such point, instead a point "in front" of \a localPos will be
|
||||||
|
/// returned.
|
||||||
|
///
|
||||||
|
/// \param ignoreHidden ignore elements specified in interactionMask that are
|
||||||
|
/// flagged as not visible.
|
||||||
|
osg::Vec3f getIntersectionPoint (const QPoint& localPos,
|
||||||
|
unsigned int interactionMask = Element_Reference | Element_Terrain,
|
||||||
|
bool ignoreHidden = false) const;
|
||||||
|
|
||||||
|
virtual std::string getCellId (const osg::Vec3f& point) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user