mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-22 19:23:52 +00:00
716eebe616
Fix terrain selection crash See merge request OpenMW/openmw!1165 (cherry picked from commitec4e3b04a7
)b84e41bd
Avoid storing ref, dynamic cast worldspacewidget for safetyd62ddc00
Use QPointer to detect object existence, less verbose debug messagescb42b528
Remove friend, make getEditMode public to allow editmode testing.4b148180
Restucture code08f7c73e
Fix text
758 lines
26 KiB
C++
758 lines
26 KiB
C++
#include "worldspacewidget.hpp"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <QEvent>
|
|
#include <QDragEnterEvent>
|
|
#include <QDragMoveEvent>
|
|
#include <QDropEvent>
|
|
#include <QMouseEvent>
|
|
#include <QKeyEvent>
|
|
#include <QApplication>
|
|
#include <QToolTip>
|
|
|
|
#include <osgUtil/LineSegmentIntersector>
|
|
|
|
#include "../../model/world/universalid.hpp"
|
|
#include "../../model/world/idtable.hpp"
|
|
|
|
#include "../../model/prefs/shortcut.hpp"
|
|
#include "../../model/prefs/state.hpp"
|
|
|
|
#include "../render/orbitcameramode.hpp"
|
|
|
|
#include "../widget/scenetoolmode.hpp"
|
|
#include "../widget/scenetooltoggle2.hpp"
|
|
#include "../widget/scenetoolrun.hpp"
|
|
|
|
#include "object.hpp"
|
|
#include "mask.hpp"
|
|
#include "instancemode.hpp"
|
|
#include "pathgridmode.hpp"
|
|
#include "cameracontroller.hpp"
|
|
|
|
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
|
: SceneWidget (document.getData().getResourceSystem(), parent, Qt::WindowFlags(), false)
|
|
, mSceneElements(nullptr)
|
|
, mRun(nullptr)
|
|
, mDocument(document)
|
|
, mInteractionMask (0)
|
|
, mEditMode (nullptr)
|
|
, mLocked (false)
|
|
, mDragMode(InteractionType_None)
|
|
, mDragging (false)
|
|
, mDragX(0)
|
|
, mDragY(0)
|
|
, mSpeedMode(false)
|
|
, mDragFactor(0)
|
|
, mDragWheelFactor(0)
|
|
, mDragShiftFactor(0)
|
|
, mToolTipPos (-1, -1)
|
|
, mShowToolTips(false)
|
|
, mToolTipDelay(0)
|
|
, mInConstructor(true)
|
|
{
|
|
setAcceptDrops(true);
|
|
|
|
QAbstractItemModel *referenceables =
|
|
document.getData().getTableModel (CSMWorld::UniversalId::Type_Referenceables);
|
|
|
|
connect (referenceables, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
|
this, SLOT (referenceableDataChanged (const QModelIndex&, const QModelIndex&)));
|
|
connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
|
this, SLOT (referenceableAboutToBeRemoved (const QModelIndex&, int, int)));
|
|
connect (referenceables, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
|
this, SLOT (referenceableAdded (const QModelIndex&, int, int)));
|
|
|
|
QAbstractItemModel *references =
|
|
document.getData().getTableModel (CSMWorld::UniversalId::Type_References);
|
|
|
|
connect (references, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
|
this, SLOT (referenceDataChanged (const QModelIndex&, const QModelIndex&)));
|
|
connect (references, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
|
this, SLOT (referenceAboutToBeRemoved (const QModelIndex&, int, int)));
|
|
connect (references, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
|
this, SLOT (referenceAdded (const QModelIndex&, int, int)));
|
|
|
|
QAbstractItemModel *pathgrids = document.getData().getTableModel (CSMWorld::UniversalId::Type_Pathgrids);
|
|
|
|
connect (pathgrids, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
|
this, SLOT (pathgridDataChanged (const QModelIndex&, const QModelIndex&)));
|
|
connect (pathgrids, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
|
this, SLOT (pathgridAboutToBeRemoved (const QModelIndex&, int, int)));
|
|
connect (pathgrids, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
|
this, SLOT (pathgridAdded (const QModelIndex&, int, int)));
|
|
|
|
QAbstractItemModel *debugProfiles =
|
|
document.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles);
|
|
|
|
connect (debugProfiles, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
|
this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&)));
|
|
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
|
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
|
|
|
|
mToolTipDelayTimer.setSingleShot (true);
|
|
connect (&mToolTipDelayTimer, SIGNAL (timeout()), this, SLOT (showToolTip()));
|
|
|
|
CSMPrefs::get()["3D Scene Input"].update();
|
|
CSMPrefs::get()["Tooltips"].update();
|
|
|
|
// Shortcuts
|
|
CSMPrefs::Shortcut* primaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", "scene-speed-modifier",
|
|
CSMPrefs::Shortcut::SM_Detach, this);
|
|
CSMPrefs::Shortcut* primaryOpenShortcut = new CSMPrefs::Shortcut("scene-open-primary", this);
|
|
|
|
connect(primaryOpenShortcut, SIGNAL(activated(bool)), this, SLOT(primaryOpen(bool)));
|
|
connect(primaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool)));
|
|
connect(primaryEditShortcut, SIGNAL(secondary(bool)), this, SLOT(speedMode(bool)));
|
|
|
|
CSMPrefs::Shortcut* secondaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-secondary", this);
|
|
connect(secondaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(secondaryEdit(bool)));
|
|
|
|
CSMPrefs::Shortcut* primarySelectShortcut = new CSMPrefs::Shortcut("scene-select-primary", this);
|
|
connect(primarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(primarySelect(bool)));
|
|
|
|
CSMPrefs::Shortcut* secondarySelectShortcut = new CSMPrefs::Shortcut("scene-select-secondary", this);
|
|
connect(secondarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(secondarySelect(bool)));
|
|
|
|
CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this);
|
|
connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag()));
|
|
|
|
mInConstructor = false;
|
|
}
|
|
|
|
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
|
|
{
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setting)
|
|
{
|
|
if (*setting=="3D Scene Input/drag-factor")
|
|
mDragFactor = setting->toDouble();
|
|
else if (*setting=="3D Scene Input/drag-wheel-factor")
|
|
mDragWheelFactor = setting->toDouble();
|
|
else if (*setting=="3D Scene Input/drag-shift-factor")
|
|
mDragShiftFactor = setting->toDouble();
|
|
else if (*setting=="Rendering/object-marker-alpha" && !mInConstructor)
|
|
{
|
|
float alpha = setting->toDouble();
|
|
// getSelection is virtual, thus this can not be called from the constructor
|
|
auto selection = getSelection(Mask_Reference);
|
|
for (osg::ref_ptr<TagBase> tag : selection)
|
|
{
|
|
if (auto objTag = dynamic_cast<ObjectTag*>(tag.get()))
|
|
objTag->mObject->setMarkerTransparency(alpha);
|
|
}
|
|
}
|
|
else if (*setting=="Tooltips/scene-delay")
|
|
mToolTipDelay = setting->toInt();
|
|
else if (*setting=="Tooltips/scene")
|
|
mShowToolTips = setting->isTrue();
|
|
else
|
|
SceneWidget::settingChanged(setting);
|
|
}
|
|
|
|
|
|
void CSVRender::WorldspaceWidget::useViewHint (const std::string& hint) {}
|
|
|
|
void CSVRender::WorldspaceWidget::selectDefaultNavigationMode()
|
|
{
|
|
selectNavigationMode("1st");
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::centerOrbitCameraOnSelection()
|
|
{
|
|
std::vector<osg::ref_ptr<TagBase> > selection = getSelection(~0u);
|
|
|
|
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it!=selection.end(); ++it)
|
|
{
|
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag*> (it->get()))
|
|
{
|
|
mOrbitCamControl->setCenter(objectTag->mObject->getPosition().asVec3());
|
|
}
|
|
}
|
|
}
|
|
|
|
CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
|
|
CSVWidget::SceneToolbar *parent)
|
|
{
|
|
CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Camera Mode");
|
|
|
|
/// \todo replace icons
|
|
/// \todo consider user-defined button-mapping
|
|
tool->addButton (":scenetoolbar/1st-person", "1st",
|
|
"First Person"
|
|
"<ul><li>Camera is held upright</li>"
|
|
"<li>Mouse-Look while holding {scene-navi-primary}</li>"
|
|
"<li>Movement keys: {free-forward}(forward), {free-left}(left), {free-backward}(back), {free-right}(right)</li>"
|
|
"<li>Strafing (also vertically) by holding {scene-navi-secondary}</li>"
|
|
"<li>Mouse wheel moves the camera forward/backward</li>"
|
|
"<li>Hold {scene-speed-modifier} to speed up movement</li>"
|
|
"</ul>");
|
|
tool->addButton (":scenetoolbar/free-camera", "free",
|
|
"Free Camera"
|
|
"<ul><li>Mouse-Look while holding {scene-navi-primary}</li>"
|
|
"<li>Movement keys: {free-forward}(forward), {free-left}(left), {free-backward}(back), {free-right}(right)</li>"
|
|
"<li>Roll camera with {free-roll-left} and {free-roll-right} keys</li>"
|
|
"<li>Strafing (also vertically) by holding {scene-navi-secondary}</li>"
|
|
"<li>Mouse wheel moves the camera forward/backward</li>"
|
|
"<li>Hold {free-forward:mod} to speed up movement</li>"
|
|
"</ul>");
|
|
tool->addButton(
|
|
new CSVRender::OrbitCameraMode(this, QIcon(":scenetoolbar/orbiting-camera"),
|
|
"Orbiting Camera"
|
|
"<ul><li>Always facing the centre point</li>"
|
|
"<li>Rotate around the centre point via {orbit-up}, {orbit-left}, {orbit-down}, {orbit-right} or by moving "
|
|
"the mouse while holding {scene-navi-primary}</li>"
|
|
"<li>Roll camera with {orbit-roll-left} and {orbit-roll-right} keys</li>"
|
|
"<li>Strafing (also vertically) by holding {scene-navi-secondary} (includes relocation of the centre point)</li>"
|
|
"<li>Mouse wheel moves camera away or towards centre point but can not pass through it</li>"
|
|
"<li>Hold {scene-speed-modifier} to speed up movement</li>"
|
|
"</ul>", tool),
|
|
"orbit");
|
|
|
|
connect (tool, SIGNAL (modeChanged (const std::string&)),
|
|
this, SLOT (selectNavigationMode (const std::string&)));
|
|
|
|
return tool;
|
|
}
|
|
|
|
CSVWidget::SceneToolToggle2 *CSVRender::WorldspaceWidget::makeSceneVisibilitySelector (CSVWidget::SceneToolbar *parent)
|
|
{
|
|
mSceneElements = new CSVWidget::SceneToolToggle2 (parent,
|
|
"Scene Element Visibility", ":scenetoolbar/scene-view-c", ":scenetoolbar/scene-view-");
|
|
|
|
addVisibilitySelectorButtons (mSceneElements);
|
|
|
|
mSceneElements->setSelectionMask (0xffffffff);
|
|
|
|
connect (mSceneElements, SIGNAL (selectionChanged()),
|
|
this, SLOT (elementSelectionChanged()));
|
|
|
|
return mSceneElements;
|
|
}
|
|
|
|
CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool (
|
|
CSVWidget::SceneToolbar *parent)
|
|
{
|
|
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
|
|
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
|
|
|
|
std::vector<std::string> profiles;
|
|
|
|
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
|
int stateColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
|
int defaultColumn = debugProfiles.findColumnIndex (
|
|
CSMWorld::Columns::ColumnId_DefaultProfile);
|
|
|
|
int size = debugProfiles.rowCount();
|
|
|
|
for (int i=0; i<size; ++i)
|
|
{
|
|
int state = debugProfiles.data (debugProfiles.index (i, stateColumn)).toInt();
|
|
|
|
bool default_ = debugProfiles.data (debugProfiles.index (i, defaultColumn)).toInt();
|
|
|
|
if (state!=CSMWorld::RecordBase::State_Deleted && default_)
|
|
profiles.emplace_back(debugProfiles.data (debugProfiles.index (i, idColumn)).
|
|
toString().toUtf8().constData());
|
|
}
|
|
|
|
std::sort (profiles.begin(), profiles.end());
|
|
|
|
mRun = new CSVWidget::SceneToolRun (parent, "Run OpenMW from the current camera position",
|
|
":scenetoolbar/play", profiles);
|
|
|
|
connect (mRun, SIGNAL (runRequest (const std::string&)),
|
|
this, SLOT (runRequest (const std::string&)));
|
|
|
|
return mRun;
|
|
}
|
|
|
|
CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeEditModeSelector (
|
|
CSVWidget::SceneToolbar *parent)
|
|
{
|
|
mEditMode = new CSVWidget::SceneToolMode (parent, "Edit Mode");
|
|
|
|
addEditModeSelectorButtons (mEditMode);
|
|
|
|
connect (mEditMode, SIGNAL (modeChanged (const std::string&)),
|
|
this, SLOT (editModeChanged (const std::string&)));
|
|
|
|
return mEditMode;
|
|
}
|
|
|
|
CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType (
|
|
const std::vector< CSMWorld::UniversalId >& data)
|
|
{
|
|
DropType output = Type_Other;
|
|
|
|
for (std::vector<CSMWorld::UniversalId>::const_iterator iter (data.begin());
|
|
iter!=data.end(); ++iter)
|
|
{
|
|
DropType type = Type_Other;
|
|
|
|
if (iter->getType()==CSMWorld::UniversalId::Type_Cell ||
|
|
iter->getType()==CSMWorld::UniversalId::Type_Cell_Missing)
|
|
{
|
|
type = iter->getId().substr (0, 1)=="#" ? Type_CellsExterior : Type_CellsInterior;
|
|
}
|
|
else if (iter->getType()==CSMWorld::UniversalId::Type_DebugProfile)
|
|
type = Type_DebugProfile;
|
|
|
|
if (iter==data.begin())
|
|
output = type;
|
|
else if (output!=type) // mixed types -> ignore
|
|
return Type_Other;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
CSVRender::WorldspaceWidget::dropRequirments
|
|
CSVRender::WorldspaceWidget::getDropRequirements (DropType type) const
|
|
{
|
|
if (type==Type_DebugProfile)
|
|
return canHandle;
|
|
|
|
return ignored;
|
|
}
|
|
|
|
bool CSVRender::WorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& universalIdData,
|
|
DropType type)
|
|
{
|
|
if (type==Type_DebugProfile)
|
|
{
|
|
if (mRun)
|
|
{
|
|
for (std::vector<CSMWorld::UniversalId>::const_iterator iter (universalIdData.begin());
|
|
iter!=universalIdData.end(); ++iter)
|
|
mRun->addProfile (iter->getId());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
unsigned int CSVRender::WorldspaceWidget::getVisibilityMask() const
|
|
{
|
|
return mSceneElements->getSelectionMask();
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::setInteractionMask (unsigned int mask)
|
|
{
|
|
mInteractionMask = mask | Mask_CellMarker | Mask_CellArrow;
|
|
}
|
|
|
|
unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const
|
|
{
|
|
return mInteractionMask & getVisibilityMask();
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::setEditLock (bool locked)
|
|
{
|
|
dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).setEditLock (locked);
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
|
|
CSVWidget::SceneToolToggle2 *tool)
|
|
{
|
|
tool->addButton (Button_Reference, Mask_Reference, "Instances");
|
|
tool->addButton (Button_Water, Mask_Water, "Water");
|
|
tool->addButton (Button_Pathgrid, Mask_Pathgrid, "Pathgrid");
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool)
|
|
{
|
|
/// \todo replace EditMode with suitable subclasses
|
|
tool->addButton (new InstanceMode (this, mRootNode, tool), "object");
|
|
tool->addButton (new PathgridMode (this, tool), "pathgrid");
|
|
}
|
|
|
|
CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
|
|
{
|
|
return mDocument;
|
|
}
|
|
|
|
CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPoint& localPos,
|
|
unsigned int interactionMask) const
|
|
{
|
|
// (0,0) is considered the lower left corner of an OpenGL window
|
|
int x = localPos.x();
|
|
int y = height() - localPos.y();
|
|
|
|
// Convert from screen space to world space
|
|
osg::Matrixd wpvMat;
|
|
wpvMat.preMult (mView->getCamera()->getViewport()->computeWindowMatrix());
|
|
wpvMat.preMult (mView->getCamera()->getProjectionMatrix());
|
|
wpvMat.preMult (mView->getCamera()->getViewMatrix());
|
|
wpvMat = osg::Matrixd::inverse (wpvMat);
|
|
|
|
osg::Vec3d start = wpvMat.preMult (osg::Vec3d(x, y, 0));
|
|
osg::Vec3d end = wpvMat.preMult (osg::Vec3d(x, y, 1));
|
|
osg::Vec3d direction = end - start;
|
|
|
|
// Get intersection
|
|
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(
|
|
osgUtil::Intersector::MODEL, start, end));
|
|
|
|
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
|
|
osgUtil::IntersectionVisitor visitor(intersector);
|
|
|
|
visitor.setTraversalMask(interactionMask);
|
|
|
|
mView->getCamera()->accept(visitor);
|
|
|
|
// Get relevant data
|
|
for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin();
|
|
it != intersector->getIntersections().end(); ++it)
|
|
{
|
|
osgUtil::LineSegmentIntersector::Intersection intersection = *it;
|
|
|
|
// reject back-facing polygons
|
|
if (direction * intersection.getWorldIntersectNormal() > 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (std::vector<osg::Node*>::iterator nodeIter = intersection.nodePath.begin(); nodeIter != intersection.nodePath.end(); ++nodeIter)
|
|
{
|
|
osg::Node* node = *nodeIter;
|
|
if (osg::ref_ptr<CSVRender::TagBase> tag = dynamic_cast<CSVRender::TagBase *>(node->getUserData()))
|
|
{
|
|
WorldspaceHitResult hit = { true, tag, 0, 0, 0, intersection.getWorldIntersectPoint() };
|
|
if (intersection.indexList.size() >= 3)
|
|
{
|
|
hit.index0 = intersection.indexList[0];
|
|
hit.index1 = intersection.indexList[1];
|
|
hit.index2 = intersection.indexList[2];
|
|
}
|
|
return hit;
|
|
}
|
|
}
|
|
|
|
// Something untagged, probably terrain
|
|
WorldspaceHitResult hit = { true, nullptr, 0, 0, 0, intersection.getWorldIntersectPoint() };
|
|
if (intersection.indexList.size() >= 3)
|
|
{
|
|
hit.index0 = intersection.indexList[0];
|
|
hit.index1 = intersection.indexList[1];
|
|
hit.index2 = intersection.indexList[2];
|
|
}
|
|
return hit;
|
|
}
|
|
|
|
// Default placement
|
|
direction.normalize();
|
|
direction *= CSMPrefs::get()["3D Scene Editing"]["distance"].toInt();
|
|
|
|
WorldspaceHitResult hit = { false, nullptr, 0, 0, 0, start + direction };
|
|
return hit;
|
|
}
|
|
|
|
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
|
|
{
|
|
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::abortDrag()
|
|
{
|
|
if (mDragging)
|
|
{
|
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
|
|
|
editMode.dragAborted();
|
|
mDragging = false;
|
|
mDragMode = InteractionType_None;
|
|
}
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event)
|
|
{
|
|
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
|
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
|
|
return;
|
|
|
|
if (mime->fromDocument (mDocument))
|
|
{
|
|
if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) ||
|
|
mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) ||
|
|
mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile))
|
|
{
|
|
// These drops are handled through the subview object.
|
|
event->accept();
|
|
}
|
|
else
|
|
dynamic_cast<EditMode&> (*mEditMode->getCurrent()).dragEnterEvent (event);
|
|
}
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event)
|
|
{
|
|
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
|
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
|
|
return;
|
|
|
|
if (mime->fromDocument (mDocument))
|
|
{
|
|
if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) ||
|
|
mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) ||
|
|
mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile))
|
|
{
|
|
// These drops are handled through the subview object.
|
|
event->accept();
|
|
}
|
|
else
|
|
dynamic_cast<EditMode&> (*mEditMode->getCurrent()).dragMoveEvent (event);
|
|
}
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
|
|
{
|
|
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
|
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
|
|
return;
|
|
|
|
if (mime->fromDocument (mDocument))
|
|
{
|
|
if (mime->holdsType (CSMWorld::UniversalId::Type_Cell) ||
|
|
mime->holdsType (CSMWorld::UniversalId::Type_Cell_Missing) ||
|
|
mime->holdsType (CSMWorld::UniversalId::Type_DebugProfile))
|
|
{
|
|
emit dataDropped(mime->getData());
|
|
}
|
|
else
|
|
dynamic_cast<EditMode&> (*mEditMode->getCurrent()).dropEvent (event);
|
|
}
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::runRequest (const std::string& profile)
|
|
{
|
|
mDocument.startRunning (profile, getStartupInstruction());
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::debugProfileDataChanged (const QModelIndex& topLeft,
|
|
const QModelIndex& bottomRight)
|
|
{
|
|
if (!mRun)
|
|
return;
|
|
|
|
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
|
|
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
|
|
|
|
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
|
int stateColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
|
|
|
for (int i=topLeft.row(); i<=bottomRight.row(); ++i)
|
|
{
|
|
int state = debugProfiles.data (debugProfiles.index (i, stateColumn)).toInt();
|
|
|
|
// As of version 0.33 this case can not happen because debug profiles exist only in
|
|
// project or session scope, which means they will never be in deleted state. But we
|
|
// are adding the code for the sake of completeness and to avoid surprises if debug
|
|
// profile ever get extended to content scope.
|
|
if (state==CSMWorld::RecordBase::State_Deleted)
|
|
mRun->removeProfile (debugProfiles.data (
|
|
debugProfiles.index (i, idColumn)).toString().toUtf8().constData());
|
|
}
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelIndex& parent,
|
|
int start, int end)
|
|
{
|
|
if (parent.isValid())
|
|
return;
|
|
|
|
if (!mRun)
|
|
return;
|
|
|
|
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
|
|
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
|
|
|
|
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
|
|
|
for (int i=start; i<=end; ++i)
|
|
{
|
|
mRun->removeProfile (debugProfiles.data (
|
|
debugProfiles.index (i, idColumn)).toString().toUtf8().constData());
|
|
}
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id)
|
|
{
|
|
dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).setEditLock (mLocked);
|
|
mDragging = false;
|
|
mDragMode = InteractionType_None;
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::showToolTip()
|
|
{
|
|
if (mShowToolTips)
|
|
{
|
|
QPoint pos = QCursor::pos();
|
|
|
|
WorldspaceHitResult hit = mousePick (mapFromGlobal (pos), getInteractionMask());
|
|
if (hit.tag)
|
|
{
|
|
bool hideBasics = CSMPrefs::get()["Tooltips"]["scene-hide-basic"].isTrue();
|
|
QToolTip::showText(pos, hit.tag->getToolTip(hideBasics, hit), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::elementSelectionChanged()
|
|
{
|
|
setVisibilityMask (getVisibilityMask());
|
|
flagAsModified();
|
|
updateOverlay();
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::updateOverlay()
|
|
{
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
|
|
{
|
|
dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).mouseMoveEvent (event);
|
|
|
|
if (mDragging)
|
|
{
|
|
int diffX = event->x() - mDragX;
|
|
int diffY = (height() - event->y()) - mDragY;
|
|
|
|
mDragX = event->x();
|
|
mDragY = height() - event->y();
|
|
|
|
double factor = mDragFactor;
|
|
|
|
if (mSpeedMode)
|
|
factor *= mDragShiftFactor;
|
|
|
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
|
|
|
editMode.drag (event->pos(), diffX, diffY, factor);
|
|
}
|
|
else if (mDragMode != InteractionType_None)
|
|
{
|
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
|
|
|
if (mDragMode == InteractionType_PrimaryEdit)
|
|
mDragging = editMode.primaryEditStartDrag (event->pos());
|
|
else if (mDragMode == InteractionType_SecondaryEdit)
|
|
mDragging = editMode.secondaryEditStartDrag (event->pos());
|
|
else if (mDragMode == InteractionType_PrimarySelect)
|
|
mDragging = editMode.primarySelectStartDrag (event->pos());
|
|
else if (mDragMode == InteractionType_SecondarySelect)
|
|
mDragging = editMode.secondarySelectStartDrag (event->pos());
|
|
|
|
if (mDragging)
|
|
{
|
|
mDragX = event->localPos().x();
|
|
mDragY = height() - event->localPos().y();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (event->globalPos()!=mToolTipPos)
|
|
{
|
|
mToolTipPos = event->globalPos();
|
|
|
|
if (mShowToolTips)
|
|
{
|
|
QToolTip::hideText();
|
|
mToolTipDelayTimer.start (mToolTipDelay);
|
|
}
|
|
}
|
|
|
|
SceneWidget::mouseMoveEvent(event);
|
|
}
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event)
|
|
{
|
|
if (mDragging)
|
|
{
|
|
double factor = mDragWheelFactor;
|
|
|
|
if (mSpeedMode)
|
|
factor *= mDragShiftFactor;
|
|
|
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
|
editMode.dragWheel (event->angleDelta().y(), factor);
|
|
}
|
|
else
|
|
SceneWidget::wheelEvent(event);
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type)
|
|
{
|
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
|
|
|
if (type == InteractionType_PrimaryEdit)
|
|
editMode.primaryEditPressed (hit);
|
|
else if (type == InteractionType_SecondaryEdit)
|
|
editMode.secondaryEditPressed (hit);
|
|
else if (type == InteractionType_PrimarySelect)
|
|
editMode.primarySelectPressed (hit);
|
|
else if (type == InteractionType_SecondarySelect)
|
|
editMode.secondarySelectPressed (hit);
|
|
else if (type == InteractionType_PrimaryOpen)
|
|
editMode.primaryOpenPressed (hit);
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::primaryOpen(bool activate)
|
|
{
|
|
handleInteraction(InteractionType_PrimaryOpen, activate);
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::primaryEdit(bool activate)
|
|
{
|
|
handleInteraction(InteractionType_PrimaryEdit, activate);
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::secondaryEdit(bool activate)
|
|
{
|
|
handleInteraction(InteractionType_SecondaryEdit, activate);
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::primarySelect(bool activate)
|
|
{
|
|
handleInteraction(InteractionType_PrimarySelect, activate);
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::secondarySelect(bool activate)
|
|
{
|
|
handleInteraction(InteractionType_SecondarySelect, activate);
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::speedMode(bool activate)
|
|
{
|
|
mSpeedMode = activate;
|
|
}
|
|
|
|
void CSVRender::WorldspaceWidget::handleInteraction(InteractionType type, bool activate)
|
|
{
|
|
if (activate)
|
|
{
|
|
if (!mDragging)
|
|
mDragMode = type;
|
|
}
|
|
else
|
|
{
|
|
mDragMode = InteractionType_None;
|
|
|
|
if (mDragging)
|
|
{
|
|
EditMode* editMode = getEditMode();
|
|
editMode->dragCompleted(mapFromGlobal(QCursor::pos()));
|
|
mDragging = false;
|
|
}
|
|
else
|
|
{
|
|
WorldspaceHitResult hit = mousePick(mapFromGlobal(QCursor::pos()), getInteractionMask());
|
|
handleInteractionPress(hit, type);
|
|
}
|
|
}
|
|
}
|