diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 196e899b23..6af04e8fc2 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -90,7 +90,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight - lightingbright object cell terrainstorage tagbase + lightingbright object cell terrainstorage tagbase cellarrow ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 95e206e2d3..3ef3e6c693 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -32,6 +32,23 @@ std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) con return stream.str(); } +std::pair CSMWorld::CellCoordinates::fromId ( + const std::string& id) +{ + // no worldspace for now, needs to be changed for 1.1 + if (!id.empty() && id[0]=='#') + { + int x, y; + char ignore; + + std::istringstream stream (id); + if (stream >> ignore >> x >> y) + return std::make_pair (CellCoordinates (x, y), true); + } + + return std::make_pair (CellCoordinates(), false); +} + bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right) { return left.getX()==right.getX() && left.getY()==right.getY(); diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index ee395ea7ee..63db60c29d 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -28,6 +28,12 @@ namespace CSMWorld std::string getId (const std::string& worldspace) const; ///< Return the ID for the cell at these coordinates. + + /// \return first: CellCoordinates (or 0, 0 if cell does not have coordinates), + /// second: is cell paged? + /// + /// \note The worldspace part of \a id is ignored + static std::pair fromId (const std::string& id); }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index c4f7445103..da40f7e7cb 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -9,6 +9,7 @@ #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" #include "../../model/world/refcollection.hpp" +#include "../../model/world/cellcoordinates.hpp" #include "elements.hpp" #include "terrainstorage.hpp" @@ -50,33 +51,39 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0) +CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, + bool deleted) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted) { + std::pair result = CSMWorld::CellCoordinates::fromId (id); + + if (result.second) + mCoordinates = result.first; + mCellNode = new osg::Group; rootNode->addChild(mCellNode); - CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - - int rows = references.rowCount(); - - addObjects (0, rows-1); - - const CSMWorld::IdCollection& land = mData.getLand(); - int landIndex = land.searchId(mId); - if (landIndex != -1) + if (!mDeleted) { - const ESM::Land& esmLand = land.getRecord(mId).get(); + CSMWorld::IdTable& references = dynamic_cast ( + *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + int rows = references.rowCount(); + + addObjects (0, rows-1); + + const CSMWorld::IdCollection& land = mData.getLand(); + int landIndex = land.searchId(mId); + if (landIndex != -1) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); - mTerrain->loadCell(esmLand.mX, - esmLand.mY); + const ESM::Land& esmLand = land.getRecord(mId).get(); - mX = esmLand.mX; - mY = esmLand.mY; + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); + mTerrain->loadCell(esmLand.mX, + esmLand.mY); + } } } } @@ -122,6 +129,9 @@ bool CSVRender::Cell::referenceableAboutToBeRemoved (const QModelIndex& parent, bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { + if (mDeleted) + return false; + CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -189,6 +199,9 @@ bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int if (parent.isValid()) return false; + if (mDeleted) + return false; + CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); @@ -209,6 +222,9 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int if (parent.isValid()) return false; + if (mDeleted) + return false; + return addObjects (start, end); } @@ -232,3 +248,31 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode) } } } + +void CSVRender::Cell::setCellArrows (int mask) +{ + for (int i=0; i<4; ++i) + { + CellArrow::Direction direction = static_cast (1< mCellNode; std::map mObjects; std::auto_ptr mTerrain; - int mX; - int mY; + CSMWorld::CellCoordinates mCoordinates; + std::auto_ptr mCellArrows[4]; + bool mDeleted; /// Ignored if cell does not have an object with the given ID. /// @@ -60,7 +63,10 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id); + /// \note Deleted covers both cells that are deleted and cells that don't exist in + /// the first place. + Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, + bool deleted = false); ~Cell(); @@ -86,6 +92,13 @@ namespace CSVRender bool referenceAdded (const QModelIndex& parent, int start, int end); void setSelection (int elementMask, Selection mode); + + void setCellArrows (int mask); + + /// Returns 0, 0 in case of an unpaged cell. + CSMWorld::CellCoordinates getCoordinates() const; + + bool isDeleted() const; }; } diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp new file mode 100644 index 0000000000..fce5ffda5c --- /dev/null +++ b/apps/opencs/view/render/cellarrow.cpp @@ -0,0 +1,161 @@ + +#include "cellarrow.hpp" + +#include +#include +#include +#include +#include + +#include "elements.hpp" + +CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) +: TagBase (Element_CellArrow), mArrow (arrow) +{} + +CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const +{ + return mArrow; +} + + +void CSVRender::CellArrow::adjustTransform() +{ + // position + const int cellSize = 8192; + const int offset = cellSize / 2 + 800; + + int x = mCoordinates.getX()*cellSize + cellSize/2; + int y = mCoordinates.getY()*cellSize + cellSize/2; + + float xr = 0; + float yr = 0; + float zr = 0; + + float angle = osg::DegreesToRadians (90.0f); + + switch (mDirection) + { + case Direction_North: y += offset; xr = -angle; zr = angle; break; + case Direction_West: x -= offset; yr = -angle; break; + case Direction_South: y -= offset; xr = angle; zr = angle; break; + case Direction_East: x += offset; yr = angle; break; + }; + + mBaseNode->setPosition (osg::Vec3f (x, y, 0)); + + // orientation + osg::Quat xr2 (xr, osg::Vec3f (1,0,0)); + osg::Quat yr2 (yr, osg::Vec3f (0,1,0)); + osg::Quat zr2 (zr, osg::Vec3f (0,0,1)); + mBaseNode->setAttitude (zr2*yr2*xr2); +} + +void CSVRender::CellArrow::buildShape() +{ + osg::ref_ptr geometry (new osg::Geometry); + + const int arrowWidth = 4000; + const int arrowLength = 1500; + const int arrowHeight = 500; + + osg::Vec3Array *vertices = new osg::Vec3Array; + for (int i2=0; i2<2; ++i2) + for (int i=0; i<2; ++i) + { + float height = i ? -arrowHeight/2 : arrowHeight/2; + vertices->push_back (osg::Vec3f (height, -arrowWidth/2, 0)); + vertices->push_back (osg::Vec3f (height, arrowWidth/2, 0)); + vertices->push_back (osg::Vec3f (height, 0, arrowLength)); + } + + geometry->setVertexArray (vertices); + + osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0); + + // top + primitives->push_back (0); + primitives->push_back (1); + primitives->push_back (2); + + // bottom + primitives->push_back (5); + primitives->push_back (4); + primitives->push_back (3); + + // back + primitives->push_back (3+6); + primitives->push_back (4+6); + primitives->push_back (1+6); + + primitives->push_back (3+6); + primitives->push_back (1+6); + primitives->push_back (0+6); + + // sides + primitives->push_back (0+6); + primitives->push_back (2+6); + primitives->push_back (5+6); + + primitives->push_back (0+6); + primitives->push_back (5+6); + primitives->push_back (3+6); + + primitives->push_back (4+6); + primitives->push_back (5+6); + primitives->push_back (2+6); + + primitives->push_back (4+6); + primitives->push_back (2+6); + primitives->push_back (1+6); + + geometry->addPrimitiveSet (primitives); + + osg::Vec4Array *colours = new osg::Vec4Array; + + for (int i=0; i<6; ++i) + colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.0f, 1.0f)); + for (int i=0; i<6; ++i) + colours->push_back (osg::Vec4f (0.8f, (i==2 || i==5) ? 0.6f : 0.4f, 0.0f, 1.0f)); + + geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX); + + geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable (geometry); + + mBaseNode->addChild (geode); +} + +CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction, + const CSMWorld::CellCoordinates& coordinates) +: mDirection (direction), mParentNode (cellNode), mCoordinates (coordinates) +{ + mBaseNode = new osg::PositionAttitudeTransform; + + mBaseNode->setUserData (new CellArrowTag (this)); + + mParentNode->addChild (mBaseNode); + + // 0x1 reserved for separating cull and update visitors + mBaseNode->setNodeMask (Element_CellArrow<<1); + + adjustTransform(); + buildShape(); +} + +CSVRender::CellArrow::~CellArrow() +{ + mParentNode->removeChild (mBaseNode); +} + +CSMWorld::CellCoordinates CSVRender::CellArrow::getCoordinates() const +{ + return mCoordinates; +} + +CSVRender::CellArrow::Direction CSVRender::CellArrow::getDirection() const +{ + return mDirection; +} diff --git a/apps/opencs/view/render/cellarrow.hpp b/apps/opencs/view/render/cellarrow.hpp new file mode 100644 index 0000000000..cbbcc9d5ee --- /dev/null +++ b/apps/opencs/view/render/cellarrow.hpp @@ -0,0 +1,72 @@ +#ifndef OPENCS_VIEW_CELLARROW_H +#define OPENCS_VIEW_CELLARROW_H + +#include "tagbase.hpp" + +#include + +#include "../../model/world/cellcoordinates.hpp" + +namespace osg +{ + class PositionAttitudeTransform; + class Group; +} + +namespace CSVRender +{ + class CellArrow; + + class CellArrowTag : public TagBase + { + CellArrow *mArrow; + + public: + + CellArrowTag (CellArrow *arrow); + + CellArrow *getCellArrow() const; + }; + + + class CellArrow + { + public: + + enum Direction + { + Direction_North = 1, + Direction_West = 2, + Direction_South = 4, + Direction_East = 8 + }; + + private: + + // not implemented + CellArrow (const CellArrow&); + CellArrow& operator= (const CellArrow&); + + Direction mDirection; + osg::Group* mParentNode; + osg::ref_ptr mBaseNode; + CSMWorld::CellCoordinates mCoordinates; + + void adjustTransform(); + + void buildShape(); + + public: + + CellArrow (osg::Group *cellNode, Direction direction, + const CSMWorld::CellCoordinates& coordinates); + + ~CellArrow(); + + CSMWorld::CellCoordinates getCoordinates() const; + + Direction getDirection() const; + }; +} + +#endif diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 7403113b37..6e5c2587d0 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -1,8 +1,10 @@ #include "pagedworldspacewidget.hpp" +#include #include #include +#include #include @@ -21,20 +23,19 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; + bool wasEmpty = mCells.empty(); const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); { - // remove (or name/region modified) + // remove/update std::map::iterator iter (mCells.begin()); while (iter!=mCells.end()) { - int index = cells.searchId (iter->first.getId (mWorldspace)); - - if (!mSelection.has (iter->first) || index==-1 || - cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted) + if (!mSelection.has (iter->first)) { + // remove delete iter->second; mCells.erase (iter++); @@ -42,12 +43,33 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() } else { - // check if name or region field has changed - // FIXME: config setting - //std::string name = cells.getRecord(index).get().mName; - //std::string region = cells.getRecord(index).get().mRegion; + // update + int index = cells.searchId (iter->first.getId (mWorldspace)); - // cell marker update goes here + bool deleted = index==-1 || + cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; + + if (deleted!=iter->second->isDeleted()) + { + modified = true; + + std::auto_ptr cell (new Cell (mDocument.getData(), mRootNode, + iter->first.getId (mWorldspace), deleted)); + + delete iter->second; + iter->second = cell.release(); + } + else if (!deleted) + { + // delete state has not changed -> just update + + // TODO check if name or region field has changed (cell marker) + // FIXME: config setting + //std::string name = cells.getRecord(index).get().mName; + //std::string region = cells.getRecord(index).get().mRegion; + + modified = true; + } ++iter; } @@ -58,20 +80,43 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); ++iter) { - int index = cells.searchId (iter->getId (mWorldspace)); - - if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && - mCells.find (*iter)==mCells.end()) + if (mCells.find (*iter)==mCells.end()) { - Cell *cell = new Cell (mDocument.getData(), mRootNode, - iter->getId (mWorldspace)); - mCells.insert (std::make_pair (*iter, cell)); - + addCellToScene (*iter); modified = true; } } if (modified) + { + for (std::map::const_iterator iter (mCells.begin()); + iter!=mCells.end(); ++iter) + { + int mask = 0; + + for (int i=CellArrow::Direction_North; i<=CellArrow::Direction_East; i *= 2) + { + CSMWorld::CellCoordinates coordinates (iter->second->getCoordinates()); + + switch (i) + { + case CellArrow::Direction_North: coordinates = coordinates.move (0, 1); break; + case CellArrow::Direction_West: coordinates = coordinates.move (-1, 0); break; + case CellArrow::Direction_South: coordinates = coordinates.move (0, -1); break; + case CellArrow::Direction_East: coordinates = coordinates.move (1, 0); break; + } + + if (!mSelection.has (coordinates)) + mask |= i; + } + + iter->second->setCellArrows (mask); + } + } + + /// \todo do not overwrite manipulator object + /// \todo move code to useViewHint function + if (modified && wasEmpty) mView->setCameraManipulator(new osgGA::TrackballManipulator); return modified; @@ -105,6 +150,76 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } +void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +{ + if (tag && tag->getElement()==Element_CellArrow) + { + if (button=="p-edit" || button=="s-edit") + { + if (CellArrowTag *cellArrowTag = + dynamic_cast (tag.get())) + { + CellArrow *arrow = cellArrowTag->getCellArrow(); + + CSMWorld::CellCoordinates coordinates = arrow->getCoordinates(); + + CellArrow::Direction direction = arrow->getDirection(); + + int x = 0; + int y = 0; + + switch (direction) + { + case CellArrow::Direction_North: y = 1; break; + case CellArrow::Direction_West: x = -1; break; + case CellArrow::Direction_South: y = -1; break; + case CellArrow::Direction_East: x = 1; break; + } + + bool modified = false; + + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) + { + if (button=="p-edit") + addCellSelection (x, y); + else + moveCellSelection (x, y); + + modified = true; + } + else + { + CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y); + + if (mCells.find (newCoordinates)==mCells.end()) + { + addCellToScene (newCoordinates); + mSelection.add (newCoordinates); + modified = true; + } + + if (button=="s-edit") + { + if (mCells.find (coordinates)!=mCells.end()) + { + removeCellFromScene (coordinates); + mSelection.remove (coordinates); + modified = true; + } + } + } + + if (modified) + adjustCells(); + + return; + } + } + } + + WorldspaceWidget::handleMouseClick (tag, button); +} + void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { @@ -184,6 +299,72 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() return stream.str(); } +void CSVRender::PagedWorldspaceWidget::addCellToScene ( + const CSMWorld::CellCoordinates& coordinates) +{ + const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); + + int index = cells.searchId (coordinates.getId (mWorldspace)); + + bool deleted = index==-1 || + cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted; + + Cell *cell = new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace), + deleted); + + mCells.insert (std::make_pair (coordinates, cell)); +} + +void CSVRender::PagedWorldspaceWidget::removeCellFromScene ( + const CSMWorld::CellCoordinates& coordinates) +{ + std::map::iterator iter = mCells.find (coordinates); + + if (iter!=mCells.end()) + { + delete iter->second; + mCells.erase (iter); + } +} + +void CSVRender::PagedWorldspaceWidget::addCellSelection (int x, int y) +{ + CSMWorld::CellSelection newSelection = mSelection; + newSelection.move (x, y); + + for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end(); + ++iter) + { + if (mCells.find (*iter)==mCells.end()) + { + addCellToScene (*iter); + mSelection.add (*iter); + } + } +} + +void CSVRender::PagedWorldspaceWidget::moveCellSelection (int x, int y) +{ + CSMWorld::CellSelection newSelection = mSelection; + newSelection.move (x, y); + + for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end(); + ++iter) + { + if (!newSelection.has (*iter)) + removeCellFromScene (*iter); + } + + for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end(); + ++iter) + { + if (!mSelection.has (*iter)) + addCellToScene (*iter); + } + + mSelection = newSelection; +} + CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), mControlElements(NULL), mDisplayCellCoord(true) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index d52efd90e4..e1a43ba7c5 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -53,6 +53,20 @@ namespace CSVRender virtual std::string getStartupInstruction(); + /// \note Does not update the view or any cell marker + void addCellToScene (const CSMWorld::CellCoordinates& coordinates); + + /// \note Does not update the view or any cell marker + /// + /// \note Calling this function for a cell that is not in the selection is a no-op. + void removeCellFromScene (const CSMWorld::CellCoordinates& coordinates); + + /// \note Does not update the view or any cell marker + void addCellSelection (int x, int y); + + /// \note Does not update the view or any cell marker + void moveCellSelection (int x, int y); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); @@ -88,6 +102,8 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + signals: void cellSelectionChanged (const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 75dd800ebc..a542a3c592 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -574,14 +574,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { osg::ref_ptr tag = mousePick (event); - EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - - if (button=="p-edit") - editMode.primaryEditPressed (tag); - else if (button=="s-edit") - editMode.secondaryEditPressed (tag); - else if (button=="select") - editMode.selectPressed (tag); + handleMouseClick (tag, button); } } @@ -650,3 +643,15 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) else RenderWidget::keyPressEvent(event); } + +void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr tag, const std::string& button) +{ + EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); + + if (button=="p-edit") + editMode.primaryEditPressed (tag); + else if (button=="s-edit") + editMode.secondaryEditPressed (tag); + else if (button=="select") + editMode.selectPressed (tag); +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index f5e7970b67..fe766cf87f 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -27,6 +27,7 @@ namespace CSVWidget namespace CSVRender { class TagBase; + class CellArrow; class WorldspaceWidget : public SceneWidget { @@ -132,6 +133,8 @@ namespace CSVRender virtual void wheelEvent (QWheelEvent *event); virtual void keyPressEvent (QKeyEvent *event); + virtual void handleMouseClick (osg::ref_ptr tag, const std::string& button); + private: void dragEnterEvent(QDragEnterEvent *event);