From 879ab49e9ccd973400cc37a24b9b7511c245dba0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Jul 2014 12:46:57 +0200 Subject: [PATCH 01/67] added resources manager --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/editor.cpp | 2 + apps/opencs/model/doc/document.cpp | 6 +- apps/opencs/model/doc/document.hpp | 7 +- apps/opencs/model/doc/documentmanager.cpp | 7 +- apps/opencs/model/doc/documentmanager.hpp | 6 ++ apps/opencs/model/world/data.cpp | 11 ++- apps/opencs/model/world/data.hpp | 9 ++- apps/opencs/model/world/resources.cpp | 78 ++++++++++++++++++++ apps/opencs/model/world/resources.hpp | 30 ++++++++ apps/opencs/model/world/resourcesmanager.cpp | 24 ++++++ apps/opencs/model/world/resourcesmanager.hpp | 24 ++++++ apps/opencs/model/world/universalid.cpp | 15 +++- apps/opencs/model/world/universalid.hpp | 19 ++++- 14 files changed, 228 insertions(+), 12 deletions(-) create mode 100644 apps/opencs/model/world/resources.cpp create mode 100644 apps/opencs/model/world/resources.hpp create mode 100644 apps/opencs/model/world/resourcesmanager.cpp create mode 100644 apps/opencs/model/world/resourcesmanager.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index c52f9d9bca..0addaab524 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 cellcoordinates cellselection + refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index b003735874..b3513a7f15 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -35,6 +35,8 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, mFsStrict); + mDocumentManager.listResources(); + mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index f452008ac9..23a47b3130 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2205,9 +2205,9 @@ void CSMDoc::Document::createBase() CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, - ToUTF8::FromType encoding) -: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding), mTools (mData), - mResDir(resDir), + ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager) +: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), + mTools (mData), mResDir(resDir), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), mSaving (*this, mProjectPath, encoding) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index a6f8aaae28..d092b47c8a 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -31,6 +31,11 @@ namespace Files class ConfigurationManager; } +namespace CSMWorld +{ + class ResourcesManager; +} + namespace CSMDoc { class Document : public QObject @@ -73,7 +78,7 @@ namespace CSMDoc Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, - ToUTF8::FromType encoding); + ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager); ~Document(); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 4020a8f72c..6953db0edb 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -52,7 +52,7 @@ CSMDoc::DocumentManager::~DocumentManager() void CSMDoc::DocumentManager::addDocument (const std::vector& files, const boost::filesystem::path& savePath, bool new_) { - Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding); + Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager); mDocuments.push_back (document); @@ -85,6 +85,11 @@ void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding) mEncoding = encoding; } +void CSMDoc::DocumentManager::listResources() +{ + mResourcesManager.listResources(); +} + void CSMDoc::DocumentManager::documentLoaded (Document *document) { emit documentAdded (document); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index d6824112bb..cebae6f6d4 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -11,6 +11,8 @@ #include +#include "../world/resourcesmanager.hpp" + #include "loader.hpp" namespace Files @@ -31,6 +33,7 @@ namespace CSMDoc QThread mLoaderThread; Loader mLoader; ToUTF8::FromType mEncoding; + CSMWorld::ResourcesManager mResourcesManager; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); @@ -50,6 +53,9 @@ namespace CSMDoc void setEncoding (ToUTF8::FromType encoding); + /// Ask OGRE for a list of available resources. + void listResources(); + private: boost::filesystem::path mResDir; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d07e8784e3..823a14395f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -15,6 +15,7 @@ #include "columnimp.hpp" #include "regionmap.hpp" #include "columns.hpp" +#include "resourcesmanager.hpp" void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update) { @@ -56,8 +57,9 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec return number; } -CSMWorld::Data::Data (ToUTF8::FromType encoding) -: mEncoder (encoding), mRefs (mCells), mReader (0), mDialogue (0) +CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) +: mEncoder (encoding), mRefs (mCells), mResourcesManager (resourcesManager), mReader (0), + mDialogue (0) { mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); @@ -498,6 +500,11 @@ CSMWorld::IdCollection& CSMWorld::Data::getBodyParts() return mBodyParts; } +const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const +{ + return mResourcesManager.get (UniversalId::getParentType (id.getType())); +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 9bdb449e0a..cbf13d8b1b 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -47,6 +47,9 @@ namespace ESM namespace CSMWorld { + class ResourcesManager; + class Resources; + class Data : public QObject { Q_OBJECT @@ -73,6 +76,7 @@ namespace CSMWorld RefIdCollection mReferenceables; RefCollection mRefs; IdCollection mFilters; + const ResourcesManager& mResourcesManager; std::vector mModels; std::map mModelIndex; std::string mAuthor; @@ -98,7 +102,7 @@ namespace CSMWorld public: - Data (ToUTF8::FromType encoding); + Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager); virtual ~Data(); @@ -186,6 +190,9 @@ namespace CSMWorld IdCollection& getBodyParts(); + /// Throws an exception, if \a id does not match a resources list. + const Resources& getResources (const UniversalId& id) const; + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp new file mode 100644 index 0000000000..c819283e18 --- /dev/null +++ b/apps/opencs/model/world/resources.cpp @@ -0,0 +1,78 @@ + +#include "resources.hpp" + +#include +#include + +#include + +#include + +CSMWorld::Resources::Resources (const std::string& baseDirectory) +: mBaseDirectory (baseDirectory) +{ + int baseSize = mBaseDirectory.size(); + + Ogre::StringVector resourcesGroups = + Ogre::ResourceGroupManager::getSingleton().getResourceGroups(); + + for (Ogre::StringVector::iterator iter (resourcesGroups.begin()); + iter!=resourcesGroups.end(); ++iter) + { + if (*iter=="General" || *iter=="Internal" || *iter=="Autodetect") + continue; + + Ogre::StringVectorPtr resources = + Ogre::ResourceGroupManager::getSingleton().listResourceNames (*iter); + + for (Ogre::StringVector::const_iterator iter (resources->begin()); + iter!=resources->end(); ++iter) + { + if (static_cast (iter->size())>=baseSize+1 && + iter->substr (0, baseSize)==mBaseDirectory && + ((*iter)[baseSize]=='/' || (*iter)[baseSize]=='\\')) + { + std::string file = iter->substr (baseSize+1); + mFiles.push_back (file); + mIndex.insert (std::make_pair (file, static_cast (mFiles.size())-1)); + } + } + } +} + +int CSMWorld::Resources::getSize() const +{ + return mFiles.size(); +} + +std::string CSMWorld::Resources::getId (int index) const +{ + return mFiles.at (index); +} + +int CSMWorld::Resources::getIndex (const std::string& id) const +{ + int index = searchId (id); + + if (index==-1) + { + std::ostringstream stream; + stream << "Invalid resource: " << mBaseDirectory << '/' << id; + + throw std::runtime_error (stream.str().c_str()); + } + + return index; +} + +int CSMWorld::Resources::searchId (const std::string& id) const +{ + std::string id2 = Misc::StringUtils::lowerCase (id); + + std::map::const_iterator iter = mIndex.find (id2); + + if (iter==mIndex.end()) + return -1; + + return iter->second; +} \ No newline at end of file diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp new file mode 100644 index 0000000000..54c4fa8214 --- /dev/null +++ b/apps/opencs/model/world/resources.hpp @@ -0,0 +1,30 @@ +#ifndef CSM_WOLRD_RESOURCES_H +#define CSM_WOLRD_RESOURCES_H + +#include +#include +#include + +namespace CSMWorld +{ + class Resources + { + std::map mIndex; + std::vector mFiles; + std::string mBaseDirectory; + + public: + + Resources (const std::string& baseDirectory); + + int getSize() const; + + std::string getId (int index) const; + + int getIndex (const std::string& id) const; + + int searchId (const std::string& id) const; + }; +} + +#endif diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp new file mode 100644 index 0000000000..980e099f4b --- /dev/null +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -0,0 +1,24 @@ + +#include "resourcesmanager.hpp" + +#include + +void CSMWorld::ResourcesManager::listResources() +{ + mResources.insert (std::make_pair (UniversalId::Type_Mesh, "meshes")); + mResources.insert (std::make_pair (UniversalId::Type_Icon, "icons")); + mResources.insert (std::make_pair (UniversalId::Type_Music, "music")); + mResources.insert (std::make_pair (UniversalId::Type_SoundRes, "sound")); + mResources.insert (std::make_pair (UniversalId::Type_Texture, "textures")); + mResources.insert (std::make_pair (UniversalId::Type_Video, "videos")); +} + +const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const +{ + std::map::const_iterator iter = mResources.find (type); + + if (iter==mResources.end()) + throw std::logic_error ("Unknown resource type"); + + return iter->second; +} \ No newline at end of file diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp new file mode 100644 index 0000000000..e3bbd8a2a3 --- /dev/null +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -0,0 +1,24 @@ +#ifndef CSM_WOLRD_RESOURCESMANAGER_H +#define CSM_WOLRD_RESOURCESMANAGER_H + +#include + +#include "universalid.hpp" +#include "resources.hpp" + +namespace CSMWorld +{ + class ResourcesManager + { + std::map mResources; + + public: + + /// Ask OGRE for a list of available resources. + void listResources(); + + const Resources& get (UniversalId::Type type) const; + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 3a5f3f0439..2056b0c4c0 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -44,6 +44,12 @@ namespace { CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap, "Region Map", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", 0 }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", 0 }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", 0 }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Musics", 0 }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sounds", 0 }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", 0 }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; @@ -97,6 +103,12 @@ namespace { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", 0 }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", 0 }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", 0 }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", 0 }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound", 0 }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", 0 }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; @@ -331,7 +343,8 @@ CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type) if (sIdArg[i].mClass==Class_RefRecord) return Type_Referenceables; - if (sIdArg[i].mClass==Class_SubRecord || sIdArg[i].mClass==Class_Record) + if (sIdArg[i].mClass==Class_SubRecord || sIdArg[i].mClass==Class_Record || + sIdArg[i].mClass==Class_Resource) { if (type==Type_Cell_Missing) return Type_Cells; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index c7514336f1..3d3f215d65 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -22,7 +22,10 @@ namespace CSMWorld Class_RecordList, Class_Collection, // multiple types of records combined Class_Transient, // not part of the world data or the project data - Class_NonRecord // record like data that is not part of the world + Class_NonRecord, // record like data that is not part of the world + Class_Resource, ///< \attention Resource IDs are unique only within the + /// respective collection + Class_ResourceList }; enum ArgumentType @@ -104,7 +107,19 @@ namespace CSMWorld Type_Enchantments, Type_Enchantment, Type_BodyParts, - Type_BodyPart + Type_BodyPart, + Type_Meshes, + Type_Mesh, + Type_Icons, + Type_Icon, + Type_Musics, + Type_Music, + Type_SoundsRes, + Type_SoundRes, + Type_Textures, + Type_Texture, + Type_Videos, + Type_Video }; enum { NumberOfTypes = Type_BodyPart+1 }; From 63d0fdee7fde1fef654655962a1efa6f610fbd5d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Jul 2014 12:48:18 +0200 Subject: [PATCH 02/67] removed leftover data member --- apps/opencs/model/world/idtable.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 5500d40b8a..de3adef7c4 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -40,7 +40,6 @@ namespace CSMWorld CollectionBase *mIdCollection; unsigned int mFeatures; - bool mPreview; // not implemented IdTable (const IdTable&); From 1b1f1bade346ad37e460bc624ebcd53f5e8b808d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Jul 2014 13:24:35 +0200 Subject: [PATCH 03/67] injected new class IdTableBase between QAbstractItemModel and IdTable --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/filter/andnode.cpp | 2 +- apps/opencs/model/filter/andnode.hpp | 2 +- apps/opencs/model/filter/booleannode.cpp | 2 +- apps/opencs/model/filter/booleannode.hpp | 2 +- apps/opencs/model/filter/node.hpp | 4 +- apps/opencs/model/filter/notnode.cpp | 2 +- apps/opencs/model/filter/notnode.hpp | 2 +- apps/opencs/model/filter/ornode.cpp | 2 +- apps/opencs/model/filter/ornode.hpp | 2 +- apps/opencs/model/filter/textnode.cpp | 4 +- apps/opencs/model/filter/textnode.hpp | 2 +- apps/opencs/model/filter/valuenode.cpp | 4 +- apps/opencs/model/filter/valuenode.hpp | 2 +- apps/opencs/model/world/commands.hpp | 2 +- apps/opencs/model/world/idtable.cpp | 16 ++--- apps/opencs/model/world/idtable.hpp | 38 +++-------- apps/opencs/model/world/idtablebase.cpp | 9 +++ apps/opencs/model/world/idtablebase.hpp | 64 +++++++++++++++++++ apps/opencs/model/world/idtableproxymodel.cpp | 8 +-- apps/opencs/view/world/table.cpp | 17 +++-- apps/opencs/view/world/table.hpp | 4 +- 22 files changed, 124 insertions(+), 68 deletions(-) create mode 100644 apps/opencs/model/world/idtablebase.cpp create mode 100644 apps/opencs/model/world/idtablebase.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0addaab524..f6349aa7d0 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data commanddispatcher + idtable idtableproxymodel regionmap data commanddispatcher idtablebase ) diff --git a/apps/opencs/model/filter/andnode.cpp b/apps/opencs/model/filter/andnode.cpp index dfaa56e782..4249fc228e 100644 --- a/apps/opencs/model/filter/andnode.cpp +++ b/apps/opencs/model/filter/andnode.cpp @@ -7,7 +7,7 @@ CSMFilter::AndNode::AndNode (const std::vector >& nodes) : NAryNode (nodes, "and") {} -bool CSMFilter::AndNode::test (const CSMWorld::IdTable& table, int row, +bool CSMFilter::AndNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { int size = getSize(); diff --git a/apps/opencs/model/filter/andnode.hpp b/apps/opencs/model/filter/andnode.hpp index 8871757008..3838b451d4 100644 --- a/apps/opencs/model/filter/andnode.hpp +++ b/apps/opencs/model/filter/andnode.hpp @@ -11,7 +11,7 @@ namespace CSMFilter AndNode (const std::vector >& nodes); - virtual bool test (const CSMWorld::IdTable& table, int row, + virtual bool test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index 267e06a64a..2daa1b6d81 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -3,7 +3,7 @@ CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true_) {} -bool CSMFilter::BooleanNode::test (const CSMWorld::IdTable& table, int row, +bool CSMFilter::BooleanNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { return mTrue; diff --git a/apps/opencs/model/filter/booleannode.hpp b/apps/opencs/model/filter/booleannode.hpp index d19219e352..d9635746c0 100644 --- a/apps/opencs/model/filter/booleannode.hpp +++ b/apps/opencs/model/filter/booleannode.hpp @@ -13,7 +13,7 @@ namespace CSMFilter BooleanNode (bool true_); - virtual bool test (const CSMWorld::IdTable& table, int row, + virtual bool test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping diff --git a/apps/opencs/model/filter/node.hpp b/apps/opencs/model/filter/node.hpp index ef18353a48..58588bdc52 100644 --- a/apps/opencs/model/filter/node.hpp +++ b/apps/opencs/model/filter/node.hpp @@ -11,7 +11,7 @@ namespace CSMWorld { - class IdTable; + class IdTableBase; } namespace CSMFilter @@ -32,7 +32,7 @@ namespace CSMFilter virtual ~Node(); - virtual bool test (const CSMWorld::IdTable& table, int row, + virtual bool test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const = 0; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping diff --git a/apps/opencs/model/filter/notnode.cpp b/apps/opencs/model/filter/notnode.cpp index 1b22ea7a6a..2317730753 100644 --- a/apps/opencs/model/filter/notnode.cpp +++ b/apps/opencs/model/filter/notnode.cpp @@ -3,7 +3,7 @@ CSMFilter::NotNode::NotNode (boost::shared_ptr child) : UnaryNode (child, "not") {} -bool CSMFilter::NotNode::test (const CSMWorld::IdTable& table, int row, +bool CSMFilter::NotNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { return !getChild().test (table, row, columns); diff --git a/apps/opencs/model/filter/notnode.hpp b/apps/opencs/model/filter/notnode.hpp index b9e80b8c6d..0281d99dac 100644 --- a/apps/opencs/model/filter/notnode.hpp +++ b/apps/opencs/model/filter/notnode.hpp @@ -11,7 +11,7 @@ namespace CSMFilter NotNode (boost::shared_ptr child); - virtual bool test (const CSMWorld::IdTable& table, int row, + virtual bool test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping diff --git a/apps/opencs/model/filter/ornode.cpp b/apps/opencs/model/filter/ornode.cpp index 4fc34e1d5a..c5d15a3846 100644 --- a/apps/opencs/model/filter/ornode.cpp +++ b/apps/opencs/model/filter/ornode.cpp @@ -7,7 +7,7 @@ CSMFilter::OrNode::OrNode (const std::vector >& nodes) : NAryNode (nodes, "or") {} -bool CSMFilter::OrNode::test (const CSMWorld::IdTable& table, int row, +bool CSMFilter::OrNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { int size = getSize(); diff --git a/apps/opencs/model/filter/ornode.hpp b/apps/opencs/model/filter/ornode.hpp index c39e350956..07ab51a6a9 100644 --- a/apps/opencs/model/filter/ornode.hpp +++ b/apps/opencs/model/filter/ornode.hpp @@ -11,7 +11,7 @@ namespace CSMFilter OrNode (const std::vector >& nodes); - virtual bool test (const CSMWorld::IdTable& table, int row, + virtual bool test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index 7d1a4845f6..24cdce4f5f 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -7,13 +7,13 @@ #include #include "../world/columns.hpp" -#include "../world/idtable.hpp" +#include "../world/idtablebase.hpp" CSMFilter::TextNode::TextNode (int columnId, const std::string& text) : mColumnId (columnId), mText (text) {} -bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row, +bool CSMFilter::TextNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { const std::map::const_iterator iter = columns.find (mColumnId); diff --git a/apps/opencs/model/filter/textnode.hpp b/apps/opencs/model/filter/textnode.hpp index 663fa7382a..60ead85def 100644 --- a/apps/opencs/model/filter/textnode.hpp +++ b/apps/opencs/model/filter/textnode.hpp @@ -14,7 +14,7 @@ namespace CSMFilter TextNode (int columnId, const std::string& text); - virtual bool test (const CSMWorld::IdTable& table, int row, + virtual bool test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index fdcce00ab3..66b6282d77 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -5,13 +5,13 @@ #include #include "../world/columns.hpp" -#include "../world/idtable.hpp" +#include "../world/idtablebase.hpp" CSMFilter::ValueNode::ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper) : mColumnId (columnId), mLowerType (lowerType), mUpperType (upperType), mLower (lower), mUpper (upper){} -bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row, +bool CSMFilter::ValueNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { const std::map::const_iterator iter = columns.find (mColumnId); diff --git a/apps/opencs/model/filter/valuenode.hpp b/apps/opencs/model/filter/valuenode.hpp index b1050709d0..5b7ffec4ef 100644 --- a/apps/opencs/model/filter/valuenode.hpp +++ b/apps/opencs/model/filter/valuenode.hpp @@ -27,7 +27,7 @@ namespace CSMFilter ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper); - virtual bool test (const CSMWorld::IdTable& table, int row, + virtual bool test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index ec6350658f..947be68fd4 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -49,7 +49,7 @@ namespace CSMWorld public: - CloneCommand (IdTable& model, const std::string& idOrigin, + CloneCommand (IdTable& model, const std::string& idOrigin, const std::string& IdDestination, const UniversalId::Type type, QUndoCommand* parent = 0); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a481ce143a..3a48317eff 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -5,7 +5,7 @@ #include "columnbase.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) -: mIdCollection (idCollection), mFeatures (features) +: IdTableBase (features), mIdCollection (idCollection) {} CSMWorld::IdTable::~IdTable() @@ -185,17 +185,12 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector& newO index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1)); } -unsigned int CSMWorld::IdTable::getFeatures() const -{ - return mFeatures; -} - std::pair CSMWorld::IdTable::view (int row) const { std::string id; std::string hint; - if (mFeatures & Feature_ViewCell) + if (getFeatures() & Feature_ViewCell) { int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell); int idColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Id); @@ -206,7 +201,7 @@ std::pair CSMWorld::IdTable::view (int row) hint = "r:" + std::string (mIdCollection->getData (row, idColumn).toString().toUtf8().constData()); } } - else if (mFeatures & Feature_ViewId) + else if (getFeatures() & Feature_ViewId) { int column = mIdCollection->searchColumnIndex (Columns::ColumnId_Id); @@ -226,6 +221,11 @@ std::pair CSMWorld::IdTable::view (int row) return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint); } +bool CSMWorld::IdTable::isDeleted (const std::string& id) const +{ + return getRecord (id).isDeleted(); +} + int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index de3adef7c4..707d7133b8 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -3,8 +3,7 @@ #include -#include - +#include "idtablebase.hpp" #include "universalid.hpp" #include "columns.hpp" @@ -13,33 +12,13 @@ namespace CSMWorld class CollectionBase; class RecordBase; - class IdTable : public QAbstractItemModel + class IdTable : public IdTableBase { Q_OBJECT - public: - - enum Features - { - Feature_ReorderWithinTopic = 1, - - /// Use ID column to generate view request (ID is transformed into - /// worldspace and original ID is passed as hint with c: prefix). - Feature_ViewId = 2, - - /// Use cell column to generate view request (cell ID is transformed - /// into worldspace and record ID is passed as hint with r: prefix). - Feature_ViewCell = 4, - - Feature_View = Feature_ViewId | Feature_ViewCell, - - Feature_Preview = 8 - }; - private: CollectionBase *mIdCollection; - unsigned int mFeatures; // not implemented IdTable (const IdTable&); @@ -78,17 +57,17 @@ namespace CSMWorld const std::string& destination, UniversalId::Type type = UniversalId::Type_None); - QModelIndex getModelIndex (const std::string& id, int column) const; + virtual QModelIndex getModelIndex (const std::string& id, int column) const; void setRecord (const std::string& id, const RecordBase& record); ///< Add record or overwrite existing recrod. const RecordBase& getRecord (const std::string& id) const; - int searchColumnIndex (Columns::ColumnId id) const; + virtual int searchColumnIndex (Columns::ColumnId id) const; ///< Return index of column with the given \a id. If no such column exists, -1 is returned. - int findColumnIndex (Columns::ColumnId id) const; + virtual int findColumnIndex (Columns::ColumnId id) const; ///< Return index of column with the given \a id. If no such column exists, an exception is /// thrown. @@ -96,12 +75,13 @@ namespace CSMWorld ///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices /// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex). - unsigned int getFeatures() const; - - std::pair view (int row) const; + virtual std::pair view (int row) const; ///< Return the UniversalId and the hint for viewing \a row. If viewing is not /// supported by this table, return (UniversalId::Type_None, ""). + /// Is \a id flagged as deleted? + virtual bool isDeleted (const std::string& id) const; + int getColumnId(int column) const; }; } diff --git a/apps/opencs/model/world/idtablebase.cpp b/apps/opencs/model/world/idtablebase.cpp new file mode 100644 index 0000000000..31d8d461e1 --- /dev/null +++ b/apps/opencs/model/world/idtablebase.cpp @@ -0,0 +1,9 @@ + +#include "idtablebase.hpp" + +CSMWorld::IdTableBase::IdTableBase (unsigned int features) : mFeatures (features) {} + +unsigned int CSMWorld::IdTableBase::getFeatures() const +{ + return mFeatures; +} \ No newline at end of file diff --git a/apps/opencs/model/world/idtablebase.hpp b/apps/opencs/model/world/idtablebase.hpp new file mode 100644 index 0000000000..e6aaea1d63 --- /dev/null +++ b/apps/opencs/model/world/idtablebase.hpp @@ -0,0 +1,64 @@ +#ifndef CSM_WOLRD_IDTABLEBASE_H +#define CSM_WOLRD_IDTABLEBASE_H + +#include + +#include "columns.hpp" + +namespace CSMWorld +{ + class UniversalId; + + class IdTableBase : public QAbstractItemModel + { + Q_OBJECT + + public: + + enum Features + { + Feature_ReorderWithinTopic = 1, + + /// Use ID column to generate view request (ID is transformed into + /// worldspace and original ID is passed as hint with c: prefix). + Feature_ViewId = 2, + + /// Use cell column to generate view request (cell ID is transformed + /// into worldspace and record ID is passed as hint with r: prefix). + Feature_ViewCell = 4, + + Feature_View = Feature_ViewId | Feature_ViewCell, + + Feature_Preview = 8 + }; + + private: + + unsigned int mFeatures; + + public: + + IdTableBase (unsigned int features); + + virtual QModelIndex getModelIndex (const std::string& id, int column) const = 0; + + /// Return index of column with the given \a id. If no such column exists, -1 is + /// returned. + virtual int searchColumnIndex (Columns::ColumnId id) const = 0; + + /// Return index of column with the given \a id. If no such column exists, an + /// exception is thrown. + virtual int findColumnIndex (Columns::ColumnId id) const = 0; + + /// Return the UniversalId and the hint for viewing \a row. If viewing is not + /// supported by this table, return (UniversalId::Type_None, ""). + virtual std::pair view (int row) const = 0; + + /// Is \a id flagged as deleted? + virtual bool isDeleted (const std::string& id) const = 0; + + unsigned int getFeatures() const; + }; +} + +#endif diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index f51b7f818f..a5e9d354af 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -3,7 +3,7 @@ #include -#include "idtable.hpp" +#include "idtablebase.hpp" void CSMWorld::IdTableProxyModel::updateColumnMap() { @@ -13,7 +13,7 @@ void CSMWorld::IdTableProxyModel::updateColumnMap() { std::vector columns = mFilter->getReferencedColumns(); - const IdTable& table = dynamic_cast (*sourceModel()); + const IdTableBase& table = dynamic_cast (*sourceModel()); for (std::vector::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter) mColumnMap.insert (std::make_pair (*iter, @@ -28,7 +28,7 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI return true; return mFilter->test ( - dynamic_cast (*sourceModel()), sourceRow, mColumnMap); + dynamic_cast (*sourceModel()), sourceRow, mColumnMap); } CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) @@ -39,7 +39,7 @@ CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const { - return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); + return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); } void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr& filter) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 6377b03539..bbac2b1ca7 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -14,6 +14,7 @@ #include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/idtableproxymodel.hpp" +#include "../../model/world/idtablebase.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/record.hpp" #include "../../model/world/columns.hpp" @@ -82,7 +83,7 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) menu.addAction (mExtendedDeleteAction); } - if (mModel->getFeatures() & CSMWorld::IdTable::Feature_ReorderWithinTopic) + if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_ReorderWithinTopic) { /// \todo allow reordering of multiple rows if (selectedRows.size()==1) @@ -119,7 +120,7 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row(); - if (mModel->getFeatures() & CSMWorld::IdTable::Feature_View) + if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_View) { CSMWorld::UniversalId id = mModel->view (row).first; @@ -131,7 +132,7 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) menu.addAction (mViewAction); } - if (mModel->getFeatures() & CSMWorld::IdTable::Feature_Preview) + if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Preview) { QModelIndex index = mModel->index (row, mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification)); @@ -152,7 +153,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, : mCreateAction (0), mCloneAction(0), mRecordStatusDisplay (0), DragRecordTable(document) { - mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); + mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); mProxyModel = new CSMWorld::IdTableProxyModel (this); mProxyModel->setSourceModel (mModel); @@ -290,7 +291,7 @@ void CSVWorld::Table::cloneRecord() { QModelIndexList selectedRows = selectionModel()->selectedRows(); const CSMWorld::UniversalId& toClone = getUniversalId(selectedRows.begin()->row()); - if (selectedRows.size()==1 && !mModel->getRecord(toClone.getId()).isDeleted()) + if (selectedRows.size()==1 && !mModel->isDeleted (toClone.getId())) { emit cloneRequest (toClone); } @@ -324,7 +325,8 @@ void CSVWorld::Table::moveUpRecord() for (int i=1; i (*mModel), row, newOrder)); } } } @@ -356,7 +358,8 @@ void CSVWorld::Table::moveDownRecord() for (int i=1; i (*mModel), row, newOrder)); } } } diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 255c430ea5..883834b602 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -23,7 +23,7 @@ namespace CSMWorld class Data; class UniversalId; class IdTableProxyModel; - class IdTable; + class IdTableBase; class CommandDispatcher; } @@ -49,7 +49,7 @@ namespace CSVWorld QAction *mExtendedDeleteAction; QAction *mExtendedRevertAction; CSMWorld::IdTableProxyModel *mProxyModel; - CSMWorld::IdTable *mModel; + CSMWorld::IdTableBase *mModel; int mRecordStatusDisplay; CSMWorld::CommandDispatcher *mDispatcher; From 97138735381c808307122cd73ffc1047cd2c4340 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 5 Jul 2014 15:41:40 +1000 Subject: [PATCH 04/67] Minor change to improve generated STL code (only tested with MSVC 2012). More details in forum post https://forum.openmw.org/viewtopic.php?f=6&t=2153#p24065 --- extern/shiny/Main/Factory.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 6254edbafb..72af07d58f 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -267,10 +267,11 @@ namespace sh MaterialInstance* Factory::searchInstance (const std::string& name) { - if (mMaterials.find(name) != mMaterials.end()) - return &mMaterials.find(name)->second; - - return NULL; + MaterialMap::iterator it = mMaterials.find(name); + if (it != mMaterials.end()) + return &(it->second); + else + return NULL; } MaterialInstance* Factory::findInstance (const std::string& name) @@ -434,8 +435,9 @@ namespace sh std::string Factory::retrieveTextureAlias (const std::string& name) { - if (mTextureAliases.find(name) != mTextureAliases.end()) - return mTextureAliases[name]; + TextureAliasMap::iterator it = mTextureAliases.find(name); + if (it != mTextureAliases.end()) + return it->second; else return ""; } From e171babd2fd6f0698b0126ea3e001bee1eab00f7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Jul 2014 12:44:11 +0200 Subject: [PATCH 05/67] added Feature_Constant to IdTable --- apps/opencs/model/world/idtablebase.hpp | 5 ++++- apps/opencs/view/world/table.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/idtablebase.hpp b/apps/opencs/model/world/idtablebase.hpp index e6aaea1d63..ef5a9c42ed 100644 --- a/apps/opencs/model/world/idtablebase.hpp +++ b/apps/opencs/model/world/idtablebase.hpp @@ -29,7 +29,10 @@ namespace CSMWorld Feature_View = Feature_ViewId | Feature_ViewCell, - Feature_Preview = 8 + Feature_Preview = 8, + + /// Table can not be modified through ordinary means. + Feature_Constant = 16 }; private: diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index bbac2b1ca7..42874d6674 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -54,7 +54,7 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) /// \todo add menu items for select all and clear selection - if (!mEditLock) + if (!mEditLock && !(mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) { if (selectedRows.size()==1) { @@ -276,7 +276,7 @@ CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const void CSVWorld::Table::editRecord() { - if (!mEditLock) + if (!mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) { QModelIndexList selectedRows = selectionModel()->selectedRows(); @@ -287,7 +287,7 @@ void CSVWorld::Table::editRecord() void CSVWorld::Table::cloneRecord() { - if (!mEditLock) + if (!mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) { QModelIndexList selectedRows = selectionModel()->selectedRows(); const CSMWorld::UniversalId& toClone = getUniversalId(selectedRows.begin()->row()); @@ -300,7 +300,7 @@ void CSVWorld::Table::cloneRecord() void CSVWorld::Table::moveUpRecord() { - if (mEditLock) + if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) return; QModelIndexList selectedRows = selectionModel()->selectedRows(); @@ -333,7 +333,7 @@ void CSVWorld::Table::moveUpRecord() void CSVWorld::Table::moveDownRecord() { - if (mEditLock) + if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) return; QModelIndexList selectedRows = selectionModel()->selectedRows(); From 4f6c7b0e843d8de14fa0e92d25ce319d5d9978d4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Jul 2014 15:07:17 +0200 Subject: [PATCH 06/67] resolved UniversalId naming ambiguity --- apps/opencs/model/world/universalid.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 2056b0c4c0..7ee7673545 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -47,7 +47,7 @@ namespace { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Musics", 0 }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sounds", 0 }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", 0 }, @@ -106,7 +106,7 @@ namespace { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", 0 }, { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", 0 }, { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", 0 }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound", 0 }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", 0 }, { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", 0 }, { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", 0 }, From 42db9a5091552d5d32ef205bb0c4dc90455e81c3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Jul 2014 15:50:17 +0200 Subject: [PATCH 07/67] make modification column optional in table views --- apps/opencs/view/world/table.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 42874d6674..43a34e41da 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -425,21 +425,27 @@ void CSVWorld::Table::tableSizeUpdate() { int rows = mProxyModel->rowCount(); - for (int i=0; isearchColumnIndex (CSMWorld::Columns::ColumnId_Modification); + + if (columnIndex!=-1) { - QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (i, 0)); - - int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification); - int state = mModel->data (mModel->index (index.row(), columnIndex)).toInt(); - - switch (state) + for (int i=0; imapToSource (mProxyModel->index (i, 0)); + + int state = mModel->data (mModel->index (index.row(), columnIndex)).toInt(); + + switch (state) + { + case CSMWorld::RecordBase::State_BaseOnly: ++size; break; + case CSMWorld::RecordBase::State_Modified: ++size; ++modified; break; + case CSMWorld::RecordBase::State_ModifiedOnly: ++size; ++modified; break; + case CSMWorld::RecordBase:: State_Deleted: ++deleted; ++modified; break; + } } } + else + size = rows; } tableSizeChanged (size, deleted, modified); From b2c957a56fd810759d71641041477a8a0e185d57 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Jul 2014 15:50:47 +0200 Subject: [PATCH 08/67] added resources tables --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/data.cpp | 13 +++ apps/opencs/model/world/resourcetable.cpp | 123 ++++++++++++++++++++++ apps/opencs/model/world/resourcetable.hpp | 57 ++++++++++ 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/world/resourcetable.cpp create mode 100644 apps/opencs/model/world/resourcetable.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f6349aa7d0..288e0394c8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data commanddispatcher idtablebase + idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable ) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 823a14395f..b9f6c6cf96 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -16,6 +16,7 @@ #include "regionmap.hpp" #include "columns.hpp" #include "resourcesmanager.hpp" +#include "resourcetable.hpp" void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update) { @@ -279,6 +280,18 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); addModel (new IdTable (&mFilters), UniversalId::Type_Filter); + addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Mesh)), + UniversalId::Type_Mesh); + addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Icon)), + UniversalId::Type_Icon); + addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Music)), + UniversalId::Type_Music); + addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_SoundRes)), + UniversalId::Type_SoundRes); + addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Texture)), + UniversalId::Type_Texture); + addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Video)), + UniversalId::Type_Video); } CSMWorld::Data::~Data() diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp new file mode 100644 index 0000000000..f46ac1dc9a --- /dev/null +++ b/apps/opencs/model/world/resourcetable.cpp @@ -0,0 +1,123 @@ + +#include "resourcetable.hpp" + +#include + +#include "resources.hpp" +#include "columnbase.hpp" +#include "universalid.hpp" + +CSMWorld::ResourceTable::ResourceTable (const Resources *resources, unsigned int features) +: IdTableBase (features | Feature_Constant), mResources (resources) +{} + +CSMWorld::ResourceTable::~ResourceTable() {} + +int CSMWorld::ResourceTable::rowCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return mResources->getSize(); +} + +int CSMWorld::ResourceTable::columnCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return 1; +} + +QVariant CSMWorld::ResourceTable::data (const QModelIndex & index, int role) const +{ + if (role!=Qt::DisplayRole) + return QVariant(); + + if (index.column()!=0) + throw std::logic_error ("Invalid column in resource table"); + + return QString::fromUtf8 (mResources->getId (index.row()).c_str()); +} + +QVariant CSMWorld::ResourceTable::headerData (int section, Qt::Orientation orientation, + int role ) const +{ + if (orientation==Qt::Vertical) + return QVariant(); + + if (role==Qt::DisplayRole) + return "ID"; + + if (role==ColumnBase::Role_Flags) + return ColumnBase::Flag_Table; + + if (role==ColumnBase::Role_Display) + return ColumnBase::Display_String; + + return QVariant(); +} + +bool CSMWorld::ResourceTable::setData ( const QModelIndex &index, const QVariant &value, + int role) +{ + return false; +} + +Qt::ItemFlags CSMWorld::ResourceTable::flags (const QModelIndex & index) const +{ + return Qt::ItemIsSelectable | Qt::ItemIsEnabled;; +} + +QModelIndex CSMWorld::ResourceTable::index (int row, int column, const QModelIndex& parent) + const +{ + if (parent.isValid()) + return QModelIndex(); + + if (row<0 || row>=mResources->getSize()) + return QModelIndex(); + + if (column!=0) + return QModelIndex(); + + return createIndex (row, column); +} + +QModelIndex CSMWorld::ResourceTable::parent (const QModelIndex& index) const +{ + return QModelIndex(); +} + +QModelIndex CSMWorld::ResourceTable::getModelIndex (const std::string& id, int column) const +{ + return index (mResources->getIndex (id), column); +} + +int CSMWorld::ResourceTable::searchColumnIndex (Columns::ColumnId id) const +{ + if (id==Columns::ColumnId_Id) + return 0; + + return -1; +} + +int CSMWorld::ResourceTable::findColumnIndex (Columns::ColumnId id) const +{ + int index = searchColumnIndex (id); + + if (index==-1) + throw std::logic_error ("invalid column index"); + + return index; +} + +std::pair CSMWorld::ResourceTable::view (int row) const +{ + return std::make_pair (UniversalId::Type_None, ""); +} + +bool CSMWorld::ResourceTable::isDeleted (const std::string& id) const +{ + return false; +} \ No newline at end of file diff --git a/apps/opencs/model/world/resourcetable.hpp b/apps/opencs/model/world/resourcetable.hpp new file mode 100644 index 0000000000..f5011ab2bd --- /dev/null +++ b/apps/opencs/model/world/resourcetable.hpp @@ -0,0 +1,57 @@ +#ifndef CSM_WOLRD_RESOURCETABLE_H +#define CSM_WOLRD_RESOURCETABLE_H + +#include "idtablebase.hpp" + +namespace CSMWorld +{ + class Resources; + + class ResourceTable : public IdTableBase + { + const Resources *mResources; + + public: + + /// \note The feature Feature_Constant will be added implicitly. + ResourceTable (const Resources *resources, unsigned int features = 0); + + virtual ~ResourceTable(); + + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; + + virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; + + virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + virtual Qt::ItemFlags flags (const QModelIndex & index) const; + + virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) + const; + + virtual QModelIndex parent (const QModelIndex& index) const; + + virtual QModelIndex getModelIndex (const std::string& id, int column) const; + + /// Return index of column with the given \a id. If no such column exists, -1 is + /// returned. + virtual int searchColumnIndex (Columns::ColumnId id) const; + + /// Return index of column with the given \a id. If no such column exists, an + /// exception is thrown. + virtual int findColumnIndex (Columns::ColumnId id) const; + + /// Return the UniversalId and the hint for viewing \a row. If viewing is not + /// supported by this table, return (UniversalId::Type_None, ""). + virtual std::pair view (int row) const; + + /// Is \a id flagged as deleted? + virtual bool isDeleted (const std::string& id) const; + }; +} + +#endif From 19828df7997a023010da172ca87aa14f698d223b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 5 Jul 2014 15:51:17 +0200 Subject: [PATCH 09/67] added subviews for resources tables --- apps/opencs/view/doc/view.cpp | 56 +++++++++++++++++++++++++++++ apps/opencs/view/doc/view.hpp | 12 +++++++ apps/opencs/view/world/subviews.cpp | 15 ++++++++ 3 files changed, 83 insertions(+) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 6a807f086a..4868f20ff1 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -204,6 +204,32 @@ void CSVDoc::View::setupAssetsMenu() QAction *sounds = new QAction (tr ("Sounds"), this); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); assets->addAction (sounds); + + assets->addSeparator(); // resources follow here + + QAction *meshes = new QAction (tr ("Meshes"), this); + connect (meshes, SIGNAL (triggered()), this, SLOT (addMeshesSubView())); + assets->addAction (meshes); + + QAction *icons = new QAction (tr ("Icons"), this); + connect (icons, SIGNAL (triggered()), this, SLOT (addIconsSubView())); + assets->addAction (icons); + + QAction *musics = new QAction (tr ("Music"), this); + connect (musics, SIGNAL (triggered()), this, SLOT (addMusicsSubView())); + assets->addAction (musics); + + QAction *soundsRes = new QAction (tr ("Sound Files"), this); + connect (soundsRes, SIGNAL (triggered()), this, SLOT (addSoundsResSubView())); + assets->addAction (soundsRes); + + QAction *textures = new QAction (tr ("Textures"), this); + connect (textures, SIGNAL (triggered()), this, SLOT (addTexturesSubView())); + assets->addAction (textures); + + QAction *videos = new QAction (tr ("Videos"), this); + connect (videos, SIGNAL (triggered()), this, SLOT (addVideosSubView())); + assets->addAction (videos); } void CSVDoc::View::setupUi() @@ -487,6 +513,36 @@ void CSVDoc::View::addBodyPartsSubView() addSubView (CSMWorld::UniversalId::Type_BodyParts); } +void CSVDoc::View::addMeshesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Meshes); +} + +void CSVDoc::View::addIconsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Icons); +} + +void CSVDoc::View::addMusicsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Musics); +} + +void CSVDoc::View::addSoundsResSubView() +{ + addSubView (CSMWorld::UniversalId::Type_SoundsRes); +} + +void CSVDoc::View::addTexturesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Textures); +} + +void CSVDoc::View::addVideosSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Videos); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index a227997c21..19171ff425 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -182,6 +182,18 @@ namespace CSVDoc void addBodyPartsSubView(); + void addMeshesSubView(); + + void addIconsSubView(); + + void addMusicsSubView(); + + void addSoundsResSubView(); + + void addTexturesSubView(); + + void addVideosSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 8c666c1fed..200a26a852 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -70,6 +70,21 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_JournalInfos, new CSVDoc::SubViewFactoryWithCreator > (false)); + // Subviews for resources tables + manager.add (CSMWorld::UniversalId::Type_Meshes, + new CSVDoc::SubViewFactoryWithCreator); + manager.add (CSMWorld::UniversalId::Type_Icons, + new CSVDoc::SubViewFactoryWithCreator); + manager.add (CSMWorld::UniversalId::Type_Musics, + new CSVDoc::SubViewFactoryWithCreator); + manager.add (CSMWorld::UniversalId::Type_SoundsRes, + new CSVDoc::SubViewFactoryWithCreator); + manager.add (CSMWorld::UniversalId::Type_Textures, + new CSVDoc::SubViewFactoryWithCreator); + manager.add (CSMWorld::UniversalId::Type_Videos, + new CSVDoc::SubViewFactoryWithCreator); + + // Subviews for editing/viewing individual records manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory); From df6996d4aecab50e6c57c0fd7756584f470d4f9e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 7 Jul 2014 11:34:24 +0200 Subject: [PATCH 10/67] filter resources files based on extension --- apps/opencs/model/world/resources.cpp | 34 ++++++++++++++++---- apps/opencs/model/world/resources.hpp | 2 +- apps/opencs/model/world/resourcesmanager.cpp | 5 ++- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index c819283e18..357661ac39 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -8,7 +8,8 @@ #include -CSMWorld::Resources::Resources (const std::string& baseDirectory) +CSMWorld::Resources::Resources (const std::string& baseDirectory, + const char * const *extensions) : mBaseDirectory (baseDirectory) { int baseSize = mBaseDirectory.size(); @@ -28,14 +29,33 @@ CSMWorld::Resources::Resources (const std::string& baseDirectory) for (Ogre::StringVector::const_iterator iter (resources->begin()); iter!=resources->end(); ++iter) { - if (static_cast (iter->size())>=baseSize+1 && - iter->substr (0, baseSize)==mBaseDirectory && - ((*iter)[baseSize]=='/' || (*iter)[baseSize]=='\\')) + if (static_cast (iter->size())substr (0, baseSize)!=mBaseDirectory || + ((*iter)[baseSize]!='/' && (*iter)[baseSize]!='\\')) + continue; + + if (extensions) { - std::string file = iter->substr (baseSize+1); - mFiles.push_back (file); - mIndex.insert (std::make_pair (file, static_cast (mFiles.size())-1)); + std::string::size_type index = iter->find_last_of ('.'); + + if (index==std::string::npos) + continue; + + std::string extension = iter->substr (index+1); + + int i = 0; + + for (; extensions[i]; ++i) + if (extensions[i]==extension) + break; + + if (!extensions[i]) + continue; } + + std::string file = iter->substr (baseSize+1); + mFiles.push_back (file); + mIndex.insert (std::make_pair (file, static_cast (mFiles.size())-1)); } } } diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp index 54c4fa8214..599f9a35b4 100644 --- a/apps/opencs/model/world/resources.hpp +++ b/apps/opencs/model/world/resources.hpp @@ -15,7 +15,7 @@ namespace CSMWorld public: - Resources (const std::string& baseDirectory); + Resources (const std::string& baseDirectory, const char * const *extensions = 0); int getSize() const; diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 980e099f4b..7c782e7c59 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -5,7 +5,10 @@ void CSMWorld::ResourcesManager::listResources() { - mResources.insert (std::make_pair (UniversalId::Type_Mesh, "meshes")); + static const char * const sMeshTypes[] = { "nif", 0 }; + + mResources.insert ( + std::make_pair (UniversalId::Type_Mesh, Resources ("meshes", sMeshTypes))); mResources.insert (std::make_pair (UniversalId::Type_Icon, "icons")); mResources.insert (std::make_pair (UniversalId::Type_Music, "music")); mResources.insert (std::make_pair (UniversalId::Type_SoundRes, "sound")); From c1bbefb8400dca56544a0731a6d74ef49278482a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 7 Jul 2014 15:20:05 +0200 Subject: [PATCH 11/67] enable dragging from resources tables --- apps/opencs/model/world/resources.cpp | 9 +++- apps/opencs/model/world/resources.hpp | 9 +++- apps/opencs/model/world/resourcesmanager.cpp | 18 +++++--- apps/opencs/model/world/resourcesmanager.hpp | 4 ++ apps/opencs/model/world/resourcetable.cpp | 45 +++++++++++++++----- 5 files changed, 65 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 357661ac39..8e255bc964 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -8,9 +8,9 @@ #include -CSMWorld::Resources::Resources (const std::string& baseDirectory, +CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::Type type, const char * const *extensions) -: mBaseDirectory (baseDirectory) +: mBaseDirectory (baseDirectory), mType (type) { int baseSize = mBaseDirectory.size(); @@ -95,4 +95,9 @@ int CSMWorld::Resources::searchId (const std::string& id) const return -1; return iter->second; +} + +CSMWorld::UniversalId::Type CSMWorld::Resources::getType() const +{ + return mType; } \ No newline at end of file diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp index 599f9a35b4..9c1c76b6f2 100644 --- a/apps/opencs/model/world/resources.hpp +++ b/apps/opencs/model/world/resources.hpp @@ -5,6 +5,8 @@ #include #include +#include "universalid.hpp" + namespace CSMWorld { class Resources @@ -12,10 +14,13 @@ namespace CSMWorld std::map mIndex; std::vector mFiles; std::string mBaseDirectory; + UniversalId::Type mType; public: - Resources (const std::string& baseDirectory, const char * const *extensions = 0); + /// \param type Type of resources in this table. + Resources (const std::string& baseDirectory, UniversalId::Type type, + const char * const *extensions = 0); int getSize() const; @@ -24,6 +29,8 @@ namespace CSMWorld int getIndex (const std::string& id) const; int searchId (const std::string& id) const; + + UniversalId::Type getType() const; }; } diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 7c782e7c59..5692d30ac3 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -3,17 +3,21 @@ #include +void CSMWorld::ResourcesManager::addResources (const Resources& resources) +{ + mResources.insert (std::make_pair (resources.getType(), resources)); +} + void CSMWorld::ResourcesManager::listResources() { static const char * const sMeshTypes[] = { "nif", 0 }; - mResources.insert ( - std::make_pair (UniversalId::Type_Mesh, Resources ("meshes", sMeshTypes))); - mResources.insert (std::make_pair (UniversalId::Type_Icon, "icons")); - mResources.insert (std::make_pair (UniversalId::Type_Music, "music")); - mResources.insert (std::make_pair (UniversalId::Type_SoundRes, "sound")); - mResources.insert (std::make_pair (UniversalId::Type_Texture, "textures")); - mResources.insert (std::make_pair (UniversalId::Type_Video, "videos")); + addResources (Resources ("meshes", UniversalId::Type_Mesh, sMeshTypes)); + addResources (Resources ("icons", UniversalId::Type_Icon)); + addResources (Resources ("music", UniversalId::Type_Music)); + addResources (Resources ("sound", UniversalId::Type_SoundRes)); + addResources (Resources ("textures", UniversalId::Type_Texture)); + addResources (Resources ("videos", UniversalId::Type_Video)); } const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index e3bbd8a2a3..77f210c478 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -12,6 +12,10 @@ namespace CSMWorld { std::map mResources; + private: + + void addResources (const Resources& resources); + public: /// Ask OGRE for a list of available resources. diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index f46ac1dc9a..167b48436e 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -26,7 +26,7 @@ int CSMWorld::ResourceTable::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 1; + return 2; // ID, type } QVariant CSMWorld::ResourceTable::data (const QModelIndex & index, int role) const @@ -34,10 +34,13 @@ QVariant CSMWorld::ResourceTable::data (const QModelIndex & index, int role) co if (role!=Qt::DisplayRole) return QVariant(); - if (index.column()!=0) - throw std::logic_error ("Invalid column in resource table"); + if (index.column()==0) + return QString::fromUtf8 (mResources->getId (index.row()).c_str()); - return QString::fromUtf8 (mResources->getId (index.row()).c_str()); + if (index.column()==1) + return static_cast (mResources->getType()); + + throw std::logic_error ("Invalid column in resource table"); } QVariant CSMWorld::ResourceTable::headerData (int section, Qt::Orientation orientation, @@ -46,14 +49,33 @@ QVariant CSMWorld::ResourceTable::headerData (int section, Qt::Orientation orien if (orientation==Qt::Vertical) return QVariant(); - if (role==Qt::DisplayRole) - return "ID"; - if (role==ColumnBase::Role_Flags) return ColumnBase::Flag_Table; - if (role==ColumnBase::Role_Display) - return ColumnBase::Display_String; + switch (section) + { + case 0: + + if (role==Qt::DisplayRole) + return Columns::getName (Columns::ColumnId_Id).c_str(); + + if (role==ColumnBase::Role_Display) + return ColumnBase::Display_String; + + break; + + case 1: + + if (role==Qt::DisplayRole) + return Columns::getName (Columns::ColumnId_RecordType).c_str(); + + if (role==ColumnBase::Role_Display) + return ColumnBase::Display_Integer; + + break; + } + + // xxx return QVariant(); } @@ -78,7 +100,7 @@ QModelIndex CSMWorld::ResourceTable::index (int row, int column, const QModelInd if (row<0 || row>=mResources->getSize()) return QModelIndex(); - if (column!=0) + if (column<0 || column>1) return QModelIndex(); return createIndex (row, column); @@ -99,6 +121,9 @@ int CSMWorld::ResourceTable::searchColumnIndex (Columns::ColumnId id) const if (id==Columns::ColumnId_Id) return 0; + if (id==Columns::ColumnId_RecordType) + return 1; + return -1; } From b2c2342988243ef0b218cdd0f9da3c4392a8b054 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jul 2014 08:53:39 +0200 Subject: [PATCH 12/67] some refactoring (removing redundant code) --- apps/opencs/model/world/tablemimedata.cpp | 227 +++++++--------------- 1 file changed, 68 insertions(+), 159 deletions(-) diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index 6d65d0ff80..fd5fab960b 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -209,170 +209,79 @@ bool CSMWorld::TableMimeData::fromDocument (const CSMDoc::Document& document) co return &document == &mDocument; } -CSMWorld::UniversalId::Type CSMWorld::TableMimeData::convertEnums (CSMWorld::ColumnBase::Display type) +namespace { - switch (type) + struct Mapping { - case CSMWorld::ColumnBase::Display_Race: - return CSMWorld::UniversalId::Type_Race; - - - case CSMWorld::ColumnBase::Display_Skill: - return CSMWorld::UniversalId::Type_Skill; - - - case CSMWorld::ColumnBase::Display_Class: - return CSMWorld::UniversalId::Type_Class; - - - case CSMWorld::ColumnBase::Display_Faction: - return CSMWorld::UniversalId::Type_Faction; - - - case CSMWorld::ColumnBase::Display_Sound: - return CSMWorld::UniversalId::Type_Sound; - - - case CSMWorld::ColumnBase::Display_Region: - return CSMWorld::UniversalId::Type_Region; - - - case CSMWorld::ColumnBase::Display_Birthsign: - return CSMWorld::UniversalId::Type_Birthsign; - - - case CSMWorld::ColumnBase::Display_Spell: - return CSMWorld::UniversalId::Type_Spell; - - - case CSMWorld::ColumnBase::Display_Cell: - return CSMWorld::UniversalId::Type_Cell; - - - case CSMWorld::ColumnBase::Display_Referenceable: - return CSMWorld::UniversalId::Type_Referenceable; - - - case CSMWorld::ColumnBase::Display_Activator: - return CSMWorld::UniversalId::Type_Activator; - - - case CSMWorld::ColumnBase::Display_Potion: - return CSMWorld::UniversalId::Type_Potion; - - - case CSMWorld::ColumnBase::Display_Apparatus: - return CSMWorld::UniversalId::Type_Apparatus; - - - case CSMWorld::ColumnBase::Display_Armor: - return CSMWorld::UniversalId::Type_Armor; - - - case CSMWorld::ColumnBase::Display_Book: - return CSMWorld::UniversalId::Type_Book; - - - case CSMWorld::ColumnBase::Display_Clothing: - return CSMWorld::UniversalId::Type_Clothing; - - - case CSMWorld::ColumnBase::Display_Container: - return CSMWorld::UniversalId::Type_Container; - - - case CSMWorld::ColumnBase::Display_Creature: - return CSMWorld::UniversalId::Type_Creature; - - - case CSMWorld::ColumnBase::Display_Door: - return CSMWorld::UniversalId::Type_Door; - - - case CSMWorld::ColumnBase::Display_Ingredient: - return CSMWorld::UniversalId::Type_Ingredient; - - - case CSMWorld::ColumnBase::Display_CreatureLevelledList: - return CSMWorld::UniversalId::Type_CreatureLevelledList; - - - case CSMWorld::ColumnBase::Display_ItemLevelledList: - return CSMWorld::UniversalId::Type_ItemLevelledList; - - - case CSMWorld::ColumnBase::Display_Light: - return CSMWorld::UniversalId::Type_Light; - - - case CSMWorld::ColumnBase::Display_Lockpick: - return CSMWorld::UniversalId::Type_Lockpick; - - - case CSMWorld::ColumnBase::Display_Miscellaneous: - return CSMWorld::UniversalId::Type_Miscellaneous; - - - case CSMWorld::ColumnBase::Display_Npc: - return CSMWorld::UniversalId::Type_Npc; - - - case CSMWorld::ColumnBase::Display_Probe: - return CSMWorld::UniversalId::Type_Probe; - - - case CSMWorld::ColumnBase::Display_Repair: - return CSMWorld::UniversalId::Type_Repair; - - - case CSMWorld::ColumnBase::Display_Static: - return CSMWorld::UniversalId::Type_Static; - - - case CSMWorld::ColumnBase::Display_Weapon: - return CSMWorld::UniversalId::Type_Weapon; - - - case CSMWorld::ColumnBase::Display_Reference: - return CSMWorld::UniversalId::Type_Reference; - - - case CSMWorld::ColumnBase::Display_Filter: - return CSMWorld::UniversalId::Type_Filter; - - - case CSMWorld::ColumnBase::Display_Topic: - return CSMWorld::UniversalId::Type_Topic; - - - case CSMWorld::ColumnBase::Display_Journal: - return CSMWorld::UniversalId::Type_Journal; - - - case CSMWorld::ColumnBase::Display_TopicInfo: - return CSMWorld::UniversalId::Type_TopicInfo; - - - case CSMWorld::ColumnBase::Display_JournalInfo: - return CSMWorld::UniversalId::Type_JournalInfo; - - - case CSMWorld::ColumnBase::Display_Scene: - return CSMWorld::UniversalId::Type_Scene; - - - case CSMWorld::ColumnBase::Display_Script: - return CSMWorld::UniversalId::Type_Script; - - - default: - return CSMWorld::UniversalId::Type_None; - - } + CSMWorld::UniversalId::Type mUniversalIdType; + CSMWorld::ColumnBase::Display mDisplayType; + }; + + const Mapping mapping[] = + { + { CSMWorld::UniversalId::Type_Race, CSMWorld::ColumnBase::Display_Race }, + { CSMWorld::UniversalId::Type_Skill, CSMWorld::ColumnBase::Display_Skill }, + { CSMWorld::UniversalId::Type_Class, CSMWorld::ColumnBase::Display_Class }, + { CSMWorld::UniversalId::Type_Class, CSMWorld::ColumnBase::Display_Class }, + { CSMWorld::UniversalId::Type_Faction, CSMWorld::ColumnBase::Display_Faction }, + { CSMWorld::UniversalId::Type_Sound, CSMWorld::ColumnBase::Display_Sound }, + { CSMWorld::UniversalId::Type_Region, CSMWorld::ColumnBase::Display_Region }, + { CSMWorld::UniversalId::Type_Birthsign, CSMWorld::ColumnBase::Display_Birthsign }, + { CSMWorld::UniversalId::Type_Spell, CSMWorld::ColumnBase::Display_Spell }, + { CSMWorld::UniversalId::Type_Cell, CSMWorld::ColumnBase::Display_Cell }, + { CSMWorld::UniversalId::Type_Referenceable, CSMWorld::ColumnBase::Display_Referenceable }, + { CSMWorld::UniversalId::Type_Activator, CSMWorld::ColumnBase::Display_Activator }, + { CSMWorld::UniversalId::Type_Potion, CSMWorld::ColumnBase::Display_Potion }, + { CSMWorld::UniversalId::Type_Apparatus, CSMWorld::ColumnBase::Display_Apparatus }, + { CSMWorld::UniversalId::Type_Armor, CSMWorld::ColumnBase::Display_Armor }, + { CSMWorld::UniversalId::Type_Book, CSMWorld::ColumnBase::Display_Book }, + { CSMWorld::UniversalId::Type_Clothing, CSMWorld::ColumnBase::Display_Clothing }, + { CSMWorld::UniversalId::Type_Container, CSMWorld::ColumnBase::Display_Container }, + { CSMWorld::UniversalId::Type_Creature, CSMWorld::ColumnBase::Display_Creature }, + { CSMWorld::UniversalId::Type_Door, CSMWorld::ColumnBase::Display_Door }, + { CSMWorld::UniversalId::Type_Ingredient, CSMWorld::ColumnBase::Display_Ingredient }, + { CSMWorld::UniversalId::Type_CreatureLevelledList, CSMWorld::ColumnBase::Display_CreatureLevelledList }, + { CSMWorld::UniversalId::Type_ItemLevelledList, CSMWorld::ColumnBase::Display_ItemLevelledList }, + { CSMWorld::UniversalId::Type_Light, CSMWorld::ColumnBase::Display_Light }, + { CSMWorld::UniversalId::Type_Lockpick, CSMWorld::ColumnBase::Display_Lockpick }, + { CSMWorld::UniversalId::Type_Miscellaneous, CSMWorld::ColumnBase::Display_Miscellaneous }, + { CSMWorld::UniversalId::Type_Npc, CSMWorld::ColumnBase::Display_Npc }, + { CSMWorld::UniversalId::Type_Probe, CSMWorld::ColumnBase::Display_Probe }, + { CSMWorld::UniversalId::Type_Repair, CSMWorld::ColumnBase::Display_Repair }, + { CSMWorld::UniversalId::Type_Static, CSMWorld::ColumnBase::Display_Static }, + { CSMWorld::UniversalId::Type_Weapon, CSMWorld::ColumnBase::Display_Weapon }, + { CSMWorld::UniversalId::Type_Reference, CSMWorld::ColumnBase::Display_Reference }, + { CSMWorld::UniversalId::Type_Filter, CSMWorld::ColumnBase::Display_Filter }, + { CSMWorld::UniversalId::Type_Topic, CSMWorld::ColumnBase::Display_Topic }, + { CSMWorld::UniversalId::Type_Journal, CSMWorld::ColumnBase::Display_Journal }, + { CSMWorld::UniversalId::Type_TopicInfo, CSMWorld::ColumnBase::Display_TopicInfo }, + { CSMWorld::UniversalId::Type_JournalInfo, CSMWorld::ColumnBase::Display_JournalInfo }, + { CSMWorld::UniversalId::Type_Scene, CSMWorld::ColumnBase::Display_Scene }, + { CSMWorld::UniversalId::Type_Script, CSMWorld::ColumnBase::Display_Script }, + + + { CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker + }; } -CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (CSMWorld::UniversalId::Type type) +CSMWorld::UniversalId::Type CSMWorld::TableMimeData::convertEnums (ColumnBase::Display type) { + for (int i=0; mapping[i].mUniversalIdType!=CSMWorld::UniversalId::Type_None; ++i) + if (mapping[i].mDisplayType==type) + return mapping[i].mUniversalIdType; + + return CSMWorld::UniversalId::Type_None; +} + +CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (UniversalId::Type type) +{ + for (int i=0; mapping[i].mUniversalIdType!=CSMWorld::UniversalId::Type_None; ++i) + if (mapping[i].mUniversalIdType==type) + return mapping[i].mDisplayType; + + return CSMWorld::ColumnBase::Display_None; + + switch (type) { case CSMWorld::UniversalId::Type_Race: From b2ce94f28addd5dac262b2f1448e56cb5d704c30 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jul 2014 08:56:28 +0200 Subject: [PATCH 13/67] fixed exceptions --- apps/opencs/model/world/tablemimedata.cpp | 165 +--------------------- 1 file changed, 3 insertions(+), 162 deletions(-) diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index fd5fab960b..18c1ee4ce4 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -37,7 +37,7 @@ std::string CSMWorld::TableMimeData::getIcon() const if (mUniversalId.empty()) { qDebug()<<"TableMimeData object does not hold any records!"; //because throwing in the event loop tends to be problematic - throw("TableMimeData object does not hold any records!"); + throw std::runtime_error ("TableMimeData object does not hold any records!"); } std::string tmpIcon; @@ -179,7 +179,7 @@ CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::Univers } } - throw ("TableMimeData object does not hold object of the seeked type"); + throw std::runtime_error ("TableMimeData object does not hold object of the seeked type"); } CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::ColumnBase::Display type) const @@ -201,7 +201,7 @@ CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::ColumnB } } - throw ("TableMimeData object does not hold object of the seeked type"); + throw std::runtime_error ("TableMimeData object does not hold object of the seeked type"); } bool CSMWorld::TableMimeData::fromDocument (const CSMDoc::Document& document) const @@ -280,165 +280,6 @@ CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (UniversalId return mapping[i].mDisplayType; return CSMWorld::ColumnBase::Display_None; - - - switch (type) - { - case CSMWorld::UniversalId::Type_Race: - return CSMWorld::ColumnBase::Display_Race; - - - case CSMWorld::UniversalId::Type_Skill: - return CSMWorld::ColumnBase::Display_Skill; - - - case CSMWorld::UniversalId::Type_Class: - return CSMWorld::ColumnBase::Display_Class; - - - case CSMWorld::UniversalId::Type_Faction: - return CSMWorld::ColumnBase::Display_Faction; - - - case CSMWorld::UniversalId::Type_Sound: - return CSMWorld::ColumnBase::Display_Sound; - - - case CSMWorld::UniversalId::Type_Region: - return CSMWorld::ColumnBase::Display_Region; - - - case CSMWorld::UniversalId::Type_Birthsign: - return CSMWorld::ColumnBase::Display_Birthsign; - - - case CSMWorld::UniversalId::Type_Spell: - return CSMWorld::ColumnBase::Display_Spell; - - - case CSMWorld::UniversalId::Type_Cell: - return CSMWorld::ColumnBase::Display_Cell; - - - case CSMWorld::UniversalId::Type_Referenceable: - return CSMWorld::ColumnBase::Display_Referenceable; - - - case CSMWorld::UniversalId::Type_Activator: - return CSMWorld::ColumnBase::Display_Activator; - - - case CSMWorld::UniversalId::Type_Potion: - return CSMWorld::ColumnBase::Display_Potion; - - - case CSMWorld::UniversalId::Type_Apparatus: - return CSMWorld::ColumnBase::Display_Apparatus; - - - case CSMWorld::UniversalId::Type_Armor: - return CSMWorld::ColumnBase::Display_Armor; - - - case CSMWorld::UniversalId::Type_Book: - return CSMWorld::ColumnBase::Display_Book; - - - case CSMWorld::UniversalId::Type_Clothing: - return CSMWorld::ColumnBase::Display_Clothing; - - - case CSMWorld::UniversalId::Type_Container: - return CSMWorld::ColumnBase::Display_Container; - - - case CSMWorld::UniversalId::Type_Creature: - return CSMWorld::ColumnBase::Display_Creature; - - - case CSMWorld::UniversalId::Type_Door: - return CSMWorld::ColumnBase::Display_Door; - - - case CSMWorld::UniversalId::Type_Ingredient: - return CSMWorld::ColumnBase::Display_Ingredient; - - - case CSMWorld::UniversalId::Type_CreatureLevelledList: - return CSMWorld::ColumnBase::Display_CreatureLevelledList; - - - case CSMWorld::UniversalId::Type_ItemLevelledList: - return CSMWorld::ColumnBase::Display_ItemLevelledList; - - - case CSMWorld::UniversalId::Type_Light: - return CSMWorld::ColumnBase::Display_Light; - - - case CSMWorld::UniversalId::Type_Lockpick: - return CSMWorld::ColumnBase::Display_Lockpick; - - - case CSMWorld::UniversalId::Type_Miscellaneous: - return CSMWorld::ColumnBase::Display_Miscellaneous; - - - case CSMWorld::UniversalId::Type_Npc: - return CSMWorld::ColumnBase::Display_Npc; - - - case CSMWorld::UniversalId::Type_Probe: - return CSMWorld::ColumnBase::Display_Probe; - - - case CSMWorld::UniversalId::Type_Repair: - return CSMWorld::ColumnBase::Display_Repair; - - - case CSMWorld::UniversalId::Type_Static: - return CSMWorld::ColumnBase::Display_Static; - - - case CSMWorld::UniversalId::Type_Weapon: - return CSMWorld::ColumnBase::Display_Weapon; - - - case CSMWorld::UniversalId::Type_Reference: - return CSMWorld::ColumnBase::Display_Reference; - - - case CSMWorld::UniversalId::Type_Filter: - return CSMWorld::ColumnBase::Display_Filter; - - - case CSMWorld::UniversalId::Type_Topic: - return CSMWorld::ColumnBase::Display_Topic; - - - case CSMWorld::UniversalId::Type_Journal: - return CSMWorld::ColumnBase::Display_Journal; - - - case CSMWorld::UniversalId::Type_TopicInfo: - return CSMWorld::ColumnBase::Display_TopicInfo; - - - case CSMWorld::UniversalId::Type_JournalInfo: - return CSMWorld::ColumnBase::Display_JournalInfo; - - - case CSMWorld::UniversalId::Type_Scene: - return CSMWorld::ColumnBase::Display_Scene; - - - case CSMWorld::UniversalId::Type_Script: - return CSMWorld::ColumnBase::Display_Script; - - - default: - return CSMWorld::ColumnBase::Display_None; - } } const CSMDoc::Document* CSMWorld::TableMimeData::getDocumentPtr() const From 9d5956585c40bca6813f85d112ae50fe83c97ecd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jul 2014 09:08:01 +0200 Subject: [PATCH 14/67] added separate display type for colours --- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/view/world/util.cpp | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 39c700fa14..149a71d42b 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -92,7 +92,8 @@ namespace CSMWorld Display_EnchantmentType, Display_BodyPartType, Display_MeshType, - Display_Gender + Display_Gender, + Display_Colour }; int mColumnId; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 72f2099fae..ebd5756d07 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -634,7 +634,7 @@ namespace CSMWorld { /// \todo Replace Display_Integer with something that displays the colour value more directly. MapColourColumn() - : Column (Columns::ColumnId_MapColour, ColumnBase::Display_Integer) + : Column (Columns::ColumnId_MapColour, ColumnBase::Display_Colour) {} virtual QVariant get (const Record& record) const diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 6f3999363e..5d26b75c4f 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -145,10 +145,11 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO if (display != CSMWorld::ColumnBase::Display_None) { - if (variant.type() == QVariant::Color) + if (display == CSMWorld::ColumnBase::Display_Colour) { return new QLineEdit(parent); } + if (display == CSMWorld::ColumnBase::Display_Integer) { return new QSpinBox(parent); From b6c5ee125d8d334c3265da0cf01e55950ec349da Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jul 2014 09:24:05 +0200 Subject: [PATCH 15/67] more refactoring --- apps/opencs/view/world/util.cpp | 63 ++++++++++++++++----------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 5d26b75c4f..0b06cfb362 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -143,50 +143,47 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO } } - if (display != CSMWorld::ColumnBase::Display_None) + switch (display) { - if (display == CSMWorld::ColumnBase::Display_Colour) - { - return new QLineEdit(parent); - } + case CSMWorld::ColumnBase::Display_Colour: - if (display == CSMWorld::ColumnBase::Display_Integer) - { - return new QSpinBox(parent); - } - if (display == CSMWorld::ColumnBase::Display_Var) - { return new QLineEdit(parent); - } - if (display == CSMWorld::ColumnBase::Display_Float) - { + + case CSMWorld::ColumnBase::Display_Integer: + + return new QSpinBox(parent); + + case CSMWorld::ColumnBase::Display_Var: + + return new QLineEdit(parent); + + case CSMWorld::ColumnBase::Display_Float: + return new QDoubleSpinBox(parent); - } - if (display == CSMWorld::ColumnBase::Display_LongString) - { + + case CSMWorld::ColumnBase::Display_LongString: + return new QTextEdit(parent); - } - if (display == CSMWorld::ColumnBase::Display_String || - display == CSMWorld::ColumnBase::Display_Skill || - display == CSMWorld::ColumnBase::Display_Script || - display == CSMWorld::ColumnBase::Display_Race || - display == CSMWorld::ColumnBase::Display_Class || - display == CSMWorld::ColumnBase::Display_Faction || - display == CSMWorld::ColumnBase::Display_Miscellaneous || - display == CSMWorld::ColumnBase::Display_Sound) - { - return new DropLineEdit(parent); - } - if (display == CSMWorld::ColumnBase::Display_Boolean) - { + + case CSMWorld::ColumnBase::Display_Boolean: + return new QCheckBox(parent); - } + + case CSMWorld::ColumnBase::Display_String: + case CSMWorld::ColumnBase::Display_Skill: + case CSMWorld::ColumnBase::Display_Script: + case CSMWorld::ColumnBase::Display_Race: + case CSMWorld::ColumnBase::Display_Class: + case CSMWorld::ColumnBase::Display_Faction: + case CSMWorld::ColumnBase::Display_Miscellaneous: + case CSMWorld::ColumnBase::Display_Sound: + + return new DropLineEdit(parent); } return QStyledItemDelegate::createEditor (parent, option, index); } - void CSVWorld::CommandDelegate::setEditLock (bool locked) { mEditLock = locked; From 1548f4670a8bf51fd1f266cfb8571d006213f8b0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jul 2014 09:51:17 +0200 Subject: [PATCH 16/67] drop part of resources drag and drop --- apps/opencs/model/world/columnbase.hpp | 6 ++++++ apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 4 ++-- apps/opencs/model/world/tablemimedata.cpp | 7 ++++++- apps/opencs/view/world/util.cpp | 12 ++++++++++-- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 149a71d42b..1444f70f1d 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -93,6 +93,12 @@ namespace CSMWorld Display_BodyPartType, Display_MeshType, Display_Gender, + Display_Mesh, + Display_Icon, + Display_Music, + Display_SoundRes, + Display_Texture, + Display_Video, Display_Colour }; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index ebd5756d07..0c033593c8 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -604,7 +604,7 @@ namespace CSMWorld struct SoundFileColumn : public Column { SoundFileColumn() - : Column (Columns::ColumnId_SoundFile, ColumnBase::Display_Sound) + : Column (Columns::ColumnId_SoundFile, ColumnBase::Display_SoundRes) {} virtual QVariant get (const Record& record) const diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index c16218a0be..779d5a40cd 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -52,7 +52,7 @@ CSMWorld::RefIdCollection::RefIdCollection() ModelColumns modelColumns (baseColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Model, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Model, ColumnBase::Display_Mesh)); modelColumns.mModel = &mColumns.back(); NameColumns nameColumns (modelColumns); @@ -64,7 +64,7 @@ CSMWorld::RefIdCollection::RefIdCollection() InventoryColumns inventoryColumns (nameColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Icon, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Icon, ColumnBase::Display_Icon)); inventoryColumns.mIcon = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Weight, ColumnBase::Display_Float)); inventoryColumns.mWeight = &mColumns.back(); diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index 18c1ee4ce4..9b80650ab9 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -258,7 +258,12 @@ namespace { CSMWorld::UniversalId::Type_JournalInfo, CSMWorld::ColumnBase::Display_JournalInfo }, { CSMWorld::UniversalId::Type_Scene, CSMWorld::ColumnBase::Display_Scene }, { CSMWorld::UniversalId::Type_Script, CSMWorld::ColumnBase::Display_Script }, - + { CSMWorld::UniversalId::Type_Mesh, CSMWorld::ColumnBase::Display_Mesh }, + { CSMWorld::UniversalId::Type_Icon, CSMWorld::ColumnBase::Display_Icon }, + { CSMWorld::UniversalId::Type_Music, CSMWorld::ColumnBase::Display_Music }, + { CSMWorld::UniversalId::Type_SoundRes, CSMWorld::ColumnBase::Display_SoundRes }, + { CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture }, + { CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video }, { CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker }; diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 0b06cfb362..ca66087fad 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -177,11 +177,19 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Faction: case CSMWorld::ColumnBase::Display_Miscellaneous: case CSMWorld::ColumnBase::Display_Sound: + case CSMWorld::ColumnBase::Display_Mesh: + case CSMWorld::ColumnBase::Display_Icon: + case CSMWorld::ColumnBase::Display_Music: + case CSMWorld::ColumnBase::Display_SoundRes: + case CSMWorld::ColumnBase::Display_Texture: + case CSMWorld::ColumnBase::Display_Video: return new DropLineEdit(parent); - } - return QStyledItemDelegate::createEditor (parent, option, index); + default: + + return QStyledItemDelegate::createEditor (parent, option, index); + } } void CSVWorld::CommandDelegate::setEditLock (bool locked) From ee81698089652ae92c78967570a41c4b21bddbbb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jul 2014 17:40:44 +0200 Subject: [PATCH 17/67] Always control movement by animation except for first person or in-air --- apps/openmw/mwmechanics/character.cpp | 19 ++++++++++++++----- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2c5d68ceb7..2f33c05916 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -361,9 +361,10 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat * beginning. */ int mode = ((movement == mCurrentMovement) ? 2 : 1); + mMovementAnimationControlled = true; + mAnimation->disable(mCurrentMovement); mCurrentMovement = movement; - mMovementAnimVelocity = 0.0f; if(!mCurrentMovement.empty()) { float vel, speedmult = 1.0f; @@ -383,16 +384,18 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) { - mMovementAnimVelocity = vel; speedmult = mMovementSpeed / vel; } else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed else if (mMovementSpeed > 0.0f) + { // The first person anims don't have any velocity to calculate a speed multiplier from. // We use the third person velocities instead. // FIXME: should be pulled from the actual animation, but it is not presently loaded. speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f); + mMovementAnimationControlled = false; + } mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false, speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } @@ -506,6 +509,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) mJumpState = JumpState_None; mAnimation->disable(mCurrentJump); mCurrentJump = ""; + mMovementAnimationControlled = true; mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, false, 1.0f, "start", "stop", startpoint, 0); @@ -547,7 +551,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mIdleState(CharState_None) , mMovementState(CharState_None) , mMovementSpeed(0.0f) - , mMovementAnimVelocity(0.0f) + , mMovementAnimationControlled(true) , mDeathState(CharState_None) , mHitState(CharState_None) , mUpperBodyState(UpperCharState_Nothing) @@ -1241,6 +1245,7 @@ void CharacterController::update(float duration) if (inwater || flying) cls.getCreatureStats(mPtr).land(); + bool inJump = true; if(!onground && !flying && !inwater) { // In the air (either getting up —ascending part of jump— or falling). @@ -1330,6 +1335,8 @@ void CharacterController::update(float duration) mJumpState = JumpState_None; vec.z = 0.0f; + inJump = false; + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) @@ -1391,6 +1398,8 @@ void CharacterController::update(float duration) forcestateupdate = updateCreatureState() || forcestateupdate; refreshCurrentAnims(idlestate, movestate, forcestateupdate); + if (inJump) + mMovementAnimationControlled = false; if (!mSkipAnim) { @@ -1402,7 +1411,7 @@ void CharacterController::update(float duration) else //avoid z-rotating for knockdown world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); - if (mMovementAnimVelocity == 0) + if (!mMovementAnimationControlled) world->queueMovement(mPtr, vec); } else @@ -1446,7 +1455,7 @@ void CharacterController::update(float duration) } // Update movement - if(mMovementAnimVelocity > 0) + if(mMovementAnimationControlled && mPtr.getClass().isActor()) world->queueMovement(mPtr, moved); } else if (mAnimation) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 59c20db8fe..b1e1738bd9 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -147,7 +147,7 @@ class CharacterController CharacterState mMovementState; std::string mCurrentMovement; float mMovementSpeed; - float mMovementAnimVelocity; + bool mMovementAnimationControlled; CharacterState mDeathState; std::string mCurrentDeath; From 0a2d5d34bcf5059536dd1fcacda77e2b403c4016 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jul 2014 19:37:12 +0200 Subject: [PATCH 18/67] Cancel queued view mode switch when switching view mode (Fixes #1618) --- apps/openmw/mwrender/camera.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 9e683cc159..4580bae70b 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -149,6 +149,8 @@ namespace MWRender mViewModeToggleQueued = true; return; } + else + mViewModeToggleQueued = false; mFirstPersonView = !mFirstPersonView; processViewChange(); From a3a8f4da705560545ea220b4d5c26a1a8e8cf804 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jul 2014 19:56:38 +0200 Subject: [PATCH 19/67] More font hackery. Will it ever end? Fixes #1606 --- apps/openmw/mwgui/fontloader.cpp | 35 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp index b7c2007b46..92d9a25b61 100644 --- a/apps/openmw/mwgui/fontloader.cpp +++ b/apps/openmw/mwgui/fontloader.cpp @@ -260,21 +260,28 @@ namespace MWGui // More hacks! The french game uses several win1252 characters that are not included // in the cp437 encoding of the font. Fall back to similar available characters. - // Same for U+2013 - std::map additional; - additional[39] = 0x2019; // apostrophe - additional[45] = 0x2013; // dash - if (additional.find(i) != additional.end() && mEncoding == ToUTF8::CP437) + if (mEncoding == ToUTF8::CP437) { - MyGUI::xml::ElementPtr code = codes->createChild("Code"); - code->addAttribute("index", additional[i]); - code->addAttribute("coord", MyGUI::utility::toString(x1) + " " - + MyGUI::utility::toString(y1) + " " - + MyGUI::utility::toString(w) + " " - + MyGUI::utility::toString(h)); - code->addAttribute("advance", data[i].width); - code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " - + MyGUI::utility::toString((fontSize-data[i].ascent))); + std::multimap additional; + additional.insert(std::make_pair(39, 0x2019)); // apostrophe + additional.insert(std::make_pair(45, 0x2013)); // dash + additional.insert(std::make_pair(34, 0x201D)); // right double quotation mark + additional.insert(std::make_pair(34, 0x201C)); // left double quotation mark + for (std::multimap::iterator it = additional.begin(); it != additional.end(); ++it) + { + if (it->first != i) + continue; + + MyGUI::xml::ElementPtr code = codes->createChild("Code"); + code->addAttribute("index", it->second); + code->addAttribute("coord", MyGUI::utility::toString(x1) + " " + + MyGUI::utility::toString(y1) + " " + + MyGUI::utility::toString(w) + " " + + MyGUI::utility::toString(h)); + code->addAttribute("advance", data[i].width); + code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + + MyGUI::utility::toString((fontSize-data[i].ascent))); + } } // ASCII vertical bar, use this as text input cursor From 742d008765f1ba2aa0b9ad94ccd7cf29d82fbca5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jul 2014 20:28:52 +0200 Subject: [PATCH 20/67] Fix initializing CharacterController with fists or spell equipped --- apps/openmw/mwmechanics/character.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2f33c05916..d4ddf53cd0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -574,10 +574,14 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if (cls.hasInventoryStore(mPtr)) { getActiveWeapon(cls.getCreatureStats(mPtr), cls.getInventoryStore(mPtr), &mWeaponType); + if (mWeaponType != WeapType_None) + { + mUpperBodyState = UpperCharState_WeapEquiped; + getWeaponGroup(mWeaponType, mCurrentWeapon); + } + if(mWeaponType != WeapType_None && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand) { - getWeaponGroup(mWeaponType, mCurrentWeapon); - mUpperBodyState = UpperCharState_WeapEquiped; mAnimation->showWeapons(true); mAnimation->setWeaponGroup(mCurrentWeapon); } From ad90d20ad8dc6e1d3f3fa28f0ecf3ef1bf986297 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jul 2014 21:00:12 +0200 Subject: [PATCH 21/67] Don't silently skip unknown NPC subrecords --- components/esm/loadnpc.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index e5b851bf0c..2fe9fe3c11 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -10,8 +10,6 @@ namespace ESM void NPC::load(ESMReader &esm) { - //mNpdt52.mGold = -10; - mPersistent = esm.getRecordFlags() & 0x0400; mModel = esm.getHNOString("MODL"); @@ -63,7 +61,6 @@ void NPC::load(ESMReader &esm) } } mAiPackage.load(esm); - esm.skipRecord(); } void NPC::save(ESMWriter &esm) const { From df80c436fb5d46773a29d3306db382534faa1f3b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 Jul 2014 18:24:55 +0200 Subject: [PATCH 22/67] Fix compile error for OPENMW_USE_FFMPEG=0 --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 03e74697c1..409e273887 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1088,7 +1088,7 @@ public: void close() { } - bool update(Ogre::MaterialPtr &mat, Ogre::Rectangle2D *rect, int screen_width, int screen_height) + bool update() { return false; } }; From 03f67cd6bdc84da0c42f37acd73fe568a054084f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jul 2014 12:39:12 +0200 Subject: [PATCH 23/67] moved low level widgets from CSVWorld into a separate namespace/directory --- apps/opencs/CMakeLists.txt | 18 +++++++++++------- apps/opencs/view/render/scenewidget.cpp | 6 +++--- apps/opencs/view/render/scenewidget.hpp | 4 ++-- apps/opencs/view/render/worldspacewidget.cpp | 11 ++++++----- apps/opencs/view/render/worldspacewidget.hpp | 4 ++-- .../view/{world => widget}/scenetool.cpp | 4 ++-- .../view/{world => widget}/scenetool.hpp | 6 +++--- .../view/{world => widget}/scenetoolbar.cpp | 8 ++++---- .../view/{world => widget}/scenetoolbar.hpp | 6 +++--- .../view/{world => widget}/scenetoolmode.cpp | 8 ++++---- .../view/{world => widget}/scenetoolmode.hpp | 6 +++--- apps/opencs/view/world/previewsubview.cpp | 8 ++++---- apps/opencs/view/world/scenesubview.cpp | 18 ++++++++++-------- apps/opencs/view/world/scenesubview.hpp | 13 +++++++++---- 14 files changed, 66 insertions(+), 54 deletions(-) rename apps/opencs/view/{world => widget}/scenetool.cpp (77%) rename apps/opencs/view/{world => widget}/scenetool.hpp (81%) rename apps/opencs/view/{world => widget}/scenetoolbar.cpp (66%) rename apps/opencs/view/{world => widget}/scenetoolbar.hpp (83%) rename apps/opencs/view/{world => widget}/scenetoolmode.cpp (82%) rename apps/opencs/view/{world => widget}/scenetoolmode.hpp (88%) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 288e0394c8..5d8d99f276 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -59,8 +59,17 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator - cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool - scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable + cellcreator referenceablecreator referencecreator scenesubview + infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable + ) + +opencs_units_noqt (view/world + subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate + scripthighlighter idvalidator dialoguecreator + ) + +opencs_units (view/widget + scenetoolbar scenetool scenetoolmode ) opencs_units (view/render @@ -73,11 +82,6 @@ opencs_units_noqt (view/render lightingbright object cell ) -opencs_units_noqt (view/world - subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator - ) - opencs_units (view/tools reportsubview diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 76f6db385d..3728dd72d9 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -11,7 +11,7 @@ #include #include -#include "../world/scenetoolmode.hpp" +#include "../widget/scenetoolmode.hpp" #include "navigation.hpp" #include "lighting.hpp" @@ -54,9 +54,9 @@ namespace CSVRender timer->start (20); /// \todo make this configurable } - CSVWorld::SceneToolMode *SceneWidget::makeLightingSelector (CSVWorld::SceneToolbar *parent) + CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent) { - CSVWorld::SceneToolMode *tool = new CSVWorld::SceneToolMode (parent); + CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent); tool->addButton (":door.png", "day"); /// \todo replace icons tool->addButton (":GMST.png", "night"); diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index f6b41942f7..8b01e71857 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -16,7 +16,7 @@ namespace Ogre class RenderWindow; } -namespace CSVWorld +namespace CSVWidget { class SceneToolMode; class SceneToolbar; @@ -38,7 +38,7 @@ namespace CSVRender QPaintEngine* paintEngine() const; - CSVWorld::SceneToolMode *makeLightingSelector (CSVWorld::SceneToolbar *parent); + CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); ///< \attention The created tool is not added to the toolbar (via addTool). Doing that /// is the responsibility of the calling function. diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index fee2f0a160..5b3dc57e23 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -7,8 +7,9 @@ #include -#include "../world/scenetoolmode.hpp" -#include +#include "../../model/world/universalid.hpp" + +#include "../widget/scenetoolmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (parent), mDocument(document) @@ -53,10 +54,10 @@ void CSVRender::WorldspaceWidget::selectDefaultNavigationMode() setNavigation (&m1st); } -CSVWorld::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( - CSVWorld::SceneToolbar *parent) +CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( + CSVWidget::SceneToolbar *parent) { - CSVWorld::SceneToolMode *tool = new CSVWorld::SceneToolMode (parent); + CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent); tool->addButton (":door.png", "1st"); /// \todo replace icons tool->addButton (":GMST.png", "free"); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 2af90b0feb..3b96779a8c 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -13,7 +13,7 @@ namespace CSMWorld { class UniversalId; } -namespace CSVWorld +namespace CSVWidget { class SceneToolMode; class SceneToolbar; @@ -49,7 +49,7 @@ namespace CSVRender WorldspaceWidget (CSMDoc::Document& document, QWidget *parent = 0); - CSVWorld::SceneToolMode *makeNavigationSelector (CSVWorld::SceneToolbar *parent); + CSVWidget::SceneToolMode *makeNavigationSelector (CSVWidget::SceneToolbar *parent); ///< \attention The created tool is not added to the toolbar (via addTool). Doing that /// is the responsibility of the calling function. diff --git a/apps/opencs/view/world/scenetool.cpp b/apps/opencs/view/widget/scenetool.cpp similarity index 77% rename from apps/opencs/view/world/scenetool.cpp rename to apps/opencs/view/widget/scenetool.cpp index 612b4c6d39..e498fdf639 100644 --- a/apps/opencs/view/world/scenetool.cpp +++ b/apps/opencs/view/widget/scenetool.cpp @@ -3,7 +3,7 @@ #include "scenetoolbar.hpp" -CSVWorld::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent) +CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent) { setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); setIconSize (QSize (parent->getIconSize(), parent->getIconSize())); @@ -12,7 +12,7 @@ CSVWorld::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent) connect (this, SIGNAL (clicked()), this, SLOT (openRequest())); } -void CSVWorld::SceneTool::openRequest() +void CSVWidget::SceneTool::openRequest() { showPanel (parentWidget()->mapToGlobal (pos())); } diff --git a/apps/opencs/view/world/scenetool.hpp b/apps/opencs/view/widget/scenetool.hpp similarity index 81% rename from apps/opencs/view/world/scenetool.hpp rename to apps/opencs/view/widget/scenetool.hpp index 07e8b58d72..312d8e00cd 100644 --- a/apps/opencs/view/world/scenetool.hpp +++ b/apps/opencs/view/widget/scenetool.hpp @@ -1,9 +1,9 @@ -#ifndef CSV_WORLD_SCENETOOL_H -#define CSV_WORLD_SCENETOOL_H +#ifndef CSV_WIDGET_SCENETOOL_H +#define CSV_WIDGET_SCENETOOL_H #include -namespace CSVWorld +namespace CSVWidget { class SceneToolbar; diff --git a/apps/opencs/view/world/scenetoolbar.cpp b/apps/opencs/view/widget/scenetoolbar.cpp similarity index 66% rename from apps/opencs/view/world/scenetoolbar.cpp rename to apps/opencs/view/widget/scenetoolbar.cpp index d60240da77..59a3a1d6e2 100644 --- a/apps/opencs/view/world/scenetoolbar.cpp +++ b/apps/opencs/view/widget/scenetoolbar.cpp @@ -5,7 +5,7 @@ #include "scenetool.hpp" -CSVWorld::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) +CSVWidget::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) : QWidget (parent), mButtonSize (buttonSize), mIconSize (buttonSize-6) { setFixedWidth (mButtonSize); @@ -18,17 +18,17 @@ CSVWorld::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) setLayout (mLayout); } -void CSVWorld::SceneToolbar::addTool (SceneTool *tool) +void CSVWidget::SceneToolbar::addTool (SceneTool *tool) { mLayout->addWidget (tool, 0, Qt::AlignTop); } -int CSVWorld::SceneToolbar::getButtonSize() const +int CSVWidget::SceneToolbar::getButtonSize() const { return mButtonSize; } -int CSVWorld::SceneToolbar::getIconSize() const +int CSVWidget::SceneToolbar::getIconSize() const { return mIconSize; } \ No newline at end of file diff --git a/apps/opencs/view/world/scenetoolbar.hpp b/apps/opencs/view/widget/scenetoolbar.hpp similarity index 83% rename from apps/opencs/view/world/scenetoolbar.hpp rename to apps/opencs/view/widget/scenetoolbar.hpp index 731806cc5f..0ef84f488e 100644 --- a/apps/opencs/view/world/scenetoolbar.hpp +++ b/apps/opencs/view/widget/scenetoolbar.hpp @@ -1,11 +1,11 @@ -#ifndef CSV_WORLD_SCENETOOLBAR_H -#define CSV_WORLD_SCENETOOLBAR_H +#ifndef CSV_WIDGET_SCENETOOLBAR_H +#define CSV_WIDGET_SCENETOOLBAR_H #include class QVBoxLayout; -namespace CSVWorld +namespace CSVWidget { class SceneTool; diff --git a/apps/opencs/view/world/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp similarity index 82% rename from apps/opencs/view/world/scenetoolmode.cpp rename to apps/opencs/view/widget/scenetoolmode.cpp index 73b01ae3a8..72efae0df1 100644 --- a/apps/opencs/view/world/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -7,7 +7,7 @@ #include "scenetoolbar.hpp" -CSVWorld::SceneToolMode::SceneToolMode (SceneToolbar *parent) +CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent) : SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()) { mPanel = new QFrame (this, Qt::Popup); @@ -19,13 +19,13 @@ CSVWorld::SceneToolMode::SceneToolMode (SceneToolbar *parent) mPanel->setLayout (mLayout); } -void CSVWorld::SceneToolMode::showPanel (const QPoint& position) +void CSVWidget::SceneToolMode::showPanel (const QPoint& position) { mPanel->move (position); mPanel->show(); } -void CSVWorld::SceneToolMode::addButton (const std::string& icon, const std::string& id) +void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id) { QPushButton *button = new QPushButton (QIcon (QPixmap (icon.c_str())), "", mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); @@ -42,7 +42,7 @@ void CSVWorld::SceneToolMode::addButton (const std::string& icon, const std::str setIcon (button->icon()); } -void CSVWorld::SceneToolMode::selected() +void CSVWidget::SceneToolMode::selected() { std::map::const_iterator iter = mButtons.find (dynamic_cast (sender())); diff --git a/apps/opencs/view/world/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp similarity index 88% rename from apps/opencs/view/world/scenetoolmode.hpp rename to apps/opencs/view/widget/scenetoolmode.hpp index a156c0c95a..175c53f966 100644 --- a/apps/opencs/view/world/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -1,5 +1,5 @@ -#ifndef CSV_WORLD_SCENETOOL_MODE_H -#define CSV_WORLD_SCENETOOL_MODE_H +#ifndef CSV_WIDGET_SCENETOOL_MODE_H +#define CSV_WIDGET_SCENETOOL_MODE_H #include "scenetool.hpp" @@ -7,7 +7,7 @@ class QHBoxLayout; -namespace CSVWorld +namespace CSVWidget { class SceneToolbar; diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 49e6d93618..bae0abb8bb 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -5,8 +5,8 @@ #include "../render/previewwidget.hpp" -#include "scenetoolbar.hpp" -#include "scenetoolmode.hpp" +#include "../widget/scenetoolbar.hpp" +#include "../widget/scenetoolmode.hpp" CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id) @@ -28,9 +28,9 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo else mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this); - SceneToolbar *toolbar = new SceneToolbar (48+6, this); + CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this); - SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); + CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); toolbar->addTool (lightingTool); layout->addWidget (toolbar, 0); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 36cce9ecd7..0ff540ec28 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -17,9 +17,11 @@ #include "../render/pagedworldspacewidget.hpp" #include "../render/unpagedworldspacewidget.hpp" +#include "../widget/scenetoolbar.hpp" +#include "../widget/scenetoolmode.hpp" + #include "tablebottombox.hpp" #include "creator.hpp" -#include "scenetoolmode.hpp" CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mLayout(new QHBoxLayout), mDocument(document), mScene(NULL), mToolbar(NULL) @@ -95,18 +97,18 @@ void CSVWorld::SceneSubView::makeConnections (CSVRender::PagedWorldspaceWidget* this, SLOT (cellSelectionChanged (const CSMWorld::CellSelection&))); } -CSVWorld::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::WorldspaceWidget* widget, widgetType type) +CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::WorldspaceWidget* widget, widgetType type) { - CSVWorld::SceneToolbar* toolbar = new SceneToolbar (48+6, this); + CSVWidget::SceneToolbar* toolbar = new CSVWidget::SceneToolbar (48+6, this); - SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar); + CSVWidget::SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar); toolbar->addTool (navigationTool); - SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); + CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); toolbar->addTool (lightingTool); /* Add buttons specific to the type. For now no need for it. - * + * switch (type) { case widget_Paged: @@ -188,7 +190,7 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI { CSVRender::PagedWorldspaceWidget* pagedNewWidget = NULL; CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL; - SceneToolbar* toolbar = NULL; + CSVWidget::SceneToolbar* toolbar = NULL; switch (mScene->getDropRequirements(CSVRender::WorldspaceWidget::getDropType(data))) { @@ -217,7 +219,7 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI } } -void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceWidget* widget, CSVWorld::SceneToolbar* toolbar) +void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceWidget* widget, CSVWidget::SceneToolbar* toolbar) { assert(mLayout); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index b9ecbe931c..b9dcdd6a38 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -4,7 +4,6 @@ #include #include "../doc/subview.hpp" -#include "scenetoolbar.hpp" class QModelIndex; @@ -25,6 +24,11 @@ namespace CSVRender class UnpagedWorldspaceWidget; } +namespace CSVWidget +{ + class SceneToolbar; +} + namespace CSVWorld { class Table; @@ -39,7 +43,7 @@ namespace CSVWorld CSVRender::WorldspaceWidget *mScene; QHBoxLayout* mLayout; CSMDoc::Document& mDocument; - SceneToolbar* mToolbar; + CSVWidget::SceneToolbar* mToolbar; public: @@ -59,14 +63,15 @@ namespace CSVWorld void makeConnections(CSVRender::UnpagedWorldspaceWidget* widget); - void replaceToolbarAndWorldspace(CSVRender::WorldspaceWidget* widget, SceneToolbar* toolbar); + void replaceToolbarAndWorldspace(CSVRender::WorldspaceWidget* widget, CSVWidget::SceneToolbar* toolbar); enum widgetType { widget_Paged, widget_Unpaged }; - SceneToolbar* makeToolbar(CSVRender::WorldspaceWidget* widget, widgetType type); + + CSVWidget::SceneToolbar* makeToolbar(CSVRender::WorldspaceWidget* widget, widgetType type); private slots: From 3333f67830c0a150c27662f5455b1e72402ed2aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jul 2014 12:53:25 +0200 Subject: [PATCH 24/67] removed a left-over marker --- apps/opencs/model/world/resourcetable.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 167b48436e..86de0a6a63 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -75,8 +75,6 @@ QVariant CSMWorld::ResourceTable::headerData (int section, Qt::Orientation orien break; } - // xxx - return QVariant(); } From 0704fa2b3dda4945b392139b220e49d40a19b695 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jul 2014 10:23:01 +0200 Subject: [PATCH 25/67] Reset local rotation axis in SetAngle (Fixes #1630) --- apps/openmw/mwscript/transformationextensions.cpp | 8 ++++++++ apps/openmw/mwworld/worldimp.cpp | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 3860257ad6..a041049ca4 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -86,16 +86,24 @@ namespace MWScript float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + MWWorld::LocalRotation localRot = ptr.getRefData().getLocalRotation(); + if (axis == "x") { + localRot.rot[0] = 0; + ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az); } else if (axis == "y") { + localRot.rot[1] = 0; + ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az); } else if (axis == "z") { + localRot.rot[2] = 0; + ptr.getRefData().setLocalRotation(localRot); MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle); } else diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 33405b4d86..30c90cfedc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1123,7 +1123,10 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - mWorldScene->updateObjectRotation(ptr); + if (ptr.getClass().isActor()) + mWorldScene->updateObjectRotation(ptr); + else + mWorldScene->updateObjectLocalRotation(ptr); } void World::localRotateObject (const Ptr& ptr, float x, float y, float z) From 930f782bc590414d5cea08defd522742ac12d3a6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 10:09:21 +0200 Subject: [PATCH 26/67] SceneWidget::setLighting was missing an update call --- apps/opencs/view/render/scenewidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 3728dd72d9..e93bf347e4 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -347,6 +347,9 @@ namespace CSVRender mLighting = lighting; mLighting->activate (mSceneMgr, mHasDefaultAmbient ? &mDefaultAmbient : 0); + + if (mWindow) + mWindow->update(); } void SceneWidget::selectLightingMode (const std::string& mode) From dd0aa20390968d5f7a3d637a0b427d872c98190d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 11:03:55 +0200 Subject: [PATCH 27/67] custom push button --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/widget/pushbutton.cpp | 29 +++++++++++++++++++++++ apps/opencs/view/widget/pushbutton.hpp | 28 ++++++++++++++++++++++ apps/opencs/view/widget/scenetoolmode.cpp | 10 ++++---- apps/opencs/view/widget/scenetoolmode.hpp | 3 ++- 5 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 apps/opencs/view/widget/pushbutton.cpp create mode 100644 apps/opencs/view/widget/pushbutton.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5d8d99f276..c03cc3138b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -69,7 +69,7 @@ opencs_units_noqt (view/world ) opencs_units (view/widget - scenetoolbar scenetool scenetoolmode + scenetoolbar scenetool scenetoolmode pushbutton ) opencs_units (view/render diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp new file mode 100644 index 0000000000..8b4cf65e39 --- /dev/null +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -0,0 +1,29 @@ + +#include "pushbutton.hpp" + +#include +#include + +void CSVWidget::PushButton::keyPressEvent (QKeyEvent *event) +{ + if (event->key()!=Qt::Key_Shift) + mKeepOpen = false; + + QPushButton::keyPressEvent (event); +} + +void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event) +{ + mKeepOpen = event->button()==Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier); + QPushButton::mouseReleaseEvent (event); +} + +CSVWidget::PushButton::PushButton (const QIcon& icon, const QString& text, QWidget *parent) +: QPushButton (icon, text, parent), mKeepOpen (false) +{ +} + +bool CSVWidget::PushButton::hasKeepOpen() const +{ + return mKeepOpen; +} \ No newline at end of file diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp new file mode 100644 index 0000000000..aa9da48857 --- /dev/null +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -0,0 +1,28 @@ +#ifndef CSV_WIDGET_PUSHBUTTON_H +#define CSV_WIDGET_PUSHBUTTON_H + +#include + +namespace CSVWidget +{ + class PushButton : public QPushButton + { + Q_OBJECT + + bool mKeepOpen; + + protected: + + virtual void keyPressEvent (QKeyEvent *event); + + virtual void mouseReleaseEvent (QMouseEvent *event); + + public: + + PushButton (const QIcon& icon, const QString& text, QWidget *parent = 0); + + bool hasKeepOpen() const; + }; +} + +#endif diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 72efae0df1..87abd81405 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -6,6 +6,7 @@ #include #include "scenetoolbar.hpp" +#include "pushbutton.hpp" CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent) : SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()) @@ -27,7 +28,7 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id) { - QPushButton *button = new QPushButton (QIcon (QPixmap (icon.c_str())), "", mPanel); + PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), "", mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); @@ -44,12 +45,13 @@ void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::st void CSVWidget::SceneToolMode::selected() { - std::map::const_iterator iter = - mButtons.find (dynamic_cast (sender())); + std::map::const_iterator iter = + mButtons.find (dynamic_cast (sender())); if (iter!=mButtons.end()) { - mPanel->hide(); + if (!iter->first->hasKeepOpen()) + mPanel->hide(); setIcon (iter->first->icon()); emit modeChanged (iter->second); diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 175c53f966..0ad5243b3c 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -10,6 +10,7 @@ class QHBoxLayout; namespace CSVWidget { class SceneToolbar; + class PushButton; ///< \brief Mode selector tool class SceneToolMode : public SceneTool @@ -18,7 +19,7 @@ namespace CSVWidget QWidget *mPanel; QHBoxLayout *mLayout; - std::map mButtons; // widget, id + std::map mButtons; // widget, id int mButtonSize; int mIconSize; From 50ee815dd8e777db3cdf4d32dde0a643f16ab302 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 11:23:48 +0200 Subject: [PATCH 28/67] make buttons in mode panel act like radiobuttons --- apps/opencs/view/widget/pushbutton.cpp | 1 + apps/opencs/view/widget/scenetoolmode.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 8b4cf65e39..61afa0d9d8 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -21,6 +21,7 @@ void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event) CSVWidget::PushButton::PushButton (const QIcon& icon, const QString& text, QWidget *parent) : QPushButton (icon, text, parent), mKeepOpen (false) { + setCheckable (true); } bool CSVWidget::PushButton::hasKeepOpen() const diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 87abd81405..5f2eecdc36 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -40,7 +40,10 @@ void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::st connect (button, SIGNAL (clicked()), this, SLOT (selected())); if (mButtons.size()==1) + { setIcon (button->icon()); + button->setChecked (true); + } } void CSVWidget::SceneToolMode::selected() @@ -53,6 +56,10 @@ void CSVWidget::SceneToolMode::selected() if (!iter->first->hasKeepOpen()) mPanel->hide(); + for (std::map::const_iterator iter2 = mButtons.begin(); + iter2!=mButtons.end(); ++iter2) + iter2->first->setChecked (iter2==iter); + setIcon (iter->first->icon()); emit modeChanged (iter->second); } From 365b7218781d3f5df48ae89709fad588d89c8dff Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 11:32:20 +0200 Subject: [PATCH 29/67] return/enter activate the selected button --- apps/opencs/view/widget/pushbutton.cpp | 11 +++++++++++ apps/opencs/view/widget/pushbutton.hpp | 2 ++ 2 files changed, 13 insertions(+) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 61afa0d9d8..8b70cb6b81 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -12,6 +12,17 @@ void CSVWidget::PushButton::keyPressEvent (QKeyEvent *event) QPushButton::keyPressEvent (event); } +void CSVWidget::PushButton::keyReleaseEvent (QKeyEvent *event) +{ + if (event->key()==Qt::Key_Return || event->key()==Qt::Key_Enter) + { + mKeepOpen = event->modifiers() & Qt::ShiftModifier; + emit clicked(); + } + + QPushButton::keyReleaseEvent (event); +} + void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event) { mKeepOpen = event->button()==Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier); diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index aa9da48857..961b3ed11b 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -15,6 +15,8 @@ namespace CSVWidget virtual void keyPressEvent (QKeyEvent *event); + virtual void keyReleaseEvent (QKeyEvent *event); + virtual void mouseReleaseEvent (QMouseEvent *event); public: From 8b239df1b1cd3c5817ffa5d9942610ce4e0649b8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 11:34:09 +0200 Subject: [PATCH 30/67] removed text argument from button constructor, because toolbar buttons will always be icon only --- apps/opencs/view/widget/pushbutton.cpp | 4 ++-- apps/opencs/view/widget/pushbutton.hpp | 2 +- apps/opencs/view/widget/scenetoolmode.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 8b70cb6b81..b010a86680 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -29,8 +29,8 @@ void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event) QPushButton::mouseReleaseEvent (event); } -CSVWidget::PushButton::PushButton (const QIcon& icon, const QString& text, QWidget *parent) -: QPushButton (icon, text, parent), mKeepOpen (false) +CSVWidget::PushButton::PushButton (const QIcon& icon, QWidget *parent) +: QPushButton (icon, "", parent), mKeepOpen (false) { setCheckable (true); } diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 961b3ed11b..984a77d578 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -21,7 +21,7 @@ namespace CSVWidget public: - PushButton (const QIcon& icon, const QString& text, QWidget *parent = 0); + PushButton (const QIcon& icon, QWidget *parent = 0); bool hasKeepOpen() const; }; diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 5f2eecdc36..4d76215bbd 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -28,7 +28,7 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id) { - PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), "", mPanel); + PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); From 44b95bbd7be6c940509decb633dd0a2fad61e1e7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 11:44:01 +0200 Subject: [PATCH 31/67] added push mode and icon-less push button constructor --- apps/opencs/view/widget/pushbutton.cpp | 10 ++++++++-- apps/opencs/view/widget/pushbutton.hpp | 6 +++++- apps/opencs/view/widget/scenetoolmode.cpp | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index b010a86680..8fb90c4d00 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -29,10 +29,16 @@ void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event) QPushButton::mouseReleaseEvent (event); } -CSVWidget::PushButton::PushButton (const QIcon& icon, QWidget *parent) +CSVWidget::PushButton::PushButton (const QIcon& icon, bool push, QWidget *parent) : QPushButton (icon, "", parent), mKeepOpen (false) { - setCheckable (true); + setCheckable (!push); +} + +CSVWidget::PushButton::PushButton (bool push, QWidget *parent) +: QPushButton (parent), mKeepOpen (false) +{ + setCheckable (!push); } bool CSVWidget::PushButton::hasKeepOpen() const diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 984a77d578..7c2a2caca0 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -21,7 +21,11 @@ namespace CSVWidget public: - PushButton (const QIcon& icon, QWidget *parent = 0); + /// \param push Do not maintain a toggle state + PushButton (const QIcon& icon, bool push = false, QWidget *parent = 0); + + /// \param push Do not maintain a toggle state + PushButton (bool push = false, QWidget *parent = 0); bool hasKeepOpen() const; }; diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 4d76215bbd..cbf20d7dcb 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -28,7 +28,7 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id) { - PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), mPanel); + PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), false, mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); From d6c0b8d0ac704917160b75b27fb9c5b53ffdc849 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 11:45:45 +0200 Subject: [PATCH 32/67] use custom button on toolbar (top level) --- apps/opencs/view/widget/scenetool.cpp | 2 +- apps/opencs/view/widget/scenetool.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/widget/scenetool.cpp b/apps/opencs/view/widget/scenetool.cpp index e498fdf639..36d1f66101 100644 --- a/apps/opencs/view/widget/scenetool.cpp +++ b/apps/opencs/view/widget/scenetool.cpp @@ -3,7 +3,7 @@ #include "scenetoolbar.hpp" -CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent) +CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) : PushButton (true, parent) { setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); setIconSize (QSize (parent->getIconSize(), parent->getIconSize())); diff --git a/apps/opencs/view/widget/scenetool.hpp b/apps/opencs/view/widget/scenetool.hpp index 312d8e00cd..24099683e0 100644 --- a/apps/opencs/view/widget/scenetool.hpp +++ b/apps/opencs/view/widget/scenetool.hpp @@ -1,14 +1,14 @@ #ifndef CSV_WIDGET_SCENETOOL_H #define CSV_WIDGET_SCENETOOL_H -#include +#include "pushbutton.hpp" namespace CSVWidget { class SceneToolbar; ///< \brief Tool base class - class SceneTool : public QPushButton + class SceneTool : public PushButton { Q_OBJECT From 57b9b8d8848780a7e7922365ba750cd2190770d4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 12:13:27 +0200 Subject: [PATCH 33/67] set focus when opening a toolbar panel --- apps/opencs/view/widget/scenetoolmode.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index cbf20d7dcb..0d8526a30c 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -24,6 +24,9 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) { mPanel->move (position); mPanel->show(); + + if (!mButtons.empty()) + mButtons.begin()->first->setFocus (Qt::OtherFocusReason); } void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id) From 67ad7d5b0ecd2c179c200401290cb7a1cb0d780b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 12:20:48 +0200 Subject: [PATCH 34/67] fixed scene subview focus problem --- apps/opencs/view/world/scenesubview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 0ff540ec28..4430d28eb6 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -242,4 +242,5 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mLayout->addWidget (mScene, 1); mScene->selectDefaultNavigationMode(); + setFocusProxy (mScene); } \ No newline at end of file From 32e48edb83b63c3f3c8f2308256dfa43871de202 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 12:53:57 +0200 Subject: [PATCH 35/67] toolbar tooltip system --- apps/opencs/view/widget/pushbutton.cpp | 25 +++++++++++++++++++---- apps/opencs/view/widget/pushbutton.hpp | 11 ++++++++-- apps/opencs/view/widget/scenetool.cpp | 2 +- apps/opencs/view/widget/scenetoolmode.cpp | 2 +- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 8fb90c4d00..52c78ff1cd 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -4,6 +4,20 @@ #include #include +void CSVWidget::PushButton::setExtendedToolTip (const std::string& text) +{ + std::string tooltip = text; + + if (tooltip.empty()) + tooltip = "(Tool tip not implemented yet)"; + + if (!mPush) + tooltip += + "

(left click to activate,
shift-left click to activate and keep panel open)"; + + setToolTip (QString::fromUtf8 (tooltip.c_str())); +} + void CSVWidget::PushButton::keyPressEvent (QKeyEvent *event) { if (event->key()!=Qt::Key_Shift) @@ -29,16 +43,19 @@ void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event) QPushButton::mouseReleaseEvent (event); } -CSVWidget::PushButton::PushButton (const QIcon& icon, bool push, QWidget *parent) -: QPushButton (icon, "", parent), mKeepOpen (false) +CSVWidget::PushButton::PushButton (const QIcon& icon, bool push, const std::string& tooltip, + QWidget *parent) +: QPushButton (icon, "", parent), mKeepOpen (false), mPush (push) { setCheckable (!push); + setExtendedToolTip (tooltip); } -CSVWidget::PushButton::PushButton (bool push, QWidget *parent) -: QPushButton (parent), mKeepOpen (false) +CSVWidget::PushButton::PushButton (bool push, const std::string& tooltip, QWidget *parent) +: QPushButton (parent), mKeepOpen (false), mPush (push) { setCheckable (!push); + setExtendedToolTip (tooltip); } bool CSVWidget::PushButton::hasKeepOpen() const diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 7c2a2caca0..6cd4f65ab4 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -10,6 +10,11 @@ namespace CSVWidget Q_OBJECT bool mKeepOpen; + bool mPush; + + private: + + void setExtendedToolTip (const std::string& text); protected: @@ -22,10 +27,12 @@ namespace CSVWidget public: /// \param push Do not maintain a toggle state - PushButton (const QIcon& icon, bool push = false, QWidget *parent = 0); + PushButton (const QIcon& icon, bool push = false, const std::string& tooltip = "", + QWidget *parent = 0); /// \param push Do not maintain a toggle state - PushButton (bool push = false, QWidget *parent = 0); + PushButton (bool push = false, const std::string& tooltip = "", + QWidget *parent = 0); bool hasKeepOpen() const; }; diff --git a/apps/opencs/view/widget/scenetool.cpp b/apps/opencs/view/widget/scenetool.cpp index 36d1f66101..d247096b03 100644 --- a/apps/opencs/view/widget/scenetool.cpp +++ b/apps/opencs/view/widget/scenetool.cpp @@ -3,7 +3,7 @@ #include "scenetoolbar.hpp" -CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) : PushButton (true, parent) +CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) : PushButton (true, "", parent) { setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); setIconSize (QSize (parent->getIconSize(), parent->getIconSize())); diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 0d8526a30c..152a7c0ced 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -31,7 +31,7 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id) { - PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), false, mPanel); + PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), false, "", mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); From 61a02d8a40385840d1277d14ec08c61d4d621bda Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 13:04:30 +0200 Subject: [PATCH 36/67] replaced custom toolbutton push flag with type enum --- apps/opencs/view/widget/pushbutton.cpp | 32 ++++++++++++++++------- apps/opencs/view/widget/pushbutton.hpp | 16 +++++++++--- apps/opencs/view/widget/scenetool.cpp | 3 ++- apps/opencs/view/widget/scenetoolmode.cpp | 3 ++- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 52c78ff1cd..35bed1627d 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -11,9 +11,23 @@ void CSVWidget::PushButton::setExtendedToolTip (const std::string& text) if (tooltip.empty()) tooltip = "(Tool tip not implemented yet)"; - if (!mPush) - tooltip += - "

(left click to activate,
shift-left click to activate and keep panel open)"; + switch (mType) + { + case Type_TopMode: + + tooltip += + "

(left click to change mode)"; + + break; + + case Type_Mode: + + tooltip += + "

(left click to activate," + "
shift-left click to activate and keep panel open)"; + + break; + } setToolTip (QString::fromUtf8 (tooltip.c_str())); } @@ -43,18 +57,18 @@ void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event) QPushButton::mouseReleaseEvent (event); } -CSVWidget::PushButton::PushButton (const QIcon& icon, bool push, const std::string& tooltip, +CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const std::string& tooltip, QWidget *parent) -: QPushButton (icon, "", parent), mKeepOpen (false), mPush (push) +: QPushButton (icon, "", parent), mKeepOpen (false), mType (type) { - setCheckable (!push); + setCheckable (type==Type_Mode); setExtendedToolTip (tooltip); } -CSVWidget::PushButton::PushButton (bool push, const std::string& tooltip, QWidget *parent) -: QPushButton (parent), mKeepOpen (false), mPush (push) +CSVWidget::PushButton::PushButton (Type type, const std::string& tooltip, QWidget *parent) +: QPushButton (parent), mKeepOpen (false), mType (type) { - setCheckable (!push); + setCheckable (type==Type_Mode); setExtendedToolTip (tooltip); } diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 6cd4f65ab4..099cba3580 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -9,8 +9,18 @@ namespace CSVWidget { Q_OBJECT + public: + + enum Type + { + Type_TopMode, // top level button for mode selector panel + Type_Mode // mode button + }; + + private: + bool mKeepOpen; - bool mPush; + Type mType; private: @@ -27,11 +37,11 @@ namespace CSVWidget public: /// \param push Do not maintain a toggle state - PushButton (const QIcon& icon, bool push = false, const std::string& tooltip = "", + PushButton (const QIcon& icon, Type type, const std::string& tooltip = "", QWidget *parent = 0); /// \param push Do not maintain a toggle state - PushButton (bool push = false, const std::string& tooltip = "", + PushButton (Type type, const std::string& tooltip = "", QWidget *parent = 0); bool hasKeepOpen() const; diff --git a/apps/opencs/view/widget/scenetool.cpp b/apps/opencs/view/widget/scenetool.cpp index d247096b03..e3f2dfd1c8 100644 --- a/apps/opencs/view/widget/scenetool.cpp +++ b/apps/opencs/view/widget/scenetool.cpp @@ -3,7 +3,8 @@ #include "scenetoolbar.hpp" -CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) : PushButton (true, "", parent) +CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) +: PushButton (PushButton::Type_TopMode, "", parent) { setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); setIconSize (QSize (parent->getIconSize(), parent->getIconSize())); diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 152a7c0ced..629cf9415e 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -31,7 +31,8 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id) { - PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), false, "", mPanel); + PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), PushButton::Type_Mode, + "", mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); From 490442cf6214b7ef8c66453638f7b27cae7a1e83 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Jul 2014 13:18:24 +0200 Subject: [PATCH 37/67] added lighting mode tooltips --- apps/opencs/view/render/scenewidget.cpp | 20 +++++++++++++++++--- apps/opencs/view/widget/scenetoolmode.cpp | 5 +++-- apps/opencs/view/widget/scenetoolmode.hpp | 3 ++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index e93bf347e4..8f6b74765f 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -58,9 +58,23 @@ namespace CSVRender { CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent); - tool->addButton (":door.png", "day"); /// \todo replace icons - tool->addButton (":GMST.png", "night"); - tool->addButton (":Info.png", "bright"); + /// \todo replace icons + tool->addButton (":door.png", "day", + "Day" + "

  • Cell specific ambient in interiors
  • " + "
  • Low ambient in exteriors
  • " + "
  • Strong directional light source/lir>" + "
  • This mode closely resembles day time in-game
"); + tool->addButton (":GMST.png", "night", + "Night" + "
  • Cell specific ambient in interiors
  • " + "
  • Low ambient in exteriors
  • " + "
  • Weak directional light source
  • " + "
  • This mode closely resembles night time in-game
"); + tool->addButton (":Info.png", "bright", + "Bright" + "
  • Maximum ambient
  • " + "
  • Strong directional light source
"); connect (tool, SIGNAL (modeChanged (const std::string&)), this, SLOT (selectLightingMode (const std::string&))); diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 629cf9415e..412959c7c4 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -29,10 +29,11 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) mButtons.begin()->first->setFocus (Qt::OtherFocusReason); } -void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id) +void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id, + const std::string& tooltip) { PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), PushButton::Type_Mode, - "", mPanel); + tooltip, mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 0ad5243b3c..5f18f712f9 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -29,7 +29,8 @@ namespace CSVWidget virtual void showPanel (const QPoint& position); - void addButton (const std::string& icon, const std::string& id); + void addButton (const std::string& icon, const std::string& id, + const std::string& tooltip = ""); signals: From 53c70dbdaac4a1eac7c83c6f3736fd4a41cdb9f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jul 2014 04:25:56 +0200 Subject: [PATCH 38/67] Exit dialogue when going to jail (Fixes #1635) --- apps/openmw/mwworld/worldimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 30c90cfedc..3868348820 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2652,6 +2652,8 @@ namespace MWWorld { mGoToJail = false; + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + MWWorld::Ptr player = getPlayerPtr(); teleportToClosestMarker(player, "prisonmarker"); int bounty = player.getClass().getNpcStats(player).getBounty(); From 5fbce67b9d2a63800d406d3d83dfa8ae805f73f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jul 2014 04:30:44 +0200 Subject: [PATCH 39/67] Don't redraw ItemView if the size did not change --- apps/openmw/mwgui/itemview.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index fdaf930399..b86f610341 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -140,26 +140,28 @@ void ItemView::onMouseWheel(MyGUI::Widget *_sender, int _rel) void ItemView::setSize(const MyGUI::IntSize &_value) { + bool changed = (_value.width != getWidth() || _value.height != getHeight()); Base::setSize(_value); - update(); + if (changed) + update(); } void ItemView::setSize(int _width, int _height) { - Base::setSize(_width, _height); - update(); + setSize(MyGUI::IntSize(_width, _height)); } void ItemView::setCoord(const MyGUI::IntCoord &_value) { + bool changed = (_value.width != getWidth() || _value.height != getHeight()); Base::setCoord(_value); - update(); + if (changed) + update(); } void ItemView::setCoord(int _left, int _top, int _width, int _height) { - Base::setCoord(_left, _top, _width, _height); - update(); + setCoord(MyGUI::IntCoord(_left, _top, _width, _height)); } void ItemView::registerComponents() From 048d07b29905522b83336cf097b2fbe704de3f59 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jul 2014 11:57:21 +0200 Subject: [PATCH 40/67] Show owner of doors in tooltip --- apps/openmw/mwclass/door.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index e435511b99..677ad462e0 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -250,8 +250,11 @@ namespace MWClass text += "\n#{sTrapped}"; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) + { text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); - + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); + } info.text = text; return info; From d91d5992697e3edf9f93ccfb85ae34b0a95436b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jul 2014 06:43:04 +0200 Subject: [PATCH 41/67] Disable quickload when in modal dialog (Fixes #1641) --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index afdde6fb01..8d4c53921c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -707,11 +707,13 @@ namespace MWInput } void InputManager::quickLoad() { - MWBase::Environment::get().getStateManager()->quickLoad(); + if (!MyGUI::InputManager::getInstance().isModalAny()) + MWBase::Environment::get().getStateManager()->quickLoad(); } void InputManager::quickSave() { - MWBase::Environment::get().getStateManager()->quickSave(); + if (!MyGUI::InputManager::getInstance().isModalAny()) + MWBase::Environment::get().getStateManager()->quickSave(); } void InputManager::toggleSpell() { From 1c41ce9b9d95e09f68cf304bd2342617742eceaa Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jul 2014 07:31:18 +0200 Subject: [PATCH 42/67] Implement Hrnchamd's player and NPC autocalc spells (Some unclarities remaining, XXX) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/npc.cpp | 49 +++- apps/openmw/mwmechanics/autocalcspell.cpp | 214 ++++++++++++++++++ apps/openmw/mwmechanics/autocalcspell.hpp | 31 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 96 ++++++-- components/esm/loadspel.hpp | 4 +- 6 files changed, 368 insertions(+), 28 deletions(-) create mode 100644 apps/openmw/mwmechanics/autocalcspell.cpp create mode 100644 apps/openmw/mwmechanics/autocalcspell.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5c5b0d16ca..23ba78dbad 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -69,7 +69,7 @@ add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting - disease pickpocket levelledlist combat steering obstacle + disease pickpocket levelledlist combat steering obstacle autocalcspell ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c003e0b227..80900d4655 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -22,6 +22,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/disease.hpp" #include "../mwmechanics/combat.hpp" +#include "../mwmechanics/autocalcspell.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" @@ -193,18 +194,6 @@ namespace majorMultiplier = 1.0f; break; } - if (class_->mData.mSkills[k][1] == skillIndex) - { - // Major skill -> add starting spells for this skill if existing - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - MWWorld::Store::iterator it = store.get().begin(); - for (; it != store.get().end(); ++it) - { - if (it->mData.mFlags & ESM::Spell::F_Autocalc - && MWMechanics::spellSchoolToSkill(MWMechanics::getSpellSchool(&*it, ptr)) == skillIndex) - npcStats.getSpells().add(it->mId); - } - } } // is this skill in the same Specialization as the class? @@ -223,6 +212,42 @@ namespace + specBonus + static_cast((level-1) * (majorMultiplier + specMultiplier)), 100)); } + + int skills[ESM::Skill::Length]; + for (int i=0; imId << std::endl; + std::cout << "Skills: " << std::endl; + for (int i=0; i spells = MWMechanics::autoCalcNpcSpells(skills, attributes, race); + std::cout << "Spells: " << spells.size() << std::endl; + for (std::set::iterator it = spells.begin(); it != spells.end(); ++it) + { + std::cout << *it << ", "; + npcStats.getSpells().add(*it); + } + std::cout << std::endl; + + const char* compare[] = { "weary","dire noise","reflect","weak spelldrinker","absorb endurance","absorb personality","absorb speed","absorb strength","absorb willpower","fortify alteration skill","fortify illusion skill","fortify unarmored skill","fortify mysticism skill","fortify restoration skill","assured sublime wisdom","surpassing sublime wisdom","surpassing golden wisdom","blood gift","surpassing silver wisdom","surpassing unseen wisdom","surpassing green wisdom","powerwell","orc's strength","surpassing fluid evasion","poet's whim","rapid regenerate","dispel","shadow weave" }; + int n = sizeof(compare) / sizeof(compare[0]); + std::set compareSet; + for (int i=0; i::iterator it = compareSet.begin(); it != compareSet.end(); ++it) + { + std::cout << *it << ", "; + } + std::cout << std::endl; } } diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp new file mode 100644 index 0000000000..5659959e84 --- /dev/null +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -0,0 +1,214 @@ +#include "autocalcspell.hpp" + +#include + +#include "../mwworld/esmstore.hpp" + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + + +namespace MWMechanics +{ + + struct SchoolCaps + { + int mCount; + int mLimit; + bool mReachedLimit; + int mMinCost; + std::string mWeakestSpell; + }; + + std::set autoCalcNpcSpells(const int *actorSkills, const int *actorAttributes, const ESM::Race* race) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->getFloat(); + float baseMagicka = fNPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence]; + + static const std::string schools[] = { + "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" + }; + static int iAutoSpellSchoolMax[6]; + static bool init = false; + if (!init) + { + for (int i=0; i<6; ++i) + { + const std::string& gmstName = "iAutoSpell" + schools[i] + "Max"; + iAutoSpellSchoolMax[i] = gmst.find(gmstName)->getInt(); + } + init = true; + } + + std::map schoolCaps; + for (int i=0; i<6; ++i) + { + SchoolCaps caps; + caps.mCount = 0; + caps.mLimit = iAutoSpellSchoolMax[i]; + caps.mReachedLimit = iAutoSpellSchoolMax[i] <= 0; + caps.mMinCost = INT_MAX; + caps.mWeakestSpell.clear(); + schoolCaps[i] = caps; + } + + std::set selectedSpells; + + const MWWorld::Store &spells = + MWBase::Environment::get().getWorld()->getStore().get(); + for (MWWorld::Store::iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = &*iter; + + if (spell->mData.mType != ESM::Spell::ST_Spell) + continue; + if (!(spell->mData.mFlags & ESM::Spell::F_Autocalc)) + continue; + static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->getInt(); + if (baseMagicka < iAutoSpellTimesCanCast * spell->mData.mCost) + continue; + + if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end()) + continue; + + if (!attrSkillCheck(spell, actorSkills, actorAttributes)) + continue; + + int school; + float skillTerm; + calcWeakestSchool(spell, actorSkills, school, skillTerm); + assert(school >= 0 && school < 6); + SchoolCaps& cap = schoolCaps[school]; + + if (cap.mReachedLimit && spell->mData.mCost <= cap.mMinCost) + continue; + + static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->getFloat(); + if (calcAutoCastChance(spell, actorSkills, actorAttributes, school) < fAutoSpellChance) + continue; + + selectedSpells.insert(spell->mId); + + if (cap.mReachedLimit) + { + selectedSpells.erase(cap.mWeakestSpell); + + // Note: not school specific + cap.mMinCost = INT_MAX; + for (std::set::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) + { + const ESM::Spell* testSpell = spells.find(*weakIt); + if (testSpell->mData.mCost < cap.mMinCost) // XXX what if 2 candidates have the same cost? + { + cap.mMinCost = testSpell->mData.mCost; + cap.mWeakestSpell = testSpell->mId; + } + } + } + else + { + cap.mCount += 1; + if (cap.mCount == cap.mLimit) + cap.mReachedLimit = true; + + if (spell->mData.mCost < cap.mMinCost) + { + cap.mWeakestSpell = spell->mId; + cap.mMinCost = spell->mData.mCost; + } + } + } + return selectedSpells; + } + + bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes) + { + const std::vector& effects = spell->mEffects.mList; + for (std::vector::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt) + { + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->mEffectID); + static const int iAutoSpellAttSkillMin = MWBase::Environment::get().getWorld()->getStore().get().find("iAutoSpellAttSkillMin")->getInt(); + + if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)) + { + assert (effectIt->mSkill >= 0 && effectIt->mSkill < ESM::Skill::Length); + if (actorSkills[effectIt->mSkill] < iAutoSpellAttSkillMin) + return false; + } + + if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)) + { + assert (effectIt->mAttribute >= 0 && effectIt->mAttribute < ESM::Attribute::Length); + if (actorAttributes[effectIt->mAttribute] < iAutoSpellAttSkillMin) + return false; + } + } + + return true; + } + + ESM::Skill::SkillEnum mapSchoolToSkill(int school) + { + std::map schoolSkillMap; // maps spell school to skill id + schoolSkillMap[0] = ESM::Skill::Alteration; + schoolSkillMap[1] = ESM::Skill::Conjuration; + schoolSkillMap[3] = ESM::Skill::Illusion; + schoolSkillMap[2] = ESM::Skill::Destruction; + schoolSkillMap[4] = ESM::Skill::Mysticism; + schoolSkillMap[5] = ESM::Skill::Restoration; + assert(schoolSkillMap.find(school) != schoolSkillMap.end()); + return schoolSkillMap[school]; + } + + void calcWeakestSchool (const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm) + { + float minChance = FLT_MAX; + + const ESM::EffectList& effects = spell->mEffects; + for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) + { + const ESM::ENAMstruct& effect = *it; + float x = effect.mDuration; + + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) + x = std::max(1.f, x); + + x *= 0.1f * magicEffect->mData.mBaseCost; + x *= 0.5f * (effect.mMagnMin + effect.mMagnMax); + x += effect.mArea * 0.05f * magicEffect->mData.mBaseCost; // XXX spell.radius + if (magicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) // XXX effect.flags & CAST_TARGET + x *= 1.5f; + + static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fEffectCostMult")->getFloat(); + x *= fEffectCostMult; + + float s = 2.f * actorSkills[mapSchoolToSkill(magicEffect->mData.mSchool)]; + if (s - x < minChance) + { + minChance = s - x; + effectiveSchool = magicEffect->mData.mSchool; + skillTerm = s; + } + } + } + + float calcAutoCastChance(const ESM::Spell *spell, const int *actorSkills, const int *actorAttributes, int effectiveSchool) + { + if (spell->mData.mType != ESM::Spell::ST_Spell) + return 100.f; + + if (spell->mData.mFlags & ESM::Spell::F_Always) + return 100.f; + + float skillTerm; + if (effectiveSchool != -1) + skillTerm = 2.f * actorSkills[mapSchoolToSkill(effectiveSchool)]; + else + calcWeakestSchool(spell, actorSkills, effectiveSchool, skillTerm); // Note effectiveSchool is unused after this + + float castChance = skillTerm - spell->mData.mCost + 0.2f * actorAttributes[ESM::Attribute::Willpower] + 0.1f * actorAttributes[ESM::Attribute::Luck]; + return castChance; + } +} diff --git a/apps/openmw/mwmechanics/autocalcspell.hpp b/apps/openmw/mwmechanics/autocalcspell.hpp new file mode 100644 index 0000000000..8ba7d833f7 --- /dev/null +++ b/apps/openmw/mwmechanics/autocalcspell.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_AUTOCALCSPELL_H +#define OPENMW_AUTOCALCSPELL_H + +#include +#include + +#include +#include +#include + +namespace MWMechanics +{ + +/// Contains algorithm for calculating an NPC's spells based on stats +/// @note We might want to move this code to a component later, so the editor can use it for preview purposes + +std::set autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race); + +// Helpers + +bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes); + +ESM::Skill::SkillEnum mapSchoolToSkill(int school); + +void calcWeakestSchool(const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm); + +float calcAutoCastChance(const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes, int effectiveSchool); + +} + +#endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 6e515142de..073cb5f74c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -19,6 +19,7 @@ #include #include "spellcasting.hpp" +#include "autocalcspell.hpp" namespace { @@ -155,19 +156,6 @@ namespace MWMechanics npcStats.getSkill (index).setBase ( npcStats.getSkill (index).getBase() + bonus); } - - if (i==1) - { - // Major skill - add starting spells for this skill if existing - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - MWWorld::Store::iterator it = store.get().begin(); - for (; it != store.get().end(); ++it) - { - if (it->mData.mFlags & ESM::Spell::F_PCStart - && spellSchoolToSkill(getSpellSchool(&*it, ptr)) == index) - creatureStats.getSpells().add(it->mId); - } - } } } @@ -190,6 +178,88 @@ namespace MWMechanics } } + // F_PCStart spells + static const float fPCbaseMagickaMult = esmStore.get().find("fPCbaseMagickaMult")->getFloat(); + + float baseMagicka = fPCbaseMagickaMult * creatureStats.getAttribute(ESM::Attribute::Intelligence).getBase(); + bool reachedLimit = false; + const ESM::Spell* weakestSpell = NULL; + int minCost = INT_MAX; + + std::set selectedSpells; + + const ESM::Race* race = NULL; + if (mRaceSelected) + race = esmStore.get().find(player->mRace); + + int skills[ESM::Skill::Length]; + for (int i=0; i &spells = + esmStore.get(); + for (MWWorld::Store::iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = &*iter; + + if (spell->mData.mType != ESM::Spell::ST_Spell) + continue; + if (!(spell->mData.mFlags & ESM::Spell::F_PCStart)) + continue; + if (reachedLimit && spell->mData.mCost <= minCost) + continue; + if (selectedSpells.find(spell->mId) != selectedSpells.end()) + continue; + if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end()) + continue; + if (baseMagicka < spell->mData.mCost) + continue; + + static const float fAutoPCSpellChance = esmStore.get().find("fAutoPCSpellChance")->getFloat(); + if (calcAutoCastChance(spell, skills, attributes, -1) < fAutoPCSpellChance) + continue; + + if (!attrSkillCheck(spell, skills, attributes)) + continue; + + selectedSpells.insert(spell->mId); + + if (reachedLimit) + { + selectedSpells.erase(weakestSpell->mId); + + minCost = INT_MAX; + for (std::set::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) + { + const ESM::Spell* testSpell = esmStore.get().find(*weakIt); + if (testSpell->mData.mCost < minCost) // XXX what if 2 candidates have the same cost? + // Note iAutoPCSpellMax is 100 by default, so reachedLimit is very unlikely to happen + { + minCost = testSpell->mData.mCost; + weakestSpell = testSpell; + } + } + } + else + { + if (spell->mData.mCost < minCost) + { + weakestSpell = spell; + minCost = weakestSpell->mData.mCost; + } + static const unsigned int iAutoPCSpellMax = esmStore.get().find("iAutoPCSpellMax")->getInt(); + if (selectedSpells.size() == iAutoPCSpellMax) + reachedLimit = true; + } + } + + for (std::set::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it) + creatureStats.getSpells().add(*it); + // forced update and current value adjustments mActors.updateActor (ptr, 0); diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index cbf5366c4b..4bd2210ec0 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -27,8 +27,8 @@ struct Spell enum Flags { - F_Autocalc = 1, - F_PCStart = 2, + F_Autocalc = 1, // Can be selected by NPC spells auto-calc + F_PCStart = 2, // Can be selected by player spells auto-calc F_Always = 4 // Casting always succeeds }; From b4f8edc186772f029411cbd317b1bf6551a2f436 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jul 2014 18:25:29 +0200 Subject: [PATCH 43/67] Use spell effect range type, not base effect --- apps/openmw/mwmechanics/autocalcspell.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 5659959e84..d2b6c46e3b 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -177,8 +177,8 @@ namespace MWMechanics x *= 0.1f * magicEffect->mData.mBaseCost; x *= 0.5f * (effect.mMagnMin + effect.mMagnMax); - x += effect.mArea * 0.05f * magicEffect->mData.mBaseCost; // XXX spell.radius - if (magicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) // XXX effect.flags & CAST_TARGET + x += effect.mArea * 0.05f * magicEffect->mData.mBaseCost; + if (effect.mRange == ESM::RT_Target) x *= 1.5f; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fEffectCostMult")->getFloat(); From 479f248c1ddebc532edae65ae954c3be1b367407 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jul 2014 18:33:39 +0200 Subject: [PATCH 44/67] Use spell effect range type, not base effect (applied to spellcasting code) --- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 6467730dda..1b0c444ab7 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -92,7 +92,7 @@ namespace MWMechanics x *= 0.1 * magicEffect->mData.mBaseCost; x *= 0.5 * (it->mMagnMin + it->mMagnMax); x *= it->mArea * 0.05 * magicEffect->mData.mBaseCost; - if (magicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) + if (it->mRange == ESM::RT_Target) x *= 1.5; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find( "fEffectCostMult")->getFloat(); From 83819b2894371d25f4be0ec79c108bda5ec06178 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jul 2014 08:05:10 +0200 Subject: [PATCH 45/67] Traverse spells in record order from content files. bronrod_the_roarer is perfect now. Other NPCs have some differences. --- apps/openmw/mwclass/npc.cpp | 28 ++---------------- apps/openmw/mwmechanics/autocalcspell.cpp | 32 +++++++++++++++----- apps/openmw/mwmechanics/autocalcspell.hpp | 2 +- apps/openmw/mwworld/store.hpp | 36 +++++++++++++++++++---- 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 80900d4655..31e09bbacf 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -221,33 +221,9 @@ namespace for (int i=0; imId << std::endl; - std::cout << "Skills: " << std::endl; - for (int i=0; i spells = MWMechanics::autoCalcNpcSpells(skills, attributes, race); - std::cout << "Spells: " << spells.size() << std::endl; - for (std::set::iterator it = spells.begin(); it != spells.end(); ++it) - { - std::cout << *it << ", "; + std::vector spells = MWMechanics::autoCalcNpcSpells(skills, attributes, race); + for (std::vector::iterator it = spells.begin(); it != spells.end(); ++it) npcStats.getSpells().add(*it); - } - std::cout << std::endl; - - const char* compare[] = { "weary","dire noise","reflect","weak spelldrinker","absorb endurance","absorb personality","absorb speed","absorb strength","absorb willpower","fortify alteration skill","fortify illusion skill","fortify unarmored skill","fortify mysticism skill","fortify restoration skill","assured sublime wisdom","surpassing sublime wisdom","surpassing golden wisdom","blood gift","surpassing silver wisdom","surpassing unseen wisdom","surpassing green wisdom","powerwell","orc's strength","surpassing fluid evasion","poet's whim","rapid regenerate","dispel","shadow weave" }; - int n = sizeof(compare) / sizeof(compare[0]); - std::set compareSet; - for (int i=0; i::iterator it = compareSet.begin(); it != compareSet.end(); ++it) - { - std::cout << *it << ", "; - } - std::cout << std::endl; } } diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index d2b6c46e3b..255decdf75 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -20,7 +20,7 @@ namespace MWMechanics std::string mWeakestSpell; }; - std::set autoCalcNpcSpells(const int *actorSkills, const int *actorAttributes, const ESM::Race* race) + std::vector autoCalcNpcSpells(const int *actorSkills, const int *actorAttributes, const ESM::Race* race) { const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->getFloat(); @@ -53,10 +53,13 @@ namespace MWMechanics schoolCaps[i] = caps; } - std::set selectedSpells; + std::vector selectedSpells; const MWWorld::Store &spells = MWBase::Environment::get().getWorld()->getStore().get(); + + // Note: the algorithm heavily depends on the traversal order of the spells. For vanilla-compatible results the + // Store must preserve the record ordering as it was in the content files. for (MWWorld::Store::iterator iter = spells.begin(); iter != spells.end(); ++iter) { const ESM::Spell* spell = &*iter; @@ -88,18 +91,32 @@ namespace MWMechanics if (calcAutoCastChance(spell, actorSkills, actorAttributes, school) < fAutoSpellChance) continue; - selectedSpells.insert(spell->mId); + selectedSpells.push_back(spell->mId); if (cap.mReachedLimit) { - selectedSpells.erase(cap.mWeakestSpell); + std::vector::iterator found = std::find(selectedSpells.begin(), selectedSpells.end(), cap.mWeakestSpell); + if (found != selectedSpells.end()) + selectedSpells.erase(found); - // Note: not school specific cap.mMinCost = INT_MAX; - for (std::set::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) + for (std::vector::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) { const ESM::Spell* testSpell = spells.find(*weakIt); - if (testSpell->mData.mCost < cap.mMinCost) // XXX what if 2 candidates have the same cost? + + //int testSchool; + //float dummySkillTerm; + //calcWeakestSchool(testSpell, actorSkills, testSchool, dummySkillTerm); + + // Note: if there are multiple spells with the same cost, we pick the first one we found. + // So the algorithm depends on the iteration order of the outer loop. + if ( + // There is a huge bug here. It is not checked that weakestSpell is of the correct school. + // As result multiple SchoolCaps could have the same mWeakestSpell. Erasing the weakest spell would then fail if another school + // already erased it, and so the number of spells would often exceed the sum of limits. + // This bug cannot be fixed without significantly changing the results of the spell autocalc, which will not have been playtested. + //testSchool == school && + testSpell->mData.mCost < cap.mMinCost) { cap.mMinCost = testSpell->mData.mCost; cap.mWeakestSpell = testSpell->mId; @@ -119,6 +136,7 @@ namespace MWMechanics } } } + return selectedSpells; } diff --git a/apps/openmw/mwmechanics/autocalcspell.hpp b/apps/openmw/mwmechanics/autocalcspell.hpp index 8ba7d833f7..1912c75c42 100644 --- a/apps/openmw/mwmechanics/autocalcspell.hpp +++ b/apps/openmw/mwmechanics/autocalcspell.hpp @@ -14,7 +14,7 @@ namespace MWMechanics /// Contains algorithm for calculating an NPC's spells based on stats /// @note We might want to move this code to a component later, so the editor can use it for preview purposes -std::set autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race); +std::vector autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race); // Helpers diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 3e7e7a5f98..9a442387b3 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -209,8 +209,6 @@ namespace MWWorld } void setUp() { - //std::sort(mStatic.begin(), mStatic.end(), RecordCmp()); - mShared.clear(); mShared.reserve(mStatic.size()); typename std::map::iterator it = mStatic.begin(); @@ -675,18 +673,15 @@ namespace MWWorld } void setUp() { - //typedef std::vector::iterator Iterator; typedef DynamicExt::iterator ExtIterator; typedef std::map::iterator IntIterator; - //std::sort(mInt.begin(), mInt.end(), RecordCmp()); mSharedInt.clear(); mSharedInt.reserve(mInt.size()); for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { mSharedInt.push_back(&(it->second)); } - //std::sort(mExt.begin(), mExt.end(), ExtCmp()); mSharedExt.clear(); mSharedExt.reserve(mExt.size()); for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { @@ -1147,6 +1142,37 @@ namespace MWWorld } }; + + // Specialisation for ESM::Spell to preserve record order as it was in the content files. + // The NPC spell autocalc code heavily depends on this order. + // We could also do this in the base class, but it's usually not a good idea to depend on record order. + template<> + inline void Store::clearDynamic() + { + // remove the dynamic part of mShared + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + mDynamic.clear(); + } + + template<> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + std::string idLower = Misc::StringUtils::lowerCase(id); + + std::pair inserted = mStatic.insert(std::make_pair(idLower, ESM::Spell())); + if (inserted.second) + mShared.push_back(&mStatic[idLower]); + + inserted.first->second.mId = idLower; + inserted.first->second.load(esm); + } + + template<> + inline void Store::setUp() + { + // remove the dynamic part of mShared + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + } + } //end namespace #endif From a1639371d3f2e637036c40222082dc85f4775072 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jul 2014 14:05:57 +0200 Subject: [PATCH 46/67] Fix rounding for skill/attribute autocalc --- apps/openmw/mwclass/npc.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 31e09bbacf..b05bc438cd 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -54,6 +54,24 @@ namespace return new NpcCustomData (*this); } + int is_even(double d) { + double int_part; + modf(d / 2.0, &int_part); + return 2.0 * int_part == d; + } + + int round_ieee_754(double d) { + double i = floor(d); + d -= i; + if(d < 0.5) + return i; + if(d > 0.5) + return i + 1.0; + if(is_even(i)) + return i; + return i + 1.0; + } + void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) { // race bonus @@ -109,8 +127,9 @@ namespace } modifierSum += add; } - creatureStats.setAttribute(attribute, std::min(creatureStats.getAttribute(attribute).getBase() - + static_cast((level-1) * modifierSum+0.5), 100) ); + creatureStats.setAttribute(attribute, std::min( + round_ieee_754(creatureStats.getAttribute(attribute).getBase() + + (level-1) * modifierSum), 100) ); } // initial health @@ -206,11 +225,12 @@ namespace npcStats.getSkill(skillIndex).setBase( std::min( - npcStats.getSkill(skillIndex).getBase() + round_ieee_754( + npcStats.getSkill(skillIndex).getBase() + 5 + raceBonus + specBonus - + static_cast((level-1) * (majorMultiplier + specMultiplier)), 100)); + + (level-1) * (majorMultiplier + specMultiplier)), 100)); } int skills[ESM::Skill::Length]; From fd3f1093626ed666ae177e0bb8febd2a0c09db8b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jul 2014 14:43:57 +0200 Subject: [PATCH 47/67] Fix underflow for NPCs with level 0 --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b05bc438cd..e2cb8ba7af 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -230,7 +230,7 @@ namespace + 5 + raceBonus + specBonus - + (level-1) * (majorMultiplier + specMultiplier)), 100)); + +(int(level)-1) * (majorMultiplier + specMultiplier)), 100)); // Must gracefully handle level 0 } int skills[ESM::Skill::Length]; From d63dd881130d87ef11463b72796eacbad7dd5c63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jul 2014 17:35:38 +0200 Subject: [PATCH 48/67] Apply autocalc corrections to player starting spells --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 073cb5f74c..d7c3e2f56d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -186,7 +186,7 @@ namespace MWMechanics const ESM::Spell* weakestSpell = NULL; int minCost = INT_MAX; - std::set selectedSpells; + std::vector selectedSpells; const ESM::Race* race = NULL; if (mRaceSelected) @@ -212,8 +212,6 @@ namespace MWMechanics continue; if (reachedLimit && spell->mData.mCost <= minCost) continue; - if (selectedSpells.find(spell->mId) != selectedSpells.end()) - continue; if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end()) continue; if (baseMagicka < spell->mData.mCost) @@ -226,18 +224,19 @@ namespace MWMechanics if (!attrSkillCheck(spell, skills, attributes)) continue; - selectedSpells.insert(spell->mId); + selectedSpells.push_back(spell->mId); if (reachedLimit) { - selectedSpells.erase(weakestSpell->mId); + std::vector::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId); + if (it != selectedSpells.end()) + selectedSpells.erase(it); minCost = INT_MAX; - for (std::set::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) + for (std::vector::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) { const ESM::Spell* testSpell = esmStore.get().find(*weakIt); - if (testSpell->mData.mCost < minCost) // XXX what if 2 candidates have the same cost? - // Note iAutoPCSpellMax is 100 by default, so reachedLimit is very unlikely to happen + if (testSpell->mData.mCost < minCost) { minCost = testSpell->mData.mCost; weakestSpell = testSpell; @@ -257,7 +256,7 @@ namespace MWMechanics } } - for (std::set::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it) + for (std::vector::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it) creatureStats.getSpells().add(*it); // forced update and current value adjustments From 7316f4dde464a58a6ec91a4a292ce3c7558d3584 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Jul 2014 12:17:24 +0200 Subject: [PATCH 49/67] increased version number --- CMakeLists.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9de8efeb54..cb9a54a6cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 30) +set(OPENMW_VERSION_MINOR 31) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/readme.txt b/readme.txt index 92cb35f31f..90f223a646 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.30.0 +Version: 0.31.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From 7cd819f24f3b213c4407ff1fbb5bdb82428e0d84 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Jul 2014 08:58:54 +0200 Subject: [PATCH 50/67] updated changelog --- readme.txt | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/readme.txt b/readme.txt index 90f223a646..bafca48a47 100644 --- a/readme.txt +++ b/readme.txt @@ -96,6 +96,188 @@ Allowed options: CHANGELOG +0.31.0 + +Bug #245: Cloud direction and weather systems differ from Morrowind +Bug #275: Local Map does not always show objects that span multiple cells +Bug #538: Update CenterOnCell (COC) function behavior +Bug #618: Local and World Map Textures are sometimes Black +Bug #640: Water behaviour at night +Bug #668: OpenMW doesn't support non-latin paths on Windows +Bug #746: OpenMW doesn't check if the background music was already played +Bug #747: Door is stuck if cell is left before animation finishes +Bug #772: Disabled statics are visible on map +Bug #829: OpenMW uses up all available vram, when playing for extended time +Bug #869: Dead bodies don't collide with anything +Bug #894: Various character creation issues +Bug #897/#1369: opencs Segmentation Fault after "new" or "load" +Bug #899: Various jumping issues +Bug #952: Reflection effects are one frame delayed +Bug #993: Able to interact with world during Wait/Rest dialog +Bug #995: Dropped items can be placed inside the wall +Bug #1008: Corpses always face up upon reentering the cell +Bug #1035: Random colour patterns appearing in automap +Bug #1037: Footstep volume issues +Bug #1047: Creation of wrong links in dialogue window +Bug #1129: Summoned creature time life duration seems infinite +Bug #1134: Crimes can be committed against hostile NPCs +Bug #1136: Creature run speed formula is incorrect +Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell +Bug #1155: NPCs killing each other +Bug #1166: Bittercup script still does not work +Bug #1178: .bsa file names are case sensitive. +Bug #1179: Crash after trying to load game after being killed +Bug #1180: Changing footstep sound location +Bug #1196: Jumping not disabled when showing messageboxes +Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works +Bug #1217: Container content changes based on the current position of the mouse +Bug #1234: Loading/saving issues with dynamic records +Bug #1277: Text pasted into the console appears twice +Bug #1284: Crash on New Game +Bug #1303: It's possible to skip the chargen +Bug #1304: Slaughterfish should not detect the player unless the player is in the water +Bug #1311: Editor: deleting Record Filter line does not reset the filter +Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp +Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table +Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running. +Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them. +Bug #1335: Actors ignore vertical axis when deciding to attack +Bug #1338: Unknown toggle option for shadows +Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process +Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard. +Bug #1348: Regression: Bug #1098 has returned with a vengeance +Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated +Bug #1352: Disabling an ESX file does not disable dependent ESX files +Bug #1355: CppCat Checks OpenMW +Bug #1356: Incorrect voice type filtering for sleep interrupts +Bug #1357: Restarting the game clears saves +Bug #1360: Seyda Neen silk rider dialog problem +Bug #1361: Some lights don't work +Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu +Bug #1370: Animation compilation mod does not work properly +Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla +Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog +Bug #1378: Installs to /usr/local are not working +Bug #1380: Loading a save file fail if one of the content files is disabled +Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp" +Bug #1386: Arkngthand door will not open +Bug #1388: Segfault when modifying View Distance in Menu options +Bug #1389: Crash when loading a save after dying +Bug #1390: Apostrophe characters not displayed [French version] +Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI. +Bug #1393: Coin icon during the level up dialogue are off of the background +Bug #1394: Alt+F4 doesn't work on Win version +Bug #1395: Changing rings switches only the last one put on +Bug #1396: Pauldron parts aren't showing when the robe is equipped +Bug #1402: Dialogue of some shrines have wrong button orientation +Bug #1403: Items are floating in the air when they're dropped onto dead bodies. +Bug #1404: Forearms are not rendered on Argonian females +Bug #1407: Alchemy allows making potions from two of the same item +Bug #1408: "Max sale" button gives you all the items AND all the trader's gold +Bug #1409: Rest "Until Healed" broken for characters with stunted magicka. +Bug #1412: Empty travel window opens while playing through start game +Bug #1413: Save game ignores missing writing permission +Bug #1414: The Underground 2 ESM Error +Bug #1416: Not all splash screens in the Splash directory are used +Bug #1417: Loading saved game does not terminate +Bug #1419: Skyrim: Home of the Nords error +Bug #1422: ClearInfoActor +Bug #1423: ForceGreeting closes existing dialogue windows +Bug #1425: Cannot load save game +Bug #1426: Read skill books aren't stored in savegame +Bug #1427: Useless items can be set under hotkeys +Bug #1429: Text variables in journal +Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing +Bug #1435: Stealing priceless items is without punishment +Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air +Bug #1440: Topic selection menu should be wider +Bug #1441: Dropping items on the rug makes them inaccessible +Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime +Bug #1444: Arrows and bolts are not dropped where the cursor points +Bug #1445: Security trainers offering acrobatics instead +Bug #1447: Character dash not displayed, French edition +Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue +Bug #1454: Script error in SkipTutorial +Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE +Bug #1457: Heart of Lorkan comes after you when attacking it +Bug #1458: Modified Keybindings are not remembered +Bug #1459: Dura Gra-Bol doesn't respond to PC attack +Bug #1462: Interior cells not loaded with Morrowind Patch active +Bug #1469: Item tooltip should show the base value, not real value +Bug #1477: Death count is not stored in savegame +Bug #1478: AiActivate does not trigger activate scripts +Bug #1481: Weapon not rendered when partially submerged in water +Bug #1483: Enemies are attacking even while dying +Bug #1486: ESM Error: Don't know what to do with INFO +Bug #1490: Arrows shot at PC can end up in inventory +Bug #1492: Monsters respawn on top of one another +Bug #1493: Dialogue box opens with follower NPC even if NPC is dead +Bug #1494: Paralysed cliffracers remain airbourne +Bug #1495: Dialogue box opens with follower NPC even the game is paused +Bug #1496: GUI messages are not cleared when loading another saved game +Bug #1499: Underwater sound sometimes plays when transitioning from interior. +Bug #1500: Targetted spells and water. +Bug #1502: Console error message on info refusal +Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow +Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius +Bug #1516: PositionCell doesn't move actors to current cell +Bug #1518: ForceGreeting broken for explicit references +Bug #1522: Crash after attempting to play non-music file +Bug #1523: World map empty after loading interior save +Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons +Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood +Bug #1527: Werewolf: Detect life detects wrong type of actor +Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal) +Bug #1530: Selected text in the console has the same color as the background +Bug #1539: Barilzar's Mazed Band: Tribunal +Bug #1542: Looping taunts from NPC`s after death: Tribunal +Bug #1543: OpenCS crash when using drag&drop in script editor +Bug #1547: Bamz-Amschend: Centurion Archers combat problem +Bug #1548: The Missing Hand: Tribunal +Bug #1549: The Mad God: Tribunal, Dome of Serlyn +Bug #1557: A bounty is calculated from actual item cost +Bug #1562: Invisible terrain on top of Red Mountain +Bug #1564: Cave of the hidden music: Bloodmoon +Bug #1567: Editor: Deleting of referenceables does not work +Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen. +Bug #1574: Solstheim: Drauger cant inflict damage on player +Bug #1578: Solstheim: Bonewolf running animation not working +Bug #1585: Particle effects on PC are stopped when paralyzed +Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed +Bug #1590: Failed to save game: compile error +Bug #1598: Segfault when making Drain/Fortify Skill spells +Bug #1599: Unable to switch to fullscreen +Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed +Feature #32: Periodic Cleanup/Refill +Feature #41: Precipitation and weather particles +Feature #568: Editor: Configuration setup +Feature #649: Editor: Threaded loading +Feature #930: Editor: Cell record saving +Feature #934: Editor: Body part table +Feature #935: Editor: Enchantment effect table +Feature #1162: Dialogue merging +Feature #1174: Saved Game: add missing creature state +Feature #1177: Saved Game: fog of war state +Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed +Feature #1314: Make NPCs and creatures fight each other +Feature #1315: Crime: Murder +Feature #1321: Sneak skill enhancements +Feature #1323: Handle restocking items +Feature #1332: Saved Game: levelled creatures +Feature #1347: modFactionReaction script instruction +Feature #1362: Animated main menu support +Feature #1433: Store walk/run toggle +Feature #1449: Use names instead of numbers for saved game files and folders +Feature #1453: Adding Delete button to the load menu +Feature #1460: Enable Journal screen while in dialogue +Feature #1480: Play Battle music when in combat +Feature #1501: Followers unable to fast travel with you +Feature #1520: Disposition and distance-based aggression/ShouldAttack +Feature #1595: Editor: Object rendering in cells +Task #940: Move license to locations where applicable +Task #1333: Remove cmake git tag reading +Task #1566: Editor: Object rendering refactoring + 0.30.0 Bug #416: Extreme shaking can occur during cell transitions while moving From 41d73377b0fa0fd6960b3d4be899bd2ffe2ccaca Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Jul 2014 23:19:40 +0200 Subject: [PATCH 51/67] Use explicit C locale in Misc::StringUtils (Fixes #1216) --- components/misc/stringops.cpp | 55 +---------------------------------- components/misc/stringops.hpp | 32 ++++++-------------- 2 files changed, 10 insertions(+), 77 deletions(-) diff --git a/components/misc/stringops.cpp b/components/misc/stringops.cpp index 0bc8e290a1..0f801e5549 100644 --- a/components/misc/stringops.cpp +++ b/components/misc/stringops.cpp @@ -12,59 +12,6 @@ namespace Misc { -bool begins(const char* str1, const char* str2) -{ - while(*str2) - { - if(*str1 == 0 || *str1 != *str2) return false; - - str1++; - str2++; - } - return true; -} - -bool ends(const char* str1, const char* str2) -{ - int len1 = strlen(str1); - int len2 = strlen(str2); - - if(len1 < len2) return false; - - return strcmp(str2, str1+len1-len2) == 0; -} - -// True if the given chars match, case insensitive -static bool icmp(char a, char b) -{ - if(a >= 'A' && a <= 'Z') - a += 'a' - 'A'; - if(b >= 'A' && b <= 'Z') - b += 'a' - 'A'; - - return a == b; -} - -bool ibegins(const char* str1, const char* str2) -{ - while(*str2) - { - if(*str1 == 0 || !icmp(*str1,*str2)) return false; - - str1++; - str2++; - } - return true; -} - -bool iends(const char* str1, const char* str2) -{ - int len1 = strlen(str1); - int len2 = strlen(str2); - - if(len1 < len2) return false; - - return strcasecmp(str2, str1+len1-len2) == 0; -} +std::locale StringUtils::mLocale = std::locale::classic(); } diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index d41463cfce..04dedb0721 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -4,15 +4,18 @@ #include #include #include +#include namespace Misc { class StringUtils { + + static std::locale mLocale; struct ci { - bool operator()(int x, int y) const { - return std::tolower(x) < std::tolower(y); + bool operator()(char x, char y) const { + return std::tolower(x, StringUtils::mLocale) < std::tolower(y, StringUtils::mLocale); } }; @@ -28,7 +31,7 @@ public: std::string::const_iterator xit = x.begin(); std::string::const_iterator yit = y.begin(); for (; xit != x.end(); ++xit, ++yit) { - if (std::tolower(*xit) != std::tolower(*yit)) { + if (std::tolower(*xit, mLocale) != std::tolower(*yit, mLocale)) { return false; } } @@ -42,7 +45,7 @@ public: for(;xit != x.end() && yit != y.end() && len > 0;++xit,++yit,--len) { int res = *xit - *yit; - if(res != 0 && std::tolower(*xit) != std::tolower(*yit)) + if(res != 0 && std::tolower(*xit, mLocale) != std::tolower(*yit, mLocale)) return (res > 0) ? 1 : -1; } if(len > 0) @@ -57,12 +60,8 @@ public: /// Transforms input string to lower case w/o copy static std::string &toLower(std::string &inout) { - std::transform( - inout.begin(), - inout.end(), - inout.begin(), - (int (*)(int)) std::tolower - ); + for (unsigned int i=0; i Date: Sat, 5 Jul 2014 07:24:30 +0200 Subject: [PATCH 52/67] Fix travis --- .../components/misc/test_stringops.cpp | 65 ------------------- 1 file changed, 65 deletions(-) diff --git a/apps/openmw_test_suite/components/misc/test_stringops.cpp b/apps/openmw_test_suite/components/misc/test_stringops.cpp index 44587c445f..55fe0e0c27 100644 --- a/apps/openmw_test_suite/components/misc/test_stringops.cpp +++ b/apps/openmw_test_suite/components/misc/test_stringops.cpp @@ -12,68 +12,3 @@ struct StringOpsTest : public ::testing::Test { } }; - -TEST_F(StringOpsTest, begins_matching) -{ - ASSERT_TRUE(Misc::begins("abc", "a")); - ASSERT_TRUE(Misc::begins("abc", "ab")); - ASSERT_TRUE(Misc::begins("abc", "abc")); - ASSERT_TRUE(Misc::begins("abcd", "abc")); -} - -TEST_F(StringOpsTest, begins_not_matching) -{ - ASSERT_FALSE(Misc::begins("abc", "b")); - ASSERT_FALSE(Misc::begins("abc", "bc")); - ASSERT_FALSE(Misc::begins("abc", "bcd")); - ASSERT_FALSE(Misc::begins("abc", "abcd")); -} - -TEST_F(StringOpsTest, ibegins_matching) -{ - ASSERT_TRUE(Misc::ibegins("Abc", "a")); - ASSERT_TRUE(Misc::ibegins("aBc", "ab")); - ASSERT_TRUE(Misc::ibegins("abC", "abc")); - ASSERT_TRUE(Misc::ibegins("abcD", "abc")); -} - -TEST_F(StringOpsTest, ibegins_not_matching) -{ - ASSERT_FALSE(Misc::ibegins("abc", "b")); - ASSERT_FALSE(Misc::ibegins("abc", "bc")); - ASSERT_FALSE(Misc::ibegins("abc", "bcd")); - ASSERT_FALSE(Misc::ibegins("abc", "abcd")); -} - -TEST_F(StringOpsTest, ends_matching) -{ - ASSERT_TRUE(Misc::ends("abc", "c")); - ASSERT_TRUE(Misc::ends("abc", "bc")); - ASSERT_TRUE(Misc::ends("abc", "abc")); - ASSERT_TRUE(Misc::ends("abcd", "abcd")); -} - -TEST_F(StringOpsTest, ends_not_matching) -{ - ASSERT_FALSE(Misc::ends("abc", "b")); - ASSERT_FALSE(Misc::ends("abc", "ab")); - ASSERT_FALSE(Misc::ends("abc", "bcd")); - ASSERT_FALSE(Misc::ends("abc", "abcd")); -} - -TEST_F(StringOpsTest, iends_matching) -{ - ASSERT_TRUE(Misc::iends("Abc", "c")); - ASSERT_TRUE(Misc::iends("aBc", "bc")); - ASSERT_TRUE(Misc::iends("abC", "abc")); - ASSERT_TRUE(Misc::iends("abcD", "abcd")); -} - -TEST_F(StringOpsTest, iends_not_matching) -{ - ASSERT_FALSE(Misc::iends("abc", "b")); - ASSERT_FALSE(Misc::iends("abc", "ab")); - ASSERT_FALSE(Misc::iends("abc", "bcd")); - ASSERT_FALSE(Misc::iends("abc", "abcd")); -} - From f2799ea1d9c986ace162f69526612bfcfc7dc1e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Jul 2014 23:37:59 +0200 Subject: [PATCH 53/67] Reset item model when reference is reset (Fixes #1628) This caused crashes when the window was resized after the reference no longer exists (e.g. when a savegame is loaded) --- apps/openmw/mwgui/companionwindow.cpp | 5 +++++ apps/openmw/mwgui/companionwindow.hpp | 2 ++ apps/openmw/mwgui/container.cpp | 6 ++++++ apps/openmw/mwgui/container.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 6 ++++++ apps/openmw/mwgui/tradewindow.hpp | 1 + 6 files changed, 22 insertions(+) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index d0ac3e7c36..8d199e7275 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -153,6 +153,11 @@ void CompanionWindow::onReferenceUnavailable() MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); } +void CompanionWindow::resetReference() +{ + ReferenceInterface::resetReference(); + mItemView->setModel(NULL); +} } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 006d0a3c35..dc460e2fc2 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -20,6 +20,8 @@ namespace MWGui virtual void exit(); + virtual void resetReference(); + void open(const MWWorld::Ptr& npc); void onFrame (); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 011feb4d35..8da3def5fa 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -258,6 +258,12 @@ namespace MWGui onTakeAllButtonClicked(mTakeButton); } + void ContainerWindow::resetReference() + { + ReferenceInterface::resetReference(); + mItemView->setModel(NULL); + } + void ContainerWindow::close() { WindowBase::close(); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 5446a4ab73..79951f70e9 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -54,6 +54,8 @@ namespace MWGui void open(const MWWorld::Ptr& container, bool loot=false); virtual void close(); + virtual void resetReference(); + virtual void exit(); private: diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index c0a51311f5..19187cde1f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -531,4 +531,10 @@ namespace MWGui sellerStats.setLastRestockTime(MWBase::Environment::get().getWorld()->getTimeStamp()); } } + + void TradeWindow::resetReference() + { + ReferenceInterface::resetReference(); + mItemView->setModel(NULL); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index cc70f1ae96..b487a8870e 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -37,6 +37,7 @@ namespace MWGui virtual void exit(); + virtual void resetReference(); private: ItemView* mItemView; From d0e1210dd7be3db928cbebae2b8511af460ef199 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sun, 13 Jul 2014 01:39:42 -0500 Subject: [PATCH 54/67] Fix for Bullet debug assert After changing the vector comparison to squaredDistance, the threshold for rejecting similar vectors needed to be readjusted. --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 2013937612..daad5b0e69 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -364,7 +364,7 @@ namespace MWWorld continue; // velocity updated, calculate nextpos again } - if(newPosition.squaredDistance(nextpos) > 0.00000001*0.00000001) + if(newPosition.squaredDistance(nextpos) > 0.0001) { // trace to where character would go if there were no obstructions tracer.doTrace(colobj, newPosition, nextpos, engine); From e855e5531837e410bb347c88d9f11b9142b69fe4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 13 Jul 2014 10:52:33 +0200 Subject: [PATCH 55/67] added tooltip to user settings button on startup window --- apps/opencs/view/doc/startup.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 5d59492c64..799a07e14b 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -81,6 +81,7 @@ QWidget *CSVDoc::StartupDialogue::createTools() config->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); config->setIcon (QIcon (":startup/configure")); + config->setToolTip ("Open user settings"); layout->addWidget (config); From 26f87f5d235630d122270998ea79ef32ba33854b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 13 Jul 2014 12:15:05 +0200 Subject: [PATCH 56/67] added navigation mode button tooltips --- apps/opencs/view/render/worldspacewidget.cpp | 31 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5b3dc57e23..33f27c8bae 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -59,9 +59,34 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( { CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent); - tool->addButton (":door.png", "1st"); /// \todo replace icons - tool->addButton (":GMST.png", "free"); - tool->addButton (":Info.png", "orbit"); + /// \todo replace icons + /// \todo consider user-defined button-mapping + tool->addButton (":door.png", "1st", + "First Person" + "
  • Mouse-Look while holding the left button
  • " + "
  • WASD movement keys
  • " + "
  • Mouse wheel moves the camera forawrd/backward
  • " + "
  • Stafing (also vertically) by holding the left mouse button and control
  • " + "
  • Camera is held upright
  • " + "
  • Hold shift to speed up movement
  • " + "
"); + tool->addButton (":GMST.png", "free", + "Free Camera" + "
  • Mouse-Look while holding the left button
  • " + "
  • Stafing (also vertically) via WASD or by holding the left mouse button and control
  • " + "
  • Mouse wheel moves the camera forawrd/backward
  • " + "
  • Roll camera with Q and E keys
  • " + "
  • Hold shift to speed up movement
  • " + "
"); + tool->addButton (":Info.png", "orbit", + "Orbiting Camera" + "
  • Always facing the centre point
  • " + "
  • Rotate around the centre point via WASD or by moving the mouse while holding the left button
  • " + "
  • Mouse wheel moves camera away or towards centre point but can not pass through it
  • " + "
  • Roll camera with Q and E keys
  • " + "
  • Stafing (also vertically) by holding the left mouse button and control (includes relocation of the centre point)
  • " + "
  • Hold shift to speed up movement
  • " + "
"); connect (tool, SIGNAL (modeChanged (const std::string&)), this, SLOT (selectNavigationMode (const std::string&))); From c2ea8f3f0a6483a55a8234c59c1377303528c38f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 13 Jul 2014 14:21:50 +0200 Subject: [PATCH 57/67] added self-adjusting tooltips to the top-level toolbar buttons --- apps/opencs/view/render/scenewidget.cpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 2 +- apps/opencs/view/widget/pushbutton.cpp | 21 ++++++++++++-------- apps/opencs/view/widget/pushbutton.hpp | 10 +++++++--- apps/opencs/view/widget/scenetoolmode.cpp | 20 ++++++++++++++++--- apps/opencs/view/widget/scenetoolmode.hpp | 7 +++++-- 6 files changed, 44 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 8f6b74765f..5cad25b254 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -56,7 +56,7 @@ namespace CSVRender CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent) { - CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent); + CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode"); /// \todo replace icons tool->addButton (":door.png", "day", diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 33f27c8bae..d3413a29dd 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -57,7 +57,7 @@ void CSVRender::WorldspaceWidget::selectDefaultNavigationMode() CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( CSVWidget::SceneToolbar *parent) { - CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent); + CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Camera Mode"); /// \todo replace icons /// \todo consider user-defined button-mapping diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 35bed1627d..056e548fbc 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -4,11 +4,11 @@ #include #include -void CSVWidget::PushButton::setExtendedToolTip (const std::string& text) +void CSVWidget::PushButton::setExtendedToolTip (const QString& text) { - std::string tooltip = text; + QString tooltip = text; - if (tooltip.empty()) + if (tooltip.isEmpty()) tooltip = "(Tool tip not implemented yet)"; switch (mType) @@ -29,7 +29,7 @@ void CSVWidget::PushButton::setExtendedToolTip (const std::string& text) break; } - setToolTip (QString::fromUtf8 (tooltip.c_str())); + setToolTip (tooltip); } void CSVWidget::PushButton::keyPressEvent (QKeyEvent *event) @@ -57,16 +57,16 @@ void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event) QPushButton::mouseReleaseEvent (event); } -CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const std::string& tooltip, +CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const QString& tooltip, QWidget *parent) -: QPushButton (icon, "", parent), mKeepOpen (false), mType (type) +: QPushButton (icon, "", parent), mKeepOpen (false), mType (type), mToolTip (tooltip) { setCheckable (type==Type_Mode); setExtendedToolTip (tooltip); } -CSVWidget::PushButton::PushButton (Type type, const std::string& tooltip, QWidget *parent) -: QPushButton (parent), mKeepOpen (false), mType (type) +CSVWidget::PushButton::PushButton (Type type, const QString& tooltip, QWidget *parent) +: QPushButton (parent), mKeepOpen (false), mType (type), mToolTip (tooltip) { setCheckable (type==Type_Mode); setExtendedToolTip (tooltip); @@ -75,4 +75,9 @@ CSVWidget::PushButton::PushButton (Type type, const std::string& tooltip, QWidge bool CSVWidget::PushButton::hasKeepOpen() const { return mKeepOpen; +} + +QString CSVWidget::PushButton::getBaseToolTip() const +{ + return mToolTip; } \ No newline at end of file diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 099cba3580..9b90bd0c66 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -21,10 +21,11 @@ namespace CSVWidget bool mKeepOpen; Type mType; + QString mToolTip; private: - void setExtendedToolTip (const std::string& text); + void setExtendedToolTip (const QString& text); protected: @@ -37,14 +38,17 @@ namespace CSVWidget public: /// \param push Do not maintain a toggle state - PushButton (const QIcon& icon, Type type, const std::string& tooltip = "", + PushButton (const QIcon& icon, Type type, const QString& tooltip = "", QWidget *parent = 0); /// \param push Do not maintain a toggle state - PushButton (Type type, const std::string& tooltip = "", + PushButton (Type type, const QString& tooltip = "", QWidget *parent = 0); bool hasKeepOpen() const; + + /// Return tooltip used at construction (without any button-specific modifications) + QString getBaseToolTip() const; }; } diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 412959c7c4..9a97924a8b 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -8,8 +8,20 @@ #include "scenetoolbar.hpp" #include "pushbutton.hpp" -CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent) -: SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()) +void CSVWidget::SceneToolMode::adjustToolTip (const PushButton *activeMode) +{ + QString toolTip = mToolTip; + + toolTip += "

Currently selected: " + activeMode->getBaseToolTip(); + + toolTip += "

(left click to change mode)"; + + setToolTip (toolTip); +} + +CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent, const QString& toolTip) +: SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()), + mToolTip (toolTip) { mPanel = new QFrame (this, Qt::Popup); @@ -30,7 +42,7 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) } void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id, - const std::string& tooltip) + const QString& tooltip) { PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), PushButton::Type_Mode, tooltip, mPanel); @@ -48,6 +60,7 @@ void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::st { setIcon (button->icon()); button->setChecked (true); + adjustToolTip (button); } } @@ -66,6 +79,7 @@ void CSVWidget::SceneToolMode::selected() iter2->first->setChecked (iter2==iter); setIcon (iter->first->icon()); + adjustToolTip (iter->first); emit modeChanged (iter->second); } } \ No newline at end of file diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 5f18f712f9..92f031fe7e 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -22,15 +22,18 @@ namespace CSVWidget std::map mButtons; // widget, id int mButtonSize; int mIconSize; + QString mToolTip; + + void adjustToolTip (const PushButton *activeMode); public: - SceneToolMode (SceneToolbar *parent); + SceneToolMode (SceneToolbar *parent, const QString& toolTip); virtual void showPanel (const QPoint& position); void addButton (const std::string& icon, const std::string& id, - const std::string& tooltip = ""); + const QString& tooltip = ""); signals: From 688d413b8c3b21c5d3d7d4ba09ccfb265dae071e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 14 Jul 2014 11:06:12 +0200 Subject: [PATCH 58/67] when scene toolbar gains focus, focus first button --- apps/opencs/view/widget/scenetoolbar.cpp | 8 ++++++++ apps/opencs/view/widget/scenetoolbar.hpp | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/apps/opencs/view/widget/scenetoolbar.cpp b/apps/opencs/view/widget/scenetoolbar.cpp index 59a3a1d6e2..f06c856cb9 100644 --- a/apps/opencs/view/widget/scenetoolbar.cpp +++ b/apps/opencs/view/widget/scenetoolbar.cpp @@ -5,6 +5,14 @@ #include "scenetool.hpp" +void CSVWidget::SceneToolbar::focusInEvent (QFocusEvent *event) +{ + QWidget::focusInEvent (event); + + if (mLayout->count()) + dynamic_cast (*mLayout->itemAt (0)).widget()->setFocus(); +} + CSVWidget::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) : QWidget (parent), mButtonSize (buttonSize), mIconSize (buttonSize-6) { diff --git a/apps/opencs/view/widget/scenetoolbar.hpp b/apps/opencs/view/widget/scenetoolbar.hpp index 0ef84f488e..bd609078db 100644 --- a/apps/opencs/view/widget/scenetoolbar.hpp +++ b/apps/opencs/view/widget/scenetoolbar.hpp @@ -17,6 +17,10 @@ namespace CSVWidget int mButtonSize; int mIconSize; + protected: + + virtual void focusInEvent (QFocusEvent *event); + public: SceneToolbar (int buttonSize, QWidget *parent = 0); From 92af0938567b2acd70a9a20bdc089c4b59b9d2e7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 14 Jul 2014 11:19:59 +0200 Subject: [PATCH 59/67] new keyboard shortcut (T): move focus from scene widget to toolbar --- apps/opencs/view/render/scenewidget.cpp | 7 ++++++- apps/opencs/view/render/scenewidget.hpp | 4 ++++ apps/opencs/view/world/previewsubview.cpp | 1 + apps/opencs/view/world/scenesubview.cpp | 2 ++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 5cad25b254..a37d1071a3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -51,7 +52,11 @@ namespace CSVRender QTimer *timer = new QTimer (this); connect (timer, SIGNAL (timeout()), this, SLOT (update())); - timer->start (20); /// \todo make this configurable + timer->start (20); ///< \todo make this configurable + + /// \todo make shortcut configurable + QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this); + connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); } CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 8b01e71857..8f548f4831 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -111,6 +111,10 @@ namespace CSVRender void update(); void selectLightingMode (const std::string& mode); + + signals: + + void focusToolbarRequest(); }; } diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index bae0abb8bb..599e9cb9d8 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -46,6 +46,7 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest())); connect (mScene, SIGNAL (referenceableIdChanged (const std::string&)), this, SLOT (referenceableIdChanged (const std::string&))); + connect (mScene, SIGNAL (focusToolbarRequest()), toolbar, SLOT (setFocus())); } void CSVWorld::PreviewSubView::setEditLock (bool locked) {} diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 4430d28eb6..60988e1bb0 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -238,6 +238,8 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mScene = widget; mToolbar = toolbar; + connect (mScene, SIGNAL (focusToolbarRequest()), mToolbar, SLOT (setFocus())); + mLayout->addWidget (mToolbar, 0); mLayout->addWidget (mScene, 1); From 17fc570e38b669bc17540d9255de77334f9de9eb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 14 Jul 2014 13:49:55 +0200 Subject: [PATCH 60/67] new keyboard shortcut (T): move focus from toolbar to scene widget --- apps/opencs/view/render/scenewidget.cpp | 2 +- apps/opencs/view/widget/scenetoolbar.cpp | 7 ++++++- apps/opencs/view/widget/scenetoolbar.hpp | 4 ++++ apps/opencs/view/world/previewsubview.cpp | 1 + apps/opencs/view/world/scenesubview.cpp | 1 + 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index a37d1071a3..ebd3eb7644 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -55,7 +55,7 @@ namespace CSVRender timer->start (20); ///< \todo make this configurable /// \todo make shortcut configurable - QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this); + QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); } diff --git a/apps/opencs/view/widget/scenetoolbar.cpp b/apps/opencs/view/widget/scenetoolbar.cpp index f06c856cb9..eac9bcec32 100644 --- a/apps/opencs/view/widget/scenetoolbar.cpp +++ b/apps/opencs/view/widget/scenetoolbar.cpp @@ -2,6 +2,7 @@ #include "scenetoolbar.hpp" #include +#include #include "scenetool.hpp" @@ -24,6 +25,10 @@ CSVWidget::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); setLayout (mLayout); + + /// \todo make shortcut configurable + QShortcut *focusScene = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); + connect (focusScene, SIGNAL (activated()), this, SIGNAL (focusSceneRequest())); } void CSVWidget::SceneToolbar::addTool (SceneTool *tool) @@ -39,4 +44,4 @@ int CSVWidget::SceneToolbar::getButtonSize() const int CSVWidget::SceneToolbar::getIconSize() const { return mIconSize; -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/scenetoolbar.hpp b/apps/opencs/view/widget/scenetoolbar.hpp index bd609078db..1902ba2bed 100644 --- a/apps/opencs/view/widget/scenetoolbar.hpp +++ b/apps/opencs/view/widget/scenetoolbar.hpp @@ -30,6 +30,10 @@ namespace CSVWidget int getButtonSize() const; int getIconSize() const; + + signals: + + void focusSceneRequest(); }; } diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 599e9cb9d8..1e106c69fe 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -47,6 +47,7 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo connect (mScene, SIGNAL (referenceableIdChanged (const std::string&)), this, SLOT (referenceableIdChanged (const std::string&))); connect (mScene, SIGNAL (focusToolbarRequest()), toolbar, SLOT (setFocus())); + connect (toolbar, SIGNAL (focusSceneRequest()), mScene, SLOT (setFocus())); } void CSVWorld::PreviewSubView::setEditLock (bool locked) {} diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 60988e1bb0..dc1525b05e 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -239,6 +239,7 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mToolbar = toolbar; connect (mScene, SIGNAL (focusToolbarRequest()), mToolbar, SLOT (setFocus())); + connect (mToolbar, SIGNAL (focusSceneRequest()), mScene, SLOT (setFocus())); mLayout->addWidget (mToolbar, 0); mLayout->addWidget (mScene, 1); From 0430558c3cac7b1805d017e6c466aca5db98aab9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 14 Jul 2014 14:17:27 +0200 Subject: [PATCH 61/67] fixed focussed button in mode tool panel when panel is opened --- apps/opencs/view/widget/scenetoolmode.cpp | 7 ++++--- apps/opencs/view/widget/scenetoolmode.hpp | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 9a97924a8b..caedfa3ee8 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -21,7 +21,7 @@ void CSVWidget::SceneToolMode::adjustToolTip (const PushButton *activeMode) CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent, const QString& toolTip) : SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()), - mToolTip (toolTip) + mToolTip (toolTip), mFirst (0) { mPanel = new QFrame (this, Qt::Popup); @@ -37,8 +37,8 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) mPanel->move (position); mPanel->show(); - if (!mButtons.empty()) - mButtons.begin()->first->setFocus (Qt::OtherFocusReason); + if (mFirst) + mFirst->setFocus (Qt::OtherFocusReason); } void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id, @@ -58,6 +58,7 @@ void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::st if (mButtons.size()==1) { + mFirst = button; setIcon (button->icon()); button->setChecked (true); adjustToolTip (button); diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 92f031fe7e..9959f98355 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -23,6 +23,7 @@ namespace CSVWidget int mButtonSize; int mIconSize; QString mToolTip; + PushButton *mFirst; void adjustToolTip (const PushButton *activeMode); From 1a1f5dfc4a1ada1ebc842075129b7bef8f169c51 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Jul 2014 12:46:52 +0200 Subject: [PATCH 62/67] added tooltips to dialgoue subview buttons --- apps/opencs/view/world/dialoguesubview.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index ad2db87231..bcf108934f 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -426,25 +426,32 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM QHBoxLayout *buttonsLayout = new QHBoxLayout; QToolButton* prevButton = new QToolButton(mainWidget); prevButton->setIcon(QIcon(":/go-previous.png")); + prevButton->setToolTip ("Switch to previous record"); QToolButton* nextButton = new QToolButton(mainWidget); nextButton->setIcon(QIcon(":/go-next.png")); + nextButton->setToolTip ("Switch to next record"); buttonsLayout->addWidget(prevButton, 0); buttonsLayout->addWidget(nextButton, 1); buttonsLayout->addStretch(2); QToolButton* cloneButton = new QToolButton(mainWidget); cloneButton->setIcon(QIcon(":/edit-clone.png")); + cloneButton->setToolTip ("Clone record"); QToolButton* addButton = new QToolButton(mainWidget); addButton->setIcon(QIcon(":/add.png")); + addButton->setToolTip ("Add new record"); QToolButton* deleteButton = new QToolButton(mainWidget); deleteButton->setIcon(QIcon(":/edit-delete.png")); + deleteButton->setToolTip ("Delete record"); QToolButton* revertButton = new QToolButton(mainWidget); revertButton->setIcon(QIcon(":/edit-undo.png")); + revertButton->setToolTip ("Revert record"); if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview) { QToolButton* previewButton = new QToolButton(mainWidget); previewButton->setIcon(QIcon(":/edit-preview.png")); + previewButton->setToolTip ("Open a preview of this record"); buttonsLayout->addWidget(previewButton); connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview())); } @@ -453,6 +460,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM { QToolButton* viewButton = new QToolButton(mainWidget); viewButton->setIcon(QIcon(":/cell.png")); + viewButton->setToolTip ("Open a scene view of the cell this record is located in"); buttonsLayout->addWidget(viewButton); connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord())); } From d5381e1bc44f85f4be7bba8aca0c982ef34429ff Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 19 Jul 2014 14:04:38 +0200 Subject: [PATCH 63/67] Dynamically resize skill widgets to fit their contents (Fixes #1610) --- apps/openmw/mwgui/statswindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 6c4e00ae5c..b11258f1cd 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -321,6 +321,11 @@ namespace MWGui skillValueWidget->_setWidgetState(state); skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + // resize dynamically according to text size + int textWidthPlusMargin = skillValueWidget->getTextSize().width + 12; + skillValueWidget->setCoord(coord2.left + coord2.width - textWidthPlusMargin, coord2.top, textWidthPlusMargin, coord2.height); + skillNameWidget->setSize(skillNameWidget->getSize() + MyGUI::IntSize(coord2.width - textWidthPlusMargin, 0)); + mSkillWidgets.push_back(skillNameWidget); mSkillWidgets.push_back(skillValueWidget); From 0f2305ae43fc4bd0d3cbc411f659409561d4be60 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 20 Jul 2014 13:07:47 +0200 Subject: [PATCH 64/67] Clear selected spell when window manager is cleared --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 865ad1dca9..668211db29 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1529,6 +1529,8 @@ namespace MWGui mCompanionWindow->resetReference(); mConsole->resetReference(); + mSelectedSpell.clear(); + mGuiModes.clear(); MWBase::Environment::get().getInputManager()->changeInputMode(false); updateVisible(); From 3b67e9b329e0fd1e4a6e6c00a54033007504dd6e Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 21 Jul 2014 20:56:02 +0200 Subject: [PATCH 65/67] Rework level up dialog to behave more like vanilla --- apps/openmw/mwgui/levelupdialog.cpp | 103 ++++++++++++++--------- apps/openmw/mwgui/levelupdialog.hpp | 7 +- files/mygui/openmw_levelup_dialog.layout | 2 +- 3 files changed, 69 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index eaa8227225..bf6181d76c 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -16,9 +16,10 @@ namespace MWGui { - + const unsigned int LevelupDialog::sMaxCoins = 3; LevelupDialog::LevelupDialog() - : WindowBase("openmw_levelup_dialog.layout") + : WindowBase("openmw_levelup_dialog.layout"), + mCoinCount(sMaxCoins) { getWidget(mOkButton, "OkButton"); getWidget(mClassImage, "ClassImage"); @@ -46,12 +47,10 @@ namespace MWGui mAttributeMultipliers.push_back(t); } - int curX = mMainWidget->getWidth()/2 - (16 + 2) * 1.5; - for (int i=0; i<3; ++i) + for (unsigned int i = 0; i < mCoinCount; ++i) { - MyGUI::ImageBox* image = mMainWidget->createWidget("ImageBox", MyGUI::IntCoord(curX,250,16,16), MyGUI::Align::Default); + MyGUI::ImageBox* image = mCoinBox->createWidget("ImageBox", MyGUI::IntCoord(0,0,16,16), MyGUI::Align::Default); image->setImageTexture ("icons\\tx_goldicon.dds"); - curX += 24+2; mCoins.push_back(image); } @@ -61,15 +60,15 @@ namespace MWGui void LevelupDialog::setAttributeValues() { MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats (player); + MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player); - for (int i=0; i<8; ++i) + for (int i = 0; i < 8; ++i) { - int val = creatureStats.getAttribute (i).getBase (); + int val = creatureStats.getAttribute(i).getBase(); if (std::find(mSpentAttributes.begin(), mSpentAttributes.end(), i) != mSpentAttributes.end()) { - val += pcStats.getLevelupAttributeMultiplier (i); + val += pcStats.getLevelupAttributeMultiplier(i); } if (val >= 100) @@ -80,20 +79,21 @@ namespace MWGui } - void LevelupDialog::resetCoins () + void LevelupDialog::resetCoins() { - int curX = 0; - for (int i=0; i<3; ++i) + const int coinSpacing = 10; + int curX = mCoinBox->getWidth()/2 - (coinSpacing*(mCoinCount - 1) + 16*mCoinCount)/2; + for (unsigned int i=0; idetachFromWidget(); image->attachToWidget(mCoinBox); image->setCoord(MyGUI::IntCoord(curX,0,16,16)); - curX += 24+2; + curX += 16+coinSpacing; } } - void LevelupDialog::assignCoins () + void LevelupDialog::assignCoins() { resetCoins(); for (unsigned int i=0; igetPlayerPtr(); - MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats (player); - MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player); - - mSpentAttributes.clear(); - resetCoins(); - - setAttributeValues(); + MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats(player); + MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player); const ESM::NPC *playerData = player.get()->mBase; @@ -144,70 +139,98 @@ namespace MWGui if(it->mData.mIsPlayable && it->mData.mSpecialization == 2 && it->mData.mAttribute[0] == 4 && it->mData.mAttribute[1] == 3) break; } - mClassImage->setImageTexture ("textures\\levelup\\" + it->mId + ".dds"); + mClassImage->setImageTexture("textures\\levelup\\" + it->mId + ".dds"); } else - mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds"); + mClassImage->setImageTexture("textures\\levelup\\" + cls->mId + ".dds"); int level = creatureStats.getLevel ()+1; mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast(level)); std::string levelupdescription; - if(level>20) + if(level > 20) levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); else levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+boost::lexical_cast(level)); mLevelDescription->setCaption (levelupdescription); - for (int i=0; i<8; ++i) + unsigned int availableAttributes = 0; + for (int i = 0; i < 8; ++i) { MyGUI::TextBox* text = mAttributeMultipliers[i]; - int mult = pcStats.getLevelupAttributeMultiplier (i); - text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast(mult)); + if (pcStats.getAttribute(i).getBase() < 100) + { + mAttributes[i]->setEnabled(true); + availableAttributes++; + + int mult = pcStats.getLevelupAttributeMultiplier (i); + text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast(mult)); + } + else + { + mAttributes[i]->setEnabled(false); + + text->setCaption(""); + } } + mCoinCount = std::min(sMaxCoins, availableAttributes); + + for (unsigned int i = 0; i < sMaxCoins; i++) + { + if (i < mCoinCount) + mCoins[i]->attachToWidget(mCoinBox); + else + mCoins[i]->detachFromWidget(); + } + + mSpentAttributes.clear(); + resetCoins(); + + setAttributeValues(); + center(); } - void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender) + void LevelupDialog::onOkButtonClicked(MyGUI::Widget* sender) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player); - if (mSpentAttributes.size() < 3) - MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage36}"); + if (mSpentAttributes.size() < mCoinCount) + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage36}"); else { // increase attributes - for (int i=0; i<3; ++i) + for (unsigned int i = 0; i < mCoinCount; ++i) { MWMechanics::AttributeValue attribute = pcStats.getAttribute(mSpentAttributes[i]); - attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i])); + attribute.setBase(attribute.getBase() + pcStats.getLevelupAttributeMultiplier(mSpentAttributes[i])); if (attribute.getBase() >= 100) attribute.setBase(100); pcStats.setAttribute(mSpentAttributes[i], attribute); } - pcStats.levelUp (); + pcStats.levelUp(); - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Levelup); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Levelup); } } - void LevelupDialog::onAttributeClicked (MyGUI::Widget *sender) + void LevelupDialog::onAttributeClicked(MyGUI::Widget *sender) { int attribute = *sender->getUserData(); std::vector::iterator found = std::find(mSpentAttributes.begin(), mSpentAttributes.end(), attribute); if (found != mSpentAttributes.end()) - mSpentAttributes.erase (found); + mSpentAttributes.erase(found); else { - if (mSpentAttributes.size() == 3) - mSpentAttributes[2] = attribute; + if (mSpentAttributes.size() == mCoinCount) + mSpentAttributes[mCoinCount - 1] = attribute; else mSpentAttributes.push_back(attribute); } diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index 69afbf0897..5ca9c8c758 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -28,8 +28,11 @@ namespace MWGui std::vector mSpentAttributes; - void onOkButtonClicked (MyGUI::Widget* sender); - void onAttributeClicked (MyGUI::Widget* sender); + unsigned int mCoinCount; + static const unsigned int sMaxCoins; + + void onOkButtonClicked(MyGUI::Widget* sender); + void onAttributeClicked(MyGUI::Widget* sender); void assignCoins(); void resetCoins(); diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 0b12d7a052..07e1e560b5 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -23,7 +23,7 @@ - + From 171c61022d432508e39616d413fd5a677f8c6eff Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Mon, 21 Jul 2014 21:16:30 +0200 Subject: [PATCH 66/67] Added initialization of weapRange in AiCombat::execute(). Signed-off-by: Lukasz Gromanowski --- apps/openmw/mwmechanics/aicombat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2606daa88e..c0a97a1b1f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -265,7 +265,7 @@ namespace MWMechanics const ESM::Weapon *weapon = NULL; MWMechanics::WeaponType weaptype; - float weapRange; + float weapRange = 1.0f; actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); @@ -300,7 +300,7 @@ namespace MWMechanics else //is creature { weaptype = WeapType_HandToHand; //doesn't matter, should only reflect if it is melee or distant weapon - weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit) + weapRange = 150.0f; //TODO: use true attack range (the same problem in Creature::hit) } float rangeAttack; From e24173f94acf12f6e48d1eb8f09a983d36b59303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=9Aciubid=C5=82o?= Date: Mon, 21 Jul 2014 23:56:38 +0100 Subject: [PATCH 67/67] Fix bug 1482: - put powers on cooldown only when they are used succedsfully --- apps/openmw/mwworld/worldimp.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3868348820..93316f8765 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2316,15 +2316,10 @@ namespace MWWorld } // If this is a power, check if it was already used in the last 24h - if (!fail && spell->mData.mType == ESM::Spell::ST_Power) + if (!fail && spell->mData.mType == ESM::Spell::ST_Power && !stats.getSpells().canUsePower(spell->mId)) { - if (stats.getSpells().canUsePower(spell->mId)) - stats.getSpells().usePower(spell->mId); - else - { - message = "#{sPowerAlreadyUsed}"; - fail = true; - } + message = "#{sPowerAlreadyUsed}"; + fail = true; } // Reduce mana @@ -2357,6 +2352,10 @@ namespace MWWorld if (!selectedSpell.empty()) { const ESM::Spell* spell = getStore().get().search(selectedSpell); + + // A power can be used once per 24h + if (spell->mData.mType == ESM::Spell::ST_Power) + stats.getSpells().usePower(spell->mId); cast.cast(spell); }