diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index a7a694463..d9e271498 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -24,7 +24,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection - refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata + refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp new file mode 100644 index 000000000..b1c8441e6 --- /dev/null +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -0,0 +1,60 @@ + +#include "cellcoordinates.hpp" + +#include +#include + +CSMWorld::CellCoordinates::CellCoordinates() : mX (0), mY (0) {} + +CSMWorld::CellCoordinates::CellCoordinates (int x, int y) : mX (x), mY (y) {} + +int CSMWorld::CellCoordinates::getX() const +{ + return mX; +} + +int CSMWorld::CellCoordinates::getY() const +{ + return mY; +} + +CSMWorld::CellCoordinates CSMWorld::CellCoordinates::move (int x, int y) const +{ + return CellCoordinates (mX + x, mY + y); +} + +std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) const +{ + // we ignore the worldspace for now, since there is only one (will change in 1.1) + std::ostringstream stream; + + stream << "#" << mX << " " << mY; + + return stream.str(); +} + +bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right) +{ + return left.getX()==right.getX() && left.getY()==right.getY(); +} + +bool CSMWorld::operator!= (const CellCoordinates& left, const CellCoordinates& right) +{ + return !(left==right); +} + +bool CSMWorld::operator< (const CellCoordinates& left, const CellCoordinates& right) +{ + if (left.getX()right.getX()) + return false; + + return left.getY() +#include + +#include + +namespace CSMWorld +{ + class CellCoordinates + { + int mX; + int mY; + + public: + + CellCoordinates(); + + CellCoordinates (int x, int y); + + int getX() const; + + int getY() const; + + CellCoordinates move (int x, int y) const; + ///< Return a copy of *this, moved by the given offset. + + std::string getId (const std::string& worldspace) const; + ///< Return the ID for the cell at these coordinates. + }; + + bool operator== (const CellCoordinates& left, const CellCoordinates& right); + bool operator!= (const CellCoordinates& left, const CellCoordinates& right); + bool operator< (const CellCoordinates& left, const CellCoordinates& right); + + std::ostream& operator<< (std::ostream& stream, const CellCoordinates& coordiantes); +} + +Q_DECLARE_METATYPE (CSMWorld::CellCoordinates) + +#endif diff --git a/apps/opencs/model/world/cellselection.cpp b/apps/opencs/model/world/cellselection.cpp new file mode 100644 index 000000000..73b5196f1 --- /dev/null +++ b/apps/opencs/model/world/cellselection.cpp @@ -0,0 +1,83 @@ + +#include "cellselection.hpp" + +#include +#include +#include + +CSMWorld::CellSelection::Iterator CSMWorld::CellSelection::begin() const +{ + return mCells.begin(); +} + +CSMWorld::CellSelection::Iterator CSMWorld::CellSelection::end() const +{ + return mCells.end(); +} + +bool CSMWorld::CellSelection::add (const CellCoordinates& coordinates) +{ + return mCells.insert (coordinates).second; +} + +void CSMWorld::CellSelection::remove (const CellCoordinates& coordinates) +{ + mCells.erase (coordinates); +} + +bool CSMWorld::CellSelection::has (const CellCoordinates& coordinates) const +{ + return mCells.find (coordinates)!=end(); +} + +int CSMWorld::CellSelection::getSize() const +{ + return mCells.size(); +} + +CSMWorld::CellCoordinates CSMWorld::CellSelection::getCentre() const +{ + if (mCells.empty()) + throw std::logic_error ("call of getCentre on empty cell selection"); + + double x = 0; + double y = 0; + + for (Iterator iter = begin(); iter!=end(); ++iter) + { + x += iter->getX(); + y += iter->getY(); + } + + x /= mCells.size(); + y /= mCells.size(); + + Iterator closest = begin(); + double distance = std::numeric_limits::max(); + + for (Iterator iter (begin()); iter!=end(); ++iter) + { + double deltaX = x - iter->getX(); + double deltaY = y - iter->getY(); + + double delta = std::sqrt (deltaX * deltaX + deltaY * deltaY); + + if (deltamove (x, y)); + + mCells.swap (moved); +} diff --git a/apps/opencs/model/world/cellselection.hpp b/apps/opencs/model/world/cellselection.hpp new file mode 100644 index 000000000..042416a33 --- /dev/null +++ b/apps/opencs/model/world/cellselection.hpp @@ -0,0 +1,57 @@ +#ifndef CSM_WOLRD_CELLSELECTION_H +#define CSM_WOLRD_CELLSELECTION_H + +#include + +#include + +#include "cellcoordinates.hpp" + +namespace CSMWorld +{ + /// \brief Selection of cells in a paged worldspace + /// + /// \note The CellSelection does not specify the worldspace it applies to. + class CellSelection + { + public: + + typedef std::set Container; + typedef Container::const_iterator Iterator; + + private: + + Container mCells; + + public: + + Iterator begin() const; + + Iterator end() const; + + bool add (const CellCoordinates& coordinates); + ///< Ignored if the cell specified by \a coordinates is already part of the selection. + /// + /// \return Was a cell added to the collection? + + void remove (const CellCoordinates& coordinates); + ///< ignored if the cell specified by \a coordinates is not part of the selection. + + bool has (const CellCoordinates& coordinates) const; + ///< \return Is the cell specified by \a coordinates part of the selection? + + int getSize() const; + ///< Return number of cells. + + CellCoordinates getCentre() const; + ///< Return the selected cell that is closest to the geometric centre of the selection. + /// + /// \attention This function must not be called on selections that are empty. + + void move (int x, int y); + }; +} + +Q_DECLARE_METATYPE (CSMWorld::CellSelection) + +#endif diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index fa32e3959..0f23dfe7b 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -1,6 +1,47 @@ #include "pagedworldspacewidget.hpp" +#include + CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget *parent) : WorldspaceWidget (parent) -{} \ No newline at end of file +{} + +void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) +{ + if (!hint.empty()) + { + CSMWorld::CellSelection selection; + + if (hint[0]=='c') + { + // syntax: c:#x1 y1; #x2 y2 (number of coordinate pairs can be 0 or larger) + char ignore; + + std::istringstream stream (hint.c_str()); + if (stream >> ignore) + { + char ignore1; // : or ; + char ignore2; // # + int x, y; + + while (stream >> ignore1 >> ignore2 >> x >> y) + selection.add (CSMWorld::CellCoordinates (x, y)); + + /// \todo adjust camera position + } + } + else if (hint[0]=='r') + { + /// \todo implement 'r' type hints + } + + setCellSelection (selection); + } +} + +void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSelection& selection) +{ + mSelection = selection; + emit cellSelectionChanged (mSelection); +} \ No newline at end of file diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 172e2477a..f6ff32dc1 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -1,6 +1,8 @@ #ifndef OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H #define OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H +#include "../../model/world/cellselection.hpp" + #include "worldspacewidget.hpp" namespace CSVRender @@ -9,9 +11,22 @@ namespace CSVRender { Q_OBJECT + CSMWorld::CellSelection mSelection; + public: PagedWorldspaceWidget (QWidget *parent); + ///< \note Sets the cell area selection to an invalid value to indicate that currently + /// no cells are displayed. The cells to be displayed will be specified later through + /// hint system. + + virtual void useViewHint (const std::string& hint); + + void setCellSelection (const CSMWorld::CellSelection& selection); + + signals: + + void cellSelectionChanged (const CSMWorld::CellSelection& selection); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 9959c5a67..4d2442c89 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -26,6 +26,8 @@ void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) setNavigation (&mOrbit); } +void CSVRender::WorldspaceWidget::useViewHint (const std::string& hint) {} + void CSVRender::WorldspaceWidget::selectDefaultNavigationMode() { setNavigation (&m1st); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 7921c3560..f7208d7a1 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -33,6 +33,9 @@ namespace CSVRender void selectDefaultNavigationMode(); + virtual void useViewHint (const std::string& hint); + ///< Default-implementation: ignored. + private slots: void selectNavigationMode (const std::string& mode); diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index ac9776d22..e9a30e65d 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -28,7 +28,7 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo else mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), this); - SceneToolbar *toolbar = new SceneToolbar (48, this); + SceneToolbar *toolbar = new SceneToolbar (48+6, this); SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); toolbar->addTool (lightingTool); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 10e8b4071..0bb11ce8c 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -1,12 +1,16 @@ #include "scenesubview.hpp" +#include + #include #include #include #include "../../model/doc/document.hpp" +#include "../../model/world/cellselection.hpp" + #include "../filter/filterbox.hpp" #include "../render/pagedworldspacewidget.hpp" @@ -32,10 +36,15 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D layout2->setContentsMargins (QMargins (0, 0, 0, 0)); - SceneToolbar *toolbar = new SceneToolbar (48, this); + SceneToolbar *toolbar = new SceneToolbar (48+6, this); if (id.getId()=="sys::default") - mScene = new CSVRender::PagedWorldspaceWidget (this); + { + CSVRender::PagedWorldspaceWidget *widget = new CSVRender::PagedWorldspaceWidget (this); + mScene = widget; + connect (widget, SIGNAL (cellSelectionChanged (const CSMWorld::CellSelection&)), + this, SLOT (cellSelectionChanged (const CSMWorld::CellSelection&))); + } else mScene = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this); @@ -83,7 +92,38 @@ void CSVWorld::SceneSubView::setStatusBar (bool show) mBottom->setStatusBar (show); } +void CSVWorld::SceneSubView::useHint (const std::string& hint) +{ + mScene->useViewHint (hint); +} + void CSVWorld::SceneSubView::closeRequest() { deleteLater(); +} + +void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::CellSelection& selection) +{ + int size = selection.getSize(); + + std::ostringstream stream; + stream << "Scene: " << getUniversalId().getId(); + + if (size==0) + stream << " (empty)"; + else if (size==1) + { + stream << " (" << *selection.begin() << ")"; + } + else + { + stream << " (" << selection.getCentre() << " and " << size-1 << " more "; + + if (size>1) + stream << "cells around it)"; + else + stream << "cell around it)"; + } + + setWindowTitle (QString::fromUtf8 (stream.str().c_str())); } \ No newline at end of file diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index ecf3fe4e4..0b15ea541 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -5,6 +5,11 @@ class QModelIndex; +namespace CSMWorld +{ + class CellSelection; +} + namespace CSMDoc { class Document; @@ -38,9 +43,13 @@ namespace CSVWorld virtual void setStatusBar (bool show); + virtual void useHint (const std::string& hint); + private slots: void closeRequest(); + + void cellSelectionChanged (const CSMWorld::CellSelection& selection); }; } diff --git a/apps/opencs/view/world/scenetool.cpp b/apps/opencs/view/world/scenetool.cpp index 320deb1ba..612b4c6d3 100644 --- a/apps/opencs/view/world/scenetool.cpp +++ b/apps/opencs/view/world/scenetool.cpp @@ -6,6 +6,7 @@ CSVWorld::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent) { setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + setIconSize (QSize (parent->getIconSize(), parent->getIconSize())); setFixedSize (parent->getButtonSize(), parent->getButtonSize()); connect (this, SIGNAL (clicked()), this, SLOT (openRequest())); diff --git a/apps/opencs/view/world/scenetoolbar.cpp b/apps/opencs/view/world/scenetoolbar.cpp index 2972c5391..d60240da7 100644 --- a/apps/opencs/view/world/scenetoolbar.cpp +++ b/apps/opencs/view/world/scenetoolbar.cpp @@ -6,7 +6,7 @@ #include "scenetool.hpp" CSVWorld::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) -: QWidget (parent), mButtonSize (buttonSize) +: QWidget (parent), mButtonSize (buttonSize), mIconSize (buttonSize-6) { setFixedWidth (mButtonSize); @@ -26,4 +26,9 @@ void CSVWorld::SceneToolbar::addTool (SceneTool *tool) int CSVWorld::SceneToolbar::getButtonSize() const { return mButtonSize; +} + +int CSVWorld::SceneToolbar::getIconSize() const +{ + return mIconSize; } \ No newline at end of file diff --git a/apps/opencs/view/world/scenetoolbar.hpp b/apps/opencs/view/world/scenetoolbar.hpp index f713ca3df..731806cc5 100644 --- a/apps/opencs/view/world/scenetoolbar.hpp +++ b/apps/opencs/view/world/scenetoolbar.hpp @@ -15,6 +15,7 @@ namespace CSVWorld QVBoxLayout *mLayout; int mButtonSize; + int mIconSize; public: @@ -23,6 +24,8 @@ namespace CSVWorld void addTool (SceneTool *tool); int getButtonSize() const; + + int getIconSize() const; }; } diff --git a/apps/opencs/view/world/scenetoolmode.cpp b/apps/opencs/view/world/scenetoolmode.cpp index 281d703b6..73b01ae3a 100644 --- a/apps/opencs/view/world/scenetoolmode.cpp +++ b/apps/opencs/view/world/scenetoolmode.cpp @@ -8,7 +8,7 @@ #include "scenetoolbar.hpp" CSVWorld::SceneToolMode::SceneToolMode (SceneToolbar *parent) -: SceneTool (parent), mButtonSize (parent->getButtonSize()) +: SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()) { mPanel = new QFrame (this, Qt::Popup); @@ -29,6 +29,7 @@ void CSVWorld::SceneToolMode::addButton (const std::string& icon, const std::str { QPushButton *button = new QPushButton (QIcon (QPixmap (icon.c_str())), "", mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); mLayout->addWidget (button); diff --git a/apps/opencs/view/world/scenetoolmode.hpp b/apps/opencs/view/world/scenetoolmode.hpp index a8fe2b5a6..a156c0c95 100644 --- a/apps/opencs/view/world/scenetoolmode.hpp +++ b/apps/opencs/view/world/scenetoolmode.hpp @@ -20,6 +20,7 @@ namespace CSVWorld QHBoxLayout *mLayout; std::map mButtons; // widget, id int mButtonSize; + int mIconSize; public: