From 5d14a2afcce241fe9b1677aa48e2b1b4a07a274f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 24 Aug 2017 17:12:15 -0400 Subject: [PATCH 001/150] Initial LTEX/LAND tables --- apps/opencs/model/prefs/state.cpp | 2 + apps/opencs/model/world/columnimp.hpp | 64 ++++++++++++++++++++++--- apps/opencs/model/world/columns.cpp | 4 +- apps/opencs/model/world/columns.hpp | 3 ++ apps/opencs/model/world/data.cpp | 14 ++++++ apps/opencs/model/world/universalid.cpp | 8 +++- apps/opencs/model/world/universalid.hpp | 4 ++ apps/opencs/view/doc/view.cpp | 20 ++++++++ apps/opencs/view/doc/view.hpp | 4 ++ apps/opencs/view/world/subviews.cpp | 2 + 10 files changed, 116 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 5c0b2e282..0101a432b 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -240,6 +240,8 @@ void CSMPrefs::State::declare() declareShortcut ("document-world-cells", "Open Cell List", QKeySequence()); declareShortcut ("document-world-referencables", "Open Object List", QKeySequence()); declareShortcut ("document-world-references", "Open Instance List", QKeySequence()); + declareShortcut ("document-world-lands", "Open Lands List", QKeySequence()); + declareShortcut ("document-world-landtextures", "Open Land Textures List", QKeySequence()); declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence()); declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence()); declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence()); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 154bdab82..a9a48ef0d 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -15,6 +15,9 @@ #include "columns.hpp" #include "info.hpp" +#include "land.hpp" +#include "landtexture.hpp" + namespace CSMWorld { /// \note Shares ID with VarValueColumn. A table can not have both. @@ -1499,9 +1502,9 @@ namespace CSMWorld template struct TopicColumn : public Column { - TopicColumn (bool journal) + TopicColumn (bool journal) : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, - journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) + journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) {} virtual QVariant get (const Record& record) const @@ -1755,7 +1758,7 @@ namespace CSMWorld return true; } }; - + template struct GenderNpcColumn : public Column { @@ -2198,8 +2201,8 @@ namespace CSMWorld struct EffectTextureColumn : public Column { EffectTextureColumn (Columns::ColumnId columnId) - : Column (columnId, - columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture + : Column (columnId, + columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture : ColumnBase::Display_Icon) { assert (this->mColumnId==Columns::ColumnId_Icon || @@ -2417,7 +2420,56 @@ namespace CSMWorld return true; } }; - + + template + struct TextureIndexColumn : public Column + { + TextureIndexColumn() + : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + {} + + QVariant get (const Record& record) const + { + return record.get().mIndex; + } + + virtual bool isEditable() const + { + return false; + } + }; + + // TODO remove + template + struct PluginIndexColumn : public Column + { + PluginIndexColumn() + : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) + {} + + QVariant get (const Record& record) const + { + return -1; + } + + virtual bool isEditable() const + { + return false; + } + }; + + template<> + inline QVariant PluginIndexColumn::get (const Record& record) const + { + return record.get().mPlugin; + } + + template<> + inline QVariant PluginIndexColumn::get (const Record& record) const + { + return record.get().mPluginIndex; + } + struct BodyPartRaceColumn : public RaceColumn { const MeshTypeColumn *mMeshType; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index aeee0d208..cec11211c 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -124,7 +124,7 @@ namespace CSMWorld { ColumnId_Portable, "Portable" }, { ColumnId_NegativeLight, "Negative Light" }, { ColumnId_EmitterType, "Emitter Type" }, - + { ColumnId_Fire, "Fire" }, { ColumnId_OffByDefault, "Off by default" }, { ColumnId_IsKey, "Is Key" }, @@ -330,6 +330,8 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, + { ColumnId_PluginIndex, "Plugin Index" }, + { ColumnId_TextureIndex, "Texture Index" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b23d86367..1ff871c84 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,6 +329,9 @@ namespace CSMWorld ColumnId_Text = 297, + ColumnId_PluginIndex = 298, + ColumnId_TextureIndex = 299, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 007190e4a..456d2bccc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -412,6 +412,18 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat Columns::ColumnId_NegativeLight, ESM::MagicEffect::NegativeLight)); mMagicEffects.addColumn (new DescriptionColumn); + mLand.addColumn (new StringIdColumn); + mLand.addColumn (new RecordStateColumn); + mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); + mLand.addColumn (new PluginIndexColumn); + + mLandTextures.addColumn (new StringIdColumn); + mLandTextures.addColumn (new RecordStateColumn); + mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); + mLandTextures.addColumn (new PluginIndexColumn); + mLandTextures.addColumn (new TextureIndexColumn); + mLandTextures.addColumn (new TextureColumn); + mPathgrids.addColumn (new StringIdColumn); mPathgrids.addColumn (new RecordStateColumn); mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); @@ -531,6 +543,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); + addModel (new IdTable (&mLand), UniversalId::Type_Land); + addModel (new IdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 77db2be10..38386f6da 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -53,6 +53,8 @@ namespace { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_LandTextures, "LandTextures", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 }, @@ -118,6 +120,8 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 }, @@ -364,8 +368,8 @@ std::vector CSMWorld::UniversalId::listTypes (int c for (int i=0; sIndexArg[i].mName; ++i) if (sIndexArg[i].mClass & classes) list.push_back (sIndexArg[i].mType); - - return list; + + return list; } CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type) diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index e9104fc22..accd1b78d 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -126,6 +126,10 @@ namespace CSMWorld Type_SoundGen, Type_MagicEffects, Type_MagicEffect, + Type_Lands, + Type_Land, + Type_LandTextures, + Type_LandTexture, Type_Pathgrids, Type_Pathgrid, Type_StartScripts, diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index dfbeea031..10de46e06 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -172,6 +172,16 @@ void CSVDoc::View::setupWorldMenu() setupShortcut("document-world-references", references); world->addAction (references); + QAction *lands = new QAction (tr ("Lands"), this); + connect (lands, SIGNAL (triggered()), this, SLOT (addLandsSubView())); + setupShortcut("document-world-lands", lands); + world->addAction (lands); + + QAction *landTextures = new QAction (tr ("Land Textures"), this); + connect (landTextures, SIGNAL (triggered()), this, SLOT (addLandTexturesSubView())); + setupShortcut("document-world-landtextures", landTextures); + world->addAction (landTextures); + QAction *grid = new QAction (tr ("Pathgrid"), this); connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView())); setupShortcut("document-world-pathgrid", grid); @@ -876,6 +886,16 @@ void CSVDoc::View::addRunLogSubView() addSubView (CSMWorld::UniversalId::Type_RunLog); } +void CSVDoc::View::addLandsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Lands); +} + +void CSVDoc::View::addLandTexturesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_LandTextures); +} + void CSVDoc::View::addPathgridSubView() { addSubView (CSMWorld::UniversalId::Type_Pathgrids); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 834407be0..46aa87891 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -224,6 +224,10 @@ namespace CSVDoc void addRunLogSubView(); + void addLandsSubView(); + + void addLandTexturesSubView(); + void addPathgridSubView(); void addStartScriptsSubView(); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 7c27bdf7a..b570397b7 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -43,6 +43,8 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Enchantments, CSMWorld::UniversalId::Type_SoundGens, + CSMWorld::UniversalId::Type_Lands, + CSMWorld::UniversalId::Type_LandTextures, CSMWorld::UniversalId::Type_None // end marker }; From 9e41f1340ae3b7bd9ee3a598b11d7fb479bc36e5 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 25 Aug 2017 19:51:30 -0400 Subject: [PATCH 002/150] Replace nonconst getId with setId, add template specialization and specialized derived classes for LandTexture --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 31 +++-- apps/opencs/model/world/columnimp.hpp | 43 ++++++- apps/opencs/model/world/columns.cpp | 1 + apps/opencs/model/world/columns.hpp | 5 +- apps/opencs/model/world/data.cpp | 5 +- apps/opencs/model/world/idtable.cpp | 31 +++++ apps/opencs/model/world/idtable.hpp | 15 +++ apps/opencs/model/world/landtexture.cpp | 17 +++ apps/opencs/model/world/landtexture.hpp | 5 + apps/opencs/view/world/landtexturecreator.cpp | 106 ++++++++++++++++++ apps/opencs/view/world/landtexturecreator.hpp | 49 ++++++++ apps/opencs/view/world/subviews.cpp | 15 ++- components/esm/loadltex.cpp | 2 +- components/esm/loadltex.hpp | 3 +- 15 files changed, 308 insertions(+), 22 deletions(-) create mode 100644 apps/opencs/view/world/landtexturecreator.cpp create mode 100644 apps/opencs/view/world/landtexturecreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0a146dc06..4207258db 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator - bodypartcreator + bodypartcreator landtexturecreator ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 16f5ce51f..9d867ff93 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -13,8 +14,8 @@ #include #include "columnbase.hpp" - #include "collectionbase.hpp" +#include "landtexture.hpp" namespace CSMWorld { @@ -22,15 +23,14 @@ namespace CSMWorld template struct IdAccessor { - std::string& getId (ESXRecordT& record); - + void setId(ESXRecordT& record, const std::string& id) const; const std::string getId (const ESXRecordT& record) const; }; template - std::string& IdAccessor::getId (ESXRecordT& record) + void IdAccessor::setId(ESXRecordT& record, const std::string& id) const { - return record.mId; + record.mId = id; } template @@ -39,6 +39,23 @@ namespace CSMWorld return record.mId; } + template<> + inline void IdAccessor::setId (LandTexture& record, const std::string& id) const + { + int plugin = 0; + int index = 0; + + LandTexture::parseUniqueRecordId(id, plugin, index); + record.mPluginIndex = plugin; + record.mIndex = index; + } + + template<> + inline const std::string IdAccessor::getId (const LandTexture& record) const + { + return LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex); + } + /// \brief Single-type record collection template > class Collection : public CollectionBase @@ -213,7 +230,7 @@ namespace CSMWorld Record copy; copy.mModified = getRecord(origin).get(); copy.mState = RecordBase::State_ModifiedOnly; - copy.get().mId = destination; + IdAccessorT().setId(copy.get(), destination); insertRecord(copy, getAppendIndex(destination, type)); } @@ -366,7 +383,7 @@ namespace CSMWorld UniversalId::Type type) { ESXRecordT record; - IdAccessorT().getId (record) = id; + IdAccessorT().setId(record, id); record.blank(); Record record2; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index a9a48ef0d..316fa4366 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -63,6 +63,13 @@ namespace CSMWorld } }; + template<> + inline QVariant StringIdColumn::get(const Record& record) const + { + const LandTexture& ltex = record.get(); + return QString::fromUtf8(std::string('L' + std::to_string(ltex.mPluginIndex) + '#' + std::to_string(ltex.mIndex)).c_str()); + } + template struct RecordStateColumn : public Column { @@ -2421,6 +2428,31 @@ namespace CSMWorld } }; + template + struct TextureHandleColumn : public Column + { + TextureHandleColumn() + : Column (Columns::ColumnId_TextureHandle, ColumnBase::Display_String) + {} + + QVariant get(const Record& record) const override + { + return QString::fromUtf8(record.get().mId.c_str()); + } + + void set(Record& record, const QVariant& data) override + { + ESXRecordT copy = record.get(); + copy.mId = data.toString().toUtf8().constData(); + record.setModified(copy); + } + + bool isEditable() const override + { + return true; + } + }; + template struct TextureIndexColumn : public Column { @@ -2428,31 +2460,30 @@ namespace CSMWorld : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) {} - QVariant get (const Record& record) const + QVariant get(const Record& record) const override { return record.get().mIndex; } - virtual bool isEditable() const + bool isEditable() const override { return false; } }; - // TODO remove template struct PluginIndexColumn : public Column { PluginIndexColumn() - : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) + : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0) {} - QVariant get (const Record& record) const + QVariant get(const Record& record) const override { return -1; } - virtual bool isEditable() const + virtual bool isEditable() const override { return false; } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index cec11211c..49935d40d 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -330,6 +330,7 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, + { ColumnId_TextureHandle, "Texture Handle" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1ff871c84..c6e2a2a41 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,8 +329,9 @@ namespace CSMWorld ColumnId_Text = 297, - ColumnId_PluginIndex = 298, - ColumnId_TextureIndex = 299, + ColumnId_TextureHandle = 298, + ColumnId_PluginIndex = 299, + ColumnId_TextureIndex = 300, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 456d2bccc..b0ab73de1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -417,9 +417,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); mLand.addColumn (new PluginIndexColumn); - mLandTextures.addColumn (new StringIdColumn); + mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); + mLandTextures.addColumn (new TextureHandleColumn); mLandTextures.addColumn (new PluginIndexColumn); mLandTextures.addColumn (new TextureIndexColumn); mLandTextures.addColumn (new TextureColumn); @@ -544,7 +545,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mLand), UniversalId::Type_Land); - addModel (new IdTable (&mLandTextures), UniversalId::Type_LandTexture); + addModel (new LandTextureIdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 7975e05ea..078484aab 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -281,3 +281,34 @@ CSMWorld::CollectionBase *CSMWorld::IdTable::idCollection() const { return mIdCollection; } + +CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, unsigned int features) + : IdTable(idCollection, features) +{ +} + +QVariant CSMWorld::LandTextureIdTable::data(const QModelIndex& index, int role) const +{ + if (role==Qt::EditRole && !idCollection()->getRecord(index.row()).isModified()) + return QVariant(); + + return IdTable::data(index, role); +} + +bool CSMWorld::LandTextureIdTable::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if (!idCollection()->getRecord(index.row()).isModified()) + return false; + else + return IdTable::setData(index, value, role); +} + +Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = IdTable::flags(index); + + if (!idCollection()->getRecord(index.row()).isModified()) + flags &= ~Qt::ItemIsEditable; + + return flags; +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 9faf64d71..ecca269d3 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -93,6 +93,21 @@ namespace CSMWorld virtual CollectionBase *idCollection() const; }; + + /// An IdTable customized to handle the more unique needs of LandTextureId's which behave + /// differently from other records. + class LandTextureIdTable : public IdTable + { + public: + + LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); + + QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; + + bool setData(const QModelIndex& index, const QVariant& value, int role) override; + + Qt::ItemFlags flags (const QModelIndex & index) const override; + }; } #endif diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 266377d0f..4b82f8d73 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,5 +1,7 @@ #include "landtexture.hpp" +#include + #include namespace CSMWorld @@ -11,4 +13,19 @@ namespace CSMWorld mPluginIndex = esm.getIndex(); } + std::string LandTexture::createUniqueRecordId(int plugin, int index) + { + return 'L' + std::to_string(plugin) + '#' + std::to_string(index); + } + + void LandTexture::parseUniqueRecordId(const std::string& id, int& plugin, int& index) + { + size_t middle = id.find('#'); + + if (middle == std::string::npos || id[0] != 'L') + throw std::runtime_error("Invalid LandTexture ID"); + + plugin = std::stoi(id.substr(1,middle-1)); + index = std::stoi(id.substr(middle+1)); + } } diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp index 91459eee2..a7376438c 100644 --- a/apps/opencs/model/world/landtexture.hpp +++ b/apps/opencs/model/world/landtexture.hpp @@ -13,6 +13,11 @@ namespace CSMWorld int mPluginIndex; void load (ESM::ESMReader &esm, bool &isDeleted); + + /// Returns a string identifier that will be unique to any LandTexture. + static std::string createUniqueRecordId(int plugin, int index); + /// Deconstructs a unique string identifier into plugin and index. + static void parseUniqueRecordId(const std::string& id, int& plugin, int& index); }; } diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp new file mode 100644 index 000000000..f79c08427 --- /dev/null +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -0,0 +1,106 @@ +#include "landtexturecreator.hpp" + +#include +#include + +#include +#include +#include + +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/landtexture.hpp" + +namespace CSVWorld +{ + LandTextureCreator::LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) + : GenericCreator(data, undoStack, id) + { + // One index is reserved for a default texture + const size_t MaxIndex = std::numeric_limits::max() - 1; + + setManualEditing(false); + + QLabel* nameLabel = new QLabel("Name"); + insertBeforeButtons(nameLabel, false); + + mNameEdit = new QLineEdit(this); + insertBeforeButtons(mNameEdit, true); + + QLabel* indexLabel = new QLabel("Index"); + insertBeforeButtons(indexLabel, false); + + QIntValidator* indexValidator = new QIntValidator(0, MaxIndex, this); + + mIndexEdit = new QLineEdit(this); + mIndexEdit->setValidator(indexValidator); + insertBeforeButtons(mIndexEdit, true); + + connect(mNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&))); + connect(mIndexEdit, SIGNAL(textChanged(const QString&)), this, SLOT(indexChanged(const QString&))); + } + + void LandTextureCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) + { + GenericCreator::cloneMode(originId, type); + + CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); + + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + + column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); + mIndexEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + } + + void LandTextureCreator::focus() + { + mIndexEdit->setFocus(); + } + + void LandTextureCreator::reset() + { + GenericCreator::reset(); + mNameEdit->setText(""); + mIndexEdit->setText(""); + } + + std::string LandTextureCreator::getErrors() const + { + std::string id = getId(); + + // TODO empty index edit? + if (getData().getLandTextures().searchId(getId()) >= 0) + { + return "Index is already in use"; + } + + return ""; + } + + void LandTextureCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const + { + GenericCreator::configureCreateCommand(command); + + CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + command.addValue(column, mName.c_str()); + } + + std::string LandTextureCreator::getId() const + { + return CSMWorld::LandTexture::createUniqueRecordId(0, mIndex); + } + + void LandTextureCreator::nameChanged(const QString& value) + { + mName = value.toUtf8().constData(); + update(); + } + + void LandTextureCreator::indexChanged(const QString& value) + { + mIndex = value.toInt(); + update(); + } +} diff --git a/apps/opencs/view/world/landtexturecreator.hpp b/apps/opencs/view/world/landtexturecreator.hpp new file mode 100644 index 000000000..46388bf03 --- /dev/null +++ b/apps/opencs/view/world/landtexturecreator.hpp @@ -0,0 +1,49 @@ +#ifndef CSV_WORLD_LANDTEXTURECREATOR_H +#define CSV_WORLD_LANDTEXTURECREATOR_H + +#include + +#include "genericcreator.hpp" + +class QLineEdit; + +namespace CSVWorld +{ + class LandTextureCreator : public GenericCreator + { + Q_OBJECT + + public: + + LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); + + void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + + void focus() override; + + void reset() override; + + std::string getErrors() const override; + + protected: + + void configureCreateCommand(CSMWorld::CreateCommand& command) const override; + + std::string getId() const override; + + private slots: + + void nameChanged(const QString& val); + void indexChanged(const QString& val); + + private: + + QLineEdit* mNameEdit; + QLineEdit* mIndexEdit; + + std::string mName; + int mIndex; + }; +} + +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index b570397b7..a33802823 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -18,6 +18,7 @@ #include "pathgridcreator.hpp" #include "previewsubview.hpp" #include "bodypartcreator.hpp" +#include "landtexturecreator.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -43,8 +44,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Enchantments, CSMWorld::UniversalId::Type_SoundGens, - CSMWorld::UniversalId::Type_Lands, - CSMWorld::UniversalId::Type_LandTextures, CSMWorld::UniversalId::Type_None // end marker }; @@ -83,6 +82,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Pathgrids, new CSVDoc::SubViewFactoryWithCreator); + manager.add (CSMWorld::UniversalId::Type_Lands, + new CSVDoc::SubViewFactoryWithCreator >); + + manager.add (CSMWorld::UniversalId::Type_LandTextures, + new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreator >); @@ -183,6 +188,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Pathgrid, new CSVDoc::SubViewFactoryWithCreator (false)); + manager.add (CSMWorld::UniversalId::Type_Land, + new CSVDoc::SubViewFactoryWithCreator >(false)); + + manager.add (CSMWorld::UniversalId::Type_LandTexture, + new CSVDoc::SubViewFactoryWithCreator >(false)); + manager.add (CSMWorld::UniversalId::Type_DebugProfile, new CSVDoc::SubViewFactoryWithCreator > (false)); diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 613b706e3..3e150f9c0 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -59,7 +59,7 @@ namespace ESM void LandTexture::blank() { + mId.clear(); mTexture.clear(); - mIndex = -1; } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 2cb5abf0c..1604e9281 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -31,14 +31,15 @@ struct LandTexture /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string getRecordType() { return "LandTexture"; } + // mId is merely a user friendly name for the texture in the editor. std::string mId, mTexture; int mIndex; void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; + /// Sets the record to the default state. Does not touch the index. Does touch mID. void blank(); - ///< Set record to default state (does not touch the ID). }; } #endif From 1d480015b46f78f747642d2d7b3b381b161119c9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 31 Aug 2017 22:01:38 -0400 Subject: [PATCH 003/150] Add ability to touch records, LAND records in particular --- apps/opencs/model/world/collection.hpp | 23 ++++++++++++ apps/opencs/model/world/collectionbase.hpp | 2 ++ apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/model/world/commands.cpp | 25 +++++++++++++ apps/opencs/model/world/commands.hpp | 19 ++++++++++ apps/opencs/model/world/data.cpp | 2 +- apps/opencs/model/world/idtable.cpp | 20 +++++++++++ apps/opencs/model/world/idtable.hpp | 5 +++ apps/opencs/model/world/idtablebase.hpp | 6 ++-- apps/opencs/model/world/refidcollection.cpp | 6 ++++ apps/opencs/model/world/refidcollection.hpp | 2 ++ apps/opencs/view/world/table.cpp | 40 +++++++++++++++++++-- apps/opencs/view/world/table.hpp | 3 ++ 13 files changed, 149 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 9d867ff93..f69d06d78 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -125,6 +125,10 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type); + virtual bool touchRecord(const std::string& id); + ///< Change the state of a record from base to modified, if it is not already. + /// \return True if the record was changed. + virtual int searchId (const std::string& id) const; ////< Search record with \a id. /// \return index of record (if found) or -1 (not found) @@ -235,6 +239,25 @@ namespace CSMWorld insertRecord(copy, getAppendIndex(destination, type)); } + template + bool Collection::touchRecord(const std::string& id) + { + int index = getIndex(id); + Record& record = mRecords.at(index); + if (record.isDeleted()) + { + throw std::runtime_error("attempt to touch deleted record"); + } + + if (!record.isModified() && !record.isDeleted() && !record.isErased()) + { + record.setModified(record.get()); + return true; + } + else + return false; + } + template Collection::Collection() {} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index ef826e31c..bac790c5d 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -78,6 +78,8 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type) = 0; + virtual bool touchRecord(const std::string& id) = 0; + virtual const RecordBase& getRecord (const std::string& id) const = 0; virtual const RecordBase& getRecord (int index) const = 0; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 316fa4366..92e899a45 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -67,7 +67,7 @@ namespace CSMWorld inline QVariant StringIdColumn::get(const Record& record) const { const LandTexture& ltex = record.get(); - return QString::fromUtf8(std::string('L' + std::to_string(ltex.mPluginIndex) + '#' + std::to_string(ltex.mIndex)).c_str()); + return QString(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); } template diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5f9422376..c6a56f7b8 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -15,6 +15,31 @@ #include "nestedtablewrapper.hpp" #include "pathgrid.hpp" +CSMWorld::TouchCommand::TouchCommand(IdTable& table, const std::string& id, QUndoCommand* parent) + : QUndoCommand(parent) + , mTable(table) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mTable.getRecord(mId).clone()); +} + +void CSMWorld::TouchCommand::redo() +{ + mChanged = mTable.touchRecord(mId); +} + +void CSMWorld::TouchCommand::undo() +{ + if (mChanged) + { + mTable.setRecord(mId, *mOld); + mChanged = false; + } +} + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index b54a1d5ac..4c9be7e8a 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -24,6 +25,24 @@ namespace CSMWorld struct RecordBase; struct NestedTableWrapperBase; + class TouchCommand : public QUndoCommand + { + public: + + TouchCommand(IdTable& model, const std::string& id, QUndoCommand* parent=nullptr); + + virtual void redo(); + virtual void undo(); + + private: + + IdTable& mTable; + std::string mId; + std::unique_ptr mOld; + + bool mChanged; + }; + class ModifyCommand : public QUndoCommand { QAbstractItemModel *mModel; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b0ab73de1..27a914aeb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -544,7 +544,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); - addModel (new IdTable (&mLand), UniversalId::Type_Land); + addModel (new IdTable (&mLand, IdTable::Feature_AllowTouch), UniversalId::Type_Land); addModel (new LandTextureIdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 078484aab..94eab3fc3 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -179,6 +179,26 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, endInsertRows(); } +bool CSMWorld::IdTable::touchRecord(const std::string& id) +{ + bool changed = mIdCollection->touchRecord(id); + + int row = mIdCollection->getIndex(id); + int column = mIdCollection->searchColumnIndex(Columns::ColumnId_RecordType); + if (changed && column != -1) + { + QModelIndex modelIndex = index(row, column); + emit dataChanged(modelIndex, modelIndex); + } + + return changed; +} + +std::string CSMWorld::IdTable::getId(int row) const +{ + return mIdCollection->getId(row); +} + ///This method can return only indexes to the top level table cells QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const { diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ecca269d3..5e5f9da4a 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -61,6 +61,11 @@ namespace CSMWorld const std::string& destination, UniversalId::Type type = UniversalId::Type_None); + bool touchRecord(const std::string& id); + ///< Will change the record state to modified, if it is not already. + + std::string getId(int row) const; + virtual QModelIndex getModelIndex (const std::string& id, int column) const; void setRecord (const std::string& id, const RecordBase& record, diff --git a/apps/opencs/model/world/idtablebase.hpp b/apps/opencs/model/world/idtablebase.hpp index 0d77d48ef..8b82f984b 100644 --- a/apps/opencs/model/world/idtablebase.hpp +++ b/apps/opencs/model/world/idtablebase.hpp @@ -32,7 +32,9 @@ namespace CSMWorld Feature_Preview = 8, /// Table can not be modified through ordinary means. - Feature_Constant = 16 + Feature_Constant = 16, + + Feature_AllowTouch = 32 }; private: @@ -61,7 +63,7 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const = 0; virtual int getColumnId (int column) const = 0; - + unsigned int getFeatures() const; }; } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 31dae256e..44a6ce07d 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -813,6 +813,12 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, mData.insertRecord(*newRecord, type, destination); } +bool CSMWorld::RefIdCollection::touchRecord(const std::string& id) +{ + throw std::runtime_error("RefIdCollection::touchRecord is unimplemented"); + return false; +} + void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record, UniversalId::Type type) { diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index de5a709c6..48558d1c2 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -80,6 +80,8 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type); + virtual bool touchRecord(const std::string& id); + virtual void appendBlankRecord (const std::string& id, UniversalId::Type type); ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 30dba4241..580d27a24 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -60,6 +60,9 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) menu.addAction(mCloneAction); } + if (mTouchAction) + menu.addAction (mTouchAction); + if (mCreateAction) menu.addAction (mCreateAction); @@ -226,8 +229,8 @@ void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event) CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool createAndDelete, bool sorting, CSMDoc::Document& document) -: DragRecordTable(document), mCreateAction (0), - mCloneAction(0), mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false) + : DragRecordTable(document), mCreateAction (nullptr), mCloneAction(nullptr), mTouchAction(nullptr), + mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false) { mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); @@ -302,6 +305,15 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, cloneShortcut->associateAction(mCloneAction); } + if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) + { + mTouchAction = new QAction(tr("Touch Record"), this); + connect(mTouchAction, SIGNAL(triggered()), this, SLOT(touchRecord())); + addAction(mTouchAction); + CSMPrefs::Shortcut* touchShortcut = new CSMPrefs::Shortcut("table-touch", this); + touchShortcut->associateAction(mTouchAction); + } + mRevertAction = new QAction (tr ("Revert Record"), this); connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert())); addAction (mRevertAction); @@ -442,6 +454,30 @@ void CSVWorld::Table::cloneRecord() } } +void CSVWorld::Table::touchRecord() +{ + if (!mEditLock && mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) + { + if (CSMWorld::IdTable* table = dynamic_cast(mModel)) + { + QUndoCommand* touchRecords = new QUndoCommand(); + touchRecords->setText("Touch records"); + + QModelIndexList selectedRows = selectionModel()->selectedRows(); + for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) + { + QModelIndex index = mProxyModel->mapToSource(mProxyModel->index(it->row(),0)); + std::string id = table->getId(index.row()); + + // command is a child of touchRecords + QUndoCommand* command = new CSMWorld::TouchCommand(*table, id, touchRecords); + } + + mDocument.getUndoStack().push(touchRecords); + } + } +} + void CSVWorld::Table::moveUpRecord() { if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 26f6e7899..d6fa17ef9 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -56,6 +56,7 @@ namespace CSVWorld QAction *mEditAction; QAction *mCreateAction; QAction *mCloneAction; + QAction *mTouchAction; QAction *mRevertAction; QAction *mDeleteAction; QAction *mMoveUpAction; @@ -129,6 +130,8 @@ namespace CSVWorld void cloneRecord(); + void touchRecord(); + void moveUpRecord(); void moveDownRecord(); From 30ba1d4c2599822730c5e6a204d383517c3206ed Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 3 Sep 2017 16:41:54 -0400 Subject: [PATCH 004/150] Move touch command to creator, to allow customization and not break abstraction --- apps/opencs/view/world/creator.hpp | 3 +++ apps/opencs/view/world/genericcreator.cpp | 17 +++++++++++++++++ apps/opencs/view/world/genericcreator.hpp | 2 ++ apps/opencs/view/world/table.cpp | 22 +++++++--------------- apps/opencs/view/world/table.hpp | 2 ++ apps/opencs/view/world/tablebottombox.cpp | 11 ++++++++--- apps/opencs/view/world/tablebottombox.hpp | 1 + apps/opencs/view/world/tablesubview.cpp | 3 +++ 8 files changed, 43 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 320bbf6ae..0020fd3c8 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -31,6 +31,9 @@ namespace CSVWorld virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) = 0; + /// Touches a record, if the creator supports it. + virtual void touch(const std::vector& ids) = 0; + virtual void setEditLock (bool locked) = 0; virtual void toggleWidgets(bool active = true) = 0; diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bf4c4967f..bde523a09 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -254,6 +254,23 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId, mClonedType = type; } +void CSVWorld::GenericCreator::touch(const std::vector& ids) +{ + // Combine multiple touch commands into one "macro" command + std::unique_ptr macro(new QUndoCommand()); + macro->setText("Touch records"); + + CSMWorld::IdTable& table = dynamic_cast(*mData.getTableModel(mListId)); + for (const CSMWorld::UniversalId& uid : ids) + { + // This is not leaked, touchCmd is a child of macro and managed by Qt + CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId(), macro.get()); + } + + // Execute + mUndoStack.push(macro.release()); +} + void CSVWorld::GenericCreator::toggleWidgets(bool active) { } diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 60d487bc1..d708c1047 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -103,6 +103,8 @@ namespace CSVWorld virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); + virtual void touch(const std::vector& ids); + virtual std::string getErrors() const; ///< Return formatted error descriptions for the current state of the creator. if an empty /// string is returned, there is no error. diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 580d27a24..3cccaaa22 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -458,23 +458,15 @@ void CSVWorld::Table::touchRecord() { if (!mEditLock && mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) { - if (CSMWorld::IdTable* table = dynamic_cast(mModel)) - { - QUndoCommand* touchRecords = new QUndoCommand(); - touchRecords->setText("Touch records"); - - QModelIndexList selectedRows = selectionModel()->selectedRows(); - for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) - { - QModelIndex index = mProxyModel->mapToSource(mProxyModel->index(it->row(),0)); - std::string id = table->getId(index.row()); - - // command is a child of touchRecords - QUndoCommand* command = new CSMWorld::TouchCommand(*table, id, touchRecords); - } + std::vector touchIds; - mDocument.getUndoStack().push(touchRecords); + QModelIndexList selectedRows = selectionModel()->selectedRows(); + for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) + { + touchIds.push_back(getUniversalId(it->row())); } + + emit touchRequest(touchIds); } } diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index d6fa17ef9..02f9023e7 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -116,6 +116,8 @@ namespace CSVWorld void cloneRequest(const CSMWorld::UniversalId&); + void touchRequest(const std::vector& ids); + void closeRequest(); void extendedDeleteConfigRequest(const std::vector &selectedIds); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 5a25bbc53..cfde5c694 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -72,9 +72,9 @@ void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandCo mExtendedConfigurator->setFocus(); } -CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, +CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent) : QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None), mHasPosition(false), mRow(0), mColumn(0) { @@ -249,6 +249,11 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mCreator->focus(); } +void CSVWorld::TableBottomBox::touchRequest(const std::vector& ids) +{ + mCreator->touch(ids); +} + void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector &selectedIds) { extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds); diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 781cccc9e..5402c466e 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -102,6 +102,7 @@ namespace CSVWorld void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); + void touchRequest(const std::vector&); void extendedDeleteConfigRequest(const std::vector &selectedIds); void extendedRevertConfigRequest(const std::vector &selectedIds); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 6664a3771..12e29995d 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -69,6 +69,9 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)), mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type))); + connect (mTable, SIGNAL(touchRequest(const std::vector&)), + mBottom, SLOT(touchRequest(const std::vector&))); + connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector &)), mBottom, SLOT(extendedDeleteConfigRequest(const std::vector &))); connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector &)), From 7cc95a11a47721cd9c3f70d6acf9b0d595f576ba Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 3 Sep 2017 20:00:19 -0400 Subject: [PATCH 005/150] Add more land table columns --- apps/opencs/model/world/columnimp.cpp | 234 ++++++++++++++++++++++++-- apps/opencs/model/world/columnimp.hpp | 45 +++++ apps/opencs/model/world/columns.hpp | 5 + apps/opencs/model/world/data.cpp | 5 + components/esm/loadland.hpp | 4 +- 5 files changed, 274 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index dc3d39edb..65d2fecd2 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,28 +1,226 @@ #include "columnimp.hpp" -CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) - : mMeshType(meshType) -{} - -QVariant CSMWorld::BodyPartRaceColumn::get(const Record &record) const +namespace CSMWorld { - if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + /* LandMapLodColumn */ + LandMapLodColumn::LandMapLodColumn() + : Column(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0) { - return QString::fromUtf8(record.get().mRace.c_str()); } - return QVariant(QVariant::UserType); -} -void CSMWorld::BodyPartRaceColumn::set(Record &record, const QVariant &data) -{ - ESM::BodyPart record2 = record.get(); + QVariant LandMapLodColumn::get(const Record& record) const + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&record.get().mWnam[0]); + return QByteArray(rawData, Land::LAND_GLOBAL_MAP_LOD_SIZE); + } + + void LandMapLodColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + QByteArray array = data.toByteArray(); + const signed char* rawData = reinterpret_cast(array.data()); - record2.mRace = data.toString().toUtf8().constData(); + assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); - record.setModified(record2); -} + for (int i = 0; i < array.count(); ++i) + { + copy.mWnam[i] = rawData[i]; + } -bool CSMWorld::BodyPartRaceColumn::isEditable() const -{ - return true; + record.setModified(copy); + } + + bool LandMapLodColumn::isEditable() const + { + return true; + } + + /* LandNormalsColumn */ + LandNormalsColumn::LandNormalsColumn() + : Column(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandNormalsColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is signed + const char* rawData = reinterpret_cast(&landData->mNormals[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + } + + void LandNormalsColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const signed char* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * 3); + + for (int i = 0; i < array.count(); ++i) + { + landData->mNormals[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandNormalsColumn::isEditable() const + { + return true; + } + + /* LandHeightsColumn */ + LandHeightsColumn::LandHeightsColumn() + : Column(Columns::ColumnId_LandHeightsIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandHeightsColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is float + const char* rawData = reinterpret_cast(&landData->mHeights[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * sizeof(float)); + } + + void LandHeightsColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const float* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + + for (int i = 0; i < array.count(); ++i) + { + landData->mHeights[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandHeightsColumn::isEditable() const + { + return true; + } + + /* LandColoursColumn */ + LandColoursColumn::LandColoursColumn() + : Column(Columns::ColumnId_LandColoursIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandColoursColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is unsigned char + const char* rawData = reinterpret_cast(&landData->mColours[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + } + + void LandColoursColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const unsigned char* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * 3); + + for (int i = 0; i < array.count(); ++i) + { + landData->mColours[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandColoursColumn::isEditable() const + { + return true; + } + + /* LandTexturesColumn */ + LandTexturesColumn::LandTexturesColumn() + : Column(Columns::ColumnId_LandTexturesIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandTexturesColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is uint16_t + const char* rawData = reinterpret_cast(&landData->mTextures[0]); + return QByteArray(rawData, Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + } + + void LandTexturesColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const uint16_t* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + + for (int i = 0; i < array.count(); ++i) + { + landData->mTextures[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandTexturesColumn::isEditable() const + { + return true; + } + + /* BodyPartRaceColumn */ + BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) + : mMeshType(meshType) + {} + + QVariant BodyPartRaceColumn::get(const Record &record) const + { + if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + { + return QString::fromUtf8(record.get().mRace.c_str()); + } + return QVariant(QVariant::UserType); + } + + void BodyPartRaceColumn::set(Record &record, const QVariant &data) + { + ESM::BodyPart record2 = record.get(); + + record2.mRace = data.toString().toUtf8().constData(); + + record.setModified(record2); + } + + bool BodyPartRaceColumn::isEditable() const + { + return true; + } } diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 92e899a45..f58a35bc4 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2501,6 +2501,51 @@ namespace CSMWorld return record.get().mPluginIndex; } + struct LandMapLodColumn : public Column + { + LandMapLodColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandNormalsColumn : public Column + { + LandNormalsColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandHeightsColumn : public Column + { + LandHeightsColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandColoursColumn : public Column + { + LandColoursColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandTexturesColumn : public Column + { + LandTexturesColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + struct BodyPartRaceColumn : public RaceColumn { const MeshTypeColumn *mMeshType; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index c6e2a2a41..432597105 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -332,6 +332,11 @@ namespace CSMWorld ColumnId_TextureHandle = 298, ColumnId_PluginIndex = 299, ColumnId_TextureIndex = 300, + ColumnId_LandMapLodIndex = 301, + ColumnId_LandNormalsIndex = 302, + ColumnId_LandHeightsIndex = 303, + ColumnId_LandColoursIndex = 304, + ColumnId_LandTexturesIndex = 305, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 27a914aeb..3284d9b05 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -416,6 +416,11 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new RecordStateColumn); mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); mLand.addColumn (new PluginIndexColumn); + mLand.addColumn (new LandMapLodColumn); + mLand.addColumn (new LandNormalsColumn); + mLand.addColumn (new LandHeightsColumn); + mLand.addColumn (new LandColoursColumn); + mLand.addColumn (new LandTexturesColumn); mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 9f33c37da..a7b97a465 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -64,6 +64,8 @@ struct Land //total number of textures per land static const int LAND_NUM_TEXTURES = LAND_TEXTURE_SIZE * LAND_TEXTURE_SIZE; + static const int LAND_GLOBAL_MAP_LOD_SIZE = 81; + #pragma pack(push,1) struct VHGT { @@ -109,7 +111,7 @@ struct Land }; // low-LOD heightmap (used for rendering the global map) - signed char mWnam[81]; + signed char mWnam[LAND_GLOBAL_MAP_LOD_SIZE]; void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; From 90c485104a8e13e9f1e876b40b7b1b539bf73c9f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 01:06:58 -0400 Subject: [PATCH 006/150] Land creator --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 86 ++++++++++++++++++++++---- apps/opencs/model/world/land.cpp | 20 +++++- apps/opencs/model/world/land.hpp | 3 + apps/opencs/view/world/landcreator.cpp | 79 +++++++++++++++++++++++ apps/opencs/view/world/landcreator.hpp | 42 +++++++++++++ apps/opencs/view/world/subviews.cpp | 5 +- 7 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 apps/opencs/view/world/landcreator.cpp create mode 100644 apps/opencs/view/world/landcreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4207258db..36ff8cf67 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator - bodypartcreator landtexturecreator + bodypartcreator landtexturecreator landcreator ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index f69d06d78..fccbebd43 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -15,6 +15,7 @@ #include "columnbase.hpp" #include "collectionbase.hpp" +#include "land.hpp" #include "landtexture.hpp" namespace CSMWorld @@ -39,6 +40,18 @@ namespace CSMWorld return record.mId; } + template<> + inline void IdAccessor::setId (Land& record, const std::string& id) const + { + int x=0, y=0; + + Land::parseUniqueRecordId(id, x, y); + record.mX = x; + record.mY = y; + // TODO check for uses of mId and remove them + record.mId = id; + } + template<> inline void IdAccessor::setId (LandTexture& record, const std::string& id) const { @@ -50,6 +63,12 @@ namespace CSMWorld record.mIndex = index; } + template<> + inline const std::string IdAccessor::getId (const Land& record) const + { + return Land::createUniqueRecordId(record.mX, record.mY); + } + template<> inline const std::string IdAccessor::getId (const LandTexture& record) const { @@ -86,6 +105,13 @@ namespace CSMWorld /// /// \return Success? + int cloneRecordImp (const std::string& origin, const std::string& dest, + UniversalId::Type type); + ///< Returns the index of the clone. + + int touchRecordImp (const std::string& id); + ///< Returns the index of the record on success, -1 on failure. + public: Collection(); @@ -227,20 +253,22 @@ namespace CSMWorld } template - void Collection::cloneRecord(const std::string& origin, - const std::string& destination, - const UniversalId::Type type) + int Collection::cloneRecordImp(const std::string& origin, + const std::string& destination, UniversalId::Type type) { - Record copy; - copy.mModified = getRecord(origin).get(); - copy.mState = RecordBase::State_ModifiedOnly; - IdAccessorT().setId(copy.get(), destination); + Record copy; + copy.mModified = getRecord(origin).get(); + copy.mState = RecordBase::State_ModifiedOnly; + IdAccessorT().setId(copy.get(), destination); - insertRecord(copy, getAppendIndex(destination, type)); + int index = getAppendIndex(destination, type); + insertRecord(copy, getAppendIndex(destination, type)); + + return index; } template - bool Collection::touchRecord(const std::string& id) + int Collection::touchRecordImp(const std::string& id) { int index = getIndex(id); Record& record = mRecords.at(index); @@ -249,13 +277,47 @@ namespace CSMWorld throw std::runtime_error("attempt to touch deleted record"); } - if (!record.isModified() && !record.isDeleted() && !record.isErased()) + if (!record.isModified()) { record.setModified(record.get()); + return index; + } + + return -1; + } + + template + void Collection::cloneRecord(const std::string& origin, + const std::string& destination, const UniversalId::Type type) + { + cloneRecordImp(origin, destination, type); + } + + template<> + inline void Collection >::cloneRecord(const std::string& origin, + const std::string& destination, const UniversalId::Type type) + { + int index = cloneRecordImp(origin, destination, type); + mRecords.at(index).get().mPlugin = 0; + } + + template + bool Collection::touchRecord(const std::string& id) + { + return touchRecordImp(id) != -1; + } + + template<> + inline bool Collection >::touchRecord(const std::string& id) + { + int index = touchRecordImp(id); + if (index >= 0) + { + mRecords.at(index).get().mPlugin = 0; return true; } - else - return false; + + return false; } template diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 80f86c746..22fc96599 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -8,8 +8,24 @@ namespace CSMWorld { ESM::Land::load(esm, isDeleted); + mId = createUniqueRecordId(mX, mY); + } + + std::string Land::createUniqueRecordId(int x, int y) + { std::ostringstream stream; - stream << "#" << mX << " " << mY; - mId = stream.str(); + stream << "#" << x << " " << y; + return stream.str(); + } + + void Land::parseUniqueRecordId(const std::string& id, int& x, int& y) + { + size_t mid = id.find(' '); + + if (mid == std::string::npos || id[0] != '#') + throw std::runtime_error("Invalid Land ID"); + + x = std::stoi(id.substr(1, mid - 1)); + y = std::stoi(id.substr(mid + 1)); } } diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e5f25c1d3..cc7e914af 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -16,6 +16,9 @@ namespace CSMWorld /// Loads the metadata and ID void load (ESM::ESMReader &esm, bool &isDeleted); + + static std::string createUniqueRecordId(int x, int y); + static void parseUniqueRecordId(const std::string& id, int& x, int& y); }; } diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp new file mode 100644 index 000000000..34599b2c4 --- /dev/null +++ b/apps/opencs/view/world/landcreator.cpp @@ -0,0 +1,79 @@ +#include "landcreator.hpp" + +#include + +#include "../../model/world/land.hpp" + +namespace CSVWorld +{ + LandCreator::LandCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) + : GenericCreator(data, undoStack, id) + , mXLabel(nullptr) + , mYLabel(nullptr) + , mX(nullptr) + , mY(nullptr) + { + const int MaxInt = std::numeric_limits::max(); + const int MinInt = std::numeric_limits::min(); + + setManualEditing(false); + + mXLabel = new QLabel("X: "); + mX = new QSpinBox(); + mX->setMinimum(MinInt); + mX->setMaximum(MaxInt); + insertBeforeButtons(mXLabel, false); + insertBeforeButtons(mX, true); + + mYLabel = new QLabel("Y: "); + mY = new QSpinBox(); + mY->setMinimum(MinInt); + mY->setMaximum(MaxInt); + insertBeforeButtons(mYLabel, false); + insertBeforeButtons(mY, true); + + connect (mX, SIGNAL(valueChanged(int)), this, SLOT(coordChanged(int))); + connect (mY, SIGNAL(valueChanged(int)), this, SLOT(coordChanged(int))); + } + + void LandCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) + { + GenericCreator::cloneMode(originId, type); + + int x = 0, y = 0; + CSMWorld::Land::parseUniqueRecordId(originId, x, y); + + mX->setValue(x); + mY->setValue(y); + } + + void LandCreator::focus() + { + mX->setFocus(); + } + + void LandCreator::reset() + { + GenericCreator::reset(); + mX->setValue(0); + mY->setValue(0); + } + + std::string LandCreator::getErrors() const + { + if (getData().getLand().searchId(getId()) >= 0) + return "A land with that name already exists."; + + return ""; + } + + std::string LandCreator::getId() const + { + return CSMWorld::Land::createUniqueRecordId(mX->value(), mY->value()); + } + + void LandCreator::coordChanged(int value) + { + update(); + } +} diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp new file mode 100644 index 000000000..aea202dcd --- /dev/null +++ b/apps/opencs/view/world/landcreator.hpp @@ -0,0 +1,42 @@ +#ifndef CSV_WORLD_LANDCREATOR_H +#define CSV_WORLD_LANDCREATOR_H + +#include +#include + +#include "genericcreator.hpp" + +namespace CSVWorld +{ + class LandCreator : public GenericCreator + { + Q_OBJECT + + QLabel* mXLabel; + QLabel* mYLabel; + QSpinBox* mX; + QSpinBox* mY; + + public: + + LandCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); + + void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + + void focus() override; + + void reset() override; + + std::string getErrors() const override; + + private slots: + + void coordChanged(int value); + + protected: + + std::string getId() const override; + }; +} + +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index a33802823..3e72f9a9e 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -18,6 +18,7 @@ #include "pathgridcreator.hpp" #include "previewsubview.hpp" #include "bodypartcreator.hpp" +#include "landcreator.hpp" #include "landtexturecreator.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) @@ -83,7 +84,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_Lands, - new CSVDoc::SubViewFactoryWithCreator >); + new CSVDoc::SubViewFactoryWithCreator >); manager.add (CSMWorld::UniversalId::Type_LandTextures, new CSVDoc::SubViewFactoryWithCreator >); @@ -189,7 +190,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator (false)); manager.add (CSMWorld::UniversalId::Type_Land, - new CSVDoc::SubViewFactoryWithCreator >(false)); + new CSVDoc::SubViewFactoryWithCreator >(false)); manager.add (CSMWorld::UniversalId::Type_LandTexture, new CSVDoc::SubViewFactoryWithCreator >(false)); From d3014cf39424972a3b86bc61bfe92cf54551d7b2 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 15:13:45 -0400 Subject: [PATCH 007/150] Temporary fix for adding new lands, cloned lands will still reference old data though --- apps/opencs/view/render/terrainstorage.cpp | 21 ++++----- components/esm/loadland.cpp | 52 +++++++++++++++++++++- components/esm/loadland.hpp | 6 ++- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index c63d41be3..51c9dd009 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -1,5 +1,8 @@ #include "terrainstorage.hpp" +#include "../../model/world/land.hpp" +#include "../../model/world/landtexture.hpp" + namespace CSVRender { @@ -11,12 +14,9 @@ namespace CSVRender osg::ref_ptr TerrainStorage::getLand(int cellX, int cellY) { - std::ostringstream stream; - stream << "#" << cellX << " " << cellY; - // The cell isn't guaranteed to have Land. This is because the terrain implementation // has to wrap the vertices of the last row and column to the next cell, which may be a nonexisting cell - int index = mData.getLand().searchId(stream.str()); + int index = mData.getLand().searchId(CSMWorld::Land::createUniqueRecordId(cellX, cellY)); if (index == -1) return NULL; @@ -26,16 +26,11 @@ namespace CSVRender const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) { - int numRecords = mData.getLandTextures().getSize(); - - for (int i=0; imIndex == index && ltex->mPluginIndex == plugin) - return ltex; - } + int row = mData.getLandTextures().searchId(CSMWorld::LandTexture::createUniqueRecordId(plugin, index)); + if (row == -1) + return nullptr; - return NULL; + return &mData.getLandTextures().getRecord(row).get(); } void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 72c3eb98d..7d48dd037 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -15,6 +15,7 @@ namespace ESM , mX(0) , mY(0) , mPlugin(0) + , mNoFile(false) , mDataTypes(0) , mLandData(NULL) { @@ -175,6 +176,47 @@ namespace ESM } + void Land::blank() + { + if (mLandData) + { + delete mLandData; + } + + mPlugin = 0; + + for (int i = 0; i < LAND_GLOBAL_MAP_LOD_SIZE; ++i) + mWnam[0] = 0; + + mLandData = new LandData; + mLandData->mHeightOffset = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + mLandData->mHeights[i] = 0; + mLandData->mMinHeight = 0; + mLandData->mMaxHeight = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + { + mLandData->mNormals[i*3+0] = 0; + mLandData->mNormals[i*3+1] = -1; + mLandData->mNormals[i*3+2] = 0; + } + for (int i = 0; i < LAND_NUM_TEXTURES; ++i) + mLandData->mTextures[i] = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + { + mLandData->mColours[i*3+0] = -1; + mLandData->mColours[i*3+1] = -1; + mLandData->mColours[i*3+2] = -1; + } + mLandData->mUnk1 = 0; + mLandData->mUnk2 = 0; + mLandData->mDataLoaded = Land::DATA_VNML | Land::DATA_VHGT | Land::DATA_WNAM | + Land::DATA_VCLR | Land::DATA_VTEX; + mDataTypes = mLandData->mDataLoaded; + + mNoFile = true; + } + void Land::loadData(int flags, LandData* target) const { // Create storage if nothing is loaded @@ -193,6 +235,13 @@ namespace ESM return; } + // Copy data to target if no file + if (mNoFile) + { + *target = *mLandData; + return; + } + ESM::ESMReader reader; reader.restoreContext(mContext); @@ -271,7 +320,7 @@ namespace ESM Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), - mContext (land.mContext), mDataTypes (land.mDataTypes), + mContext (land.mContext), mNoFile(land.mNoFile), mDataTypes (land.mDataTypes), mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) {} @@ -288,6 +337,7 @@ namespace ESM std::swap (mY, land.mY); std::swap (mPlugin, land.mPlugin); std::swap (mContext, land.mContext); + std::swap (mNoFile, land.mNoFile); std::swap (mDataTypes, land.mDataTypes); std::swap (mLandData, land.mLandData); } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index a7b97a465..223b7975a 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -33,6 +33,10 @@ struct Land // location later when we are ready to load the full data set. ESM_Context mContext; + // In the editor, a new Land is not associated with a file, thus mContext should not be accessed + // when land data is being requested. Instead simply copy over the data. + bool mNoFile; + int mDataTypes; enum @@ -116,7 +120,7 @@ struct Land void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; - void blank() {} + void blank(); /** * Actually loads data into target From 5c3e90da881948ff1f2fde5dd595fe7e2a0882e9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 15:14:42 -0400 Subject: [PATCH 008/150] Fix includes --- apps/opencs/model/world/land.cpp | 1 + apps/opencs/model/world/landtexture.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 22fc96599..2b12b55fe 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -1,6 +1,7 @@ #include "land.hpp" #include +#include namespace CSMWorld { diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4b82f8d73..63ebbc11f 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,6 +1,7 @@ #include "landtexture.hpp" #include +#include #include From 97d0fd756a2dff3ac73bd308a1ad7f88c3e4e13d Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 19:31:09 -0400 Subject: [PATCH 009/150] LTEX importing --- apps/opencs/model/world/commands.cpp | 85 +++++++++++++++++++++++++ apps/opencs/model/world/commands.hpp | 25 +++++++- apps/opencs/model/world/idtable.cpp | 57 +++++++++++++++++ apps/opencs/model/world/idtable.hpp | 16 ++++- apps/opencs/model/world/land.cpp | 2 +- apps/opencs/model/world/landtexture.cpp | 2 +- apps/opencs/view/world/landcreator.cpp | 20 ++++++ apps/opencs/view/world/landcreator.hpp | 2 + 8 files changed, 204 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index c6a56f7b8..c98f52777 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -40,6 +41,90 @@ void CSMWorld::TouchCommand::undo() } } +CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, QUndoCommand* parent) + : QUndoCommand(parent) + , mLands(landTable) + , mLtexs(ltexTable) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mLands.getRecord(mId).clone()); +} + +void CSMWorld::TouchLandCommand::redo() +{ + int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); + int oldPlugin = mLands.data(mLands.getModelIndex(mId, pluginColumn)).toInt(); + + mChanged = mLands.touchRecord(mId); + if (mChanged) + { + // Original data + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + QByteArray textureByteArray = mLands.data(mLands.getModelIndex(mId, textureColumn)).toByteArray(); + const uint16_t* textureData = reinterpret_cast(textureByteArray.data()); + + // Need to make a copy so the old values can be looked up + QByteArray newTextureByteArray(textureByteArray.data(), textureByteArray.size()); + uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + + // Find all indices used + std::unordered_set texIndices; + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + { + // All indices are offset by 1 for a default texture + if (textureData[i] > 0) + texIndices.insert(textureData[i] - 1); + } + + std::vector oldTextures; + for (int index : texIndices) + { + oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); + } + + // Import the textures, replace old values + LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); + mCreatedTextures = std::move(results.createdRecords); + for (const auto& it : results.recordMapping) + { + int plugin = 0, newIndex = 0, oldIndex = 0; + LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); + LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); + + if (newIndex != oldIndex) + { + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + { + // All indices are offset by 1 for a default texture + if (textureData[i] == oldIndex) + newTextureData[i] = newIndex + 1; + } + } + } + + mLands.setData(mLands.getModelIndex(mId, textureColumn), newTextureByteArray); + } +} + +void CSMWorld::TouchLandCommand::undo() +{ + if (mChanged) + { + mLands.setRecord(mId, *mOld); + mChanged = false; + + for (const std::string& id : mCreatedTextures) + { + int row = mLtexs.getModelIndex(id, 0).row(); + mLtexs.removeRows(row, 1); + } + mCreatedTextures.clear(); + } +} + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 4c9be7e8a..5f4259cb8 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -31,8 +31,8 @@ namespace CSMWorld TouchCommand(IdTable& model, const std::string& id, QUndoCommand* parent=nullptr); - virtual void redo(); - virtual void undo(); + void redo() override; + void undo() override; private: @@ -43,6 +43,27 @@ namespace CSMWorld bool mChanged; }; + class TouchLandCommand : public QUndoCommand + { + public: + + TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, + QUndoCommand* parent = nullptr); + + void redo() override; + void undo() override; + + private: + + IdTable& mLands; + IdTable& mLtexs; + std::string mId; + std::unique_ptr mOld; + std::vector mCreatedTextures; + + bool mChanged; + }; + class ModifyCommand : public QUndoCommand { QAbstractItemModel *mModel; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 94eab3fc3..5543fc13f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,11 +1,13 @@ #include "idtable.hpp" +#include #include #include #include "collectionbase.hpp" #include "columnbase.hpp" +#include "landtexture.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) : IdTableBase (features), mIdCollection (idCollection) @@ -332,3 +334,58 @@ Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) cons return flags; } + +CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures(const std::vector& ids) +{ + ImportResults results; + + for (const std::string& id : ids) + { + int plugin, index; + + LandTexture::parseUniqueRecordId(id, plugin, index); + int oldRow = idCollection()->searchId(id); + + // If it does not exist or it is in the current plugin, it can be skipped. + if (oldRow <= 0 || plugin == 0) + { + results.recordMapping.push_back(std::make_pair(id, id)); + continue; + } + + // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. + // Iteration is deterministic to avoid duplicates. + do { + std::string newId = LandTexture::createUniqueRecordId(0, index); + int newRow = idCollection()->searchId(newId); + + if (newRow < 0) + { + // Id not taken, clone it + cloneRecord(id, newId, UniversalId::Type_LandTexture); + results.createdRecords.push_back(newId); + results.recordMapping.push_back(std::make_pair(id, newId)); + break; + } + + // Id is taken, check if same handle and texture. Note that mId is the handle. + const LandTexture& oldLtex = dynamic_cast&>(idCollection()->getRecord(oldRow)).get(); + const LandTexture& newLtex = dynamic_cast&>(idCollection()->getRecord(newRow)).get(); + if (oldLtex.mId == newLtex.mId && oldLtex.mTexture == newLtex.mTexture) + { + // It's a match + results.recordMapping.push_back(std::make_pair(id, newId)); + break; + } + + // Determine next index. Spread out the indices to reduce conflicts. + size_t MaxIndex = std::numeric_limits::max(); + size_t Prime = (1 << 19) - 1; // A mersenne prime + size_t K = 2154; + + index = ((K * index) % Prime) % MaxIndex; + } while (true); + } + + return results; +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 5e5f9da4a..ccc5ac404 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -100,11 +100,22 @@ namespace CSMWorld }; /// An IdTable customized to handle the more unique needs of LandTextureId's which behave - /// differently from other records. + /// differently from other records. The major difference is that base records cannot be + /// modified. class LandTextureIdTable : public IdTable { public: + struct ImportResults + { + using StringPair = std::pair; + + /// The newly added records + std::vector createdRecords; + /// The 1st string is the original id, the 2nd is the mapped id + std::vector recordMapping; + }; + LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; @@ -112,6 +123,9 @@ namespace CSMWorld bool setData(const QModelIndex& index, const QVariant& value, int role) override; Qt::ItemFlags flags (const QModelIndex & index) const override; + + /// Finds and maps/recreates the specified ids. + ImportResults importTextures(const std::vector& ids); }; } diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 2b12b55fe..74833d7ef 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -1,7 +1,7 @@ #include "land.hpp" #include -#include +#include namespace CSMWorld { diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 63ebbc11f..32bab1e6d 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,7 +1,7 @@ #include "landtexture.hpp" #include -#include +#include #include diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index 34599b2c4..08b8b3620 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -2,6 +2,8 @@ #include +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" #include "../../model/world/land.hpp" namespace CSVWorld @@ -47,6 +49,24 @@ namespace CSVWorld mY->setValue(y); } + void LandCreator::touch(const std::vector& ids) + { + // Combine multiple touch commands into one "macro" command + std::unique_ptr macro(new QUndoCommand()); + macro->setText("Touch records"); + + CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); + for (const CSMWorld::UniversalId& uid : ids) + { + // This is not leaked, touchCmd is a child of macro and managed by Qt + CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId(), macro.get()); + } + + // Execute + getUndoStack().push(macro.release()); + } + void LandCreator::focus() { mX->setFocus(); diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index aea202dcd..ef8cf60d5 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -23,6 +23,8 @@ namespace CSVWorld void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + void touch(const std::vector& ids) override; + void focus() override; void reset() override; From 99e90ef808ec95d3c5e22e3e72d99ef10e58b0d9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 5 Sep 2017 19:29:07 -0400 Subject: [PATCH 010/150] Cleanup. Also modify ltex index generation. --- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/model/world/collection.hpp | 2 -- apps/opencs/model/world/columnimp.hpp | 9 ++++++- apps/opencs/model/world/columns.cpp | 5 ++++ apps/opencs/model/world/idtable.cpp | 8 +++--- apps/opencs/model/world/land.cpp | 2 -- apps/opencs/model/world/land.hpp | 2 -- apps/opencs/model/world/landtexture.cpp | 6 +++-- apps/opencs/view/world/landcreator.cpp | 3 +++ apps/opencs/view/world/landcreator.hpp | 6 ++--- apps/opencs/view/world/landtexturecreator.cpp | 27 ++++++++----------- apps/opencs/view/world/landtexturecreator.hpp | 6 ++--- 12 files changed, 42 insertions(+), 35 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 0101a432b..1f84c5a87 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -278,6 +278,7 @@ void CSMPrefs::State::declare() declareShortcut ("table-edit", "Edit Record", QKeySequence()); declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A)); declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D)); + declareShortcut ("touch-record", "Touch Record", QKeySequence()); declareShortcut ("table-revert", "Revert Record", QKeySequence()); declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete)); declareShortcut ("table-moveup", "Move Record Up", QKeySequence()); diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index fccbebd43..80117d0c6 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -48,8 +48,6 @@ namespace CSMWorld Land::parseUniqueRecordId(id, x, y); record.mX = x; record.mY = y; - // TODO check for uses of mId and remove them - record.mId = id; } template<> diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index f58a35bc4..8e5908bd3 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -63,6 +63,13 @@ namespace CSMWorld } }; + template<> + inline QVariant StringIdColumn::get(const Record& record) const + { + const Land& land = record.get(); + return QString(Land::createUniqueRecordId(land.mX, land.mY).c_str()); + } + template<> inline QVariant StringIdColumn::get(const Record& record) const { @@ -2483,7 +2490,7 @@ namespace CSMWorld return -1; } - virtual bool isEditable() const override + bool isEditable() const override { return false; } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 49935d40d..63ccb6017 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -333,6 +333,11 @@ namespace CSMWorld { ColumnId_TextureHandle, "Texture Handle" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, + { ColumnId_LandMapLodIndex, "Land map height LOD" }, + { ColumnId_LandNormalsIndex, "Land normals" }, + { ColumnId_LandHeightsIndex, "Land heights" }, + { ColumnId_LandColoursIndex, "Land colors" }, + { ColumnId_LandTexturesIndex, "Land textures" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 5543fc13f..127ffde2c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,6 @@ #include "idtable.hpp" +#include #include #include @@ -379,11 +380,10 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import } // Determine next index. Spread out the indices to reduce conflicts. - size_t MaxIndex = std::numeric_limits::max(); - size_t Prime = (1 << 19) - 1; // A mersenne prime - size_t K = 2154; + size_t MaxIndex = std::numeric_limits::max() - 1; + size_t Prime = (1 << 13) - 1; // A mersenne prime - index = ((K * index) % Prime) % MaxIndex; + index = (index + Prime) % MaxIndex; } while (true); } diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 74833d7ef..bfa927444 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -8,8 +8,6 @@ namespace CSMWorld void Land::load(ESM::ESMReader &esm, bool &isDeleted) { ESM::Land::load(esm, isDeleted); - - mId = createUniqueRecordId(mX, mY); } std::string Land::createUniqueRecordId(int x, int y) diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index cc7e914af..e604f1311 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -12,8 +12,6 @@ namespace CSMWorld /// \todo Add worldspace support to the Land record. struct Land : public ESM::Land { - std::string mId; - /// Loads the metadata and ID void load (ESM::ESMReader &esm, bool &isDeleted); diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 32bab1e6d..43deb64a4 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,6 +1,6 @@ #include "landtexture.hpp" -#include +#include #include #include @@ -16,7 +16,9 @@ namespace CSMWorld std::string LandTexture::createUniqueRecordId(int plugin, int index) { - return 'L' + std::to_string(plugin) + '#' + std::to_string(index); + std::stringstream ss; + ss << 'L' << plugin << '#' << index; + return ss.str(); } void LandTexture::parseUniqueRecordId(const std::string& id, int& plugin, int& index) diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index 08b8b3620..a227a6a87 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/land.hpp" diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index ef8cf60d5..9674a2b58 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -1,11 +1,11 @@ #ifndef CSV_WORLD_LANDCREATOR_H #define CSV_WORLD_LANDCREATOR_H -#include -#include - #include "genericcreator.hpp" +class QLabel; +class QSpinBox; + namespace CSVWorld { class LandCreator : public GenericCreator diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp index f79c08427..fdabfb281 100644 --- a/apps/opencs/view/world/landtexturecreator.cpp +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -3,9 +3,9 @@ #include #include -#include #include #include +#include #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" @@ -30,14 +30,13 @@ namespace CSVWorld QLabel* indexLabel = new QLabel("Index"); insertBeforeButtons(indexLabel, false); - QIntValidator* indexValidator = new QIntValidator(0, MaxIndex, this); - - mIndexEdit = new QLineEdit(this); - mIndexEdit->setValidator(indexValidator); - insertBeforeButtons(mIndexEdit, true); + mIndexBox = new QSpinBox(this); + mIndexBox->setMinimum(0); + mIndexBox->setMaximum(MaxIndex); + insertBeforeButtons(mIndexBox, true); connect(mNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&))); - connect(mIndexEdit, SIGNAL(textChanged(const QString&)), this, SLOT(indexChanged(const QString&))); + connect(mIndexBox, SIGNAL(valueChanged(int)), this, SLOT(indexChanged(int))); } void LandTextureCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) @@ -50,26 +49,23 @@ namespace CSVWorld mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); - mIndexEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + mIndexBox->setValue((table.data(table.getModelIndex(originId, column)).toInt())); } void LandTextureCreator::focus() { - mIndexEdit->setFocus(); + mIndexBox->setFocus(); } void LandTextureCreator::reset() { GenericCreator::reset(); mNameEdit->setText(""); - mIndexEdit->setText(""); + mIndexBox->setValue(0); } std::string LandTextureCreator::getErrors() const { - std::string id = getId(); - - // TODO empty index edit? if (getData().getLandTextures().searchId(getId()) >= 0) { return "Index is already in use"; @@ -89,7 +85,7 @@ namespace CSVWorld std::string LandTextureCreator::getId() const { - return CSMWorld::LandTexture::createUniqueRecordId(0, mIndex); + return CSMWorld::LandTexture::createUniqueRecordId(0, mIndexBox->value()); } void LandTextureCreator::nameChanged(const QString& value) @@ -98,9 +94,8 @@ namespace CSVWorld update(); } - void LandTextureCreator::indexChanged(const QString& value) + void LandTextureCreator::indexChanged(int value) { - mIndex = value.toInt(); update(); } } diff --git a/apps/opencs/view/world/landtexturecreator.hpp b/apps/opencs/view/world/landtexturecreator.hpp index 46388bf03..b11c47758 100644 --- a/apps/opencs/view/world/landtexturecreator.hpp +++ b/apps/opencs/view/world/landtexturecreator.hpp @@ -6,6 +6,7 @@ #include "genericcreator.hpp" class QLineEdit; +class QSpinBox; namespace CSVWorld { @@ -34,15 +35,14 @@ namespace CSVWorld private slots: void nameChanged(const QString& val); - void indexChanged(const QString& val); + void indexChanged(int val); private: QLineEdit* mNameEdit; - QLineEdit* mIndexEdit; + QSpinBox* mIndexBox; std::string mName; - int mIndex; }; } From ab607f302834c1409e1f0d72caa0dc68be83361c Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 00:51:46 -0400 Subject: [PATCH 011/150] Tweaks to land loading, land cloning, terrain signals, placeholder land update handling --- apps/opencs/model/world/collection.hpp | 2 + apps/opencs/model/world/commands.cpp | 170 ++++++++++++------ apps/opencs/model/world/commands.hpp | 54 +++++- apps/opencs/view/render/cell.cpp | 72 ++++++-- apps/opencs/view/render/cell.hpp | 14 ++ .../view/render/pagedworldspacewidget.cpp | 81 +++++++++ .../view/render/pagedworldspacewidget.hpp | 8 + apps/opencs/view/world/genericcreator.cpp | 5 + apps/opencs/view/world/genericcreator.hpp | 2 + apps/opencs/view/world/landcreator.cpp | 19 ++ apps/opencs/view/world/landcreator.hpp | 11 +- components/esm/loadland.cpp | 9 +- components/esm/loadland.hpp | 6 +- 13 files changed, 363 insertions(+), 90 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 80117d0c6..6e74a1726 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -297,6 +297,7 @@ namespace CSMWorld { int index = cloneRecordImp(origin, destination, type); mRecords.at(index).get().mPlugin = 0; + mRecords.at(index).get().mContext.filename.clear(); } template @@ -312,6 +313,7 @@ namespace CSMWorld if (index >= 0) { mRecords.at(index).get().mPlugin = 0; + mRecords.at(index).get().mContext.filename.clear(); return true; } diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index c98f52777..5bfcd6846 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -41,87 +41,145 @@ void CSMWorld::TouchCommand::undo() } } -CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, QUndoCommand* parent) +CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand(IdTable& landTable, + IdTable& ltexTable, QUndoCommand* parent) : QUndoCommand(parent) , mLands(landTable) , mLtexs(ltexTable) - , mId(id) - , mOld(nullptr) - , mChanged(false) + , mOldState(0) { - setText(("Touch " + mId).c_str()); - mOld.reset(mLands.getRecord(mId).clone()); + setText("Import land textures"); } -void CSMWorld::TouchLandCommand::redo() +void CSMWorld::ImportLandTexturesCommand::redo() { int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); - int oldPlugin = mLands.data(mLands.getModelIndex(mId, pluginColumn)).toInt(); + int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt(); - mChanged = mLands.touchRecord(mId); - if (mChanged) + // Original data + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).toByteArray(); + const uint16_t* textureData = reinterpret_cast(mOld.data()); + + // Need to make a copy so the old values can be looked up + QByteArray newTextureByteArray(mOld.data(), mOld.size()); + uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + + // Perform touch/copy/etc... + onRedo(); + + // Find all indices used + std::unordered_set texIndices; + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { - // Original data - int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - QByteArray textureByteArray = mLands.data(mLands.getModelIndex(mId, textureColumn)).toByteArray(); - const uint16_t* textureData = reinterpret_cast(textureByteArray.data()); - - // Need to make a copy so the old values can be looked up - QByteArray newTextureByteArray(textureByteArray.data(), textureByteArray.size()); - uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); - - // Find all indices used - std::unordered_set texIndices; - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) - { - // All indices are offset by 1 for a default texture - if (textureData[i] > 0) - texIndices.insert(textureData[i] - 1); - } + // All indices are offset by 1 for a default texture + if (textureData[i] > 0) + texIndices.insert(textureData[i] - 1); + } - std::vector oldTextures; - for (int index : texIndices) - { - oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); - } + std::vector oldTextures; + for (int index : texIndices) + { + oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); + } - // Import the textures, replace old values - LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); - mCreatedTextures = std::move(results.createdRecords); - for (const auto& it : results.recordMapping) - { - int plugin = 0, newIndex = 0, oldIndex = 0; - LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); - LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); + // Import the textures, replace old values + LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); + mCreatedTextures = std::move(results.createdRecords); + for (const auto& it : results.recordMapping) + { + int plugin = 0, newIndex = 0, oldIndex = 0; + LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); + LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); - if (newIndex != oldIndex) + if (newIndex != oldIndex) + { + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) - { - // All indices are offset by 1 for a default texture - if (textureData[i] == oldIndex) - newTextureData[i] = newIndex + 1; - } + // All indices are offset by 1 for a default texture + if (textureData[i] == oldIndex + 1) + newTextureData[i] = newIndex + 1; } } + } - mLands.setData(mLands.getModelIndex(mId, textureColumn), newTextureByteArray); + // Apply modification + int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); + mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt(); + + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), newTextureByteArray); +} + +void CSMWorld::ImportLandTexturesCommand::undo() +{ + // Restore to previous + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), mOld); + + int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); + mLands.setData(mLands.getModelIndex(getDestinationId(), stateColumn), mOldState); + + // Undo copy/touch/etc... + onUndo(); + + for (const std::string& id : mCreatedTextures) + { + int row = mLtexs.getModelIndex(id, 0).row(); + mLtexs.removeRows(row, 1); } + mCreatedTextures.clear(); } -void CSMWorld::TouchLandCommand::undo() +CSMWorld::CopyLandTexturesCommand::CopyLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& origin, const std::string& dest, QUndoCommand* parent) + : ImportLandTexturesCommand(landTable, ltexTable, parent) + , mOriginId(origin) + , mDestId(dest) +{ +} + +const std::string& CSMWorld::CopyLandTexturesCommand::getOriginId() const +{ + return mOriginId; +} + +const std::string& CSMWorld::CopyLandTexturesCommand::getDestinationId() const +{ + return mDestId; +} + +CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& id, QUndoCommand* parent) + : ImportLandTexturesCommand(landTable, ltexTable, parent) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mLands.getRecord(mId).clone()); +} + +const std::string& CSMWorld::TouchLandCommand::getOriginId() const +{ + return mId; +} + +const std::string& CSMWorld::TouchLandCommand::getDestinationId() const +{ + return mId; +} + +void CSMWorld::TouchLandCommand::onRedo() +{ + mChanged = mLands.touchRecord(mId); +} + +void CSMWorld::TouchLandCommand::onUndo() { if (mChanged) { mLands.setRecord(mId, *mOld); mChanged = false; - - for (const std::string& id : mCreatedTextures) - { - int row = mLtexs.getModelIndex(id, 0).row(); - mLtexs.removeRows(row, 1); - } - mCreatedTextures.clear(); } } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 5f4259cb8..aab0c5410 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -43,23 +43,67 @@ namespace CSMWorld bool mChanged; }; - class TouchLandCommand : public QUndoCommand + class ImportLandTexturesCommand : public QUndoCommand { public: - TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, - QUndoCommand* parent = nullptr); + ImportLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, + QUndoCommand* parent); void redo() override; void undo() override; - private: + protected: + + virtual const std::string& getOriginId() const = 0; + virtual const std::string& getDestinationId() const = 0; + + virtual void onRedo() = 0; + virtual void onUndo() = 0; IdTable& mLands; IdTable& mLtexs; + QByteArray mOld; + int mOldState; + std::vector mCreatedTextures; + }; + + class CopyLandTexturesCommand : public ImportLandTexturesCommand + { + public: + + CopyLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, const std::string& origin, + const std::string& dest, QUndoCommand* parent = nullptr); + + private: + + const std::string& getOriginId() const override; + const std::string& getDestinationId() const override; + + void onRedo() override {} + void onUndo() override {} + + std::string mOriginId; + std::string mDestId; + }; + + class TouchLandCommand : public ImportLandTexturesCommand + { + public: + + TouchLandCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& id, QUndoCommand* parent = nullptr); + + private: + + const std::string& getOriginId() const override; + const std::string& getDestinationId() const override; + + void onRedo() override; + void onUndo() override; + std::string mId; std::unique_ptr mOld; - std::vector mCreatedTextures; bool mChanged; }; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 765c5b316..51279cac4 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -75,6 +75,31 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } +void CSVRender::Cell::createLand() +{ + if (mDeleted) + { + mTerrain.reset(); + return; + } + + const CSMWorld::IdCollection& land = mData.getLand(); + int landIndex = land.searchId(mId); + if (landIndex != -1) + { + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + mTerrain->loadCell(esmLand.mX, esmLand.mY); + + mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + mCellBorder->buildShape(esmLand); + } + } +} + CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), @@ -99,22 +124,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st addObjects (0, rows-1); - const CSMWorld::IdCollection& land = mData.getLand(); - int landIndex = land.searchId(mId); - if (landIndex != -1) - { - const ESM::Land& esmLand = land.getRecord(mId).get(); - - if (esmLand.getLandData (ESM::Land::DATA_VHGT)) - { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, data.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); - mTerrain->loadCell(esmLand.mX, - esmLand.mY); - - mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); - mCellBorder->buildShape(esmLand); - } - } + createLand(); mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); @@ -285,6 +295,36 @@ void CSVRender::Cell::pathgridRemoved() mPathgrid->removeGeometry(); } +void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + createLand(); +} + +void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + createLand(); +} + +void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + void CSVRender::Cell::reloadAssets() { for (std::map::const_iterator iter (mObjects.begin()); diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f53f61973..f6db475d7 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -72,6 +72,8 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); + void createLand(); + public: enum Selection @@ -118,6 +120,18 @@ namespace CSVRender void pathgridRemoved(); + void landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void landAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + void landAdded (const QModelIndex& parent, int start, int end); + + void landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + void landTextureAdded (const QModelIndex& parent, int start, int end); + void reloadAssets(); void setSelection (int elementMask, Selection mode); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b1077139c..b224ac1c4 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -351,6 +351,69 @@ void CSVRender::PagedWorldspaceWidget::pathgridAdded(const QModelIndex& parent, } } +void CSVRender::PagedWorldspaceWidget::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + for (int r = topLeft.row(); r <= bottomRight.row(); ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landDataChanged(topLeft, bottomRight); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + for (int r = start; r <= end; ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landAboutToBeRemoved(parent, start, end); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landAdded (const QModelIndex& parent, int start, int end) +{ + for (int r = start; r <= end; ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landAdded(parent, start, end); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landTextureDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureChanged(topLeft, bottomRight); +} + +void CSVRender::PagedWorldspaceWidget::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureAboutToBeRemoved(parent, start, end); +} + +void CSVRender::PagedWorldspaceWidget::landTextureAdded (const QModelIndex& parent, int start, int end) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureAdded(parent, start, end); +} + std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { @@ -475,6 +538,24 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc connect (&document.getData(), SIGNAL (assetTablesChanged ()), this, SLOT (assetTablesChanged ())); + QAbstractItemModel *lands = document.getData().getTableModel (CSMWorld::UniversalId::Type_Lands); + + connect (lands, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (landDataChanged (const QModelIndex&, const QModelIndex&))); + connect (lands, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (landAboutToBeRemoved (const QModelIndex&, int, int))); + connect (lands, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (landAdded (const QModelIndex&, int, int))); + + QAbstractItemModel *ltexs = document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures); + + connect (ltexs, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (landTextureDataChanged (const QModelIndex&, const QModelIndex&))); + connect (ltexs, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (landTextureAboutToBeRemoved (const QModelIndex&, int, int))); + connect (ltexs, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (landTextureAdded (const QModelIndex&, int, int))); + // Shortcuts CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this); connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell())); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 8c41df51e..6672c2268 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -155,6 +155,14 @@ namespace CSVRender virtual void cellAdded (const QModelIndex& index, int start, int end); + virtual void landDataChanged (const QModelIndex& topLeft, const QModelIndex& botomRight); + virtual void landAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual void landAdded (const QModelIndex& parent, int start, int end); + + virtual void landTextureDataChanged (const QModelIndex& topLeft, const QModelIndex& botomRight); + virtual void landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual void landTextureAdded (const QModelIndex& parent, int start, int end); + void assetTablesChanged (); void loadCameraCell(); diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bde523a09..bd3da230d 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -51,6 +51,11 @@ std::string CSVWorld::GenericCreator::getId() const return mId->text().toUtf8().constData(); } +std::string CSVWorld::GenericCreator::getClonedId() const +{ + return mClonedId; +} + std::string CSVWorld::GenericCreator::getIdValidatorResult() const { std::string errors; diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index d708c1047..3baacfc06 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -64,6 +64,8 @@ namespace CSVWorld virtual std::string getId() const; + std::string getClonedId() const; + virtual std::string getIdValidatorResult() const; /// Allow subclasses to add additional data to \a command. diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index a227a6a87..dd7bfe68d 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -95,6 +95,25 @@ namespace CSVWorld return CSMWorld::Land::createUniqueRecordId(mX->value(), mY->value()); } + void LandCreator::pushCommand(std::unique_ptr command, const std::string& id) + { + if (mCloneMode) + { + CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); + + getUndoStack().beginMacro(("Clone " + id).c_str()); + getUndoStack().push(command.release()); + + CSMWorld::CopyLandTexturesCommand* ltexCopy = new CSMWorld::CopyLandTexturesCommand(lands, ltexs, getClonedId(), getId()); + getUndoStack().push(ltexCopy); + + getUndoStack().endMacro(); + } + else + getUndoStack().push (command.release()); + } + void LandCreator::coordChanged(int value) { update(); diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index 9674a2b58..e0c5577e4 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -31,13 +31,16 @@ namespace CSVWorld std::string getErrors() const override; - private slots: - - void coordChanged(int value); - protected: std::string getId() const override; + + void pushCommand(std::unique_ptr command, + const std::string& id) override; + + private slots: + + void coordChanged(int value); }; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 7d48dd037..c81675556 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -15,7 +15,6 @@ namespace ESM , mX(0) , mY(0) , mPlugin(0) - , mNoFile(false) , mDataTypes(0) , mLandData(NULL) { @@ -214,7 +213,8 @@ namespace ESM Land::DATA_VCLR | Land::DATA_VTEX; mDataTypes = mLandData->mDataLoaded; - mNoFile = true; + // No file associated with the land now + mContext.filename.clear(); } void Land::loadData(int flags, LandData* target) const @@ -236,7 +236,7 @@ namespace ESM } // Copy data to target if no file - if (mNoFile) + if (mContext.filename.empty()) { *target = *mLandData; return; @@ -320,7 +320,7 @@ namespace ESM Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), - mContext (land.mContext), mNoFile(land.mNoFile), mDataTypes (land.mDataTypes), + mContext (land.mContext), mDataTypes (land.mDataTypes), mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) {} @@ -337,7 +337,6 @@ namespace ESM std::swap (mY, land.mY); std::swap (mPlugin, land.mPlugin); std::swap (mContext, land.mContext); - std::swap (mNoFile, land.mNoFile); std::swap (mDataTypes, land.mDataTypes); std::swap (mLandData, land.mLandData); } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 223b7975a..d7b736f99 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -31,12 +31,10 @@ struct Land // File context. This allows the ESM reader to be 'reset' to this // location later when we are ready to load the full data set. + // In the editor, there may not be a file associated with the Land, + // in which case the filename will be empty. ESM_Context mContext; - // In the editor, a new Land is not associated with a file, thus mContext should not be accessed - // when land data is being requested. Instead simply copy over the data. - bool mNoFile; - int mDataTypes; enum From 2eacc2f093e921c983047308eaf0a400b5294889 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 14:37:03 -0400 Subject: [PATCH 012/150] Changes to land creation, add ability to specifically clear terrain cache --- apps/opencs/view/render/cell.cpp | 36 ++++++++++++++++--- apps/opencs/view/render/cell.hpp | 1 + .../view/render/pagedworldspacewidget.cpp | 3 ++ components/terrain/world.cpp | 6 ++++ components/terrain/world.hpp | 4 +++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 51279cac4..18614a85f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -77,27 +77,55 @@ bool CSVRender::Cell::addObjects (int start, int end) void CSVRender::Cell::createLand() { + // Cell is deleted if (mDeleted) { - mTerrain.reset(); + unloadLand(); return; } + // Setup land if available const CSMWorld::IdCollection& land = mData.getLand(); int landIndex = land.searchId(mId); - if (landIndex != -1) + if (landIndex != -1 && !land.getRecord(mId).isDeleted()) { const ESM::Land& esmLand = land.getRecord(mId).get(); if (esmLand.getLandData (ESM::Land::DATA_VHGT)) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + if (mTerrain) + { + mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); + mTerrain->clearAssociatedCaches(); + } + else + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, + mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + } + mTerrain->loadCell(esmLand.mX, esmLand.mY); - mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + if (!mCellBorder) + mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + mCellBorder->buildShape(esmLand); + + return; } } + + // No land data + unloadLand(); +} + +void CSVRender::Cell::unloadLand() +{ + if (mTerrain) + mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); + + if (mCellBorder) + mCellBorder.reset(); } CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f6db475d7..6418ed249 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -73,6 +73,7 @@ namespace CSVRender bool addObjects (int start, int end); void createLand(); + void unloadLand(); public: diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b224ac1c4..4a745195b 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -400,18 +400,21 @@ void CSVRender::PagedWorldspaceWidget::landTextureDataChanged (const QModelIndex { for (auto cellIt : mCells) cellIt.second->landTextureChanged(topLeft, bottomRight); + flagAsModified(); } void CSVRender::PagedWorldspaceWidget::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { for (auto cellIt : mCells) cellIt.second->landTextureAboutToBeRemoved(parent, start, end); + flagAsModified(); } void CSVRender::PagedWorldspaceWidget::landTextureAdded (const QModelIndex& parent, int start, int end) { for (auto cellIt : mCells) cellIt.second->landTextureAdded(parent, start, end); + flagAsModified(); } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index b7cc0ae01..22c65b62c 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -75,4 +75,10 @@ void World::updateTextureFiltering() mTextureManager->updateTextureFiltering(); } +void World::clearAssociatedCaches() +{ + mTextureManager->clearCache(); + mChunkManager->clearCache(); +} + } diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index d0576fbd3..e1c3828fc 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -63,6 +63,10 @@ namespace Terrain float getHeightAt (const osg::Vec3f& worldPos); + /// Clears the cached land and landtexture data. + /// @note Thread safe. + virtual void clearAssociatedCaches(); + /// Load a terrain cell at maximum LOD and store it in the View for later use. /// @note Thread safe. virtual void cacheCell(View* view, int x, int y) {} From 72cb405de220d5cfe706c5c1c0e57358c32ab2dc Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 21:03:52 -0400 Subject: [PATCH 013/150] Some bug fixes, changes to land load code. --- apps/opencs/model/world/columnimp.cpp | 6 ++++-- apps/opencs/model/world/data.cpp | 14 +------------- apps/opencs/model/world/idcollection.hpp | 17 +++++++++++++++++ components/esm/loadland.cpp | 4 ++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 65d2fecd2..e6b406864 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -103,7 +103,8 @@ namespace CSMWorld assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); - for (int i = 0; i < array.count(); ++i) + int count = array.count() / sizeof(float); + for (int i = 0; i < count; ++i) { landData->mHeights[i] = rawData[i]; } @@ -183,7 +184,8 @@ namespace CSMWorld assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); - for (int i = 0; i < array.count(); ++i) + int count = array.count() / sizeof(uint16_t); + for (int i = 0; i < count; ++i) { landData->mTextures[i] = rawData[i]; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3284d9b05..0ffe5fa21 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1013,19 +1013,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break; - case ESM::REC_LAND: - { - int index = mLand.load(*mReader, mBase); - - // Load all land data for now. A future optimisation may only load non-base data - // if a suitable mechanism for avoiding race conditions can be established. - if (index!=-1/* && !mBase*/) - mLand.getRecord (index).get().loadData ( - ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | - ESM::Land::DATA_VTEX); - - break; - } + case ESM::REC_LAND: mLand.load(*mReader, mBase); break; case ESM::REC_CELL: { diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index ea6eefb88..7849aab92 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -4,6 +4,7 @@ #include #include "collection.hpp" +#include "land.hpp" namespace CSMWorld { @@ -39,6 +40,22 @@ namespace CSMWorld record.load (reader, isDeleted); } + template<> + inline void IdCollection >::loadRecord (Land& record, + ESM::ESMReader& reader, bool& isDeleted) + { + record.load (reader, isDeleted); + + // Load all land data for now. A future optimisation may only load non-base data + // if a suitable mechanism for avoiding race conditions can be established. + int flags = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX; + record.loadData (flags); + + // Prevent data from being reloaded. + record.mContext.filename.clear(); + } + template int IdCollection::load (ESM::ESMReader& reader, bool base) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index c81675556..6f118c1ab 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -196,8 +196,8 @@ namespace ESM for (int i = 0; i < LAND_NUM_VERTS; ++i) { mLandData->mNormals[i*3+0] = 0; - mLandData->mNormals[i*3+1] = -1; - mLandData->mNormals[i*3+2] = 0; + mLandData->mNormals[i*3+1] = 0; + mLandData->mNormals[i*3+2] = 127; } for (int i = 0; i < LAND_NUM_TEXTURES; ++i) mLandData->mTextures[i] = 0; From d030b595f8460e92eea09052805fbfcd2fdaeef9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 11:48:13 -0400 Subject: [PATCH 014/150] Fix potential segfault, cleanup, get rid of warnings. --- apps/opencs/model/world/collection.hpp | 2 -- apps/opencs/view/render/cell.cpp | 16 ++++++++-------- apps/opencs/view/render/cell.hpp | 2 +- apps/opencs/view/world/genericcreator.cpp | 9 ++++----- apps/opencs/view/world/landcreator.cpp | 9 ++++----- components/esm/loadland.cpp | 6 +++++- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 6e74a1726..80117d0c6 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -297,7 +297,6 @@ namespace CSMWorld { int index = cloneRecordImp(origin, destination, type); mRecords.at(index).get().mPlugin = 0; - mRecords.at(index).get().mContext.filename.clear(); } template @@ -313,7 +312,6 @@ namespace CSMWorld if (index >= 0) { mRecords.at(index).get().mPlugin = 0; - mRecords.at(index).get().mContext.filename.clear(); return true; } diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 18614a85f..1c1d496bb 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -75,7 +75,7 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -void CSVRender::Cell::createLand() +void CSVRender::Cell::updateLand() { // Cell is deleted if (mDeleted) @@ -152,7 +152,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st addObjects (0, rows-1); - createLand(); + updateLand(); mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); @@ -325,32 +325,32 @@ void CSVRender::Cell::pathgridRemoved() void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - createLand(); + updateLand(); } void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::reloadAssets() diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 6418ed249..101aebd58 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -72,7 +72,7 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); - void createLand(); + void updateLand(); void unloadLand(); public: diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bd3da230d..5e2118e9b 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -262,18 +262,17 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId, void CSVWorld::GenericCreator::touch(const std::vector& ids) { // Combine multiple touch commands into one "macro" command - std::unique_ptr macro(new QUndoCommand()); - macro->setText("Touch records"); + mUndoStack.beginMacro("Touch Records"); CSMWorld::IdTable& table = dynamic_cast(*mData.getTableModel(mListId)); for (const CSMWorld::UniversalId& uid : ids) { - // This is not leaked, touchCmd is a child of macro and managed by Qt - CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId(), macro.get()); + CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId()); + mUndoStack.push(touchCmd); } // Execute - mUndoStack.push(macro.release()); + mUndoStack.endMacro(); } void CSVWorld::GenericCreator::toggleWidgets(bool active) diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index dd7bfe68d..2ebfe1869 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -55,19 +55,18 @@ namespace CSVWorld void LandCreator::touch(const std::vector& ids) { // Combine multiple touch commands into one "macro" command - std::unique_ptr macro(new QUndoCommand()); - macro->setText("Touch records"); + getUndoStack().beginMacro("Touch records"); CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); for (const CSMWorld::UniversalId& uid : ids) { - // This is not leaked, touchCmd is a child of macro and managed by Qt - CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId(), macro.get()); + CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId()); + getUndoStack().push(touchCmd); } // Execute - getUndoStack().push(macro.release()); + getUndoStack().endMacro(); } void LandCreator::focus() diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 6f118c1ab..f597defd7 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -238,7 +238,11 @@ namespace ESM // Copy data to target if no file if (mContext.filename.empty()) { - *target = *mLandData; + if (mLandData) + *target = *mLandData; + else + target = new LandData; + return; } From 25d4a0370f7022c8c83b80d99741ad9d9345e5b1 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 15:37:52 -0400 Subject: [PATCH 015/150] Changes to land data access in tables, also update Land once per frame in scene view. --- apps/opencs/model/world/columnimp.cpp | 131 ++++++++++++++++---------- apps/opencs/model/world/idtable.cpp | 3 +- apps/opencs/view/render/cell.cpp | 51 ++++++++-- apps/opencs/view/render/cell.hpp | 3 + components/esm/loadland.cpp | 9 ++ components/esm/loadland.hpp | 3 + 6 files changed, 143 insertions(+), 57 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index e6b406864..1ee7f8a03 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -10,19 +10,31 @@ namespace CSMWorld QVariant LandMapLodColumn::get(const Record& record) const { - // Note: original data is signed - const char* rawData = reinterpret_cast(&record.get().mWnam[0]); - return QByteArray(rawData, Land::LAND_GLOBAL_MAP_LOD_SIZE); + const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE; + const Land& land = record.get(); + + if (land.isDataLoaded(Land::DATA_WNAM)) + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&land.mWnam[0]); + return QByteArray(rawData, Size); + } + else + { + // Return a blank array + return QByteArray(Size, 0); + } } void LandMapLodColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_WNAM); + for (int i = 0; i < array.count(); ++i) { copy.mWnam[i] = rawData[i]; @@ -44,28 +56,34 @@ namespace CSMWorld QVariant LandNormalsColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * 3; + const Land& land = record.get(); - // Note: original data is signed - const char* rawData = reinterpret_cast(&landData->mNormals[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + if (land.isDataLoaded(Land::DATA_VNML)) + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&land.getLandData()->mNormals[0]); + return QByteArray(rawData, Size); + } + else + { + // Return a blank array + return QByteArray(Size, 0); + } } void LandNormalsColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VNML); + for (int i = 0; i < array.count(); ++i) { - landData->mNormals[i] = rawData[i]; + copy.getLandData()->mNormals[i] = rawData[i]; } record.setModified(copy); @@ -84,29 +102,34 @@ namespace CSMWorld QVariant LandHeightsColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * sizeof(float); + const Land& land = record.get(); - // Note: original data is float - const char* rawData = reinterpret_cast(&landData->mHeights[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * sizeof(float)); + if (land.isDataLoaded(Land::DATA_VHGT)) + { + // Note: original data is float + const char* rawData = reinterpret_cast(&land.getLandData()->mHeights[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandHeightsColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const float* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VHGT); + int count = array.count() / sizeof(float); for (int i = 0; i < count; ++i) { - landData->mHeights[i] = rawData[i]; + copy.getLandData()->mHeights[i] = rawData[i]; } record.setModified(copy); @@ -125,28 +148,33 @@ namespace CSMWorld QVariant LandColoursColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * 3; + const Land& land = record.get(); - // Note: original data is unsigned char - const char* rawData = reinterpret_cast(&landData->mColours[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + if (land.isDataLoaded(Land::DATA_VCLR)) + { + // Note: original data is unsigned char + const char* rawData = reinterpret_cast(&land.getLandData()->mColours[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandColoursColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const unsigned char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VCLR); + for (int i = 0; i < array.count(); ++i) { - landData->mColours[i] = rawData[i]; + copy.getLandData()->mColours[i] = rawData[i]; } record.setModified(copy); @@ -165,29 +193,34 @@ namespace CSMWorld QVariant LandTexturesColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_TEXTURES * sizeof(uint16_t); + const Land& land = record.get(); - // Note: original data is uint16_t - const char* rawData = reinterpret_cast(&landData->mTextures[0]); - return QByteArray(rawData, Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + if (land.isDataLoaded(Land::DATA_VTEX)) + { + // Note: original data is uint16_t + const char* rawData = reinterpret_cast(&land.getLandData()->mTextures[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandTexturesColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const uint16_t* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VTEX); + int count = array.count() / sizeof(uint16_t); for (int i = 0; i < count; ++i) { - landData->mTextures[i] = rawData[i]; + copy.getLandData()->mTextures[i] = rawData[i]; } record.setModified(copy); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 127ffde2c..b41eea8f8 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -356,6 +356,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. // Iteration is deterministic to avoid duplicates. + int startIndex = index; do { std::string newId = LandTexture::createUniqueRecordId(0, index); int newRow = idCollection()->searchId(newId); @@ -384,7 +385,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import size_t Prime = (1 << 13) - 1; // A mersenne prime index = (index + Prime) % MaxIndex; - } while (true); + } while (index != startIndex); } return results; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 1c1d496bb..552a54ac2 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -26,6 +26,33 @@ #include "terrainstorage.hpp" #include "object.hpp" +namespace CSVRender +{ + class CellNodeContainer : public osg::Referenced + { + public: + + CellNodeContainer(Cell* cell) : mCell(cell) {} + + Cell* getCell(){ return mCell; } + + private: + + Cell* mCell; + }; + + class CellNodeCallback : public osg::NodeCallback + { + public: + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + CellNodeContainer* container = static_cast(node->getUserData()); + container->getCell()->updateLand(); + } + }; +} + bool CSVRender::Cell::removeObject (const std::string& id) { std::map::iterator iter = @@ -77,6 +104,11 @@ bool CSVRender::Cell::addObjects (int start, int end) void CSVRender::Cell::updateLand() { + if (!mUpdateLand || mLandDeleted) + return; + + mUpdateLand = false; + // Cell is deleted if (mDeleted) { @@ -116,6 +148,7 @@ void CSVRender::Cell::updateLand() } // No land data + mLandDeleted = true; unloadLand(); } @@ -131,7 +164,7 @@ void CSVRender::Cell::unloadLand() CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), - mSubModeElementMask (0) + mSubModeElementMask (0), mUpdateLand(true), mLandDeleted(false) { std::pair result = CSMWorld::CellCoordinates::fromId (id); @@ -139,6 +172,8 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCoordinates = result.first; mCellNode = new osg::Group; + mCellNode->setUserData(new CellNodeContainer(this)); + mCellNode->setUpdateCallback(new CellNodeCallback); rootNode->addChild(mCellNode); setCellMarker(); @@ -325,32 +360,34 @@ void CSVRender::Cell::pathgridRemoved() void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - updateLand(); + mLandDeleted = true; + unloadLand(); } void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; + mLandDeleted = false; } void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::reloadAssets() diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 101aebd58..444608688 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -57,6 +57,7 @@ namespace CSVRender bool mDeleted; int mSubMode; unsigned int mSubModeElementMask; + bool mUpdateLand, mLandDeleted; /// Ignored if cell does not have an object with the given ID. /// @@ -160,6 +161,8 @@ namespace CSVRender /// Erase all overrides and restore the visual representation of the cell to its /// true state. void reset (unsigned int elementMask); + + friend class CellNodeCallback; }; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index f597defd7..1d2cf7575 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -322,6 +322,15 @@ namespace ESM return mLandData && (mLandData->mDataLoaded & flags) == (flags & mDataTypes); } + void Land::setDataLoaded(int flags) + { + if (!mLandData) + mLandData = new LandData; + + mDataTypes |= flags; + mLandData->mDataLoaded |= flags; + } + Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), mContext (land.mContext), mDataTypes (land.mDataTypes), diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index d7b736f99..7be954b3e 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -135,6 +135,9 @@ struct Land /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; + /// Sets the flags and creates a LandData if needed + void setDataLoaded(int flags); + Land (const Land& land); Land& operator= (Land land); From 09e645a0e094950891ec19a7a4dc210a0fd11ae5 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 23:18:09 -0400 Subject: [PATCH 016/150] Fix careless mistake. --- components/esm/loadland.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 1d2cf7575..083f27cef 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -238,10 +238,9 @@ namespace ESM // Copy data to target if no file if (mContext.filename.empty()) { - if (mLandData) + // Make sure there is data, and that it doesn't point to the same object. + if (mLandData && mLandData != target) *target = *mLandData; - else - target = new LandData; return; } From 2abf7f1752bfd06530425c5d33d6ae73653d90be Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 15 Sep 2017 12:19:12 -0400 Subject: [PATCH 017/150] Remove unnecessary cache dump --- components/terrain/world.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 22c65b62c..335bb496b 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -77,7 +77,6 @@ void World::updateTextureFiltering() void World::clearAssociatedCaches() { - mTextureManager->clearCache(); mChunkManager->clearCache(); } From 50d9d9f78f4f66b2721986bff2151f61282af216 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 17 Sep 2017 20:29:51 -0400 Subject: [PATCH 018/150] Get rid of some templates, exceptions instead of assert, and other small changes. --- apps/opencs/model/world/columnimp.cpp | 93 ++++++++++++++++++- apps/opencs/model/world/columnimp.hpp | 80 ++++------------ apps/opencs/model/world/columns.cpp | 2 +- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/commands.cpp | 2 +- apps/opencs/model/world/data.cpp | 8 +- apps/opencs/view/world/landtexturecreator.cpp | 4 +- components/esm/loadland.cpp | 9 +- 8 files changed, 120 insertions(+), 80 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 1ee7f8a03..6a19df0d5 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,7 +1,80 @@ #include "columnimp.hpp" +#include + namespace CSMWorld { + /* LandTextureNicknameColumn */ + LandTextureNicknameColumn::LandTextureNicknameColumn() + : Column(Columns::ColumnId_TextureNickname, ColumnBase::Display_String) + { + } + + QVariant LandTextureNicknameColumn::get(const Record& record) const + { + return QString::fromUtf8(record.get().mId.c_str()); + } + + void LandTextureNicknameColumn::set(Record& record, const QVariant& data) + { + LandTexture copy = record.get(); + copy.mId = data.toString().toUtf8().constData(); + record.setModified(copy); + } + + bool LandTextureNicknameColumn::isEditable() const + { + return true; + } + + /* LandTextureIndexColumn */ + LandTextureIndexColumn::LandTextureIndexColumn() + : Column(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + { + } + + QVariant LandTextureIndexColumn::get(const Record& record) const + { + return record.get().mIndex; + } + + bool LandTextureIndexColumn::isEditable() const + { + return false; + } + + /* LandPluginIndexColumn */ + LandPluginIndexColumn::LandPluginIndexColumn() + : Column(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) + { + } + + QVariant LandPluginIndexColumn::get(const Record& record) const + { + return record.get().mPlugin; + } + + bool LandPluginIndexColumn::isEditable() const + { + return false; + } + + /* LandTexturePluginIndexColumn */ + LandTexturePluginIndexColumn::LandTexturePluginIndexColumn() + : Column(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) + { + } + + QVariant LandTexturePluginIndexColumn::get(const Record& record) const + { + return record.get().mPluginIndex; + } + + bool LandTexturePluginIndexColumn::isEditable() const + { + return false; + } + /* LandMapLodColumn */ LandMapLodColumn::LandMapLodColumn() : Column(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0) @@ -30,7 +103,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); + + if (array.count() != Land::LAND_GLOBAL_MAP_LOD_SIZE) + throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_WNAM); @@ -76,7 +151,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + + if (array.count() != Land::LAND_NUM_VERTS * 3) + throw std::runtime_error("invalid land normals data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VNML); @@ -121,7 +198,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const float* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + + if (array.count() != Land::LAND_NUM_VERTS * sizeof(float)) + throw std::runtime_error("invalid land heights data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VHGT); @@ -167,7 +246,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const unsigned char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + + if (array.count() != Land::LAND_NUM_VERTS * 3) + throw std::runtime_error("invalid land colours data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VCLR); @@ -212,7 +293,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const uint16_t* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + + if (array.count() != Land::LAND_NUM_TEXTURES * sizeof(uint16_t)) + throw std::runtime_error("invalid land textures data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VTEX); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 8e5908bd3..025b064c6 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -67,14 +67,14 @@ namespace CSMWorld inline QVariant StringIdColumn::get(const Record& record) const { const Land& land = record.get(); - return QString(Land::createUniqueRecordId(land.mX, land.mY).c_str()); + return QString::fromUtf8(Land::createUniqueRecordId(land.mX, land.mY).c_str()); } template<> inline QVariant StringIdColumn::get(const Record& record) const { const LandTexture& ltex = record.get(); - return QString(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); + return QString::fromUtf8(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); } template @@ -2435,78 +2435,38 @@ namespace CSMWorld } }; - template - struct TextureHandleColumn : public Column + struct LandTextureNicknameColumn : public Column { - TextureHandleColumn() - : Column (Columns::ColumnId_TextureHandle, ColumnBase::Display_String) - {} - - QVariant get(const Record& record) const override - { - return QString::fromUtf8(record.get().mId.c_str()); - } + LandTextureNicknameColumn(); - void set(Record& record, const QVariant& data) override - { - ESXRecordT copy = record.get(); - copy.mId = data.toString().toUtf8().constData(); - record.setModified(copy); - } - - bool isEditable() const override - { - return true; - } + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; }; - template - struct TextureIndexColumn : public Column + struct LandTextureIndexColumn : public Column { - TextureIndexColumn() - : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) - {} + LandTextureIndexColumn(); - QVariant get(const Record& record) const override - { - return record.get().mIndex; - } - - bool isEditable() const override - { - return false; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; }; - template - struct PluginIndexColumn : public Column + struct LandPluginIndexColumn : public Column { - PluginIndexColumn() - : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0) - {} - - QVariant get(const Record& record) const override - { - return -1; - } + LandPluginIndexColumn(); - bool isEditable() const override - { - return false; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; }; - template<> - inline QVariant PluginIndexColumn::get (const Record& record) const + struct LandTexturePluginIndexColumn : public Column { - return record.get().mPlugin; - } + LandTexturePluginIndexColumn(); - template<> - inline QVariant PluginIndexColumn::get (const Record& record) const - { - return record.get().mPluginIndex; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; + }; struct LandMapLodColumn : public Column { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 63ccb6017..ec010ba36 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -330,7 +330,7 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, - { ColumnId_TextureHandle, "Texture Handle" }, + { ColumnId_TextureNickname, "Texture Nickname" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, { ColumnId_LandMapLodIndex, "Land map height LOD" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 432597105..15018795c 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,7 +329,7 @@ namespace CSMWorld ColumnId_Text = 297, - ColumnId_TextureHandle = 298, + ColumnId_TextureNickname = 298, ColumnId_PluginIndex = 299, ColumnId_TextureIndex = 300, ColumnId_LandMapLodIndex = 301, diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5bfcd6846..b654eb00d 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -48,7 +48,7 @@ CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand(IdTable& landTabl , mLtexs(ltexTable) , mOldState(0) { - setText("Import land textures"); + setText("Copy land textures to current plugin"); } void CSMWorld::ImportLandTexturesCommand::redo() diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0ffe5fa21..2216d5ca6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -415,7 +415,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new StringIdColumn); mLand.addColumn (new RecordStateColumn); mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); - mLand.addColumn (new PluginIndexColumn); + mLand.addColumn (new LandPluginIndexColumn); mLand.addColumn (new LandMapLodColumn); mLand.addColumn (new LandNormalsColumn); mLand.addColumn (new LandHeightsColumn); @@ -425,9 +425,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); - mLandTextures.addColumn (new TextureHandleColumn); - mLandTextures.addColumn (new PluginIndexColumn); - mLandTextures.addColumn (new TextureIndexColumn); + mLandTextures.addColumn (new LandTextureNicknameColumn); + mLandTextures.addColumn (new LandTexturePluginIndexColumn); + mLandTextures.addColumn (new LandTextureIndexColumn); mLandTextures.addColumn (new TextureColumn); mPathgrids.addColumn (new StringIdColumn); diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp index fdabfb281..43d911e50 100644 --- a/apps/opencs/view/world/landtexturecreator.cpp +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -45,7 +45,7 @@ namespace CSVWorld CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); - int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname); mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); @@ -79,7 +79,7 @@ namespace CSVWorld GenericCreator::configureCreateCommand(command); CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); - int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname); command.addValue(column, mName.c_str()); } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 083f27cef..f3f72e88a 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -177,17 +177,14 @@ namespace ESM void Land::blank() { - if (mLandData) - { - delete mLandData; - } - mPlugin = 0; for (int i = 0; i < LAND_GLOBAL_MAP_LOD_SIZE; ++i) mWnam[0] = 0; - mLandData = new LandData; + if (!mLandData) + mLandData = new LandData; + mLandData->mHeightOffset = 0; for (int i = 0; i < LAND_NUM_VERTS; ++i) mLandData->mHeights[i] = 0; From 186cc1e37066abe92c2117f5b14deb5fb1da4fe6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:29:34 +0200 Subject: [PATCH 019/150] Fix skins incorrectly named 'Client' to avoid a collision with new MyGUI feature cfdaf5f --- .../openmw_chargen_class_description.layout | 2 +- files/mygui/openmw_dialogue_window.layout | 2 +- files/mygui/openmw_hud_box.skin.xml | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 43b0518fd..906ca2352 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index a85bd5b02..1ed399572 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e53493bb1..a1c4f608b 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -8,27 +8,27 @@ - + - + - + - + - + @@ -36,11 +36,11 @@ - + - + @@ -48,11 +48,11 @@ - + - + From fb975d02dba79d9eb73ce3be14cb1127a8ce47ea Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:41:50 +0200 Subject: [PATCH 020/150] Use client coordinates in HBox/VBox --- components/widgets/box.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index 0ce8ce951..eeddc22dd 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -171,9 +171,11 @@ namespace Gui total_width += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } @@ -191,19 +193,19 @@ namespace Gui continue; bool vstretch = w->getUserString ("VStretch") == "true"; - int max_height = getSize().height - mPadding*2; + int max_height = getClientCoord().height - mPadding*2; int height = vstretch ? max_height : sizes[i].first.height; MyGUI::IntCoord widgetCoord; widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + widgetCoord.top = mPadding + (getClientCoord().height-mPadding*2 - height) / 2; int width = 0; if (sizes[i].second) { if (h_stretched_count == 0) throw std::logic_error("unexpected"); - width = sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count; + width = sizes[i].first.width + (getClientCoord().width-mPadding*2 - total_width)/h_stretched_count; } else width = sizes[i].first.width; @@ -317,13 +319,14 @@ namespace Gui total_height += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } - int curY = 0; for (unsigned int i = 0; i < count; ++i) { @@ -337,19 +340,19 @@ namespace Gui continue; bool hstretch = w->getUserString ("HStretch") == "true"; - int maxWidth = getSize().width - mPadding*2; + int maxWidth = getClientCoord().width - mPadding*2; int width = hstretch ? maxWidth : sizes[i].first.width; MyGUI::IntCoord widgetCoord; widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + widgetCoord.left = mPadding + (getClientCoord().width-mPadding*2 - width) / 2; int height = 0; if (sizes[i].second) { if (v_stretched_count == 0) throw std::logic_error("unexpected"); - height = sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count; + height = sizes[i].first.height + (getClientCoord().height-mPadding*2 - total_height)/v_stretched_count; } else height = sizes[i].first.height; From d07fe91cfef85dc8a530bd12237bf3ece7ef6388 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:53:59 +0200 Subject: [PATCH 021/150] Don't use MW_Dialog skin with plain Widgets After MyGUI commit cfdaf5f , the 'Client' area will be used for every type of widget, whereas previously it would only be used for some widgets like 'Window'. Use 'Window' widget where the client was always used. This fixes a wrong margin when built with cfdaf5f or later. --- files/mygui/openmw_hud.layout | 10 +++++----- files/mygui/openmw_jail_screen.layout | 6 +++--- files/mygui/openmw_loading_screen.layout | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 8fe25a5dc..366b0c4c6 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,19 +32,19 @@ - + - + - - + + - + diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout index ef37c73d8..76aa05b86 100644 --- a/files/mygui/openmw_jail_screen.layout +++ b/files/mygui/openmw_jail_screen.layout @@ -1,14 +1,14 @@ - + - + - + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 89b35d05e..69df20022 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ - + - + - + From 7dec773ea95379538aa02a8907381c3864cabcf5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 23:03:14 +0200 Subject: [PATCH 022/150] Fix global map arrow/button not showing for a split second when the window is opened for the first time --- apps/openmw/mwgui/mapwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7d81b6ab3..ed9dabd2d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1002,6 +1002,9 @@ namespace MWGui mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + + // Redraw children in proper order + mGlobalMap->getParent()->_updateChilds(); } } From 4921e7f5c1e2be8c4820bf8228ce83851ceccb16 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 21:29:40 -0400 Subject: [PATCH 023/150] Get rid of reinterpret cast. --- apps/opencs/model/world/columnimp.cpp | 129 +++++++++++++------------- apps/opencs/model/world/columnimp.hpp | 12 +++ apps/opencs/model/world/commands.cpp | 24 ++--- apps/opencs/model/world/commands.hpp | 6 +- 4 files changed, 93 insertions(+), 78 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 6a19df0d5..18da81b53 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,6 +1,7 @@ #include "columnimp.hpp" #include +#include namespace CSMWorld { @@ -86,33 +87,32 @@ namespace CSMWorld const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_WNAM)) { - // Note: original data is signed - const char* rawData = reinterpret_cast(&land.mWnam[0]); - return QByteArray(rawData, Size); - } - else - { - // Return a blank array - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.mWnam[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandMapLodColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const signed char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_GLOBAL_MAP_LOD_SIZE) + if (values.size() != Land::LAND_GLOBAL_MAP_LOD_SIZE) throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_WNAM); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.mWnam[i] = rawData[i]; + copy.mWnam[i] = values[i]; } record.setModified(copy); @@ -134,33 +134,32 @@ namespace CSMWorld const int Size = Land::LAND_NUM_VERTS * 3; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VNML)) { - // Note: original data is signed - const char* rawData = reinterpret_cast(&land.getLandData()->mNormals[0]); - return QByteArray(rawData, Size); - } - else - { - // Return a blank array - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mNormals[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandNormalsColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const signed char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * 3) + if (values.size() != Land::LAND_NUM_VERTS * 3) throw std::runtime_error("invalid land normals data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VNML); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mNormals[i] = rawData[i]; + copy.getLandData()->mNormals[i] = values[i]; } record.setModified(copy); @@ -179,36 +178,35 @@ namespace CSMWorld QVariant LandHeightsColumn::get(const Record& record) const { - const int Size = Land::LAND_NUM_VERTS * sizeof(float); + const int Size = Land::LAND_NUM_VERTS; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VHGT)) { - // Note: original data is float - const char* rawData = reinterpret_cast(&land.getLandData()->mHeights[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mHeights[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandHeightsColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const float* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * sizeof(float)) + if (values.size() != Land::LAND_NUM_VERTS) throw std::runtime_error("invalid land heights data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VHGT); - int count = array.count() / sizeof(float); - for (int i = 0; i < count; ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mHeights[i] = rawData[i]; + copy.getLandData()->mHeights[i] = values[i]; } record.setModified(copy); @@ -230,32 +228,32 @@ namespace CSMWorld const int Size = Land::LAND_NUM_VERTS * 3; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VCLR)) { - // Note: original data is unsigned char - const char* rawData = reinterpret_cast(&land.getLandData()->mColours[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mColours[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandColoursColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const unsigned char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * 3) + if (values.size() != Land::LAND_NUM_VERTS * 3) throw std::runtime_error("invalid land colours data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VCLR); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mColours[i] = rawData[i]; + copy.getLandData()->mColours[i] = values[i]; } record.setModified(copy); @@ -274,36 +272,35 @@ namespace CSMWorld QVariant LandTexturesColumn::get(const Record& record) const { - const int Size = Land::LAND_NUM_TEXTURES * sizeof(uint16_t); + const int Size = Land::LAND_NUM_TEXTURES; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VTEX)) { - // Note: original data is uint16_t - const char* rawData = reinterpret_cast(&land.getLandData()->mTextures[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mTextures[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandTexturesColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const uint16_t* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_TEXTURES * sizeof(uint16_t)) + if (values.size() != Land::LAND_NUM_TEXTURES) throw std::runtime_error("invalid land textures data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VTEX); - int count = array.count() / sizeof(uint16_t); - for (int i = 0; i < count; ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mTextures[i] = rawData[i]; + copy.getLandData()->mTextures[i] = values[i]; } record.setModified(copy); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 025b064c6..d653ddece 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2,10 +2,12 @@ #define CSM_WOLRD_COLUMNIMP_H #include +#include #include #include #include +#include #include #include @@ -2470,6 +2472,8 @@ namespace CSMWorld struct LandMapLodColumn : public Column { + using DataType = QVector; + LandMapLodColumn(); QVariant get(const Record& record) const override; @@ -2479,6 +2483,8 @@ namespace CSMWorld struct LandNormalsColumn : public Column { + using DataType = QVector; + LandNormalsColumn(); QVariant get(const Record& record) const override; @@ -2488,6 +2494,8 @@ namespace CSMWorld struct LandHeightsColumn : public Column { + using DataType = QVector; + LandHeightsColumn(); QVariant get(const Record& record) const override; @@ -2497,6 +2505,8 @@ namespace CSMWorld struct LandColoursColumn : public Column { + using DataType = QVector; + LandColoursColumn(); QVariant get(const Record& record) const override; @@ -2506,6 +2516,8 @@ namespace CSMWorld struct LandTexturesColumn : public Column { + using DataType = QVector; + LandTexturesColumn(); QVariant get(const Record& record) const override; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index b654eb00d..79900c6c4 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -58,23 +58,21 @@ void CSMWorld::ImportLandTexturesCommand::redo() // Original data int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).toByteArray(); - const uint16_t* textureData = reinterpret_cast(mOld.data()); + mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).value(); // Need to make a copy so the old values can be looked up - QByteArray newTextureByteArray(mOld.data(), mOld.size()); - uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + DataType copy(mOld); // Perform touch/copy/etc... onRedo(); // Find all indices used std::unordered_set texIndices; - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + for (int i = 0; i < mOld.size(); ++i) { // All indices are offset by 1 for a default texture - if (textureData[i] > 0) - texIndices.insert(textureData[i] - 1); + if (mOld[i] > 0) + texIndices.insert(mOld[i] - 1); } std::vector oldTextures; @@ -97,8 +95,8 @@ void CSMWorld::ImportLandTexturesCommand::redo() for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { // All indices are offset by 1 for a default texture - if (textureData[i] == oldIndex + 1) - newTextureData[i] = newIndex + 1; + if (mOld[i] == oldIndex + 1) + copy[i] = newIndex + 1; } } } @@ -107,14 +105,18 @@ void CSMWorld::ImportLandTexturesCommand::redo() int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt(); - mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), newTextureByteArray); + QVariant variant; + variant.setValue(copy); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), variant); } void CSMWorld::ImportLandTexturesCommand::undo() { // Restore to previous int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), mOld); + QVariant variant; + variant.setValue(mOld); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), variant); int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); mLands.setData(mLands.getModelIndex(getDestinationId(), stateColumn), mOldState); diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index aab0c5410..0f9d3591c 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,12 +3,14 @@ #include "record.hpp" +#include #include #include #include #include #include +#include #include #include @@ -55,6 +57,8 @@ namespace CSMWorld protected: + using DataType = QVector; + virtual const std::string& getOriginId() const = 0; virtual const std::string& getDestinationId() const = 0; @@ -63,7 +67,7 @@ namespace CSMWorld IdTable& mLands; IdTable& mLtexs; - QByteArray mOld; + DataType mOld; int mOldState; std::vector mCreatedTextures; }; From 054e6a780e2c8fa4bbf1863751020ab036e5ad96 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 22:43:45 -0400 Subject: [PATCH 024/150] Use map for texture lookup. --- apps/opencs/model/world/idtable.cpp | 39 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index b41eea8f8..2c066ff6c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -340,6 +341,15 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import { ImportResults results; + // Map existing textures to ids + std::map reverseLookupMap; + for (int i = 0; i < idCollection()->getSize(); ++i) + { + auto& record = static_cast&>(idCollection()->getRecord(i)); + if (record.isModified()) + reverseLookupMap.emplace(record.get().mTexture, idCollection()->getId(i)); + } + for (const std::string& id : ids) { int plugin, index; @@ -354,8 +364,16 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import continue; } - // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. - // Iteration is deterministic to avoid duplicates. + // Look for a pre-existing record + auto& record = static_cast&>(idCollection()->getRecord(oldRow)); + auto searchIt = reverseLookupMap.find(record.get().mTexture); + if (searchIt != reverseLookupMap.end()) + { + results.recordMapping.push_back(std::make_pair(id, searchIt->second)); + continue; + } + + // Iterate until an unused index or found, or the index has completely wrapped around. int startIndex = index; do { std::string newId = LandTexture::createUniqueRecordId(0, index); @@ -370,21 +388,8 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import break; } - // Id is taken, check if same handle and texture. Note that mId is the handle. - const LandTexture& oldLtex = dynamic_cast&>(idCollection()->getRecord(oldRow)).get(); - const LandTexture& newLtex = dynamic_cast&>(idCollection()->getRecord(newRow)).get(); - if (oldLtex.mId == newLtex.mId && oldLtex.mTexture == newLtex.mTexture) - { - // It's a match - results.recordMapping.push_back(std::make_pair(id, newId)); - break; - } - - // Determine next index. Spread out the indices to reduce conflicts. - size_t MaxIndex = std::numeric_limits::max() - 1; - size_t Prime = (1 << 13) - 1; // A mersenne prime - - index = (index + Prime) % MaxIndex; + const size_t MaxIndex = std::numeric_limits::max() - 1; + index = (index + 1) % MaxIndex; } while (index != startIndex); } From 3981f79d38af642f423b4adb5666b98a596a24f9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 22:59:50 -0400 Subject: [PATCH 025/150] Change flag for base land textures --- apps/opencs/model/world/idtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2c066ff6c..54d65ac3f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -332,7 +332,7 @@ Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) cons Qt::ItemFlags flags = IdTable::flags(index); if (!idCollection()->getRecord(index.row()).isModified()) - flags &= ~Qt::ItemIsEditable; + flags &= ~Qt::ItemIsEnabled; return flags; } From 1fe1ec63c43af800d3988081b802e690ad8d0a34 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 23:33:50 -0400 Subject: [PATCH 026/150] Fix Qt4 build --- apps/opencs/model/world/columnimp.hpp | 7 +++++++ apps/opencs/model/world/commands.hpp | 5 ++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index d653ddece..e36e386c9 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2537,4 +2537,11 @@ namespace CSMWorld }; } +// This is required to access the type as a QVariant. +Q_DECLARE_METATYPE(CSMWorld::LandMapLodColumn::DataType) +//Q_DECLARE_METATYPE(CSMWorld::LandNormalsColumn::DataType) // Same as LandMapLodColumn::DataType +Q_DECLARE_METATYPE(CSMWorld::LandHeightsColumn::DataType) +Q_DECLARE_METATYPE(CSMWorld::LandColoursColumn::DataType) +Q_DECLARE_METATYPE(CSMWorld::LandTexturesColumn::DataType) + #endif diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 0f9d3591c..be86dd508 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,17 +3,16 @@ #include "record.hpp" -#include #include #include #include #include #include -#include #include #include +#include "columnimp.hpp" #include "universalid.hpp" #include "nestedtablewrapper.hpp" @@ -57,7 +56,7 @@ namespace CSMWorld protected: - using DataType = QVector; + using DataType = LandTexturesColumn::DataType; virtual const std::string& getOriginId() const = 0; virtual const std::string& getDestinationId() const = 0; From b22fedf4ae922a0b3dab3c9f7d7b3374a921fdc8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:13:22 +0200 Subject: [PATCH 027/150] Check 'sYes' in addition to 'sOk' for message box's default keyfocus --- apps/openmw/mwgui/messagebox.cpp | 30 +++++++++++------------------- apps/openmw/mwgui/messagebox.hpp | 1 - 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index ab43df0f1..f9c445d36 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -228,8 +228,7 @@ namespace MWGui int buttonHeight = 0; MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - std::vector::const_iterator it; - for(it = buttons.begin(); it != buttons.end(); ++it) + for(std::vector::const_iterator it = buttons.begin(); it != buttons.end(); ++it) { MyGUI::Button* button = mButtonsWidget->createWidget( MyGUI::WidgetStyle::Child, @@ -289,8 +288,7 @@ namespace MWGui MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { buttonCord.left = left; buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding; @@ -319,8 +317,7 @@ namespace MWGui int top = textPadding + textSize.height + textButtonPadding; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; @@ -354,25 +351,20 @@ namespace MWGui } // Set key focus to "Ok" button - std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + std::vector keywords { "sOk", "sYes" }; + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { - if(Misc::StringUtils::ciEqual((*button)->getCaption(), ok)) + for (const std::string& keyword : keywords) { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(*button); - (*button)->eventKeyButtonPressed += MyGUI::newDelegate(this, &InteractiveMessageBox::onKeyPressed); - break; + if(Misc::StringUtils::ciEqual(MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}"), (*button)->getCaption())) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(*button); + return; + } } } } - void InteractiveMessageBox::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) - { - if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter || _key == MyGUI::KeyCode::Space) - buttonActivated(_sender); - } - void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) { buttonActivated (pressed); diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index b4121fed3..38e6590b7 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -81,7 +81,6 @@ namespace MWGui private: void buttonActivated (MyGUI::Widget* _widget); - void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char); MessageBoxManager& mMessageBoxManager; MyGUI::EditBox* mMessageWidget; From e7ad01297753e0184bd34c817a4ee79552560052 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:34:34 +0200 Subject: [PATCH 028/150] Pass repeat key events to the GUI For example, one can scroll to the last element in a list by holding down the 'Down Arrow' key. --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ components/sdlutil/sdlinputwrapper.cpp | 11 ++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e4fa8fc2b..cc41b3831 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -679,6 +679,9 @@ namespace MWInput bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); setPlayerControlsEnabled(!guiFocus); } + if (arg.repeat) + return; + if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); mJoystickLastUsed = false; diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index a76de00d1..634c4884f 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -85,14 +85,11 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mMouseListener->mouseReleased(evt.button, evt.button.button); break; case SDL_KEYDOWN: - if (!evt.key.repeat) - { - mKeyboardListener->keyPressed(evt.key); + mKeyboardListener->keyPressed(evt.key); - if (!isModifierHeld(KMOD_ALT) && evt.key.keysym.sym >= SDLK_F1 && evt.key.keysym.sym <= SDLK_F12) - { - mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F1 + (evt.key.keysym.sym - SDLK_F1)); - } + if (!isModifierHeld(KMOD_ALT) && evt.key.keysym.sym >= SDLK_F1 && evt.key.keysym.sym <= SDLK_F12) + { + mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F1 + (evt.key.keysym.sym - SDLK_F1)); } break; From c11fe6788fff68a73444c60409d6551f13678995 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:52:39 +0200 Subject: [PATCH 029/150] Add basic keyboard navigation for the GUI (Shift)Tab cycles, arrow keys move to the next button in that direction, Enter/Space accepts. Note: Unless MyGUI is hacked to bits, clicking on an empty space will annoyingly reset the key focus. Not sure how to deal with that yet. The visual highlight for selected buttons requires MyGUI commit 632d007429d0bf0c7d7f6c5db4a08353a63dd839 or later to appear (to be released in 3.2.3). --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 4 + apps/openmw/mwgui/keyboardnavigation.cpp | 140 +++++++++++++++++++++++ apps/openmw/mwgui/keyboardnavigation.hpp | 27 +++++ apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 5 + apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- files/mygui/openmw_button.skin.xml | 1 + 8 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 apps/openmw/mwgui/keyboardnavigation.cpp create mode 100644 apps/openmw/mwgui/keyboardnavigation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 00ae2fa4a..43952afdb 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -42,7 +42,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen itemchargeview + draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4560ab270..37c3ce0d3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include "../mwgui/mode.hpp" namespace Loading @@ -368,6 +370,8 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp new file mode 100644 index 000000000..840a12f1e --- /dev/null +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -0,0 +1,140 @@ +#include "keyboardnavigation.hpp" + +#include +#include +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +namespace MWGui +{ + +/// Recursively get all child widgets that accept keyboard input +void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) +{ + MyGUI::EnumeratorWidgetPtr enumerator = parent->getEnumerator(); + while (enumerator.next()) + { + MyGUI::Widget* w = enumerator.current(); + if (!w->getVisible() || !w->getEnabled()) + continue; + if (w->getNeedKeyFocus()) + results.push_back(w); + else + getKeyFocusWidgets(w, results); + } +} + +KeyboardNavigation::KeyboardNavigation() +{ +} + +KeyboardNavigation::~KeyboardNavigation() +{ +} + +bool isButtonFocus() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + return focus->getTypeName().find("Button") != std::string::npos; +} + +enum Direction +{ + D_Left, + D_Up, + D_Right, + D_Down, + D_Next, + D_Prev +}; + +bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) +{ + switch (key.getValue()) + { + case MyGUI::KeyCode::ArrowLeft: + return switchFocus(D_Left, false); + case MyGUI::KeyCode::ArrowRight: + return switchFocus(D_Right, false); + case MyGUI::KeyCode::ArrowUp: + return switchFocus(D_Up, false); + case MyGUI::KeyCode::ArrowDown: + return switchFocus(D_Down, false); + case MyGUI::KeyCode::Tab: + return switchFocus(MyGUI::InputManager::getInstance().isShiftPressed() ? D_Prev : D_Next, true); + case MyGUI::KeyCode::Return: + case MyGUI::KeyCode::NumpadEnter: + case MyGUI::KeyCode::Space: + return accept(); + default: + return false; + } +} + +bool KeyboardNavigation::switchFocus(int direction, bool wrap) +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus) + return false; + + if (!isButtonFocus() && direction != D_Prev && direction != D_Next) + return false; + + MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + while (window->getParent()) + window = window->getParent(); + + MyGUI::VectorWidgetPtr keyFocusList; + getKeyFocusWidgets(window, keyFocusList); + + if (keyFocusList.empty()) + return false; + + MyGUI::VectorWidgetPtr::iterator found = std::find(keyFocusList.begin(), keyFocusList.end(), focus); + if (found == keyFocusList.end()) + return false; + + bool forward = (direction == D_Next || direction == D_Right || direction == D_Down); + + int index = found - keyFocusList.begin(); + index = forward ? (index+1) : (index-1); + if (wrap) + index = (index + keyFocusList.size())%keyFocusList.size(); + else + index = std::min(std::max(0, index), static_cast(keyFocusList.size())-1); + + MyGUI::Widget* next = keyFocusList[index]; + int vertdiff = next->getTop() - focus->getTop(); + int horizdiff = next->getLeft() - focus->getLeft(); + if (direction == D_Right && horizdiff <= 0) + return false; + else if (direction == D_Left && horizdiff >= 0) + return false; + else if (direction == D_Down && vertdiff <= 0) + return false; + else if (direction == D_Up && vertdiff >= 0) + return false; + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[index]); + return true; +} + +bool KeyboardNavigation::accept() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus) + return false; + //MyGUI::Button* button = focus->castType(false); + //if (button && button->getEnabled()) + if (focus->getTypeName().find("Button") != std::string::npos && focus->getEnabled()) + { + focus->eventMouseButtonClick(focus); + return true; + } + return false; +} + + +} diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp new file mode 100644 index 000000000..86cc67962 --- /dev/null +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_MWGUI_KEYBOARDNAVIGATION_H +#define OPENMW_MWGUI_KEYBOARDNAVIGATION_H + +#include + +namespace MWGui +{ + + class KeyboardNavigation + { + public: + KeyboardNavigation(); + ~KeyboardNavigation(); + + /// @return Was the key handled by this class? + bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + + private: + bool switchFocus(int direction, bool wrap); + + /// Send button press event to focused button + bool accept(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1526949a3..5d7a54735 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -112,6 +112,7 @@ #include "controllers.hpp" #include "jailscreen.hpp" #include "itemchargeview.hpp" +#include "keyboardnavigation.hpp" namespace { @@ -248,6 +249,8 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); + mKeyboardNavigation.reset(new KeyboardNavigation()); + mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); //set up the hardware cursor manager @@ -433,6 +436,8 @@ namespace MWGui WindowManager::~WindowManager() { + mKeyboardNavigation.reset(); + MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear(); MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear(); @@ -2202,4 +2207,11 @@ namespace MWGui return mTextColours; } + bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) + { + if (!mKeyboardNavigation->injectKeyPress(key, text)) + return MyGUI::InputManager::getInstance().injectKeyPress(key, text); + else + return true; + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 4f06afb7d..3e17046df 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -122,6 +122,7 @@ namespace MWGui class ScreenFader; class DebugWindow; class JailScreen; + class KeyboardNavigation; class WindowManager : public MWBase::WindowManager { @@ -397,6 +398,8 @@ namespace MWGui virtual const MWGui::TextColours& getTextColours(); + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + private: const MWWorld::ESMStore* mStore; Resource::ResourceSystem* mResourceSystem; @@ -522,6 +525,8 @@ namespace MWGui MWGui::TextColours mTextColours; + std::unique_ptr mKeyboardNavigation; + /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cc41b3831..33f1edb6c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -676,7 +676,7 @@ namespace MWInput { consumed = SDL_IsTextInputActive() && ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)); // Little trick to check if key is printable - bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + bool guiFocus = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); setPlayerControlsEnabled(!guiFocus); } if (arg.repeat) diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 5aee8de7a..ac9bf042d 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -71,6 +71,7 @@ + From 1ad14b232fd93d4f96493169830969f42b2fe498 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:57:01 +0200 Subject: [PATCH 030/150] Adjust ImageButton to accept key focus and use the 'highlighted' texture --- components/widgets/imagebutton.cpp | 54 +++++++++++++++++++++++++----- components/widgets/imagebutton.hpp | 11 ++++++ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/components/widgets/imagebutton.cpp b/components/widgets/imagebutton.cpp index 8e3f8ed69..ab0739c2c 100644 --- a/components/widgets/imagebutton.cpp +++ b/components/widgets/imagebutton.cpp @@ -5,6 +5,15 @@ namespace Gui { + ImageButton::ImageButton() + : Base() + , mMouseFocus(false) + , mMousePress(false) + , mKeyFocus(false) + { + setNeedKeyFocus(true); + } + void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value) { if (_key == "ImageHighlighted") @@ -24,22 +33,36 @@ namespace Gui } void ImageButton::onMouseSetFocus(Widget* _old) { - setImageTexture(mImageHighlighted); - ImageBox::onMouseSetFocus(_old); + mMouseFocus = true; + updateImage(); + Base::onMouseSetFocus(_old); } void ImageButton::onMouseLostFocus(Widget* _new) { - setImageTexture(mImageNormal); - ImageBox::onMouseLostFocus(_new); + mMouseFocus = false; + updateImage(); + Base::onMouseLostFocus(_new); } void ImageButton::onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id) { if (_id == MyGUI::MouseButton::Left) - setImageTexture(mImagePushed); + { + mMousePress = true; + updateImage(); + } + Base::onMouseButtonPressed(_left, _top, _id); + } - ImageBox::onMouseButtonPressed(_left, _top, _id); + void ImageButton::updateImage() + { + if (mMousePress) + setImageTexture(mImagePushed); + else if (mMouseFocus || mKeyFocus) + setImageTexture(mImageHighlighted); + else + setImageTexture(mImageNormal); } MyGUI::IntSize ImageButton::getRequestedSize() @@ -70,8 +93,23 @@ namespace Gui void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) { if (_id == MyGUI::MouseButton::Left) - setImageTexture(mImageHighlighted); + { + mMousePress = false; + updateImage(); + } + + Base::onMouseButtonReleased(_left, _top, _id); + } - ImageBox::onMouseButtonReleased(_left, _top, _id); + void ImageButton::onKeySetFocus(MyGUI::Widget *_old) + { + mKeyFocus = true; + updateImage(); + } + + void ImageButton::onKeyLostFocus(MyGUI::Widget *_new) + { + mKeyFocus = false; + updateImage(); } } diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index a539f15c9..509b1c8c2 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -16,19 +16,30 @@ namespace Gui public: MyGUI::IntSize getRequestedSize(); + ImageButton(); + /// Set mImageNormal, mImageHighlighted and mImagePushed based on file convention (image_idle.ext, image_over.ext and image_pressed.ext) void setImage(const std::string& image); + private: + void updateImage(); + protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); virtual void onMouseLostFocus(MyGUI::Widget* _new); virtual void onMouseSetFocus(MyGUI::Widget* _old); virtual void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id); virtual void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id); + virtual void onKeySetFocus(MyGUI::Widget* _old); + virtual void onKeyLostFocus(MyGUI::Widget* _new); std::string mImageHighlighted; std::string mImageNormal; std::string mImagePushed; + + bool mMouseFocus; + bool mMousePress; + bool mKeyFocus; }; } From c203a0774a5cabd46919c149b82c3c38895de90b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:58:05 +0200 Subject: [PATCH 031/150] Adjust some layouts to take better advantage of keyboard navigation --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +-- apps/openmw/mwgui/confirmationdialog.cpp | 5 ++++ apps/openmw/mwgui/dialogue.cpp | 11 ++++----- apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/mainmenu.cpp | 24 +++++++++++++++---- files/mygui/openmw_confirmation_dialog.layout | 1 + .../openmw_interactive_messagebox.layout | 1 + files/mygui/openmw_savegame_dialog.layout | 1 + files/mygui/openmw_trade_window.layout | 7 +++--- 9 files changed, 39 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index fa5bfbe2f..6da1f7806 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -139,8 +139,6 @@ namespace MWDialogue // If the dialogue window was already open, keep the existing history bool resetHistory = (!MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue)); - win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -156,6 +154,7 @@ namespace MWDialogue { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); + win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); creatureStats.talkedToPlayer(); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 33f8dbe3e..f3a06f245 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -3,6 +3,9 @@ #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { ConfirmationDialog::ConfirmationDialog() : @@ -38,6 +41,8 @@ namespace MWGui mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height + 24); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton); + center(); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2e80301d2..9f59cd443 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -259,9 +259,8 @@ namespace MWGui getWidget(mTopicsList, "TopicsList"); mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); - byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); + getWidget(mGoodbyeButton, "ByeButton"); + mGoodbyeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); getWidget(mDispositionBar, "Disposition"); getWidget(mDispositionText,"DispositionText"); @@ -360,6 +359,8 @@ namespace MWGui void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory) { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + mGoodbye = false; mEnabled = true; bool sameActor = (mPtr == actor); @@ -528,10 +529,8 @@ namespace MWGui onScrollbarMoved(mScrollBar, 0); } - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); bool goodbyeEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() || mGoodbye; - byeButton->setEnabled(goodbyeEnabled); + mGoodbyeButton->setEnabled(goodbyeEnabled); bool topicsEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye; mTopicsList->setEnabled(topicsEnabled); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5b5ae5b68..9f0b2245a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -169,6 +169,7 @@ namespace MWGui MyGUI::ScrollBar* mScrollBar; MyGUI::ProgressBar* mDispositionBar; MyGUI::TextBox* mDispositionText; + MyGUI::Button* mGoodbyeButton; PersuasionDialog mPersuasionDialog; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 5a435b9cf..265b08fd6 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -56,9 +56,24 @@ namespace MWGui if (visible) updateMenu(); - showBackground( - MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && - MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); + bool isMainMenu = + MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && + MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; + + showBackground(isMainMenu); + + if (visible) + { + if (isMainMenu) + { + if (mButtons["loadgame"]->getVisible()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["loadgame"]); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["newgame"]); + } + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["return"]); + } Layout::setVisible (visible); } @@ -231,7 +246,8 @@ namespace MWGui buttons.push_back("exitgame"); // Create new buttons if needed - for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) + std::vector allButtons { "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame"}; + for (std::vector::iterator it = allButtons.begin(); it != allButtons.end(); ++it) { if (mButtons.find(*it) == mButtons.end()) { diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index 39e77cb93..c5eb573a7 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -10,6 +10,7 @@ + diff --git a/files/mygui/openmw_interactive_messagebox.layout b/files/mygui/openmw_interactive_messagebox.layout index 50bc178ed..410426656 100644 --- a/files/mygui/openmw_interactive_messagebox.layout +++ b/files/mygui/openmw_interactive_messagebox.layout @@ -9,6 +9,7 @@ + diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index f18218430..a7b7703de 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -46,6 +46,7 @@ + diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 6d5dfb89b..f9f24581f 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -48,6 +48,10 @@ + + + + @@ -60,9 +64,6 @@ - - - From 5482ad0482cc242069a80df6a3adb21bd38b8600 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 17:03:31 +0200 Subject: [PATCH 032/150] Fix tab completion in console to not cycle key focus --- apps/openmw/mwgui/keyboardnavigation.cpp | 3 +++ files/mygui/openmw_console.layout | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 840a12f1e..ba09ce369 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -82,6 +82,9 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) if (!isButtonFocus() && direction != D_Prev && direction != D_Next) return false; + if ((direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + return false; + MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); while (window->getParent()) window = window->getParent(); diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index 854568f9b..103cdcf14 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -18,6 +18,7 @@ + From 01391b7eed79925623348a29cdd1ee4abe35edb8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 17:10:53 +0200 Subject: [PATCH 033/150] Rename WindowBase's open/close to onOpen/onClose --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/birth.cpp | 4 ++-- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/class.cpp | 8 ++++---- apps/openmw/mwgui/class.hpp | 4 ++-- apps/openmw/mwgui/console.cpp | 4 ++-- apps/openmw/mwgui/console.hpp | 4 ++-- apps/openmw/mwgui/container.cpp | 4 ++-- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 4 ++-- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 6 +++--- apps/openmw/mwgui/mapwindow.hpp | 4 ++-- apps/openmw/mwgui/merchantrepair.cpp | 2 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 4 ++-- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/race.cpp | 6 +++--- apps/openmw/mwgui/race.hpp | 4 ++-- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/recharge.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 4 ++-- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/savegamedialog.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 2 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 6 +++--- apps/openmw/mwgui/spellcreationdialog.hpp | 4 ++-- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.hpp | 2 +- apps/openmw/mwgui/textinput.cpp | 4 ++-- apps/openmw/mwgui/textinput.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 4 ++-- apps/openmw/mwgui/waitdialog.hpp | 4 ++-- apps/openmw/mwgui/windowbase.cpp | 8 ++++---- apps/openmw/mwgui/windowbase.hpp | 8 ++++---- 51 files changed, 82 insertions(+), 82 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 7379f3613..c68bad02a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -101,7 +101,7 @@ namespace MWGui update(); } - void AlchemyWindow::open() + void AlchemyWindow::onOpen() { mAlchemy->setAlchemist (MWMechanics::getPlayer()); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index e1f48d4a3..8b7bcaaca 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -24,7 +24,7 @@ namespace MWGui public: AlchemyWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index ecc011fc1..b4a6b7d2f 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -64,9 +64,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void BirthDialog::open() + void BirthDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); updateBirths(); updateSpells(); } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index c8ec9da09..c13d49838 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -20,7 +20,7 @@ namespace MWGui void setBirthId(const std::string &raceId); void setNextButtonShow(bool shown); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e1f5a165e..2278b5141 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -125,9 +125,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void PickClassDialog::open() + void PickClassDialog::onOpen() { - WindowModal::open (); + WindowModal::onOpen (); updateClasses(); updateStats(); } @@ -341,9 +341,9 @@ namespace MWGui } } - void InfoBoxDialog::open() + void InfoBoxDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); // Fix layout layoutVertically(mTextBox, 4); layoutVertically(mButtonBar, 6); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 8206d6b03..2b205d12f 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -21,7 +21,7 @@ namespace MWGui std::string getText() const; void setButtons(ButtonList &buttons); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; @@ -100,7 +100,7 @@ namespace MWGui void setClassId(const std::string &classId); void setNextButtonShow(bool shown); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index aeff7dc39..62690a0f1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -145,14 +145,14 @@ namespace MWGui mCompilerContext.setExtensions (&mExtensions); } - void Console::open() + void Console::onOpen() { // Give keyboard focus to the combo box whenever the console is // turned on MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine); } - void Console::close() + void Console::onClose() { // Apparently, hidden widgets can retain key focus // Remove for MyGUI 3.2.2 diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 98e46a559..1232036ca 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -39,8 +39,8 @@ namespace MWGui Console(int w, int h, bool consoleOnlyScripts); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); virtual void exit(); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c9be21322..4f9201f06 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -172,9 +172,9 @@ namespace MWGui mSortModel = NULL; } - void ContainerWindow::close() + void ContainerWindow::onClose() { - WindowBase::close(); + WindowBase::onClose(); if (dynamic_cast(mModel) // Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 520bce9d9..65cfa35c7 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -34,7 +34,7 @@ namespace MWGui ContainerWindow(DragAndDrop* dragAndDrop); void openContainer(const MWWorld::Ptr& container, bool loot=false); - virtual void close(); + virtual void onClose(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 9f59cd443..d9954a792 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -73,9 +73,9 @@ namespace MWGui setVisible(false); } - void PersuasionDialog::open() + void PersuasionDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 9f0b2245a..682baef3c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -28,7 +28,7 @@ namespace MWGui public: PersuasionDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index c7d2ef7de..25568da07 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -60,7 +60,7 @@ namespace MWGui delete mItemSelectionDialog; } - void EnchantingDialog::open() + void EnchantingDialog::onOpen() { center(); } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index cb7c6c0d0..7c49ae54a 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -19,7 +19,7 @@ namespace MWGui EnchantingDialog(); virtual ~EnchantingDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 6eb0c554e..dcfb075db 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -363,7 +363,7 @@ namespace MWGui dirtyPreview(); } - void InventoryWindow::open() + void InventoryWindow::onOpen() { if (!mPtr.isEmpty()) { diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 761464540..fb5be3493 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -35,7 +35,7 @@ namespace MWGui public: InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem); - virtual void open(); + virtual void onOpen(); /// start trading, disables item drag&drop void setTrading(bool trading); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index e96cc8b70..73b196cf8 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -211,7 +211,7 @@ namespace button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0)); } - void open() + void onOpen() { if (!MWBase::Environment::get().getWindowManager ()->getJournalAllowed ()) { @@ -240,7 +240,7 @@ namespace updateShowingPages(); } - void close() + void onClose() { mModel->unload (); diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index da8e93279..a068d71f3 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -128,7 +128,7 @@ namespace MWGui setAttributeValues(); } - void LevelupDialog::open() + void LevelupDialog::onOpen() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index d49f7536d..36810665e 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -11,7 +11,7 @@ namespace MWGui public: LevelupDialog(); - virtual void open(); + virtual void onOpen(); private: MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index ed9dabd2d..7bc66fab4 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -943,7 +943,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); } - void MapWindow::open() + void MapWindow::onOpen() { ensureGlobalMapLoaded(); @@ -1107,9 +1107,9 @@ namespace MWGui return MyGUI::TextIterator::getOnlyText(mTextEdit->getCaption()); } - void EditNoteDialog::open() + void EditNoteDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 312447a24..eae1cec7e 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -169,7 +169,7 @@ namespace MWGui public: EditNoteDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void showDeleteButton(bool show); @@ -218,7 +218,7 @@ namespace MWGui void ensureGlobalMapLoaded(); - virtual void open(); + virtual void onOpen(); void onFrame(float dt); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 9e27c0154..9c706851f 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -111,7 +111,7 @@ void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) mList->setViewOffset(MyGUI::IntPoint(0, static_cast(mList->getViewOffset().top + _rel*0.3f))); } -void MerchantRepair::open() +void MerchantRepair::onOpen() { center(); // Reset scrollbars diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 8dcdfee12..5006b08a4 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -12,7 +12,7 @@ class MerchantRepair : public WindowBase public: MerchantRepair(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index f9c445d36..6b5ba506b 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -200,7 +200,7 @@ namespace MWGui , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { - WindowModal::open(); + WindowModal::onOpen(); int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 10; // padding between the text-widget und the button-widget diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index e912193bf..19dd6fa03 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -590,9 +590,9 @@ namespace MWGui mParent->onAssignMagicCancel(); } - void MagicSelectionDialog::open () + void MagicSelectionDialog::onOpen () { - WindowModal::open(); + WindowModal::onOpen(); mMagicList->setModel(new SpellModel(MWMechanics::getPlayer())); mMagicList->resetScrollbars(); diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 64db9043e..d07cdef3d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -94,7 +94,7 @@ namespace MWGui public: MagicSelectionDialog(QuickKeysMenu* parent); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 047f65263..374a5d3d8 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -120,9 +120,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void RaceDialog::open() + void RaceDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); updateRaces(); updateSkills(); @@ -183,7 +183,7 @@ namespace MWGui updateSpellPowers(); } - void RaceDialog::close() + void RaceDialog::onClose() { mPreviewImage->setRenderItemTexture(NULL); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index b762745cd..911bce577 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -51,8 +51,8 @@ namespace MWGui void setGender(Gender gender) { mGenderIndex = gender == GM_Male ? 0 : 1; } void setNextButtonShow(bool shown); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 390a1f83c..00af45695 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -50,7 +50,7 @@ Recharge::Recharge() setVisible(false); } -void Recharge::open() +void Recharge::onOpen() { center(); diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index cc3db14df..d963e9d66 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -22,7 +22,7 @@ class Recharge : public WindowBase public: Recharge(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 4d6441450..f917cef0f 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -46,7 +46,7 @@ Repair::Repair() mToolIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onSelectItem); } -void Repair::open() +void Repair::onOpen() { center(); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index c50ba861a..44c380b51 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -19,7 +19,7 @@ class Repair : public WindowBase public: Repair(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index bf18e7355..61a7a2ac0 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -101,9 +101,9 @@ namespace MWGui okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); } - void ReviewDialog::open() + void ReviewDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); mUpdateSkillArea = true; } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index f21f2fa9d..34dd5a7d4 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -45,7 +45,7 @@ namespace MWGui void configureSkills(const SkillList& major, const SkillList& minor); void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value); - virtual void open(); + virtual void onOpen(); void onFrame(float duration); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 84d4ca959..7a4c3a22e 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -118,9 +118,9 @@ namespace MWGui accept(); } - void SaveGameDialog::open() + void SaveGameDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); mSaveNameEdit->setCaption (""); if (mSaving) diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index be0e47cab..2a49cf48a 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -17,7 +17,7 @@ namespace MWGui public: SaveGameDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index f46199c80..4e8547d33 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -553,7 +553,7 @@ namespace MWGui updateControlsBox (); } - void SettingsWindow::open() + void SettingsWindow::onOpen() { updateControlsBox (); resetScrollbars(); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 2ac06dcaa..447331574 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -15,7 +15,7 @@ namespace MWGui public: SettingsWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 354253fa4..6a36554d8 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -96,9 +96,9 @@ namespace MWGui mConstantEffect = constant; } - void EditEffectDialog::open() + void EditEffectDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); } @@ -415,7 +415,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } - void SpellCreationDialog::open() + void SpellCreationDialog::onOpen() { center(); } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 6cdf74d10..d12115c88 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -23,7 +23,7 @@ namespace MWGui public: EditEffectDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void setConstantEffect(bool constant); @@ -150,7 +150,7 @@ namespace MWGui public: SpellCreationDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void startSpellMaking(MWWorld::Ptr actor); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 5ce3fd1fe..9261912b4 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -62,7 +62,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); } - void SpellWindow::open() + void SpellWindow::onOpen() { updateSpells(); } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index dcce10f9d..f8fead9ea 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -37,7 +37,7 @@ namespace MWGui virtual void onPinToggled(); virtual void onTitleDoubleClicked(); - virtual void open(); + virtual void onOpen(); SpellView* mSpellView; SpellIcons* mSpellIcons; diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 1fe3cb68d..487953e00 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -37,7 +37,7 @@ namespace MWGui void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } void updateSkillArea(); - virtual void open() { onWindowResize(mMainWidget->castType()); } + virtual void onOpen() { onWindowResize(mMainWidget->castType()); } private: void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 958b52dc0..169c9e742 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -42,9 +42,9 @@ namespace MWGui setText("LabelT", label); } - void TextInputDialog::open() + void TextInputDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); // Make sure the edit box has focus MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index 57dd34dd6..ccfa19c87 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -20,7 +20,7 @@ namespace MWGui void setNextButtonShow(bool shown); void setTextLabel(const std::string &label); - virtual void open(); + virtual void onOpen(); /** Event : Dialog finished, OK button clicked.\n signature : void method()\n diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 82218fef1..d2e771918 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -55,7 +55,7 @@ namespace MWGui mProgressBar.setVisible(false); } - void TrainingWindow::open() + void TrainingWindow::onOpen() { center(); } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 7c4582062..95a35be7f 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -14,7 +14,7 @@ namespace MWGui public: TrainingWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index ba58a9c69..476d19bd6 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -35,7 +35,7 @@ namespace MWGui getWidget(mProgressText, "ProgressText"); } - void WaitDialogProgressBar::open() + void WaitDialogProgressBar::onOpen() { center(); } @@ -85,7 +85,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode(); } - void WaitDialog::open() + void WaitDialog::onOpen() { if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 13df1f8ae..829659d16 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -13,7 +13,7 @@ namespace MWGui public: WaitDialogProgressBar(); - virtual void open(); + virtual void onOpen(); void setProgress(int cur, int total); @@ -27,7 +27,7 @@ namespace MWGui public: WaitDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 99b74529e..1ba4c7ed6 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -23,9 +23,9 @@ void WindowBase::setVisible(bool visible) mMainWidget->setVisible(visible); if (visible) - open(); + onOpen(); else if (wasVisible && !visible) - close(); + onClose(); // This is needed as invisible widgets can retain key focus. // Remove for MyGUI 3.2.2 @@ -64,13 +64,13 @@ WindowModal::WindowModal(const std::string& parLayout) { } -void WindowModal::open() +void WindowModal::onOpen() { MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed } -void WindowModal::close() +void WindowModal::onClose() { MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 43fb8901e..400dc0ce4 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -22,9 +22,9 @@ namespace MWGui typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; /// Notify that window has been made visible - virtual void open() {} + virtual void onOpen() {} /// Notify that window has been hidden - virtual void close () {} + virtual void onClose () {} /// Gracefully exits the window virtual void exit() {} /// Sets the visibility of the window @@ -42,8 +42,8 @@ namespace MWGui { public: WindowModal(const std::string& parLayout); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); virtual void exit() {} }; From 622e3ebd60f2de42e7a6e15a947c7bab1a6db606 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 20:43:53 +0200 Subject: [PATCH 034/150] Remove excessive padding in some GUI layouts --- ...openmw_chargen_generate_class_result.layout | 2 +- files/mygui/openmw_recharge_dialog.layout | 2 +- files/mygui/openmw_repair.layout | 2 +- files/mygui/openmw_savegame_dialog.layout | 2 +- files/mygui/openmw_tooltips.layout | 18 +++++++++--------- files/mygui/openmw_wait_dialog.layout | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/files/mygui/openmw_chargen_generate_class_result.layout b/files/mygui/openmw_chargen_generate_class_result.layout index 83595fafd..d49f57dde 100644 --- a/files/mygui/openmw_chargen_generate_class_result.layout +++ b/files/mygui/openmw_chargen_generate_class_result.layout @@ -3,7 +3,7 @@ - + diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index d620aadab..200d345e3 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index 340711bb1..abc429594 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index a7b7703de..236eaaa61 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index a7eeabfa5..c038066f1 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -32,7 +32,7 @@ - + @@ -44,7 +44,7 @@ - + @@ -61,7 +61,7 @@ - + @@ -77,7 +77,7 @@ - + @@ -137,7 +137,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -211,7 +211,7 @@ - + @@ -245,7 +245,7 @@ - + @@ -277,7 +277,7 @@ - + diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 112fa6001..4bc60ceb4 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -2,7 +2,7 @@ - + From 3820416277802709b03d29749535443b1c3913d7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 20:46:08 +0200 Subject: [PATCH 035/150] Refactor the unholy mess that is WindowManager::updateVisible GUI modes are now defined in a general and extensible way. The next commits are going to take advantage of this. --- apps/openmw/mwgui/journalwindow.cpp | 10 +- apps/openmw/mwgui/journalwindow.hpp | 6 +- apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/mainmenu.hpp | 4 +- apps/openmw/mwgui/messagebox.cpp | 3 +- apps/openmw/mwgui/windowbase.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 314 +++++++++++-------------- apps/openmw/mwgui/windowmanagerimp.hpp | 19 ++ 8 files changed, 177 insertions(+), 182 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 73b196cf8..a0e424021 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -44,7 +44,7 @@ namespace static char const LeftTopicIndex [] = "LeftTopicIndex"; static char const RightTopicIndex [] = "RightTopicIndex"; - struct JournalWindowImpl : MWGui::WindowBase, MWGui::JournalBooks, MWGui::JournalWindow + struct JournalWindowImpl : MWGui::JournalBooks, MWGui::JournalWindow { struct DisplayState { @@ -94,7 +94,7 @@ namespace } JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) - : WindowBase("openmw_journal.layout"), JournalBooks (Model) + : JournalBooks (Model), JournalWindow() { mMainWidget->setVisible(false); center(); @@ -603,3 +603,9 @@ MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model { return new JournalWindowImpl (Model, questList); } + +MWGui::JournalWindow::JournalWindow() + :WindowBase("openmw_journal.layout") +{ + +} diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cc645ca44..c9bf0ef0a 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H +#include "windowbase.hpp" + #include namespace MWBase { class WindowManager; } @@ -9,8 +11,10 @@ namespace MWGui { struct JournalViewModel; - struct JournalWindow + struct JournalWindow : public WindowBase { + JournalWindow(); + /// construct a new instance of the one JournalWindow implementation static JournalWindow * create (std::shared_ptr Model, bool questList); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 265b08fd6..657f0e4ec 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -22,7 +22,7 @@ namespace MWGui { MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription) - : Layout("openmw_mainmenu.layout") + : WindowBase("openmw_mainmenu.layout") , mWidth (w), mHeight (h) , mVFS(vfs), mButtonBox(0) , mBackground(NULL) diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index fe256dc8e..612f7d1bd 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_GAME_MWGUI_MAINMENU_H #define OPENMW_GAME_MWGUI_MAINMENU_H -#include "layout.hpp" +#include "windowbase.hpp" namespace Gui { @@ -20,7 +20,7 @@ namespace MWGui class SaveGameDialog; class VideoWidget; - class MainMenu : public Layout + class MainMenu : public WindowBase { int mWidth; int mHeight; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 6b5ba506b..dd0495051 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -77,6 +77,7 @@ namespace MWGui if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { mLastButtonPressed = mInterMessageBoxe->readPressedButton(); + mInterMessageBoxe->setVisible(false); delete mInterMessageBoxe; mInterMessageBoxe = NULL; MWBase::Environment::get().getInputManager()->changeInputMode( @@ -200,7 +201,7 @@ namespace MWGui , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { - WindowModal::onOpen(); + setVisible(true); int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 10; // padding between the text-widget und the button-widget diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 1ba4c7ed6..5ed564737 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -15,6 +15,7 @@ using namespace MWGui; WindowBase::WindowBase(const std::string& parLayout) : Layout(parLayout) { + mMainWidget->setVisible(false); } void WindowBase::setVisible(bool visible) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5d7a54735..81edc4a00 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -320,51 +320,103 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); mRecharge = new Recharge(); + mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); + mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); + mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); + mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); mMap->renderGlobalMap(); trackWindow(mMap, "map"); mStatsWindow = new StatsWindow(mDragAndDrop); trackWindow(mStatsWindow, "stats"); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); + mSpellWindow = new SpellWindow(mDragAndDrop); + trackWindow(mSpellWindow, "spells"); + + mGuiModeStates[GM_Inventory] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); + mGuiModeStates[GM_None] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); + + mTradeWindow = new TradeWindow(); + trackWindow(mTradeWindow, "barter"); + + mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); + mConsole = new Console(w,h, mConsoleOnlyScripts); trackWindow(mConsole, "console"); + mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); mJournal = JournalWindow::create(JournalViewModel::create (), questList); + mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); - mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); - mTradeWindow = new TradeWindow(); - trackWindow(mTradeWindow, "barter"); mSpellBuyingWindow = new SpellBuyingWindow(); + mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); + mTravelWindow = new TravelWindow(); + mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); + mDialogueWindow = new DialogueWindow(); trackWindow(mDialogueWindow, "dialogue"); + mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); + mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); + mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); + mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); + mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); + mBookWindow = new BookWindow(); + mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); + mCountDialog = new CountDialog(); mSettingsWindow = new SettingsWindow(); + mGuiModeStates[GM_Settings] = GuiModeState(mSettingsWindow); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); trackWindow(mAlchemyWindow, "alchemy"); - mSpellWindow = new SpellWindow(mDragAndDrop); - trackWindow(mSpellWindow, "spells"); + mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); + mQuickKeysMenu = new QuickKeysMenu(); + mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); + mLevelupDialog = new LevelupDialog(); + mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); + mWaitDialog = new WaitDialog(); + mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); + mGuiModeStates[GM_RestBed] = GuiModeState(mWaitDialog); + mSpellCreationDialog = new SpellCreationDialog(); + mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); + mEnchantingDialog = new EnchantingDialog(); + mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); + mTrainingWindow = new TrainingWindow(); + mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); + mMerchantRepair = new MerchantRepair(); + mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); + mRepair = new Repair(); + mGuiModeStates[GM_Repair] = GuiModeState(mRepair); + mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); + mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); + mJailScreen = new JailScreen(); + mGuiModeStates[GM_Jail] = GuiModeState(mJailScreen); std::string werewolfFaderTex = "textures\\werewolfoverlay.dds"; if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) @@ -531,196 +583,77 @@ namespace MWGui { if (!mMap) return; // UI not created yet - // Start out by hiding everything except the HUD - mMap->setVisible(false); - mMenu->setVisible(false); - mStatsWindow->setVisible(false); - mConsole->setVisible(false); - mJournal->setVisible(false); - mDialogueWindow->setVisible(false); - mContainerWindow->setVisible(false); - mInventoryWindow->setVisible(false); - mScrollWindow->setVisible(false); - mBookWindow->setVisible(false); - mTradeWindow->setVisible(false); - mSpellBuyingWindow->setVisible(false); - mTravelWindow->setVisible(false); - mSettingsWindow->setVisible(false); - mAlchemyWindow->setVisible(false); - mSpellWindow->setVisible(false); - mQuickKeysMenu->setVisible(false); - mLevelupDialog->setVisible(false); - mWaitDialog->setVisible(false); - mSpellCreationDialog->setVisible(false); - mEnchantingDialog->setVisible(false); - mTrainingWindow->setVisible(false); - mMerchantRepair->setVisible(false); - mRepair->setVisible(false); - mCompanionWindow->setVisible(false); - mInventoryWindow->setTrading(false); - mRecharge->setVisible(false); - mVideoBackground->setVisible(false); - mJailScreen->setVisible(false); - mHud->setVisible(mHudEnabled && mGuiEnabled); - mToolTips->setVisible(mGuiEnabled); + bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper); + + mHud->setVisible(mHudEnabled && mGuiEnabled && !loading); + mToolTips->setVisible(mGuiEnabled && !loading); bool gameMode = !isGuiMode(); mInputBlocker->setVisible (gameMode); - setCursorVisible(!gameMode); + + if (loading) + setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); + else + setCursorVisible(!gameMode); if (gameMode) setKeyFocusWidget (NULL); - if (!mGuiEnabled) - { - if (containsMode(GM_Console)) - mConsole->setVisible(true); - return; - } - // Icons of forced hidden windows are displayed setMinimapVisibility((mAllowed & GW_Map) && (!mMap->pinned() || (mForceHidden & GW_Map))); setWeaponVisibility((mAllowed & GW_Inventory) && (!mInventoryWindow->pinned() || (mForceHidden & GW_Inventory))); setSpellVisibility((mAllowed & GW_Magic) && (!mSpellWindow->pinned() || (mForceHidden & GW_Magic))); setHMSVisibility((mAllowed & GW_Stats) && (!mStatsWindow->pinned() || (mForceHidden & GW_Stats))); - // If in game mode (or interactive messagebox), show only the pinned windows + // If in game mode (or interactive messagebox), show the pinned windows if (mGuiModes.empty()) { - mInventoryWindow->setGuiMode(GM_None); mMap->setVisible(mMap->pinned() && !(mForceHidden & GW_Map) && (mAllowed & GW_Map)); mStatsWindow->setVisible(mStatsWindow->pinned() && !(mForceHidden & GW_Stats) && (mAllowed & GW_Stats)); mInventoryWindow->setVisible(mInventoryWindow->pinned() && !(mForceHidden & GW_Inventory) && (mAllowed & GW_Inventory)); mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); - return; } - if(mGuiModes.size() != 0) + GuiMode mode = mGuiModes.back(); + + mInventoryWindow->setTrading(mode == GM_Barter); + mInventoryWindow->setGuiMode(mode); + + // For the inventory mode, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed & ~mForceHidden; + mGuiModeStates[GM_Inventory].mVisibilityMask.resize(4); + mGuiModeStates[GM_Inventory].mVisibilityMask[0] = eff & GW_Map; + mGuiModeStates[GM_Inventory].mVisibilityMask[1] = eff & GW_Inventory; + mGuiModeStates[GM_Inventory].mVisibilityMask[2] = eff & GW_Magic; + mGuiModeStates[GM_Inventory].mVisibilityMask[3] = eff & GW_Stats; + if (getMode() == GM_Inventory) + mGuiModeStates[GM_Inventory].update(true); + + switch (mode) { - GuiMode mode = mGuiModes.back(); - - switch(mode) { - case GM_QuickKeysMenu: - mQuickKeysMenu->setVisible (true); - break; - case GM_MainMenu: - mMenu->setVisible(true); - break; - case GM_Settings: - mSettingsWindow->setVisible(true); - break; - case GM_Console: - mConsole->setVisible(true); - break; - case GM_Scroll: - mScrollWindow->setVisible(true); - break; - case GM_Book: - mBookWindow->setVisible(true); - break; - case GM_Alchemy: - mAlchemyWindow->setVisible(true); - break; - case GM_Rest: - mWaitDialog->setVisible(true); - break; - case GM_RestBed: - mWaitDialog->setVisible(true); - mWaitDialog->bedActivated(); - break; - case GM_Levelup: - mLevelupDialog->setVisible(true); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - mCharGen->spawnDialog(mode); - break; - case GM_Inventory: - { - // First, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed & ~mForceHidden; - - // Show the windows we want - mMap ->setVisible((eff & GW_Map) != 0); - mStatsWindow ->setVisible((eff & GW_Stats) != 0); - mInventoryWindow->setVisible((eff & GW_Inventory) != 0); - mInventoryWindow->setGuiMode(mode); - mSpellWindow ->setVisible((eff & GW_Magic) != 0); - break; - } - case GM_Container: - mContainerWindow->setVisible(true); - mInventoryWindow->setVisible(true); - mInventoryWindow->setGuiMode(mode); - break; - case GM_Companion: - mCompanionWindow->setVisible(true); - mInventoryWindow->setVisible(true); - mInventoryWindow->setGuiMode(mode); - break; - case GM_Dialogue: - mDialogueWindow->setVisible(true); - break; - case GM_Barter: - mInventoryWindow->setVisible(true); - mInventoryWindow->setTrading(true); - mInventoryWindow->setGuiMode(mode); - mTradeWindow->setVisible(true); - break; - case GM_SpellBuying: - mSpellBuyingWindow->setVisible(true); - break; - case GM_Travel: - mTravelWindow->setVisible(true); - break; - case GM_SpellCreation: - mSpellCreationDialog->setVisible(true); - break; - case GM_Recharge: - mRecharge->setVisible(true); - break; - case GM_Enchanting: - mEnchantingDialog->setVisible(true); - break; - case GM_Training: - mTrainingWindow->setVisible(true); - break; - case GM_MerchantRepair: - mMerchantRepair->setVisible(true); - break; - case GM_Repair: - mRepair->setVisible(true); - break; - case GM_Journal: - mJournal->setVisible(true); - break; - case GM_Jail: - mJailScreen->setVisible(true); - break; - case GM_LoadingWallpaper: - case GM_Loading: - // Don't need to show anything here - GM_LoadingWallpaper covers everything else anyway, - // GM_Loading uses a texture of the last rendered frame so everything previously visible will be rendered. - mHud->setVisible(false); - mToolTips->setVisible(false); - setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); - break; - default: - // Unsupported mode, switch back to game - break; - } + // FIXME: refactor chargen windows to use modes properly (or not use them at all) + case GM_Name: + case GM_Race: + case GM_Class: + case GM_ClassPick: + case GM_ClassCreate: + case GM_Birth: + case GM_ClassGenerate: + case GM_Review: + mCharGen->spawnDialog(mode); + break; + case GM_RestBed: + // FIXME: use GM_Rest and push the 'bed' argument in some other way + mWaitDialog->bedActivated(); + break; + default: + break; } } @@ -1267,11 +1200,18 @@ namespace MWGui mSpellBuyingWindow->center(); } + void WindowManager::onCursorChange(const std::string &name) + { + mCursorManager->cursorChanged(name); + } + void WindowManager::pushGuiMode(GuiMode mode) { if (mode==GM_Inventory && mAllowed==GW_None) return; + if (!mGuiModes.empty() && mGuiModes.back() == mode) + return; // If this mode already exists somewhere in the stack, just bring it to the front. if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) @@ -1279,23 +1219,29 @@ namespace MWGui mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); } + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(false); + mGuiModes.push_back(mode); + mGuiModeStates[mode].update(true); + bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } - void WindowManager::onCursorChange(const std::string &name) - { - mCursorManager->cursorChanged(name); - } - void WindowManager::popGuiMode() { if (!mGuiModes.empty()) + { + mGuiModeStates[mGuiModes.back()].update(false); mGuiModes.pop_back(); + } + + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(true); bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1305,6 +1251,12 @@ namespace MWGui void WindowManager::removeGuiMode(GuiMode mode) { + if (!mGuiModes.empty() && mGuiModes.back() == mode) + { + popGuiMode(); + return; + } + std::vector::iterator it = mGuiModes.begin(); while (it != mGuiModes.end()) { @@ -2214,4 +2166,16 @@ namespace MWGui else return true; } + + void WindowManager::GuiModeState::update(bool visible) + { + for (unsigned int i=0; isetVisible(visible && visibilityMask); + } + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3e17046df..524575c6a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -494,6 +494,25 @@ namespace MWGui std::map mPlayerSkillValues; MyGUI::Gui *mGui; // Gui + + struct GuiModeState + { + GuiModeState(WindowBase* window) + { + mWindows.push_back(window); + } + GuiModeState(const std::vector& windows) + : mWindows(windows) {} + GuiModeState() {} + + void update(bool visible); + + std::vector mWindows; + std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. + }; + // Defines the windows that should be shown in a particular GUI mode. + std::map mGuiModeStates; + // The currently active stack of GUI modes (top mode is the one we are in). std::vector mGuiModes; SDLUtil::SDLCursorManager* mCursorManager; From 84657271c7603aeead51ccee523f12b9608bb165 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 21:26:41 +0200 Subject: [PATCH 036/150] Improve WindowManager API with a generic way of passing a Ptr to the opened GUI window --- apps/openmw/mwbase/windowmanager.hpp | 18 +-- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 6 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/console.cpp | 6 +- apps/openmw/mwgui/console.hpp | 2 +- apps/openmw/mwgui/container.cpp | 4 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 16 +-- apps/openmw/mwgui/enchantingdialog.cpp | 63 ++++------ apps/openmw/mwgui/enchantingdialog.hpp | 5 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/merchantrepair.cpp | 4 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/recharge.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 6 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/soulgemdialog.cpp | 6 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 9 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 3 +- apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.hpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 2 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/windowbase.hpp | 8 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 116 +++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 20 +-- apps/openmw/mwworld/actionopen.cpp | 5 +- apps/openmw/mwworld/actionopen.hpp | 5 +- apps/openmw/mwworld/actionread.cpp | 6 +- apps/openmw/mwworld/actionread.hpp | 2 +- apps/openmw/mwworld/actionrepair.cpp | 2 +- 43 files changed, 125 insertions(+), 235 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 37c3ce0d3..242f358a9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -115,6 +115,7 @@ namespace MWBase virtual void setNewGame(bool newgame) = 0; + virtual void pushGuiMode (MWGui::GuiMode mode, const MWWorld::Ptr& arg) = 0; virtual void pushGuiMode (MWGui::GuiMode mode) = 0; virtual void popGuiMode() = 0; @@ -157,8 +158,6 @@ namespace MWBase virtual void updateSpellWindow() = 0; - virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; @@ -284,21 +283,6 @@ namespace MWBase virtual bool getPlayerSleeping() = 0; virtual void wakeUpPlayer() = 0; - virtual void showCompanionWindow(MWWorld::Ptr actor) = 0; - virtual void startSpellMaking(MWWorld::Ptr actor) = 0; - virtual void startEnchanting(MWWorld::Ptr actor) = 0; - virtual void startRecharge(MWWorld::Ptr soulgem) = 0; - virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0; - virtual void startTraining(MWWorld::Ptr actor) = 0; - virtual void startRepair(MWWorld::Ptr actor) = 0; - virtual void startRepairItem(MWWorld::Ptr item) = 0; - virtual void startTravel(const MWWorld::Ptr& actor) = 0; - virtual void startSpellBuying(const MWWorld::Ptr& actor) = 0; - virtual void startTrade(const MWWorld::Ptr& actor) = 0; - virtual void openContainer(const MWWorld::Ptr& container, bool loot) = 0; - virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton) = 0; - virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton) = 0; - virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; virtual void changePointer (const std::string& name) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 65f8c80d8..d6926f11d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -457,11 +457,11 @@ namespace MWClass // by default user can loot friendly actors during death animation if (canLoot && !stats.getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // otherwise wait until death animation if(stats.isDeathAnimationFinished()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // death animation is not finished, do nothing return std::shared_ptr (new MWWorld::FailedAction("")); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ca6c85aba..e7085bfbc 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -872,11 +872,11 @@ namespace MWClass // by default user can loot friendly actors during death animation if (canLoot && !stats.getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // otherwise wait until death animation if(stats.isDeathAnimationFinished()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // death animation is not finished, do nothing return std::shared_ptr (new MWWorld::FailedAction("")); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 6da1f7806..fb4ba1016 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -186,7 +186,7 @@ namespace MWDialogue bool isCompanion = !mActor.getClass().getScript(mActor).empty() && mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion"); if (isCompanion) - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mActor); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mActor); } bool DialogueManager::compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index b3296e7a7..ca697d0b6 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/class.hpp" #include "formatting.hpp" @@ -74,10 +75,13 @@ namespace MWGui mPages.clear(); } - void BookWindow::openBook (MWWorld::Ptr book, bool showTakeButton) + void BookWindow::setPtr (const MWWorld::Ptr& book) { mBook = book; + MWWorld::Ptr player = MWMechanics::getPlayer(); + bool showTakeButton = book.getContainerStore() != &player.getClass().getContainerStore(player); + clearPages(); mCurrentPage = 0; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 881b9997c..e8a1a42ff 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,7 +16,7 @@ namespace MWGui virtual void exit(); - void openBook(MWWorld::Ptr book, bool showTakeButton); + void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index fc4a98489..07753ab11 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -103,7 +103,7 @@ void CompanionWindow::onBackgroundSelected() } } -void CompanionWindow::openCompanion(const MWWorld::Ptr& npc) +void CompanionWindow::setPtr(const MWWorld::Ptr& npc) { mPtr = npc; updateEncumbranceBar(); diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index d37f0c4e4..ec70146f2 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -22,7 +22,7 @@ namespace MWGui virtual void resetReference(); - void openCompanion(const MWWorld::Ptr& npc); + void setPtr(const MWWorld::Ptr& npc); void onFrame (); private: diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 62690a0f1..55a03bafd 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -422,7 +422,7 @@ namespace MWGui setCoord(10,10, width-10, height/2); } - void Console::setSelectedObject(const MWWorld::Ptr& object) + void Console::setPtr(const MWWorld::Ptr& object) { if (!object.isEmpty()) { @@ -448,12 +448,12 @@ namespace MWGui void Console::onReferenceUnavailable() { - setSelectedObject(MWWorld::Ptr()); + setPtr(MWWorld::Ptr()); } void Console::resetReference() { ReferenceInterface::resetReference(); - setSelectedObject(MWWorld::Ptr()); + setPtr(MWWorld::Ptr()); } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 1232036ca..927fdd5fe 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -25,7 +25,7 @@ namespace MWGui { public: /// Set the implicit object for script execution - void setSelectedObject(const MWWorld::Ptr& object); + void setPtr(const MWWorld::Ptr& object); MyGUI::EditBox* mCommandLine; MyGUI::EditBox* mHistory; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 4f9201f06..6ea2e3e9a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -129,11 +129,13 @@ namespace MWGui dropItem(); } - void ContainerWindow::openContainer(const MWWorld::Ptr& container, bool loot) + void ContainerWindow::setPtr(const MWWorld::Ptr& container) { mPickpocketDetected = false; mPtr = container; + bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); + if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) { // we are stealing stuff diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 65cfa35c7..2758f57c9 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -33,7 +33,7 @@ namespace MWGui public: ContainerWindow(DragAndDrop* dragAndDrop); - void openContainer(const MWWorld::Ptr& container, bool loot=false); + void setPtr(const MWWorld::Ptr& container); virtual void onClose(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d9954a792..d2d97a437 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -336,23 +336,23 @@ namespace MWGui if (topic == gmst.find("sPersuasion")->getString()) mPersuasionDialog.setVisible(true); else if (topic == gmst.find("sCompanionShare")->getString()) - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) - MWBase::Environment::get().getWindowManager()->startTrade(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); else if (topic == gmst.find("sSpells")->getString()) - MWBase::Environment::get().getWindowManager()->startSpellBuying(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying, mPtr); else if (topic == gmst.find("sTravel")->getString()) - MWBase::Environment::get().getWindowManager()->startTravel(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel, mPtr); else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation, mPtr); else if (topic == gmst.find("sEnchanting")->getString()) - MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mPtr); else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - MWBase::Environment::get().getWindowManager()->startTraining (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training, mPtr); else if (topic == gmst.find("sRepair")->getString()) - MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } } } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 25568da07..94e8b329d 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -143,51 +143,36 @@ namespace MWGui } } - void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) + void EnchantingDialog::setPtr (const MWWorld::Ptr& ptr) { mName->setCaption(""); - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(actor); - - mBuyButton->setCaptionWithReplacing("#{sBuy}"); - - mChanceLayout->setVisible(false); - - mPtr = actor; + if (ptr.getClass().isActor()) + { + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(ptr); + mBuyButton->setCaptionWithReplacing("#{sBuy}"); + mChanceLayout->setVisible(false); + mPtr = ptr; + setSoulGem(MWWorld::Ptr()); + mPrice->setVisible(true); + mPriceText->setVisible(true); + } + else + { + mEnchanting.setSelfEnchanting(true); + mEnchanting.setEnchanter(MWMechanics::getPlayer()); + mBuyButton->setCaptionWithReplacing("#{sCreate}"); + bool enabled = Settings::Manager::getBool("show enchant chance","Game"); + mChanceLayout->setVisible(enabled); + mPtr = MWMechanics::getPlayer(); + setSoulGem(ptr); + mPrice->setVisible(false); + mPriceText->setVisible(false); + } - setSoulGem(MWWorld::Ptr()); setItem(MWWorld::Ptr()); - startEditing (); - mPrice->setVisible(true); - mPriceText->setVisible(true); - updateLabels(); - } - - void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) - { - mName->setCaption(""); - - MWWorld::Ptr player = MWMechanics::getPlayer(); - - mEnchanting.setSelfEnchanting(true); - mEnchanting.setEnchanter(player); - - mBuyButton->setCaptionWithReplacing("#{sCreate}"); - - bool enabled = Settings::Manager::getBool("show enchant chance","Game"); - - mChanceLayout->setVisible(enabled); - - mPtr = player; - startEditing(); - - setSoulGem(soulgem); - setItem(MWWorld::Ptr()); - - mPrice->setVisible(false); - mPriceText->setVisible(false); updateLabels(); } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 7c49ae54a..41d6382cc 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -26,8 +26,9 @@ namespace MWGui void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); - void startEnchanting(MWWorld::Ptr actor); - void startSelfEnchanting(MWWorld::Ptr soulgem); + /// Actor Ptr: buy enchantment from this actor + /// Soulgem Ptr: player self-enchant + void setPtr(const MWWorld::Ptr& ptr); virtual void resetReference(); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0e1b2cc89..ba4d05d75 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -260,7 +260,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Console, object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 9c706851f..785b5ee48 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -32,7 +32,7 @@ MerchantRepair::MerchantRepair() mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onOkButtonClick); } -void MerchantRepair::startRepair(const MWWorld::Ptr &actor) +void MerchantRepair::setPtr(const MWWorld::Ptr &actor) { mActor = actor; @@ -145,7 +145,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) MWMechanics::CreatureStats& actorStats = mActor.getClass().getCreatureStats(mActor); actorStats.setGoldPool(actorStats.getGoldPool() + price); - startRepair(mActor); + setPtr(mActor); } void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 5006b08a4..76ccd28cc 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -16,7 +16,7 @@ public: virtual void exit(); - void startRepair(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor); private: MyGUI::ScrollView* mList; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 00af45695..54473746a 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -67,7 +67,7 @@ void Recharge::exit() MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); } -void Recharge::start (const MWWorld::Ptr &item) +void Recharge::setPtr (const MWWorld::Ptr &item) { mGemIcon->setItem(item); mGemIcon->setUserString("ToolTipType", "ItemPtr"); diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index d963e9d66..93f86ab65 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -26,7 +26,7 @@ public: virtual void exit(); - void start (const MWWorld::Ptr& gem); + void setPtr (const MWWorld::Ptr& gem); protected: ItemChargeView* mBox; diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index f917cef0f..295b8254b 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -63,7 +63,7 @@ void Repair::exit() MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } -void Repair::startRepairItem(const MWWorld::Ptr &item) +void Repair::setPtr(const MWWorld::Ptr &item) { MWBase::Environment::get().getWindowManager()->playSound("Item Repair Up"); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 44c380b51..a2573d780 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -23,7 +23,7 @@ public: virtual void exit(); - void startRepairItem (const MWWorld::Ptr& item); + void setPtr (const MWWorld::Ptr& item); protected: ItemChargeView* mRepairBox; diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index a5d4c3324..3649afe23 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,6 +12,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/class.hpp" #include "formatting.hpp" @@ -49,13 +50,16 @@ namespace MWGui center(); } - void ScrollWindow::openScroll (MWWorld::Ptr scroll, bool showTakeButton) + void ScrollWindow::setPtr (const MWWorld::Ptr& scroll) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getWindowManager()->playSound("scroll"); mScroll = scroll; + MWWorld::Ptr player = MWMechanics::getPlayer(); + bool showTakeButton = scroll.getContainerStore() != &player.getClass().getContainerStore(player); + MWWorld::LiveCellRef *ref = mScroll.get(); Formatting::BookFormatter formatter; diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 961f1b675..5ae8e972a 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -17,7 +17,7 @@ namespace MWGui public: ScrollWindow (); - void openScroll (MWWorld::Ptr scroll, bool showTakeButton); + void setPtr (const MWWorld::Ptr& scroll); virtual void exit(); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index 0232eb7b3..104c81eab 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -22,13 +22,11 @@ namespace MWGui { if (button == 0) { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Recharge); - MWBase::Environment::get().getWindowManager()->startRecharge(mSoulgem); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Recharge, mSoulgem); } else { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); - MWBase::Environment::get().getWindowManager()->startSelfEnchanting(mSoulgem); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mSoulgem); } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 6a7376aa0..592316274 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -88,7 +88,12 @@ namespace MWGui mSpellsWidgetMap.clear(); } - void SpellBuyingWindow::startSpellBuying(const MWWorld::Ptr& actor, int startOffset) + void SpellBuyingWindow::setPtr(const MWWorld::Ptr &actor) + { + setPtr(actor, 0); + } + + void SpellBuyingWindow::setPtr(const MWWorld::Ptr& actor, int startOffset) { center(); mPtr = actor; @@ -161,7 +166,7 @@ namespace MWGui MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr); npcStats.setGoldPool(npcStats.getGoldPool() + price); - startSpellBuying(mPtr, mSpellsView->getViewOffset().top); + setPtr(mPtr, mSpellsView->getViewOffset().top); MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up"); } diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 37210819f..b96896e4c 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -25,7 +25,8 @@ namespace MWGui public: SpellBuyingWindow(); - void startSpellBuying(const MWWorld::Ptr& actor, int startOffset); + void setPtr(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor, int startOffset); virtual void exit(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6a36554d8..d5982a174 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -352,7 +352,7 @@ namespace MWGui setWidgets(mAvailableEffectsList, mUsedEffectsView); } - void SpellCreationDialog::startSpellMaking (MWWorld::Ptr actor) + void SpellCreationDialog::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; mNameEdit->setCaption(""); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index d12115c88..76038abb4 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -153,7 +153,7 @@ namespace MWGui virtual void onOpen(); virtual void exit(); - void startSpellMaking(MWWorld::Ptr actor); + void setPtr(const MWWorld::Ptr& actor); protected: virtual void onReferenceUnavailable (); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ca0bb48e8..60abf4ac7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -115,7 +115,7 @@ namespace MWGui } } - void TradeWindow::startTrade(const MWWorld::Ptr& actor) + void TradeWindow::setPtr(const MWWorld::Ptr& actor) { mPtr = actor; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 4b03c8d90..984f5a394 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -27,7 +27,7 @@ namespace MWGui public: TradeWindow(); - void startTrade(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor); void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index d2e771918..3079adb6d 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -65,7 +65,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); } - void TrainingWindow::startTraining (MWWorld::Ptr actor) + void TrainingWindow::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 95a35be7f..e52a889ef 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -18,7 +18,7 @@ namespace MWGui virtual void exit(); - void startTraining(MWWorld::Ptr actor); + void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 3a7afe497..4c4dc436c 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -108,7 +108,7 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(mDestinationsView->getChildAt(0)); } - void TravelWindow::startTravel(const MWWorld::Ptr& actor) + void TravelWindow::setPtr(const MWWorld::Ptr& actor) { center(); mPtr = actor; diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 3230f897f..529d5ebe1 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -26,7 +26,7 @@ namespace MWGui virtual void exit(); - void startTravel(const MWWorld::Ptr& actor); + void setPtr (const MWWorld::Ptr& actor); protected: MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 400dc0ce4..73574ce7c 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -8,6 +8,11 @@ namespace MWBase class WindowManager; } +namespace MWWorld +{ + class Ptr; +} + namespace MWGui { class WindowManager; @@ -21,6 +26,9 @@ namespace MWGui // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; + /// Open this object in the GUI, for windows that support it + virtual void setPtr(const MWWorld::Ptr& ptr) {} + /// Notify that window has been made visible virtual void onOpen() {} /// Notify that window has been hidden diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 81edc4a00..54ff8c30f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1207,24 +1207,31 @@ namespace MWGui void WindowManager::pushGuiMode(GuiMode mode) { - if (mode==GM_Inventory && mAllowed==GW_None) - return; + pushGuiMode(mode, MWWorld::Ptr()); + } - if (!mGuiModes.empty() && mGuiModes.back() == mode) + void WindowManager::pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg) + { + if (mode==GM_Inventory && mAllowed==GW_None) return; - // If this mode already exists somewhere in the stack, just bring it to the front. - if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + if (mGuiModes.empty() || mGuiModes.back() != mode) { - mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); - } + // If this mode already exists somewhere in the stack, just bring it to the front. + if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + { + mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + } - if (!mGuiModes.empty()) - mGuiModeStates[mGuiModes.back()].update(false); + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(false); - mGuiModes.push_back(mode); + mGuiModes.push_back(mode); - mGuiModeStates[mode].update(true); + mGuiModeStates[mode].update(true); + } + for (WindowBase* window : mGuiModeStates[mode].mWindows) + window->setPtr(arg); bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1543,52 +1550,11 @@ namespace MWGui mMap->addVisitedLocation (name, x, y); } - void WindowManager::startSpellMaking(MWWorld::Ptr actor) - { - pushGuiMode(GM_SpellCreation); - mSpellCreationDialog->startSpellMaking (actor); - } - - void WindowManager::startEnchanting (MWWorld::Ptr actor) - { - pushGuiMode(GM_Enchanting); - mEnchantingDialog->startEnchanting (actor); - } - - void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) - { - mEnchantingDialog->startSelfEnchanting(soulgem); - } - - void WindowManager::startTraining(MWWorld::Ptr actor) - { - pushGuiMode(GM_Training); - mTrainingWindow->startTraining(actor); - } - - void WindowManager::startRepair(MWWorld::Ptr actor) - { - pushGuiMode(GM_MerchantRepair); - mMerchantRepair->startRepair(actor); - } - - void WindowManager::startRepairItem(MWWorld::Ptr item) - { - pushGuiMode(MWGui::GM_Repair); - mRepair->startRepairItem(item); - } - const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; } - void WindowManager::showCompanionWindow(MWWorld::Ptr actor) - { - pushGuiMode(MWGui::GM_Companion); - mCompanionWindow->openCompanion(actor); - } - void WindowManager::changePointer(const std::string &name) { MyGUI::PointerManager::getInstance().setPointer(name); @@ -1642,11 +1608,6 @@ namespace MWGui return mLoadingScreen; } - void WindowManager::startRecharge(MWWorld::Ptr soulgem) - { - mRecharge->start(soulgem); - } - bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1996,53 +1957,12 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } - void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) - { - mConsole->setSelectedObject(object); - } - void WindowManager::updateSpellWindow() { if (mSpellWindow) mSpellWindow->updateSpells(); } - void WindowManager::startTravel(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_Travel); - mTravelWindow->startTravel(actor); - } - - void WindowManager::startSpellBuying(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_SpellBuying); - mSpellBuyingWindow->startSpellBuying(actor, 0); - } - - void WindowManager::startTrade(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_Barter); - mTradeWindow->startTrade(actor); - } - - void WindowManager::openContainer(const MWWorld::Ptr &container, bool loot) - { - pushGuiMode(GM_Container); - mContainerWindow->openContainer(container, loot); - } - - void WindowManager::showBook(const MWWorld::Ptr &item, bool showTakeButton) - { - pushGuiMode(GM_Book); - mBookWindow->openBook(item, showTakeButton); - } - - void WindowManager::showScroll(const MWWorld::Ptr &item, bool showTakeButton) - { - pushGuiMode(GM_Scroll); - mScrollWindow->openScroll(item, showTakeButton); - } - std::string WindowManager::correctIconPath(const std::string& path) { return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 524575c6a..c267f505a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -158,7 +158,8 @@ namespace MWGui virtual void setNewGame(bool newgame); - virtual void pushGuiMode(GuiMode mode); + virtual void pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg); + virtual void pushGuiMode (GuiMode mode); virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack @@ -196,8 +197,6 @@ namespace MWGui virtual void updateSpellWindow(); - virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); @@ -315,21 +314,6 @@ namespace MWGui virtual void updatePlayer(); - virtual void showCompanionWindow(MWWorld::Ptr actor); - virtual void startSpellMaking(MWWorld::Ptr actor); - virtual void startEnchanting(MWWorld::Ptr actor); - virtual void startSelfEnchanting(MWWorld::Ptr soulgem); - virtual void startTraining(MWWorld::Ptr actor); - virtual void startRepair(MWWorld::Ptr actor); - virtual void startRepairItem(MWWorld::Ptr item); - virtual void startRecharge(MWWorld::Ptr soulgem); - virtual void startTravel(const MWWorld::Ptr& actor); - virtual void startSpellBuying(const MWWorld::Ptr &actor); - virtual void startTrade(const MWWorld::Ptr &actor); - virtual void openContainer(const MWWorld::Ptr &container, bool loot); - virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton); - virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton); - virtual void showSoulgemDialog (MWWorld::Ptr item); virtual void changePointer (const std::string& name); diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 0df451b18..7ff6dd068 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -10,9 +10,8 @@ namespace MWWorld { - ActionOpen::ActionOpen (const MWWorld::Ptr& container, bool loot) + ActionOpen::ActionOpen (const MWWorld::Ptr& container) : Action (false, container) - , mLoot(loot) { } @@ -23,6 +22,6 @@ namespace MWWorld MWMechanics::diseaseContact(actor, getTarget()); - MWBase::Environment::get().getWindowManager()->openContainer(getTarget(), mLoot); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, getTarget()); } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 454cc09f1..3bce25c6b 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -12,12 +12,9 @@ namespace MWWorld virtual void executeImp (const MWWorld::Ptr& actor); public: - ActionOpen (const Ptr& container, bool loot=false); + ActionOpen (const Ptr& container); ///< \param container The Container the Player has activated. - /// \param loot If true, display the "dispose of corpse" button - private: - bool mLoot; }; } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index b3ac772ae..d2dc972fc 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -32,14 +32,12 @@ namespace MWWorld return; } - bool showTakeButton = (getTarget().getContainerStore() != &actor.getClass().getContainerStore(actor)); - LiveCellRef *ref = getTarget().get(); if (ref->mBase->mData.mIsScroll) - MWBase::Environment::get().getWindowManager()->showScroll(getTarget(), showTakeButton); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Scroll, getTarget()); else - MWBase::Environment::get().getWindowManager()->showBook(getTarget(), showTakeButton); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Book, getTarget()); MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index 00a4756dd..c23bf2900 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -16,4 +16,4 @@ namespace MWWorld }; } -#endif // ACTIONOPEN_H +#endif // ACTIONREAD_H diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 8e19927b8..191cf2063 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -23,6 +23,6 @@ namespace MWWorld return; } - MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair, getTarget()); } } From bbafe1e4561fc54da1f240d9083b6592eb6f758d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 21:31:10 +0200 Subject: [PATCH 037/150] Remove redundant player cell variable --- apps/openmw/mwgui/referenceinterface.cpp | 10 ---------- apps/openmw/mwgui/referenceinterface.hpp | 5 +---- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 9aaa98f19..6213d9e25 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -1,14 +1,8 @@ #include "referenceinterface.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" - -#include "../mwmechanics/actorutil.hpp" - namespace MWGui { ReferenceInterface::ReferenceInterface() - : mCurrentPlayerCell(NULL) { } @@ -18,8 +12,6 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - MWWorld::CellStore* playerCell = MWMechanics::getPlayer().getCell(); - // check if count of the reference has become 0 if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0) { @@ -29,7 +21,5 @@ namespace MWGui onReferenceUnavailable(); } } - - mCurrentPlayerCell = playerCell; } } diff --git a/apps/openmw/mwgui/referenceinterface.hpp b/apps/openmw/mwgui/referenceinterface.hpp index 0ba180de8..6428a5b54 100644 --- a/apps/openmw/mwgui/referenceinterface.hpp +++ b/apps/openmw/mwgui/referenceinterface.hpp @@ -17,15 +17,12 @@ namespace MWGui void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable - virtual void resetReference() { mPtr = MWWorld::Ptr(); mCurrentPlayerCell = NULL; } + virtual void resetReference() { mPtr = MWWorld::Ptr(); } protected: virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable MWWorld::Ptr mPtr; - - private: - MWWorld::CellStore* mCurrentPlayerCell; }; } From 269094ba8d84945de1b86b40c4c9db81fe46efbf Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 23:01:34 +0200 Subject: [PATCH 038/150] Restore the previous key focus widget when exiting modal dialog --- apps/openmw/mwgui/windowbase.cpp | 5 +++-- apps/openmw/mwgui/windowmanagerimp.cpp | 26 ++++++++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 8 ++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 5ed564737..e563d9aa9 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -67,14 +67,15 @@ WindowModal::WindowModal(const std::string& parLayout) void WindowModal::onOpen() { - MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); + // Order important. We need to save the key focus widget before its unset MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed + MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); } void WindowModal::onClose() { - MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); } NoDrop::NoDrop(DragAndDrop *drag, MyGUI::Widget *widget) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 54ff8c30f..2d17db643 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,7 @@ namespace MWGui , mWorkQueue(workQueue) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) + , mSaveKeyFocus(NULL) , mCurrentModals() , mHud(NULL) , mMap(NULL) @@ -260,6 +262,8 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + MyGUI::WidgetManager::getInstance().registerUnlinker(this); + // Create all cursors in advance createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); @@ -496,6 +500,8 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); + MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); + delete mConsole; delete mMessageBoxManager; delete mHud; @@ -1608,6 +1614,12 @@ namespace MWGui return mLoadingScreen; } + void WindowManager::_unlinkWidget(MyGUI::Widget *widget) + { + if (widget == mSaveKeyFocus) + mSaveKeyFocus = NULL; + } + bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1818,6 +1830,17 @@ namespace MWGui { if (!mCurrentModals.empty()) mCurrentModals.top()->exit(); + + if (mCurrentModals.empty()) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + } + + void WindowManager::addCurrentModal(WindowModal *input) + { + if (mCurrentModals.empty()) + mSaveKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + mCurrentModals.push(input); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1827,6 +1850,9 @@ namespace MWGui if(!mCurrentModals.empty()) if(input == mCurrentModals.top()) mCurrentModals.pop(); + + if (mCurrentModals.empty()) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c267f505a..18ece21f9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -124,7 +124,7 @@ namespace MWGui class JailScreen; class KeyboardNavigation; - class WindowManager : public MWBase::WindowManager + class WindowManager : public MWBase::WindowManager, MyGUI::IUnlinkWidget { public: typedef std::pair Faction; @@ -142,6 +142,8 @@ namespace MWGui virtual Loading::Listener* getLoadingScreen(); + void _unlinkWidget(MyGUI::Widget* widget); + /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); @@ -341,7 +343,7 @@ namespace MWGui /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ - virtual void addCurrentModal(WindowModal* input) {mCurrentModals.push(input);} + virtual void addCurrentModal(WindowModal* input); /// Removes the top Modal /** Used when one Modal adds another Modal @@ -404,6 +406,8 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; + MyGUI::Widget* mSaveKeyFocus; + std::stack mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). From 531e7ac58677dc44fe94c433d2d979caed8710dc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 23:25:20 +0200 Subject: [PATCH 039/150] Allow drag-and-drop to be cancelled (Esc or Inventory key) --- apps/openmw/mwgui/draganddrop.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 14 +++++++++++++- apps/openmw/mwinput/inputmanagerimp.cpp | 6 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index fa17d974d..fe0ad3374 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -125,6 +125,8 @@ void DragAndDrop::finish() { mIsOnDragAndDrop = false; mSourceSortModel->clearDragItems(); + // since mSourceView doesn't get updated in drag() + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); mDraggedWidget = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2d17db643..4964af7d8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -755,7 +755,14 @@ namespace MWGui mGarbageDialogs.push_back(dialog); } - void WindowManager::exitCurrentGuiMode() { + void WindowManager::exitCurrentGuiMode() + { + if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) + { + mDragAndDrop->finish(); + return; + } + switch(mGuiModes.back()) { case GM_QuickKeysMenu: mQuickKeysMenu->exit(); @@ -1247,6 +1254,11 @@ namespace MWGui void WindowManager::popGuiMode() { + if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) + { + mDragAndDrop->finish(); + } + if (!mGuiModes.empty()) { mGuiModeStates[mGuiModes.back()].update(false); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 33f1edb6c..3ed259c58 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -177,13 +177,13 @@ namespace MWInput void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { - if (mDragDrop) - return; - resetIdleTime (); int action = channel->getNumber(); + if (mDragDrop && action != A_GameMenu && action != A_Inventory) + return; + if((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0)) { //Is a normal button press, so don't change it at all From 20766fb508f6f4a286a786f1b2d63225de11fd8a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 00:00:40 +0200 Subject: [PATCH 040/150] Associate open/close sounds with the GUI mode --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwgui/bookwindow.cpp | 5 ----- apps/openmw/mwgui/scrollwindow.cpp | 7 +------ apps/openmw/mwgui/windowmanagerimp.cpp | 18 ++++++++++++++---- apps/openmw/mwgui/windowmanagerimp.hpp | 7 +++++-- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 242f358a9..243ec3ccf 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -117,9 +117,9 @@ namespace MWBase virtual void pushGuiMode (MWGui::GuiMode mode, const MWWorld::Ptr& arg) = 0; virtual void pushGuiMode (MWGui::GuiMode mode) = 0; - virtual void popGuiMode() = 0; + virtual void popGuiMode(bool noSound=false) = 0; - virtual void removeGuiMode (MWGui::GuiMode mode) = 0; + virtual void removeGuiMode (MWGui::GuiMode mode, bool noSound=false) = 0; ///< can be anywhere in the stack virtual void goToJail(int days) = 0; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ca697d0b6..7cabf68b1 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -85,8 +85,6 @@ namespace MWGui clearPages(); mCurrentPage = 0; - MWBase::Environment::get().getWindowManager()->playSound("book open"); - MWWorld::LiveCellRef *ref = mBook.get(); Formatting::BookFormatter formatter; @@ -100,9 +98,6 @@ namespace MWGui void BookWindow::exit() { - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getWindowManager()->playSound("book close"); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 3649afe23..ccbd1d7c0 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -52,9 +52,6 @@ namespace MWGui void ScrollWindow::setPtr (const MWWorld::Ptr& scroll) { - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getWindowManager()->playSound("scroll"); - mScroll = scroll; MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -81,8 +78,6 @@ namespace MWGui void ScrollWindow::exit() { - MWBase::Environment::get().getWindowManager()->playSound("scroll"); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } @@ -110,6 +105,6 @@ namespace MWGui MWWorld::ActionTake take(mScroll); take.execute (MWMechanics::getPlayer()); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll, true); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4964af7d8..70b95351b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -354,6 +354,8 @@ namespace MWGui bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); mJournal = JournalWindow::create(JournalViewModel::create (), questList); mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + mGuiModeStates[GM_Journal].mCloseSound = "book close"; + mGuiModeStates[GM_Journal].mOpenSound = "book open"; mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); mSpellBuyingWindow = new SpellBuyingWindow(); @@ -374,9 +376,13 @@ namespace MWGui mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); + mGuiModeStates[GM_Scroll].mOpenSound = "scroll"; + mGuiModeStates[GM_Scroll].mCloseSound = "scroll"; mBookWindow = new BookWindow(); mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); + mGuiModeStates[GM_Book].mOpenSound = "book open"; + mGuiModeStates[GM_Book].mCloseSound = "book close"; mCountDialog = new CountDialog(); mSettingsWindow = new SettingsWindow(); @@ -840,7 +846,6 @@ namespace MWGui mRepair->exit(); break; case GM_Journal: - playSound("book close"); removeGuiMode(GM_Journal); //Simple way to remove it break; default: @@ -1242,6 +1247,7 @@ namespace MWGui mGuiModes.push_back(mode); mGuiModeStates[mode].update(true); + playSound(mGuiModeStates[mode].mOpenSound); } for (WindowBase* window : mGuiModeStates[mode].mWindows) window->setPtr(arg); @@ -1252,7 +1258,7 @@ namespace MWGui updateVisible(); } - void WindowManager::popGuiMode() + void WindowManager::popGuiMode(bool noSound) { if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) { @@ -1262,6 +1268,8 @@ namespace MWGui if (!mGuiModes.empty()) { mGuiModeStates[mGuiModes.back()].update(false); + if (!noSound) + playSound(mGuiModeStates[mGuiModes.back()].mCloseSound); mGuiModes.pop_back(); } @@ -1274,11 +1282,11 @@ namespace MWGui updateVisible(); } - void WindowManager::removeGuiMode(GuiMode mode) + void WindowManager::removeGuiMode(GuiMode mode, bool noSound) { if (!mGuiModes.empty() && mGuiModes.back() == mode) { - popGuiMode(); + popGuiMode(noSound); return; } @@ -1992,6 +2000,8 @@ namespace MWGui void WindowManager::playSound(const std::string& soundId, float volume, float pitch) { + if (soundId.empty()) + return; MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 18ece21f9..9fa921a4c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -162,8 +162,8 @@ namespace MWGui virtual void pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg); virtual void pushGuiMode (GuiMode mode); - virtual void popGuiMode(); - virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack + virtual void popGuiMode(bool noSound=false); + virtual void removeGuiMode(GuiMode mode, bool noSound=false); ///< can be anywhere in the stack virtual void goToJail(int days); @@ -497,6 +497,9 @@ namespace MWGui std::vector mWindows; std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. + + std::string mCloseSound; + std::string mOpenSound; }; // Defines the windows that should be shown in a particular GUI mode. std::map mGuiModeStates; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3ed259c58..cf42db04b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1039,12 +1039,10 @@ namespace MWInput && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { - MWBase::Environment::get().getWindowManager()->playSound ("book open"); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal); } else if(MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Journal)) { - MWBase::Environment::get().getWindowManager()->playSound ("book close"); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Journal); } } From 4fff2e2e34eeac62f7c510e63085bf8c676785d9 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:18:39 +0200 Subject: [PATCH 041/150] Refactor exitCurrentGuiMode --- apps/openmw/mwgui/alchemywindow.cpp | 9 +- apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/birth.hpp | 2 + apps/openmw/mwgui/bookwindow.cpp | 7 +- apps/openmw/mwgui/bookwindow.hpp | 2 - apps/openmw/mwgui/class.cpp | 9 +- apps/openmw/mwgui/class.hpp | 14 ++- apps/openmw/mwgui/companionwindow.cpp | 9 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.cpp | 7 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/console.cpp | 5 - apps/openmw/mwgui/console.hpp | 2 - apps/openmw/mwgui/container.cpp | 10 +- apps/openmw/mwgui/container.hpp | 2 - apps/openmw/mwgui/countdialog.cpp | 12 +-- apps/openmw/mwgui/countdialog.hpp | 2 - apps/openmw/mwgui/dialogue.cpp | 16 ++-- apps/openmw/mwgui/dialogue.hpp | 3 +- apps/openmw/mwgui/enchantingdialog.cpp | 7 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 - apps/openmw/mwgui/itemselection.cpp | 3 +- apps/openmw/mwgui/itemselection.hpp | 2 +- apps/openmw/mwgui/jailscreen.hpp | 2 + apps/openmw/mwgui/mapwindow.cpp | 5 - apps/openmw/mwgui/mapwindow.hpp | 1 - apps/openmw/mwgui/merchantrepair.cpp | 7 +- apps/openmw/mwgui/merchantrepair.hpp | 2 - apps/openmw/mwgui/quickkeysmenu.cpp | 13 +-- apps/openmw/mwgui/quickkeysmenu.hpp | 5 +- apps/openmw/mwgui/race.hpp | 2 + apps/openmw/mwgui/recharge.cpp | 7 +- apps/openmw/mwgui/recharge.hpp | 2 - apps/openmw/mwgui/repair.cpp | 7 +- apps/openmw/mwgui/repair.hpp | 2 - apps/openmw/mwgui/review.hpp | 2 + apps/openmw/mwgui/savegamedialog.cpp | 7 +- apps/openmw/mwgui/savegamedialog.hpp | 2 - apps/openmw/mwgui/scrollwindow.cpp | 7 +- apps/openmw/mwgui/scrollwindow.hpp | 1 - apps/openmw/mwgui/settingswindow.cpp | 7 +- apps/openmw/mwgui/settingswindow.hpp | 2 - apps/openmw/mwgui/spellbuyingwindow.cpp | 7 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 - apps/openmw/mwgui/spellcreationdialog.cpp | 12 +-- apps/openmw/mwgui/spellcreationdialog.hpp | 3 +- apps/openmw/mwgui/textinput.hpp | 2 + apps/openmw/mwgui/tradewindow.cpp | 5 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 7 +- apps/openmw/mwgui/trainingwindow.hpp | 2 - apps/openmw/mwgui/travelwindow.cpp | 7 +- apps/openmw/mwgui/travelwindow.hpp | 2 - apps/openmw/mwgui/waitdialog.cpp | 5 +- apps/openmw/mwgui/waitdialog.hpp | 2 +- apps/openmw/mwgui/windowbase.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 110 +++++----------------- 57 files changed, 101 insertions(+), 284 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index c68bad02a..5b1489821 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -59,7 +59,7 @@ namespace MWGui void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); } void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) @@ -103,6 +103,7 @@ namespace MWGui void AlchemyWindow::onOpen() { + mAlchemy->clear(); mAlchemy->setAlchemist (MWMechanics::getPlayer()); InventoryItemModel* model = new InventoryItemModel(MWMechanics::getPlayer()); @@ -129,12 +130,6 @@ namespace MWGui update(); } - void AlchemyWindow::exit() { - mAlchemy->clear(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); - } - void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) { removeIngredient(_sender); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 8b7bcaaca..8dffaaad1 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -25,7 +25,6 @@ namespace MWGui AlchemyWindow(); virtual void onOpen(); - virtual void exit(); private: std::string mSuggestedPotionName; diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index c13d49838..86af14286 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -22,6 +22,8 @@ namespace MWGui void setNextButtonShow(bool shown); virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 7cabf68b1..5abc63c55 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -96,11 +96,6 @@ namespace MWGui setTakeButtonShow(showTakeButton); } - void BookWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); - } - void BookWindow::setTakeButtonShow(bool show) { mTakeButtonShow = show; @@ -115,7 +110,7 @@ namespace MWGui void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index e8a1a42ff..4f7224ea8 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -14,8 +14,6 @@ namespace MWGui public: BookWindow(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 2278b5141..c63d470d7 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -730,9 +730,10 @@ namespace MWGui exit(); } - void SelectSpecializationDialog::exit() + bool SelectSpecializationDialog::exit() { eventCancel(); + return true; } /* SelectAttributeDialog */ @@ -778,9 +779,10 @@ namespace MWGui exit(); } - void SelectAttributeDialog::exit() + bool SelectAttributeDialog::exit() { eventCancel(); + return true; } @@ -869,9 +871,10 @@ namespace MWGui exit(); } - void SelectSkillDialog::exit() + bool SelectSkillDialog::exit() { eventCancel(); + return true; } /* DescriptionDialog */ diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 2b205d12f..3a2573fd4 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -23,6 +23,8 @@ namespace MWGui virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; @@ -67,6 +69,8 @@ namespace MWGui std::string getClassId() const; void setClassId(const std::string &classId); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; @@ -102,6 +106,8 @@ namespace MWGui void setNextButtonShow(bool shown); virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; @@ -142,7 +148,7 @@ namespace MWGui SelectSpecializationDialog(); ~SelectSpecializationDialog(); - virtual void exit(); + virtual bool exit(); ESM::Class::Specialization getSpecializationId() const { return mSpecializationId; } @@ -175,7 +181,7 @@ namespace MWGui SelectAttributeDialog(); ~SelectAttributeDialog(); - virtual void exit(); + virtual bool exit(); ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; } @@ -206,7 +212,7 @@ namespace MWGui SelectSkillDialog(); ~SelectSkillDialog(); - virtual void exit(); + virtual bool exit(); ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } @@ -262,6 +268,8 @@ namespace MWGui CreateClassDialog(); virtual ~CreateClassDialog(); + bool exit() { return false; } + std::string getName() const; std::string getDescription() const; ESM::Class::Specialization getSpecializationId() const; diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 07753ab11..c4e50c8c2 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -139,10 +139,11 @@ void CompanionWindow::updateEncumbranceBar() void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { - exit(); + if (exit()) + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); } -void CompanionWindow::exit() +bool CompanionWindow::exit() { if (mModel && mModel->hasProfit(mPtr) && getProfit(mPtr) < 0) { @@ -151,9 +152,9 @@ void CompanionWindow::exit() buttons.push_back("#{sCompanionWarningButtonTwo}"); mMessageBoxManager->createInteractiveMessageBox("#{sCompanionWarningMessage}", buttons); mMessageBoxManager->eventButtonPressed += MyGUI::newDelegate(this, &CompanionWindow::onMessageBoxButtonClicked); + return false; } - else - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); + return true; } void CompanionWindow::onMessageBoxButtonClicked(int button) diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index ec70146f2..fd66cfa80 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -18,7 +18,7 @@ namespace MWGui public: CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); - virtual void exit(); + virtual bool exit(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index f3a06f245..697d90862 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -46,15 +46,16 @@ namespace MWGui center(); } - void ConfirmationDialog::exit() + bool ConfirmationDialog::exit() { - setVisible(false); - eventCancelClicked(); + return true; } void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { + setVisible(false); + exit(); } diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 745c7a1a5..259579376 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -11,7 +11,7 @@ namespace MWGui ConfirmationDialog(); void askForConfirmation(const std::string& message); void askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage); - virtual void exit(); + virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 55a03bafd..182b6ef97 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -159,11 +159,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); } - void Console::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Console); - } - void Console::setFont(const std::string &fntName) { mHistory->setFontName(fntName); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 927fdd5fe..6257b5617 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -42,8 +42,6 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); - virtual void exit(); - void setFont(const std::string &fntName); void onResChange(int width, int height); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6ea2e3e9a..85afc1aa3 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -198,17 +198,9 @@ namespace MWGui } } - void ContainerWindow::exit() - { - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); - } - } - void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 2758f57c9..3ae73a01f 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -38,8 +38,6 @@ namespace MWGui virtual void resetReference(); - virtual void exit(); - private: DragAndDrop* mDragAndDrop; diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 03cf1cab6..cf058caac 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -56,19 +56,9 @@ namespace MWGui mItemEdit->setValue(maxCount); } - void CountDialog::cancel() //Keeping this here as I don't know if anything else relies on it. - { - exit(); - } - - void CountDialog::exit() - { - setVisible(false); - } - void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { - cancel(); + setVisible(false); } void CountDialog::onOkButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 7014b5fad..766612f68 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -15,8 +15,6 @@ namespace MWGui public: CountDialog(); void openCountDialog(const std::string& item, const std::string& message, const int maxCount); - void cancel(); - virtual void exit(); typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d2d97a437..48d291325 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -52,7 +52,7 @@ namespace MWGui void PersuasionDialog::onCancel(MyGUI::Widget *sender) { - exit(); + setVisible(false); } void PersuasionDialog::onPersuade(MyGUI::Widget *sender) @@ -88,11 +88,6 @@ namespace MWGui mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); } - void PersuasionDialog::exit() - { - setVisible(false); - } - // -------------------------------------------------------------------------------------------------- Response::Response(const std::string &text, const std::string &title, bool needMargin) @@ -275,18 +270,18 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } - void DialogueWindow::exit() + bool DialogueWindow::exit() { if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) && !mGoodbye) { - // in choice, not allowed to escape, but give access to main menu to allow loading other saves - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + return false; } else { MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); mTopicsList->scrollToTop(); + return true; } } @@ -311,7 +306,8 @@ namespace MWGui void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { - exit(); + if (exit()) + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void DialogueWindow::onSelectTopic(const std::string& topic, int id) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 682baef3c..12e2328f4 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -29,7 +29,6 @@ namespace MWGui PersuasionDialog(); virtual void onOpen(); - virtual void exit(); private: MyGUI::Button* mCancelButton; @@ -100,7 +99,7 @@ namespace MWGui public: DialogueWindow(); - virtual void exit(); + virtual bool exit(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 94e8b329d..88973bd46 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -100,11 +100,6 @@ namespace MWGui } } - void EnchantingDialog::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); - } - void EnchantingDialog::updateLabels() { std::stringstream enchantCost; @@ -194,7 +189,7 @@ namespace MWGui void EnchantingDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Enchanting); } void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 41d6382cc..ace63ae5c 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -21,8 +21,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 095f392b7..effd11d55 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -29,9 +29,10 @@ namespace MWGui center(); } - void ItemSelectionDialog::exit() + bool ItemSelectionDialog::exit() { eventDialogCanceled(); + return true; } void ItemSelectionDialog::openContainer(const MWWorld::Ptr& container) diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 50e15a3fe..07b6452a5 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -21,7 +21,7 @@ namespace MWGui public: ItemSelectionDialog(const std::string& label); - virtual void exit(); + virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp index 7a544126d..36d19b5a9 100644 --- a/apps/openmw/mwgui/jailscreen.hpp +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -14,6 +14,8 @@ namespace MWGui void onFrame(float dt); + bool exit() { return false; } + private: int mDays; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7bc66fab4..8c7ec6bfe 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1114,11 +1114,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } - void EditNoteDialog::exit() - { - setVisible(false); - } - void EditNoteDialog::onCancelButtonClicked(MyGUI::Widget *sender) { setVisible(false); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index eae1cec7e..ed6e4874f 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -170,7 +170,6 @@ namespace MWGui EditNoteDialog(); virtual void onOpen(); - virtual void exit(); void showDeleteButton(bool show); bool getDeleteButtonShown(); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 785b5ee48..d3504ebc3 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -118,11 +118,6 @@ void MerchantRepair::onOpen() mList->setViewOffset(MyGUI::IntPoint(0, 0)); } -void MerchantRepair::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); -} - void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -150,7 +145,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 76ccd28cc..4e4e7164f 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -14,8 +14,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& actor); private: diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 19dd6fa03..6da7b0905 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -64,11 +64,6 @@ namespace MWGui } } - void QuickKeysMenu::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_QuickKeysMenu); - } - void QuickKeysMenu::clear() { mActivatedIndex = -1; @@ -449,11 +444,6 @@ namespace MWGui center(); } - void QuickKeysMenuAssign::exit() - { - setVisible(false); - } - void QuickKeysMenu::write(ESM::ESMWriter &writer) { writer.startRecord(ESM::REC_KEYS); @@ -585,9 +575,10 @@ namespace MWGui exit(); } - void MagicSelectionDialog::exit() + bool MagicSelectionDialog::exit() { mParent->onAssignMagicCancel(); + return true; } void MagicSelectionDialog::onOpen () diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index d07cdef3d..c99d482ee 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -22,8 +22,6 @@ namespace MWGui QuickKeysMenu(); ~QuickKeysMenu(); - virtual void exit(); - void onItemButtonClicked(MyGUI::Widget* sender); void onMagicButtonClicked(MyGUI::Widget* sender); void onUnassignButtonClicked(MyGUI::Widget* sender); @@ -77,7 +75,6 @@ namespace MWGui { public: QuickKeysMenuAssign(QuickKeysMenu* parent); - virtual void exit(); private: MyGUI::TextBox* mLabel; @@ -95,7 +92,7 @@ namespace MWGui MagicSelectionDialog(QuickKeysMenu* parent); virtual void onOpen(); - virtual void exit(); + virtual bool exit(); private: MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 911bce577..c9e31d42d 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -54,6 +54,8 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 54473746a..0398112ba 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -62,11 +62,6 @@ void Recharge::onOpen() mBox->resetScrollbars(); } -void Recharge::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); -} - void Recharge::setPtr (const MWWorld::Ptr &item) { mGemIcon->setItem(item); @@ -107,7 +102,7 @@ void Recharge::updateView() void Recharge::onCancel(MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); } void Recharge::onSelectItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 93f86ab65..f4602ce30 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -24,8 +24,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& gem); protected: diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 295b8254b..a461f7b3d 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -58,11 +58,6 @@ void Repair::onOpen() mRepairBox->resetScrollbars(); } -void Repair::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); -} - void Repair::setPtr(const MWWorld::Ptr &item) { MWBase::Environment::get().getWindowManager()->playSound("Item Repair Up"); @@ -145,7 +140,7 @@ void Repair::onItemCancel() void Repair::onCancel(MyGUI::Widget* /*sender*/) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index a2573d780..f31625095 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -21,8 +21,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& item); protected: diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 34dd5a7d4..8e9ec0ec7 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -31,6 +31,8 @@ namespace MWGui ReviewDialog(); + bool exit() { return false; } + void setPlayerName(const std::string &name); void setRace(const std::string &raceId); void setClass(const ESM::Class& class_); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 7a4c3a22e..e7c27b268 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -191,11 +191,6 @@ namespace MWGui } - void SaveGameDialog::exit() - { - setVisible(false); - } - void SaveGameDialog::setLoadOrSave(bool load) { mSaving = !load; @@ -217,7 +212,7 @@ namespace MWGui void SaveGameDialog::onCancelButtonClicked(MyGUI::Widget *sender) { - exit(); + setVisible(false); } void SaveGameDialog::onDeleteButtonClicked(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 2a49cf48a..39e3d310a 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -19,8 +19,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setLoadOrSave(bool load); private: diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index ccbd1d7c0..a92ef92ab 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -76,11 +76,6 @@ namespace MWGui setTakeButtonShow(showTakeButton); } - void ScrollWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); - } - void ScrollWindow::setTakeButtonShow(bool show) { mTakeButtonShow = show; @@ -95,7 +90,7 @@ namespace MWGui void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 5ae8e972a..596db06ad 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -18,7 +18,6 @@ namespace MWGui ScrollWindow (); void setPtr (const MWWorld::Ptr& scroll); - virtual void exit(); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 4e8547d33..c239fc12f 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -258,7 +258,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -559,11 +559,6 @@ namespace MWGui resetScrollbars(); } - void SettingsWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); - } - void SettingsWindow::onWindowResize(MyGUI::Window *_sender) { layoutControlsBox(); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 447331574..4f8607fda 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -17,8 +17,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void updateControlsBox(); protected: diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 592316274..aeb5cfbe5 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -31,11 +31,6 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); } - void SpellBuyingWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); - } - bool SpellBuyingWindow::sortSpells (const ESM::Spell* left, const ESM::Spell* right) { std::string leftName = Misc::StringUtils::lowerCase(left->mName); @@ -173,7 +168,7 @@ namespace MWGui void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellBuying); } void SpellBuyingWindow::updateLabels() diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index b96896e4c..01cc6c2f9 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,8 +28,6 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void setPtr(const MWWorld::Ptr& actor, int startOffset); - virtual void exit(); - protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index d5982a174..8d0639d25 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -102,13 +102,13 @@ namespace MWGui center(); } - void EditEffectDialog::exit() + bool EditEffectDialog::exit() { - setVisible(false); if(mEditing) eventEffectModified(mOldEffect); else eventEffectRemoved(mEffect); + return true; } void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) @@ -275,6 +275,7 @@ namespace MWGui void EditEffectDialog::onCancelButtonClicked (MyGUI::Widget* sender) { + setVisible(false); exit(); } @@ -362,7 +363,7 @@ namespace MWGui void SpellCreationDialog::onCancelButtonClicked (MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); } void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender) @@ -420,11 +421,6 @@ namespace MWGui center(); } - void SpellCreationDialog::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); - } - void SpellCreationDialog::onReferenceUnavailable () { MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 76038abb4..f7bb8a101 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -24,7 +24,7 @@ namespace MWGui EditEffectDialog(); virtual void onOpen(); - virtual void exit(); + virtual bool exit(); void setConstantEffect(bool constant); @@ -151,7 +151,6 @@ namespace MWGui SpellCreationDialog(); virtual void onOpen(); - virtual void exit(); void setPtr(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index ccfa19c87..56c6632e1 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -22,6 +22,8 @@ namespace MWGui void setTextLabel(const std::string &label); virtual void onOpen(); + bool exit() { return false; } + /** Event : Dialog finished, OK button clicked.\n signature : void method()\n */ diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 60abf4ac7..2a6c61a16 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -171,11 +171,11 @@ namespace MWGui return mPtr.getClass().getServices(mPtr); } - void TradeWindow::exit() + bool TradeWindow::exit() { mTradeModel->abort(); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->abort(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + return true; } void TradeWindow::onItemSelected (int index) @@ -362,6 +362,7 @@ namespace MWGui void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 984f5a394..55164b934 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -34,7 +34,7 @@ namespace MWGui int getMerchantServices(); - virtual void exit(); + virtual bool exit(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 3079adb6d..ca6f2246e 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -60,11 +60,6 @@ namespace MWGui center(); } - void TrainingWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - } - void TrainingWindow::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; @@ -124,7 +119,7 @@ namespace MWGui void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Training); } void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index e52a889ef..d4785194a 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -16,8 +16,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 4c4dc436c..02df6bd8e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -45,11 +45,6 @@ namespace MWGui mSelect->getHeight()); } - void TravelWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - } - void TravelWindow::addDestination(const std::string& name,ESM::Position pos,bool interior) { int price; @@ -194,7 +189,7 @@ namespace MWGui void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); } void TravelWindow::updateLabels() diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 529d5ebe1..5ae466047 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -24,8 +24,6 @@ namespace MWGui public: TravelWindow(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& actor); protected: diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 476d19bd6..b39b1a8ab 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -79,10 +79,9 @@ namespace MWGui mProgressBar.setVisible (false); } - void WaitDialog::exit() + bool WaitDialog::exit() { - if(!mProgressBar.isVisible()) //Only exit if not currently waiting - MWBase::Environment::get().getWindowManager()->popGuiMode(); + return (!mProgressBar.isVisible()); //Only exit if not currently waiting } void WaitDialog::onOpen() diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 829659d16..9bf8279be 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -29,7 +29,7 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); + virtual bool exit(); void onFrame(float dt); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 73574ce7c..e6817358f 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -34,7 +34,7 @@ namespace MWGui /// Notify that window has been hidden virtual void onClose () {} /// Gracefully exits the window - virtual void exit() {} + virtual bool exit() {return true;} /// Sets the visibility of the window virtual void setVisible(bool visible); /// Returns the visibility state of the window @@ -52,7 +52,7 @@ namespace MWGui WindowModal(const std::string& parLayout); virtual void onOpen(); virtual void onClose(); - virtual void exit() {} + virtual bool exit() {return true;} }; /// A window that cannot be the target of a drag&drop action. diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 70b95351b..31a072fd1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -769,89 +769,19 @@ namespace MWGui return; } - switch(mGuiModes.back()) { - case GM_QuickKeysMenu: - mQuickKeysMenu->exit(); - break; - case GM_MainMenu: - removeGuiMode(GM_MainMenu); //Simple way to remove it - break; - case GM_Settings: - mSettingsWindow->exit(); - break; - case GM_Console: - mConsole->exit(); - break; - case GM_Scroll: - mScrollWindow->exit(); - break; - case GM_Book: - mBookWindow->exit(); - break; - case GM_Alchemy: - mAlchemyWindow->exit(); - break; - case GM_Rest: - mWaitDialog->exit(); - break; - case GM_RestBed: - mWaitDialog->exit(); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - break; - case GM_Inventory: - removeGuiMode(GM_Inventory); //Simple way to remove it - break; - case GM_Container: - mContainerWindow->exit(); - break; - case GM_Companion: - mCompanionWindow->exit(); - break; - case GM_Dialogue: - mDialogueWindow->exit(); - break; - case GM_Barter: - mTradeWindow->exit(); - break; - case GM_SpellBuying: - mSpellBuyingWindow->exit(); - break; - case GM_Travel: - mTravelWindow->exit(); - break; - case GM_SpellCreation: - mSpellCreationDialog->exit(); - break; - case GM_Recharge: - mRecharge->exit(); - break; - case GM_Enchanting: - mEnchantingDialog->exit(); - break; - case GM_Training: - mTrainingWindow->exit(); - break; - case GM_MerchantRepair: - mMerchantRepair->exit(); - break; - case GM_Repair: - mRepair->exit(); - break; - case GM_Journal: - removeGuiMode(GM_Journal); //Simple way to remove it - break; - default: - // Unsupported mode, switch back to game - break; + GuiModeState& state = mGuiModeStates[mGuiModes.back()]; + for (WindowBase* window : state.mWindows) + { + if (!window->exit()) + { + // unable to exit window, but give access to main menu + if (!MyGUI::InputManager::getInstance().isModalAny()) + pushGuiMode (MWGui::GM_MainMenu); + return; + } } + + popGuiMode(); } void WindowManager::interactiveMessageBox(const std::string &message, const std::vector &buttons, bool block) @@ -1267,10 +1197,11 @@ namespace MWGui if (!mGuiModes.empty()) { - mGuiModeStates[mGuiModes.back()].update(false); - if (!noSound) - playSound(mGuiModeStates[mGuiModes.back()].mCloseSound); + const GuiMode mode = mGuiModes.back(); mGuiModes.pop_back(); + mGuiModeStates[mode].update(false); + if (!noSound) + playSound(mGuiModeStates[mode].mCloseSound); } if (!mGuiModes.empty()) @@ -1849,10 +1780,11 @@ namespace MWGui void WindowManager::exitCurrentModal() { if (!mCurrentModals.empty()) - mCurrentModals.top()->exit(); - - if (mCurrentModals.empty()) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + { + if (!mCurrentModals.top()->exit()) + return; + mCurrentModals.top()->setVisible(false); + } } void WindowManager::addCurrentModal(WindowModal *input) From be19f51013ece60db26a860388778c1b5b6f103c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:55:28 +0200 Subject: [PATCH 042/150] Adjust some more windows to be keyboard friendlier --- apps/openmw/mwgui/birth.cpp | 1 + apps/openmw/mwgui/class.cpp | 1 + apps/openmw/mwgui/dialogue.cpp | 3 +++ apps/openmw/mwgui/race.cpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.cpp | 1 + apps/openmw/mwgui/spellview.cpp | 1 + files/mygui/openmw_inventory_window.layout | 5 +++++ files/mygui/openmw_trade_window.layout | 5 +++++ 8 files changed, 19 insertions(+) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index b4a6b7d2f..92f29e3ef 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -69,6 +69,7 @@ namespace MWGui WindowModal::onOpen(); updateBirths(); updateSpells(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList); } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index c63d470d7..33daa0ad1 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -130,6 +130,7 @@ namespace MWGui WindowModal::onOpen (); updateClasses(); updateStats(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 48d291325..2effcc700 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -526,7 +526,10 @@ namespace MWGui } bool goodbyeEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() || mGoodbye; + bool goodbyeWasEnabled = mGoodbyeButton->getEnabled(); mGoodbyeButton->setEnabled(goodbyeEnabled); + if (goodbyeEnabled && !goodbyeWasEnabled) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); bool topicsEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye; mTopicsList->setEnabled(topicsEnabled); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 374a5d3d8..2b407ac93 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -163,6 +163,8 @@ namespace MWGui size_t initialPos = mHeadRotate->getScrollRange()/2+mHeadRotate->getScrollRange()/10; mHeadRotate->setScrollPosition(initialPos); onHeadRotate(mHeadRotate, initialPos); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mRaceList); } void RaceDialog::setRaceId(const std::string &raceId) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 8d0639d25..d5dee1139 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -419,6 +419,7 @@ namespace MWGui void SpellCreationDialog::onOpen() { center(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); } void SpellCreationDialog::onReferenceUnavailable () diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index ebda8873c..4268b33a0 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -106,6 +106,7 @@ namespace MWGui Gui::SharedStateButton* t = mScrollView->createWidget(skin, MyGUI::IntCoord(0, 0, 0, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setNeedKeyFocus(true); t->setCaption(spell.mName); t->setTextAlign(MyGUI::Align::Left); adjustSpellWidget(spell, i, t); diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index bb707fa0d..6221799b5 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -32,18 +32,23 @@ + + + + + diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index f9f24581f..d1f31c475 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -9,18 +9,23 @@ + + + + + From ad4b91131f998253bf3fedca03f405c79dcc3d11 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:58:28 +0200 Subject: [PATCH 043/150] toggleGui renamed to toggleHud, remove unused variable --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++++++------- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ++--- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwscript/guiextensions.cpp | 2 +- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 243ec3ccf..190768f26 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -229,7 +229,7 @@ namespace MWBase virtual void showCrosshair(bool show) = 0; virtual bool getSubtitlesEnabled() = 0; - virtual bool toggleGui() = 0; + virtual bool toggleHud() = 0; virtual void disallowMouse() = 0; virtual void allowMouse() = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 31a072fd1..2c58336da 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -190,7 +190,6 @@ namespace MWGui , mHitFaderEnabled(Settings::Manager::getBool ("hit fader", "GUI")) , mWerewolfOverlayEnabled(Settings::Manager::getBool ("werewolf overlay", "GUI")) , mHudEnabled(true) - , mGuiEnabled(true) , mCursorVisible(true) , mPlayerName() , mPlayerRaceId() @@ -450,7 +449,7 @@ namespace MWGui mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); - mHud->setVisible(mHudEnabled); + mHud->setVisible(true); mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem); @@ -598,8 +597,8 @@ namespace MWGui bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper); - mHud->setVisible(mHudEnabled && mGuiEnabled && !loading); - mToolTips->setVisible(mGuiEnabled && !loading); + mHud->setVisible(mHudEnabled && !loading); + mToolTips->setVisible(mHudEnabled && !loading); bool gameMode = !isGuiMode(); @@ -1477,11 +1476,11 @@ namespace MWGui return mSubtitlesEnabled; } - bool WindowManager::toggleGui() + bool WindowManager::toggleHud() { - mGuiEnabled = !mGuiEnabled; + mHudEnabled = !mHudEnabled; updateVisible(); - return mGuiEnabled; + return mHudEnabled; } bool WindowManager::getRestEnabled() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9fa921a4c..17707d2c3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -260,8 +260,8 @@ namespace MWGui virtual void showCrosshair(bool show); virtual bool getSubtitlesEnabled(); - /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) - virtual bool toggleGui(); + /// Turn visibility of HUD on or off + virtual bool toggleHud(); virtual void disallowMouse(); virtual void allowMouse(); @@ -468,7 +468,6 @@ namespace MWGui bool mHitFaderEnabled; bool mWerewolfOverlayEnabled; bool mHudEnabled; - bool mGuiEnabled; bool mCursorVisible; void setCursorVisible(bool visible); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf42db04b..cd17c5175 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -289,7 +289,7 @@ namespace MWInput showQuickKeysMenu(); break; case A_ToggleHUD: - MWBase::Environment::get().getWindowManager()->toggleGui(); + MWBase::Environment::get().getWindowManager()->toggleHud(); break; case A_ToggleDebug: MWBase::Environment::get().getWindowManager()->toggleDebugWindow(); diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 254da56d6..6f2c146b1 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -209,7 +209,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - bool state = MWBase::Environment::get().getWindowManager()->toggleGui(); + bool state = MWBase::Environment::get().getWindowManager()->toggleHud(); runtime.getContext().report(state ? "GUI -> On" : "GUI -> Off"); if (!state) From 35110fb2f8e1b43b6200a307c33d3bc50066a941 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 13:31:22 +0200 Subject: [PATCH 044/150] Remove unused and slightly broken custom button titles in ConfirmationDialog --- apps/openmw/mwgui/confirmationdialog.cpp | 8 -------- apps/openmw/mwgui/confirmationdialog.hpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 697d90862..65b079d85 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -19,14 +19,6 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); } - void ConfirmationDialog::askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage) - { - mCancelButton->setCaptionWithReplacing(cancelMessage); - mOkButton->setCaptionWithReplacing(confirmMessage); - - askForConfirmation(message); - } - void ConfirmationDialog::askForConfirmation(const std::string& message) { setVisible(true); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 259579376..ab52549ec 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -10,7 +10,6 @@ namespace MWGui public: ConfirmationDialog(); void askForConfirmation(const std::string& message); - void askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage); virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 8c7ec6bfe..d3c1ec292 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -701,7 +701,7 @@ namespace MWGui void MapWindow::onNoteEditDelete() { ConfirmationDialog* confirmation = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - confirmation->askForConfirmation("#{sDeleteNote}", "#{sYes}", "#{sNo}"); + confirmation->askForConfirmation("#{sDeleteNote}"); confirmation->eventCancelClicked.clear(); confirmation->eventOkClicked.clear(); confirmation->eventOkClicked += MyGUI::newDelegate(this, &MapWindow::onNoteEditDeleteConfirm); From 5f440a29bda58ce9f5afa80e02148155b4d1cc37 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 13:49:09 +0200 Subject: [PATCH 045/150] Remember key focus per GUI mode Among other things, this will remember the focused button in the container window, allowing quick looting of multiple containers. --- apps/openmw/mwgui/keyboardnavigation.cpp | 25 +++++++++++++++++++++ apps/openmw/mwgui/keyboardnavigation.hpp | 10 ++++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 28 +++++++++++------------- apps/openmw/mwgui/windowmanagerimp.hpp | 6 +---- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index ba09ce369..c97532df5 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -28,10 +28,35 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu KeyboardNavigation::KeyboardNavigation() { + MyGUI::WidgetManager::getInstance().registerUnlinker(this); } KeyboardNavigation::~KeyboardNavigation() { + MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); +} + +void KeyboardNavigation::saveFocus(int mode) +{ + mKeyFocus[mode] = MyGUI::InputManager::getInstance().getKeyFocusWidget(); +} + +void KeyboardNavigation::restoreFocus(int mode) +{ + std::map::const_iterator found = mKeyFocus.find(mode); + if (found != mKeyFocus.end()) + { + MyGUI::Widget* w = found->second; + if (w && w->getVisible() && w->getEnabled()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(found->second); + } +} + +void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) +{ + for (std::pair& w : mKeyFocus) + if (w.second == widget) + w.second = nullptr; } bool isButtonFocus() diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index 86cc67962..fff36d862 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -2,11 +2,12 @@ #define OPENMW_MWGUI_KEYBOARDNAVIGATION_H #include +#include namespace MWGui { - class KeyboardNavigation + class KeyboardNavigation : public MyGUI::IUnlinkWidget { public: KeyboardNavigation(); @@ -15,11 +16,18 @@ namespace MWGui /// @return Was the key handled by this class? bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + void saveFocus(int mode); + void restoreFocus(int mode); + + void _unlinkWidget(MyGUI::Widget* widget); + private: bool switchFocus(int direction, bool wrap); /// Send button press event to focused button bool accept(); + + std::map mKeyFocus; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2c58336da..6306ef81a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -137,7 +137,6 @@ namespace MWGui , mWorkQueue(workQueue) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) - , mSaveKeyFocus(NULL) , mCurrentModals() , mHud(NULL) , mMap(NULL) @@ -261,8 +260,6 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); - MyGUI::WidgetManager::getInstance().registerUnlinker(this); - // Create all cursors in advance createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); @@ -505,8 +502,6 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); - MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); - delete mConsole; delete mMessageBoxManager; delete mHud; @@ -1171,8 +1166,10 @@ namespace MWGui } if (!mGuiModes.empty()) + { + mKeyboardNavigation->saveFocus(mGuiModes.back()); mGuiModeStates[mGuiModes.back()].update(false); - + } mGuiModes.push_back(mode); mGuiModeStates[mode].update(true); @@ -1181,6 +1178,8 @@ namespace MWGui for (WindowBase* window : mGuiModeStates[mode].mWindows) window->setPtr(arg); + mKeyboardNavigation->restoreFocus(mode); + bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1197,6 +1196,7 @@ namespace MWGui if (!mGuiModes.empty()) { const GuiMode mode = mGuiModes.back(); + mKeyboardNavigation->saveFocus(mode); mGuiModes.pop_back(); mGuiModeStates[mode].update(false); if (!noSound) @@ -1204,7 +1204,11 @@ namespace MWGui } if (!mGuiModes.empty()) - mGuiModeStates[mGuiModes.back()].update(true); + { + const GuiMode mode = mGuiModes.back(); + mGuiModeStates[mode].update(true); + mKeyboardNavigation->restoreFocus(mode); + } bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1564,12 +1568,6 @@ namespace MWGui return mLoadingScreen; } - void WindowManager::_unlinkWidget(MyGUI::Widget *widget) - { - if (widget == mSaveKeyFocus) - mSaveKeyFocus = NULL; - } - bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1789,7 +1787,7 @@ namespace MWGui void WindowManager::addCurrentModal(WindowModal *input) { if (mCurrentModals.empty()) - mSaveKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + mKeyboardNavigation->saveFocus(getMode()); mCurrentModals.push(input); } @@ -1803,7 +1801,7 @@ namespace MWGui mCurrentModals.pop(); if (mCurrentModals.empty()) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + mKeyboardNavigation->restoreFocus(getMode()); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 17707d2c3..30d19e9f1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -124,7 +124,7 @@ namespace MWGui class JailScreen; class KeyboardNavigation; - class WindowManager : public MWBase::WindowManager, MyGUI::IUnlinkWidget + class WindowManager : public MWBase::WindowManager { public: typedef std::pair Faction; @@ -142,8 +142,6 @@ namespace MWGui virtual Loading::Listener* getLoadingScreen(); - void _unlinkWidget(MyGUI::Widget* widget); - /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); @@ -406,8 +404,6 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; - MyGUI::Widget* mSaveKeyFocus; - std::stack mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). From 65a707348caf471eed2d7f5211aff7de6f1575a3 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 14:27:10 +0200 Subject: [PATCH 046/150] Make Tab select the first widget if none is selected --- apps/openmw/mwgui/keyboardnavigation.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index c97532df5..8ce26e1d0 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -13,6 +14,9 @@ namespace MWGui /// Recursively get all child widgets that accept keyboard input void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) { + if (!parent->getVisible() || !parent->getEnabled()) + return; + MyGUI::EnumeratorWidgetPtr enumerator = parent->getEnumerator(); while (enumerator.next()) { @@ -101,6 +105,22 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + if (!focus && (direction == D_Next || direction == D_Prev)) + { + // if nothing is selected, select the first widget + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + } + if (!focus) return false; From 9ead331741fb4ccd1a2615047739e5c03b9030d6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 14:42:25 +0200 Subject: [PATCH 047/150] Fix pinned windows showing in other GUI modes --- apps/openmw/mwgui/windowmanagerimp.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6306ef81a..8266e3e8d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -613,6 +613,8 @@ namespace MWGui setSpellVisibility((mAllowed & GW_Magic) && (!mSpellWindow->pinned() || (mForceHidden & GW_Magic))); setHMSVisibility((mAllowed & GW_Stats) && (!mStatsWindow->pinned() || (mForceHidden & GW_Stats))); + mInventoryWindow->setGuiMode(getMode()); + // If in game mode (or interactive messagebox), show the pinned windows if (mGuiModes.empty()) { @@ -622,11 +624,17 @@ namespace MWGui mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); return; } + else if (getMode() != GM_Inventory) + { + mMap->setVisible(false); + mStatsWindow->setVisible(false); + mSpellWindow->setVisible(false); + mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter); + } GuiMode mode = mGuiModes.back(); mInventoryWindow->setTrading(mode == GM_Barter); - mInventoryWindow->setGuiMode(mode); // For the inventory mode, compute the effective set of windows to show. // This is controlled both by what windows the From 32f9c8058a5e919ed60306e4ce986d839d8bd8bb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 15:06:11 +0200 Subject: [PATCH 048/150] Remove redundant RestBed gui mode --- apps/openmw/mwgui/mode.hpp | 1 - apps/openmw/mwgui/waitdialog.cpp | 10 ++++++---- apps/openmw/mwgui/waitdialog.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +------ apps/openmw/mwscript/guiextensions.cpp | 2 +- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index db851e067..c452a1f5f 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -23,7 +23,6 @@ namespace MWGui GM_Dialogue, // NPC interaction GM_Barter, GM_Rest, - GM_RestBed, GM_SpellBuying, GM_Travel, GM_SpellCreation, diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index b39b1a8ab..afcf23be3 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -79,6 +79,11 @@ namespace MWGui mProgressBar.setVisible (false); } + void WaitDialog::setPtr(const MWWorld::Ptr &ptr) + { + setCanRest(!ptr.isEmpty() || MWBase::Environment::get().getWorld ()->canRest () == 0); + } + bool WaitDialog::exit() { return (!mProgressBar.isVisible()); //Only exit if not currently waiting @@ -100,8 +105,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode (); } - setCanRest(canRest == 0); - onHourSliderChangedPosition(mHourSlider, 0); mHourSlider->setScrollPosition (0); @@ -176,7 +179,7 @@ namespace MWGui void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Rest); } void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) @@ -264,7 +267,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); mTimeAdvancer.stop(); } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 9bf8279be..19c265204 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -27,14 +27,14 @@ namespace MWGui public: WaitDialog(); + void setPtr(const MWWorld::Ptr &ptr); + virtual void onOpen(); virtual bool exit(); void onFrame(float dt); - void bedActivated() { setCanRest(true); } - bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8266e3e8d..bfd6fd20d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -398,7 +398,6 @@ namespace MWGui mWaitDialog = new WaitDialog(); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); - mGuiModeStates[GM_RestBed] = GuiModeState(mWaitDialog); mSpellCreationDialog = new SpellCreationDialog(); mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); @@ -662,10 +661,6 @@ namespace MWGui case GM_Review: mCharGen->spawnDialog(mode); break; - case GM_RestBed: - // FIXME: use GM_Rest and push the 'bed' argument in some other way - mWaitDialog->bedActivated(); - break; default: break; } @@ -1700,7 +1695,7 @@ namespace MWGui { return !MyGUI::InputManager::getInstance().isModalAny() // TODO: remove this, once we have properly serialized the state of open windows - && (!isGuiMode() || (mGuiModes.size() == 1 && (getMode() == GM_MainMenu || getMode() == GM_Rest || getMode() == GM_RestBed))); + && (!isGuiMode() || (mGuiModes.size() == 1 && (getMode() == GM_MainMenu || getMode() == GM_Rest))); } void WindowManager::playVideo(const std::string &name, bool allowSkipping) diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 6f2c146b1..cea176ff6 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -57,7 +57,7 @@ namespace MWScript if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWMechanics::getPlayer(), bed)) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Rest, bed); } }; From ba7ae2663f26b7376ab79a878719a6e617021e00 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 21:45:52 +0200 Subject: [PATCH 049/150] Use a generic container to delete windows --- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 92 ++++++++++++++------------ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +- 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ba4d05d75..ed7273384 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -68,7 +68,7 @@ namespace MWGui HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) - : Layout("openmw_hud.layout") + : WindowBase("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender, Settings::Manager::getBool("local map hud fog of war", "Map")) , mHealth(NULL) , mMagicka(NULL) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index e2ef52be0..4ea9d7ac3 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -16,7 +16,7 @@ namespace MWGui class SpellIcons; class ItemWidget; - class HUD : public Layout, public LocalMapBase + class HUD : public WindowBase, public LocalMapBase { public: HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bfd6fd20d..47557f369 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -146,7 +146,6 @@ namespace MWGui , mStatsWindow(NULL) , mMessageBoxManager(NULL) , mConsole(NULL) - , mJournal(NULL) , mDialogueWindow(NULL) , mContainerWindow(NULL) , mDragAndDrop(NULL) @@ -252,6 +251,7 @@ namespace MWGui mKeyboardNavigation.reset(new KeyboardNavigation()); mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); + mWindows.push_back(mLoadingScreen); //set up the hardware cursor manager mCursorManager = new SDLUtil::SDLCursorManager(); @@ -321,112 +321,153 @@ namespace MWGui mRecharge = new Recharge(); mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); + mWindows.push_back(mRecharge); mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); + mWindows.push_back(mMenu); mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); + mWindows.push_back(mMap); mMap->renderGlobalMap(); trackWindow(mMap, "map"); + mStatsWindow = new StatsWindow(mDragAndDrop); + mWindows.push_back(mStatsWindow); trackWindow(mStatsWindow, "stats"); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); + mWindows.push_back(mInventoryWindow); + mSpellWindow = new SpellWindow(mDragAndDrop); + mWindows.push_back(mSpellWindow); trackWindow(mSpellWindow, "spells"); mGuiModeStates[GM_Inventory] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); mGuiModeStates[GM_None] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); mTradeWindow = new TradeWindow(); + mWindows.push_back(mTradeWindow); trackWindow(mTradeWindow, "barter"); mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); mConsole = new Console(w,h, mConsoleOnlyScripts); + mWindows.push_back(mConsole); trackWindow(mConsole, "console"); mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); - mJournal = JournalWindow::create(JournalViewModel::create (), questList); - mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList); + mWindows.push_back(journal); + mGuiModeStates[GM_Journal] = GuiModeState(journal); mGuiModeStates[GM_Journal].mCloseSound = "book close"; mGuiModeStates[GM_Journal].mOpenSound = "book open"; mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); + mSpellBuyingWindow = new SpellBuyingWindow(); + mWindows.push_back(mSpellBuyingWindow); mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); mTravelWindow = new TravelWindow(); + mWindows.push_back(mTravelWindow); mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); mDialogueWindow = new DialogueWindow(); + mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); mContainerWindow = new ContainerWindow(mDragAndDrop); + mWindows.push_back(mContainerWindow); trackWindow(mContainerWindow, "container"); mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); + mWindows.push_back(mHud); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mWindows.push_back(mScrollWindow); mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); mGuiModeStates[GM_Scroll].mOpenSound = "scroll"; mGuiModeStates[GM_Scroll].mCloseSound = "scroll"; mBookWindow = new BookWindow(); + mWindows.push_back(mBookWindow); mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); mGuiModeStates[GM_Book].mOpenSound = "book open"; mGuiModeStates[GM_Book].mCloseSound = "book close"; mCountDialog = new CountDialog(); + mWindows.push_back(mCountDialog); + mSettingsWindow = new SettingsWindow(); + mWindows.push_back(mSettingsWindow); mGuiModeStates[GM_Settings] = GuiModeState(mSettingsWindow); mConfirmationDialog = new ConfirmationDialog(); + mWindows.push_back(mConfirmationDialog); mAlchemyWindow = new AlchemyWindow(); + mWindows.push_back(mAlchemyWindow); trackWindow(mAlchemyWindow, "alchemy"); mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); mQuickKeysMenu = new QuickKeysMenu(); + mWindows.push_back(mQuickKeysMenu); mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); mLevelupDialog = new LevelupDialog(); + mWindows.push_back(mLevelupDialog); mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); mWaitDialog = new WaitDialog(); + mWindows.push_back(mWaitDialog); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); mSpellCreationDialog = new SpellCreationDialog(); + mWindows.push_back(mSpellCreationDialog); mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); mEnchantingDialog = new EnchantingDialog(); + mWindows.push_back(mEnchantingDialog); mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); mTrainingWindow = new TrainingWindow(); + mWindows.push_back(mTrainingWindow); mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); mMerchantRepair = new MerchantRepair(); + mWindows.push_back(mMerchantRepair); mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); mRepair = new Repair(); + mWindows.push_back(mRepair); mGuiModeStates[GM_Repair] = GuiModeState(mRepair); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); + mWindows.push_back(mCompanionWindow); trackWindow(mCompanionWindow, "companion"); mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); mJailScreen = new JailScreen(); + mWindows.push_back(mJailScreen); mGuiModeStates[GM_Jail] = GuiModeState(mJailScreen); std::string werewolfFaderTex = "textures\\werewolfoverlay.dds"; if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) + { mWerewolfFader = new ScreenFader(werewolfFaderTex); + mWindows.push_back(mWerewolfFader); + } mBlindnessFader = new ScreenFader("black"); + mWindows.push_back(mBlindnessFader); // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; @@ -438,10 +479,13 @@ namespace MWGui hitFaderCoord = MyGUI::FloatCoord(0.2, 0.25, 0.6, 0.5); } mHitFader = new ScreenFader(hitFaderTexture, hitFaderLayout, hitFaderCoord); + mWindows.push_back(mHitFader); mScreenFader = new ScreenFader("black"); + mWindows.push_back(mScreenFader); mDebugWindow = new DebugWindow(); + mWindows.push_back(mDebugWindow); mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); @@ -501,49 +545,15 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); - delete mConsole; + for (WindowBase* window : mWindows) + delete window; + mWindows.clear(); + delete mMessageBoxManager; - delete mHud; - delete mMap; delete mLocalMapRender; - delete mMenu; - delete mStatsWindow; - delete mJournal; - delete mDialogueWindow; - delete mContainerWindow; - delete mInventoryWindow; - delete mToolTips; delete mCharGen; delete mDragAndDrop; - delete mBookWindow; - delete mScrollWindow; - delete mTradeWindow; - delete mSpellBuyingWindow; - delete mTravelWindow; - delete mSettingsWindow; - delete mConfirmationDialog; - delete mAlchemyWindow; - delete mSpellWindow; - delete mLoadingScreen; - delete mLevelupDialog; - delete mWaitDialog; - delete mSpellCreationDialog; - delete mEnchantingDialog; - delete mTrainingWindow; - delete mCountDialog; - delete mQuickKeysMenu; - delete mMerchantRepair; - delete mRepair; delete mSoulgemDialog; - delete mRecharge; - delete mCompanionWindow; - delete mHitFader; - delete mWerewolfFader; - delete mScreenFader; - delete mBlindnessFader; - delete mDebugWindow; - delete mJailScreen; - delete mCursorManager; cleanupGarbage(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 30d19e9f1..90fcf8979 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -417,7 +417,6 @@ namespace MWGui StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; - JournalWindow* mJournal; DialogueWindow *mDialogueWindow; ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; @@ -453,6 +452,8 @@ namespace MWGui DebugWindow* mDebugWindow; JailScreen* mJailScreen; + std::vector mWindows; + Translation::Storage& mTranslationDataStorage; CharacterCreation* mCharGen; From 2b03bc0c5695623ffc5693fae30b875b34ee8f07 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:00:15 +0200 Subject: [PATCH 050/150] Call WindowBase::onFrame() for every active window --- apps/openmw/mwgui/companionwindow.cpp | 3 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/console.hpp | 2 ++ apps/openmw/mwgui/container.hpp | 2 ++ apps/openmw/mwgui/dialogue.cpp | 5 ++-- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 ++ apps/openmw/mwgui/inventorywindow.cpp | 5 +--- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/mainmenu.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.hpp | 2 ++ apps/openmw/mwgui/spellwindow.cpp | 15 ++++------ apps/openmw/mwgui/statswindow.cpp | 3 -- apps/openmw/mwgui/tradewindow.cpp | 5 ++++ apps/openmw/mwgui/tradewindow.hpp | 2 ++ apps/openmw/mwgui/trainingwindow.cpp | 1 + apps/openmw/mwgui/windowbase.hpp | 3 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 35 ++++++----------------- 20 files changed, 47 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index c4e50c8c2..90ef32ced 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -116,8 +116,9 @@ void CompanionWindow::setPtr(const MWWorld::Ptr& npc) setTitle(npc.getClass().getName(npc)); } -void CompanionWindow::onFrame() +void CompanionWindow::onFrame(float dt) { + checkReferenceAvailable(); updateEncumbranceBar(); } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index fd66cfa80..23af6bc96 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -23,7 +23,7 @@ namespace MWGui virtual void resetReference(); void setPtr(const MWWorld::Ptr& npc); - void onFrame (); + void onFrame (float dt); private: ItemView* mItemView; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 6257b5617..a68f1cb43 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -42,6 +42,8 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setFont(const std::string &fntName); void onResChange(int width, int height); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 3ae73a01f..27b0e408b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -36,6 +36,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& container); virtual void onClose(); + void onFrame(float dt) { checkReferenceAvailable(); } + virtual void resetReference(); private: diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2effcc700..ec6dcb2cb 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -630,9 +630,10 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } - void DialogueWindow::onFrame() + void DialogueWindow::onFrame(float dt) { - if(mMainWidget->getVisible() && mPtr.getTypeName() == typeid(ESM::NPC).name()) + checkReferenceAvailable(); + if(mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 12e2328f4..4ac5bd9d0 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -117,7 +117,7 @@ namespace MWGui void clearChoices(); void goodbye(); - void onFrame(); + void onFrame(float dt); // make sure to call these before setKeywords() void setServices(int services) { mServices = services; } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index ace63ae5c..335e5fda9 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -21,6 +21,8 @@ namespace MWGui virtual void onOpen(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index dcfb075db..735bf3682 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -589,11 +589,8 @@ namespace MWGui mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); } - void InventoryWindow::onFrame() + void InventoryWindow::onFrame(float dt) { - if (!mMainWidget->getVisible()) - return; - updateEncumbranceBar(); } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fb5be3493..5576b52ed 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -40,7 +40,7 @@ namespace MWGui /// start trading, disables item drag&drop void setTrading(bool trading); - void onFrame(); + void onFrame(float dt); void pickUpObject (MWWorld::Ptr object); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 657f0e4ec..4e629403a 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -197,7 +197,7 @@ namespace MWGui } } - void MainMenu::update(float dt) + void MainMenu::onFrame(float dt) { if (mVideo) { diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 612f7d1bd..1beb9ee16 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -36,7 +36,7 @@ namespace MWGui virtual void setVisible (bool visible); - void update(float dt); + void onFrame(float dt); private: const VFS::Manager* mVFS; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 01cc6c2f9..6eb52366b 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,6 +28,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void setPtr(const MWWorld::Ptr& actor, int startOffset); + void onFrame(float dt) { checkReferenceAvailable(); } + protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index f7bb8a101..7bacda385 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -152,6 +152,8 @@ namespace MWGui virtual void onOpen(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setPtr(const MWWorld::Ptr& actor); protected: diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 9261912b4..601204aa1 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -68,16 +68,13 @@ namespace MWGui } void SpellWindow::onFrame(float dt) - { - if (mMainWidget->getVisible()) + { + NoDrop::onFrame(dt); + mUpdateTimer += dt; + if (0.5f < mUpdateTimer) { - NoDrop::onFrame(dt); - mUpdateTimer += dt; - if (0.5f < mUpdateTimer) - { - mUpdateTimer = 0; - mSpellView->incrementalUpdate(); - } + mUpdateTimer = 0; + mSpellView->incrementalUpdate(); } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 17e51e338..bf505b00f 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -297,9 +297,6 @@ namespace MWGui void StatsWindow::onFrame (float dt) { - if (!mMainWidget->getVisible()) - return; - NoDrop::onFrame(dt); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2a6c61a16..feccfd942 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -142,6 +142,11 @@ namespace MWGui onFilterChanged(mFilterAll); } + void TradeWindow::onFrame(float dt) + { + checkReferenceAvailable(); + } + void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) { if (_sender == mFilterAll) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 55164b934..69fdc135b 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -29,6 +29,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); + void onFrame(float dt); + void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index ca6f2246e..c1f7f8ac1 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -195,6 +195,7 @@ namespace MWGui void TrainingWindow::onFrame(float dt) { + checkReferenceAvailable(); mTimeAdvancer.onFrame(dt); if (mFadeTimeRemaining <= 0) diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index e6817358f..6889ad9ec 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -29,6 +29,9 @@ namespace MWGui /// Open this object in the GUI, for windows that support it virtual void setPtr(const MWWorld::Ptr& ptr) {} + /// Called every frame if the window is in an active GUI mode + virtual void onFrame(float duration) {} + /// Notify that window has been made visible virtual void onOpen() {} /// Notify that window has been hidden diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 47557f369..9635f804e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -890,12 +890,19 @@ namespace MWGui void WindowManager::onFrame (float frameDuration) { + if (!mGuiModes.empty()) + { + GuiModeState& state = mGuiModeStates[mGuiModes.back()]; + for (WindowBase* window : state.mWindows) + window->onFrame(frameDuration); + } + if (!mCurrentModals.empty()) + mCurrentModals.top()->onFrame(frameDuration); + mMessageBoxManager->onFrame(frameDuration); mToolTips->onFrame(frameDuration); - mMenu->update(frameDuration); - if (mLocalMapRender) mLocalMapRender->cleanupCameras(); @@ -909,34 +916,10 @@ namespace MWGui mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); } - mDialogueWindow->onFrame(); - - mInventoryWindow->onFrame(); - updateMap(); - mStatsWindow->onFrame(frameDuration); - mMap->onFrame(frameDuration); - mSpellWindow->onFrame(frameDuration); - - mWaitDialog->onFrame(frameDuration); - mHud->onFrame(frameDuration); - mTrainingWindow->onFrame (frameDuration); - - mTrainingWindow->checkReferenceAvailable(); - mDialogueWindow->checkReferenceAvailable(); - mTradeWindow->checkReferenceAvailable(); - mSpellBuyingWindow->checkReferenceAvailable(); - mSpellCreationDialog->checkReferenceAvailable(); - mEnchantingDialog->checkReferenceAvailable(); - mContainerWindow->checkReferenceAvailable(); - mCompanionWindow->checkReferenceAvailable(); - mConsole->checkReferenceAvailable(); - mCompanionWindow->onFrame(); - mJailScreen->onFrame(frameDuration); - if (mWerewolfFader) mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); From c6c01870ec299c0f99065d474107bf253a39ec78 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:07:30 +0200 Subject: [PATCH 051/150] Call onResChange for every window --- apps/openmw/mwgui/alchemywindow.hpp | 2 ++ apps/openmw/mwgui/bookwindow.hpp | 2 ++ apps/openmw/mwgui/quickkeysmenu.hpp | 2 ++ apps/openmw/mwgui/scrollwindow.hpp | 2 ++ apps/openmw/mwgui/settingswindow.hpp | 2 ++ apps/openmw/mwgui/spellbuyingwindow.hpp | 2 ++ apps/openmw/mwgui/windowbase.hpp | 4 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++++-------- 8 files changed, 20 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 8dffaaad1..a27d9c749 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -26,6 +26,8 @@ namespace MWGui virtual void onOpen(); + void onResChange(int, int) { center(); } + private: std::string mSuggestedPotionName; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 4f7224ea8..b20498feb 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -17,6 +17,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); + void onResChange(int, int) { center(); } + protected: void onNextPageButtonClicked (MyGUI::Widget* sender); void onPrevPageButtonClicked (MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index c99d482ee..0070aa55b 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -22,6 +22,8 @@ namespace MWGui QuickKeysMenu(); ~QuickKeysMenu(); + void onResChange(int, int) { center(); } + void onItemButtonClicked(MyGUI::Widget* sender); void onMagicButtonClicked(MyGUI::Widget* sender); void onUnassignButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 596db06ad..35016e5dc 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -20,6 +20,8 @@ namespace MWGui void setPtr (const MWWorld::Ptr& scroll); void setInventoryAllowed(bool allowed); + void onResChange(int, int) { center(); } + protected: void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 4f8607fda..c6e48819c 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -19,6 +19,8 @@ namespace MWGui void updateControlsBox(); + void onResChange(int, int) { center(); } + protected: MyGUI::TabControl* mSettingsTab; MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 6eb52366b..36f7499a0 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -30,6 +30,8 @@ namespace MWGui void onFrame(float dt) { checkReferenceAvailable(); } + void onResChange(int, int) { center(); } + protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 6889ad9ec..c9f9555b0 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -42,7 +42,11 @@ namespace MWGui virtual void setVisible(bool visible); /// Returns the visibility state of the window bool isVisible(); + void center(); + + /// Called when GUI viewport changes size + virtual void onResChange(int width, int height) {} }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9635f804e..3e55060f8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1128,14 +1128,10 @@ namespace MWGui it->first->setSize(size); } - mConsole->onResChange(x, y); - mMenu->onResChange(x, y); - mSettingsWindow->center(); - mAlchemyWindow->center(); - mScrollWindow->center(); - mBookWindow->center(); - mQuickKeysMenu->center(); - mSpellBuyingWindow->center(); + for (WindowBase* window : mWindows) + window->onResChange(x, y); + + // TODO: check if any windows are now off-screen and move them back if so } void WindowManager::onCursorChange(const std::string &name) From e7d2a8a4dc6d205a08ed2c7f372f49d56be6bf15 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:16:56 +0200 Subject: [PATCH 052/150] Call clear() for every window --- apps/openmw/mwgui/companionwindow.hpp | 1 + apps/openmw/mwgui/console.hpp | 1 + apps/openmw/mwgui/container.hpp | 1 + apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/enchantingdialog.hpp | 1 + apps/openmw/mwgui/hud.hpp | 2 ++ apps/openmw/mwgui/spellbuyingwindow.hpp | 1 + apps/openmw/mwgui/spellcreationdialog.hpp | 1 + apps/openmw/mwgui/tradewindow.hpp | 1 + apps/openmw/mwgui/trainingwindow.hpp | 2 ++ apps/openmw/mwgui/waitdialog.cpp | 5 +++++ apps/openmw/mwgui/waitdialog.hpp | 1 + apps/openmw/mwgui/windowbase.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 26 ++++++----------------- 14 files changed, 27 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 23af6bc96..891106853 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -24,6 +24,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& npc); void onFrame (float dt); + void clear() { resetReference(); } private: ItemView* mItemView; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index a68f1cb43..f243b8387 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -47,6 +47,7 @@ namespace MWGui void setFont(const std::string &fntName); void onResChange(int width, int height); + void clear() { resetReference(); } // Print a message to the console, in specified color. void print(const std::string &msg, const std::string& color = "#FFFFFF"); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 27b0e408b..a53d4f782 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -35,6 +35,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& container); virtual void onClose(); + void clear() { resetReference(); } void onFrame(float dt) { checkReferenceAvailable(); } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 4ac5bd9d0..224ecba66 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -118,6 +118,7 @@ namespace MWGui void goodbye(); void onFrame(float dt); + void clear() { resetReference(); } // make sure to call these before setKeywords() void setServices(int services) { mServices = services; } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 335e5fda9..39614ebd1 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -22,6 +22,7 @@ namespace MWGui virtual void onOpen(); void onFrame(float dt) { checkReferenceAvailable(); } + void clear() { resetReference(); } void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 4ea9d7ac3..3dae2157f 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -60,6 +60,8 @@ namespace MWGui void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); + void clear() { resetEnemy(); } + private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; MyGUI::Widget* mHealthFrame; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 36f7499a0..649aab3f2 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -29,6 +29,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor, int startOffset); void onFrame(float dt) { checkReferenceAvailable(); } + void clear() { resetReference(); } void onResChange(int, int) { center(); } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 7bacda385..855016666 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -151,6 +151,7 @@ namespace MWGui SpellCreationDialog(); virtual void onOpen(); + void clear() { resetReference(); } void onFrame(float dt) { checkReferenceAvailable(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 69fdc135b..00f38024d 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -30,6 +30,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); + void clear() { resetReference(); } void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index d4785194a..127c85f6a 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -20,6 +20,8 @@ namespace MWGui void onFrame(float dt); + void clear() { resetReference(); } + protected: virtual void onReferenceUnavailable (); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index afcf23be3..cd1d29854 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -262,6 +262,11 @@ namespace MWGui } } + void WaitDialog::clear() + { + mProgressBar.setVisible(false); + } + void WaitDialog::stopWaiting () { MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 19c265204..6bd90473f 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -34,6 +34,7 @@ namespace MWGui virtual bool exit(); void onFrame(float dt); + void clear(); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index c9f9555b0..f183c97fe 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -45,6 +45,9 @@ namespace MWGui void center(); + /// Clear any state specific to the running game + virtual void clear() {} + /// Called when GUI viewport changes size virtual void onResChange(int width, int height) {} }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3e55060f8..b512d8fc8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -514,10 +514,6 @@ namespace MWGui void WindowManager::setNewGame(bool newgame) { - // This method will always be called after loading a savegame or starting a new game - // Reset enemy, it could be a dangling pointer from a previous game - mHud->resetEnemy(); - if (newgame) { disallowAll(); @@ -1596,36 +1592,26 @@ namespace MWGui void WindowManager::clear() { + for (WindowBase* window : mWindows) + window->clear(); + if (mLocalMapRender) mLocalMapRender->clear(); - mMap->clear(); - mQuickKeysMenu->clear(); mMessageBoxManager->clear(); - mTrainingWindow->resetReference(); - mDialogueWindow->resetReference(); - mTradeWindow->resetReference(); - mSpellBuyingWindow->resetReference(); - mSpellCreationDialog->resetReference(); - mEnchantingDialog->resetReference(); - mContainerWindow->resetReference(); - mCompanionWindow->resetReference(); - mConsole->resetReference(); - mToolTips->setFocusObject(MWWorld::ConstPtr()); - mInventoryWindow->clear(); - mSelectedSpell.clear(); - mCustomMarkers.clear(); mForceHidden = GW_None; setWerewolfOverlay(false); - mGuiModes.clear(); + while (!mGuiModes.empty()) + popGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(false); updateVisible(); } From f67dbc8aa034adb3ac9740803a943cf7bb732d60 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:24:22 +0200 Subject: [PATCH 053/150] Remove redundant update function --- apps/openmw/engine.cpp | 5 ----- apps/openmw/mwbase/windowmanager.hpp | 7 ------ apps/openmw/mwgui/hud.cpp | 31 ++++++++++++-------------- apps/openmw/mwgui/hud.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++++------- apps/openmw/mwgui/windowmanagerimp.hpp | 7 ------ 6 files changed, 18 insertions(+), 47 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f5ec86cc3..3e5ab7ce6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -161,11 +161,6 @@ void OMW::Engine::frame(float frametime) // update GUI mEnvironment.getWindowManager()->onFrame(frametime); - if (mEnvironment.getStateManager()->getState()!= - MWBase::StateManager::State_NoGame) - { - mEnvironment.getWindowManager()->update(); - } unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); osg::Stats* stats = mViewer->getViewerStats(); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 190768f26..43d99b6b3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -102,13 +102,6 @@ namespace MWBase virtual ~WindowManager() {} - /** - * Should be called each frame to update windows/gui elements. - * This could mean updating sizes of gui elements or opening - * new dialogs. - */ - virtual void update() = 0; - /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping) = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ed7273384..87c1b2f3c 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -371,6 +371,20 @@ namespace MWGui if (mIsDrowning) mDrowningFlashTheta += dt * osg::PI*2; + + mSpellIcons->updateWidgets(mEffectBox, true); + + if (mEnemyActorId != -1 && mEnemyHealth->getVisible()) + { + updateEnemyHealthBar(); + } + + if (mIsDrowning) + { + float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f; + + mDrowningFlash->setAlpha(intensity); + } } void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) @@ -602,23 +616,6 @@ namespace MWGui } - void HUD::update() - { - mSpellIcons->updateWidgets(mEffectBox, true); - - if (mEnemyActorId != -1 && mEnemyHealth->getVisible()) - { - updateEnemyHealthBar(); - } - - if (mIsDrowning) - { - float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f; - - mDrowningFlash->setAlpha(intensity); - } - } - void HUD::setEnemy(const MWWorld::Ptr &enemy) { mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId(); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 3dae2157f..fc335d1e7 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -55,8 +55,6 @@ namespace MWGui MyGUI::Widget* getEffectBox() { return mEffectBox; } - void update(); - void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b512d8fc8..c9dec0287 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -581,15 +581,6 @@ namespace MWGui } } - void WindowManager::update() - { - cleanupGarbage(); - - mHud->update(); - - updateActivatedQuickKey (); - } - void WindowManager::updateVisible() { if (!mMap) @@ -926,6 +917,10 @@ namespace MWGui if (mCharGen) mCharGen->onFrame(frameDuration); + + updateActivatedQuickKey (); + + cleanupGarbage(); } void WindowManager::changeCell(const MWWorld::CellStore* cell) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 90fcf8979..773eed4fc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -146,13 +146,6 @@ namespace MWGui /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); - /** - * Should be called each frame to update windows/gui elements. - * This could mean updating sizes of gui elements or opening - * new dialogs. - */ - virtual void update(); - /// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this. virtual void setKeyFocusWidget (MyGUI::Widget* widget); From d10985e4814baea6a331a1d94698b949788e039e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:42:55 +0200 Subject: [PATCH 054/150] Remove unneeded window pointers --- apps/openmw/mwgui/windowmanagerimp.cpp | 97 +++++++++++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 13 ---- 2 files changed, 42 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c9dec0287..906151ab1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -141,37 +141,24 @@ namespace MWGui , mHud(NULL) , mMap(NULL) , mLocalMapRender(NULL) - , mMenu(NULL) , mToolTips(NULL) , mStatsWindow(NULL) , mMessageBoxManager(NULL) , mConsole(NULL) , mDialogueWindow(NULL) - , mContainerWindow(NULL) , mDragAndDrop(NULL) , mInventoryWindow(NULL) , mScrollWindow(NULL) , mBookWindow(NULL) , mCountDialog(NULL) , mTradeWindow(NULL) - , mSpellBuyingWindow(NULL) - , mTravelWindow(NULL) , mSettingsWindow(NULL) , mConfirmationDialog(NULL) - , mAlchemyWindow(NULL) , mSpellWindow(NULL) , mQuickKeysMenu(NULL) , mLoadingScreen(NULL) - , mLevelupDialog(NULL) , mWaitDialog(NULL) - , mSpellCreationDialog(NULL) - , mEnchantingDialog(NULL) - , mTrainingWindow(NULL) - , mMerchantRepair(NULL) , mSoulgemDialog(NULL) - , mRepair(NULL) - , mRecharge(NULL) - , mCompanionWindow(NULL) , mVideoBackground(NULL) , mVideoWidget(NULL) , mWerewolfFader(NULL) @@ -319,13 +306,13 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); - mRecharge = new Recharge(); - mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); - mWindows.push_back(mRecharge); + Recharge* recharge = new Recharge(); + mGuiModeStates[GM_Recharge] = GuiModeState(recharge); + mWindows.push_back(recharge); - mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); - mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); - mWindows.push_back(mMenu); + MainMenu* menu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); + mGuiModeStates[GM_MainMenu] = GuiModeState(menu); + mWindows.push_back(menu); mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); @@ -367,23 +354,23 @@ namespace MWGui mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); - mSpellBuyingWindow = new SpellBuyingWindow(); - mWindows.push_back(mSpellBuyingWindow); - mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); + SpellBuyingWindow* spellBuyingWindow = new SpellBuyingWindow(); + mWindows.push_back(spellBuyingWindow); + mGuiModeStates[GM_SpellBuying] = GuiModeState(spellBuyingWindow); - mTravelWindow = new TravelWindow(); - mWindows.push_back(mTravelWindow); - mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); + TravelWindow* travelWindow = new TravelWindow(); + mWindows.push_back(travelWindow); + mGuiModeStates[GM_Travel] = GuiModeState(travelWindow); mDialogueWindow = new DialogueWindow(); mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); - mContainerWindow = new ContainerWindow(mDragAndDrop); - mWindows.push_back(mContainerWindow); - trackWindow(mContainerWindow, "container"); - mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); + ContainerWindow* containerWindow = new ContainerWindow(mDragAndDrop); + mWindows.push_back(containerWindow); + trackWindow(containerWindow, "container"); + mGuiModeStates[GM_Container] = GuiModeState({containerWindow, mInventoryWindow}); mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mWindows.push_back(mHud); @@ -412,49 +399,49 @@ namespace MWGui mConfirmationDialog = new ConfirmationDialog(); mWindows.push_back(mConfirmationDialog); - mAlchemyWindow = new AlchemyWindow(); - mWindows.push_back(mAlchemyWindow); - trackWindow(mAlchemyWindow, "alchemy"); - mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); + AlchemyWindow* alchemyWindow = new AlchemyWindow(); + mWindows.push_back(alchemyWindow); + trackWindow(alchemyWindow, "alchemy"); + mGuiModeStates[GM_Alchemy] = GuiModeState(alchemyWindow); mQuickKeysMenu = new QuickKeysMenu(); mWindows.push_back(mQuickKeysMenu); mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); - mLevelupDialog = new LevelupDialog(); - mWindows.push_back(mLevelupDialog); - mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); + LevelupDialog* levelupDialog = new LevelupDialog(); + mWindows.push_back(levelupDialog); + mGuiModeStates[GM_Levelup] = GuiModeState(levelupDialog); mWaitDialog = new WaitDialog(); mWindows.push_back(mWaitDialog); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); - mSpellCreationDialog = new SpellCreationDialog(); - mWindows.push_back(mSpellCreationDialog); - mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); + SpellCreationDialog* spellCreationDialog = new SpellCreationDialog(); + mWindows.push_back(spellCreationDialog); + mGuiModeStates[GM_SpellCreation] = GuiModeState(spellCreationDialog); - mEnchantingDialog = new EnchantingDialog(); - mWindows.push_back(mEnchantingDialog); - mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); + EnchantingDialog* enchantingDialog = new EnchantingDialog(); + mWindows.push_back(enchantingDialog); + mGuiModeStates[GM_Enchanting] = GuiModeState(enchantingDialog); - mTrainingWindow = new TrainingWindow(); - mWindows.push_back(mTrainingWindow); - mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); + TrainingWindow* trainingWindow = new TrainingWindow(); + mWindows.push_back(trainingWindow); + mGuiModeStates[GM_Training] = GuiModeState(trainingWindow); - mMerchantRepair = new MerchantRepair(); - mWindows.push_back(mMerchantRepair); - mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); + MerchantRepair* merchantRepair = new MerchantRepair(); + mWindows.push_back(merchantRepair); + mGuiModeStates[GM_MerchantRepair] = GuiModeState(merchantRepair); - mRepair = new Repair(); - mWindows.push_back(mRepair); - mGuiModeStates[GM_Repair] = GuiModeState(mRepair); + Repair* repair = new Repair(); + mWindows.push_back(repair); + mGuiModeStates[GM_Repair] = GuiModeState(repair); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - mWindows.push_back(mCompanionWindow); - trackWindow(mCompanionWindow, "companion"); - mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); + CompanionWindow* companionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); + mWindows.push_back(companionWindow); + trackWindow(companionWindow, "companion"); + mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, companionWindow}); mJailScreen = new JailScreen(); mWindows.push_back(mJailScreen); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 773eed4fc..f315bb906 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -405,37 +405,24 @@ namespace MWGui HUD *mHud; MapWindow *mMap; MWRender::LocalMap* mLocalMapRender; - MainMenu *mMenu; ToolTips *mToolTips; StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; DialogueWindow *mDialogueWindow; - ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; InventoryWindow *mInventoryWindow; ScrollWindow* mScrollWindow; BookWindow* mBookWindow; CountDialog* mCountDialog; TradeWindow* mTradeWindow; - SpellBuyingWindow* mSpellBuyingWindow; - TravelWindow* mTravelWindow; SettingsWindow* mSettingsWindow; ConfirmationDialog* mConfirmationDialog; - AlchemyWindow* mAlchemyWindow; SpellWindow* mSpellWindow; QuickKeysMenu* mQuickKeysMenu; LoadingScreen* mLoadingScreen; - LevelupDialog* mLevelupDialog; WaitDialog* mWaitDialog; - SpellCreationDialog* mSpellCreationDialog; - EnchantingDialog* mEnchantingDialog; - TrainingWindow* mTrainingWindow; - MerchantRepair* mMerchantRepair; SoulgemDialog* mSoulgemDialog; - Repair* mRepair; - Recharge* mRecharge; - CompanionWindow* mCompanionWindow; MyGUI::ImageBox* mVideoBackground; VideoWidget* mVideoWidget; ScreenFader* mWerewolfFader; From f6c227b966e17325541ac7b9b010da8babb1aceb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:02:17 +0200 Subject: [PATCH 055/150] Reset screen faders in clear() Fixes a black screen when loading a game while waiting/resting. --- apps/openmw/mwgui/screenfader.cpp | 6 ++++++ apps/openmw/mwgui/screenfader.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 -- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index be0346e88..1d04e871e 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -119,6 +119,12 @@ namespace MWGui queue(time, percent/100.f); } + void ScreenFader::clear() + { + clearQueue(); + notifyAlphaChanged(0.f); + } + void ScreenFader::setFactor(float factor) { mFactor = factor; diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index b510e133a..19468de3c 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -42,6 +42,8 @@ namespace MWGui void fadeOut(const float time); void fadeTo(const int percent, const float time); + void clear(); + void setFactor (float factor); void setRepeat(bool repeat); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 906151ab1..29425e7c3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1589,8 +1589,6 @@ namespace MWGui mForceHidden = GW_None; - setWerewolfOverlay(false); - while (!mGuiModes.empty()) popGuiMode(); From 222defc6d873f1cb9cc93abeff939ed77e442e6d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:09:41 +0200 Subject: [PATCH 056/150] Extend HUD::clear() --- apps/openmw/mwgui/hud.cpp | 7 +++++++ apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 9 ++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 87c1b2f3c..779e358d3 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -632,6 +632,13 @@ namespace MWGui mEnemyHealthTimer = -1; } + void HUD::clear() + { + unsetSelectedSpell(); + unsetSelectedWeapon(); + resetEnemy(); + } + void HUD::customMarkerCreated(MyGUI::Widget *marker) { marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index fc335d1e7..3542f3ebf 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -58,7 +58,7 @@ namespace MWGui void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); - void clear() { resetEnemy(); } + void clear(); private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 29425e7c3..2cfafd0a2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -506,16 +506,9 @@ namespace MWGui disallowAll(); delete mCharGen; mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem); - mGuiModes.clear(); - MWBase::Environment::get().getInputManager()->changeInputMode(false); - mHud->unsetSelectedWeapon(); - mHud->unsetSelectedSpell(); - unsetForceHide(GW_ALL); } else allow(GW_ALL); - - mRestAllowed = !newgame; } WindowManager::~WindowManager() @@ -1338,6 +1331,7 @@ namespace MWGui void WindowManager::disallowAll() { mAllowed = GW_None; + mRestAllowed = false; mBookWindow->setInventoryAllowed (false); mScrollWindow->setInventoryAllowed (false); @@ -1588,6 +1582,7 @@ namespace MWGui mCustomMarkers.clear(); mForceHidden = GW_None; + mRestAllowed = true; while (!mGuiModes.empty()) popGuiMode(); From c0d8bef82fb5964a278bf53005b9135c8954ca63 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:14:53 +0200 Subject: [PATCH 057/150] Call changeInputMode() from updateVisible() --- apps/openmw/mwgui/windowmanagerimp.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2cfafd0a2..8349ca0bc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -495,8 +495,6 @@ namespace MWGui // Set up visibility updateVisible(); - - MWBase::Environment::get().getInputManager()->changeInputMode(false); } void WindowManager::setNewGame(bool newgame) @@ -573,6 +571,8 @@ namespace MWGui bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + mInputBlocker->setVisible (gameMode); if (loading) @@ -761,7 +761,6 @@ namespace MWGui void WindowManager::interactiveMessageBox(const std::string &message, const std::vector &buttons, bool block) { mMessageBoxManager->createInteractiveMessageBox(message, buttons); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); updateVisible(); if (block) @@ -1143,9 +1142,6 @@ namespace MWGui mKeyboardNavigation->restoreFocus(mode); - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1173,9 +1169,6 @@ namespace MWGui mKeyboardNavigation->restoreFocus(mode); } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1196,9 +1189,6 @@ namespace MWGui ++it; } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1488,7 +1478,6 @@ namespace MWGui void WindowManager::showSoulgemDialog(MWWorld::Ptr item) { mSoulgemDialog->show(item); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); updateVisible(); } @@ -1587,7 +1576,6 @@ namespace MWGui while (!mGuiModes.empty()) popGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(false); updateVisible(); } From d58ff4a736d8f5003d5dff234524e6fb697fc69b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:47:47 +0200 Subject: [PATCH 058/150] Remove obsolete Container GUI keyboard handling --- apps/openmw/mwgui/container.cpp | 9 --------- apps/openmw/mwgui/container.hpp | 1 - 2 files changed, 10 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 85afc1aa3..90ed1a596 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -46,7 +46,6 @@ namespace MWGui mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); - mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ContainerWindow::onKeyPressed); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); setCoord(200,0,600,300); @@ -158,14 +157,6 @@ namespace MWGui setTitle(container.getClass().getName(container)); } - void ContainerWindow::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) - { - if (_key == MyGUI::KeyCode::Space) - onCloseButtonClicked(mCloseButton); - if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter) - onTakeAllButtonClicked(mTakeButton); - } - void ContainerWindow::resetReference() { ReferenceInterface::resetReference(); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index a53d4f782..50c69da3b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -62,7 +62,6 @@ namespace MWGui void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onDisposeCorpseButtonClicked(MyGUI::Widget* sender); - void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char); /// @return is taking the item allowed? bool onTakeItem(const ItemStack& item, int count); From 331192f2d688ebd7452726e3861434fe9d537619 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 00:23:08 +0200 Subject: [PATCH 059/150] Improve keyboard navigation of book/scroll windows --- apps/openmw/mwgui/bookwindow.cpp | 15 +++++++++++++++ apps/openmw/mwgui/bookwindow.hpp | 2 ++ apps/openmw/mwgui/formatting.cpp | 9 +++++---- apps/openmw/mwgui/keyboardnavigation.cpp | 9 +++++---- apps/openmw/mwgui/scrollwindow.cpp | 21 +++++++++++++++++++-- apps/openmw/mwgui/scrollwindow.hpp | 1 + 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 5abc63c55..ae20b8e43 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -52,6 +52,11 @@ namespace MWGui mRightPage->setNeedMouseFocus(true); mRightPage->eventMouseWheel += MyGUI::newDelegate(this, &BookWindow::onMouseWheel); + mNextPageButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mPrevPageButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + if (mNextPageButton->getSize().width == 64) { // english button has a 7 pixel wide strip of garbage on its right edge @@ -94,6 +99,8 @@ namespace MWGui updatePages(); setTakeButtonShow(showTakeButton); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); } void BookWindow::setTakeButtonShow(bool show) @@ -102,6 +109,14 @@ namespace MWGui mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } + void BookWindow::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + prevPage(); + else if (key == MyGUI::KeyCode::ArrowDown) + nextPage(); + } + void BookWindow::setInventoryAllowed(bool allowed) { mTakeButtonAllowed = allowed; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index b20498feb..2459c3464 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -27,6 +27,8 @@ namespace MWGui void onMouseWheel(MyGUI::Widget* _sender, int _rel); void setTakeButtonShow(bool show); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); + void nextPage(); void prevPage(); diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index cf4a5b589..a9319048e 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -406,10 +406,11 @@ namespace MWGui MyGUI::EditBox* box = parent->createWidget("NormalText", MyGUI::IntCoord(0, pag.getCurrentTop(), pag.getPageWidth(), 0), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - box->setProperty("WordWrap", "true"); - box->setProperty("NeedMouse", "false"); + box->setEditStatic(true); + box->setEditMultiLine(true); + box->setEditWordWrap(true); + box->setNeedMouseFocus(false); + box->setNeedKeyFocus(false); box->setMaxTextLength(text.size()); box->setTextAlign(mBlockStyle.mAlign); box->setTextColour(mTextStyle.mColour); diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 8ce26e1d0..ddfd8f662 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -156,13 +156,14 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) MyGUI::Widget* next = keyFocusList[index]; int vertdiff = next->getTop() - focus->getTop(); int horizdiff = next->getLeft() - focus->getLeft(); - if (direction == D_Right && horizdiff <= 0) + bool isVertical = std::abs(vertdiff) > std::abs(horizdiff); + if (direction == D_Right && (horizdiff <= 0 || isVertical)) return false; - else if (direction == D_Left && horizdiff >= 0) + else if (direction == D_Left && (horizdiff >= 0 || isVertical)) return false; - else if (direction == D_Down && vertdiff <= 0) + else if (direction == D_Down && (vertdiff <= 0 || !isVertical)) return false; - else if (direction == D_Up && vertdiff >= 0) + else if (direction == D_Up && (vertdiff >= 0 || !isVertical)) return false; MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[index]); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index a92ef92ab..ea811f5b1 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -47,6 +47,9 @@ namespace MWGui adjustButton(mCloseButton); adjustButton(mTakeButton); + mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); + mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); + center(); } @@ -66,14 +69,28 @@ namespace MWGui // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mTextView->setVisibleVScroll(false); if (size.height > mTextView->getSize().height) - mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); + mTextView->setCanvasSize(mTextView->getWidth(), size.height); else - mTextView->setCanvasSize(410, mTextView->getSize().height); + mTextView->setCanvasSize(mTextView->getWidth(), mTextView->getSize().height); mTextView->setVisibleVScroll(true); mTextView->setViewOffset(MyGUI::IntPoint(0,0)); setTakeButtonShow(showTakeButton); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); + } + + void ScrollWindow::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + int scroll = 0; + if (key == MyGUI::KeyCode::ArrowUp) + scroll = 40; + else if (key == MyGUI::KeyCode::ArrowDown) + scroll = -40; + + if (scroll != 0) + mTextView->setViewOffset(mTextView->getViewOffset() + MyGUI::IntPoint(0, scroll)); } void ScrollWindow::setTakeButtonShow(bool show) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 35016e5dc..adc0bd93e 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -26,6 +26,7 @@ namespace MWGui void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); void setTakeButtonShow(bool show); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); private: Gui::ImageButton* mCloseButton; From 0e57f1317b6dc7f0ebc6f14d73477296f6160a4e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 11:50:55 +0200 Subject: [PATCH 060/150] Remove redundant setVisible(false) --- apps/openmw/mwgui/jailscreen.cpp | 2 -- apps/openmw/mwgui/journalwindow.cpp | 1 - apps/openmw/mwgui/loadingscreen.cpp | 2 -- apps/openmw/mwgui/recharge.cpp | 2 -- apps/openmw/mwgui/screenfader.cpp | 1 - 5 files changed, 8 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 8ac133d76..11d7466a8 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -26,8 +26,6 @@ namespace MWGui { getWidget(mProgressBar, "ProgressBar"); - setVisible(false); - mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index a0e424021..3a67e857d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -96,7 +96,6 @@ namespace JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) : JournalBooks (Model), JournalWindow() { - mMainWidget->setVisible(false); center(); adviseButtonClick (OptionsBTN, &JournalWindowImpl::notifyOptions ); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 15d9d555f..f22d825dd 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -51,8 +51,6 @@ namespace MWGui mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); - setVisible(false); - findSplashScreens(); } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 0398112ba..32da7876c 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -46,8 +46,6 @@ Recharge::Recharge() mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge); mGemIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onSelectItem); - - setVisible(false); } void Recharge::onOpen() diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 1d04e871e..76e79a348 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -74,7 +74,6 @@ namespace MWGui , mRepeat(false) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); - setVisible(false); MyGUI::ImageBox* imageBox = mMainWidget->castType(false); if (imageBox) From 2c4b0cc40800110b3cbcc92e7451c0c17709642b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:11:02 +0200 Subject: [PATCH 061/150] Hide sneak indicator by default --- files/mygui/openmw_hud.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 366b0c4c6..cee3f4682 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -82,6 +82,7 @@ + From 9ed1b165537561dd9b34dbb94a6940f40a4afcd5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:47:50 +0200 Subject: [PATCH 062/150] Extend code that detects whether a key was consumed by the GUI (Fixes #4016) --- apps/openmw/mwgui/windowmanagerimp.cpp | 25 ++++++++++++++++++++++++- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8349ca0bc..6c69dffbc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2000,7 +2000,30 @@ namespace MWGui bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) { if (!mKeyboardNavigation->injectKeyPress(key, text)) - return MyGUI::InputManager::getInstance().injectKeyPress(key, text); + { + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool widgetActive = MyGUI::InputManager::getInstance().injectKeyPress(key, text); + if (!widgetActive || !focus) + return false; + // FIXME: MyGUI doesn't allow widgets to state if a given key was actually used, so make a guess + if (focus->getTypeName().find("Button") != std::string::npos) + { + switch (key.getValue()) + { + case MyGUI::KeyCode::ArrowDown: + case MyGUI::KeyCode::ArrowUp: + case MyGUI::KeyCode::ArrowLeft: + case MyGUI::KeyCode::ArrowRight: + case MyGUI::KeyCode::Return: + case MyGUI::KeyCode::NumpadEnter: + case MyGUI::KeyCode::Space: + return true; + default: + return false; + } + } + return false; + } else return true; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cd17c5175..c5b18ff17 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -674,10 +674,11 @@ namespace MWInput bool consumed = false; if (kc != OIS::KC_UNASSIGNED) { - consumed = SDL_IsTextInputActive() && - ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)); // Little trick to check if key is printable - bool guiFocus = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - setPlayerControlsEnabled(!guiFocus); + consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + if (SDL_IsTextInputActive() && // Little trick to check if key is printable + ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym))) + consumed = true; + setPlayerControlsEnabled(!consumed); } if (arg.repeat) return; From 843106fc616488ca174cd9d30d504254546fe631 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:58:14 +0200 Subject: [PATCH 063/150] Handle the wait progress bar as part of the GUI mode --- apps/openmw/mwgui/trainingwindow.cpp | 19 +++++++++++++------ apps/openmw/mwgui/trainingwindow.hpp | 4 ++++ apps/openmw/mwgui/waitdialog.cpp | 20 ++++++++++++-------- apps/openmw/mwgui/waitdialog.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index c1f7f8ac1..13a0a6883 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -51,12 +51,18 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); - - mProgressBar.setVisible(false); } void TrainingWindow::onOpen() { + if (mTimeAdvancer.isRunning()) + { + mProgressBar.setVisible(true); + setVisible(false); + } + else + mProgressBar.setVisible(false); + center(); } @@ -166,15 +172,12 @@ namespace MWGui // add gold to NPC trading gold pool npcStats.setGoldPool(npcStats.getGoldPool() + price); - // go back to game mode - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - // advance time MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getWorld ()->advanceTime (2); + setVisible(false); mProgressBar.setVisible(true); mProgressBar.setProgress(0, 2); mTimeAdvancer.run(2); @@ -191,6 +194,10 @@ namespace MWGui void TrainingWindow::onTrainingFinished() { mProgressBar.setVisible(false); + + // go back to game mode + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 127c85f6a..fb7b10deb 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -16,10 +16,14 @@ namespace MWGui virtual void onOpen(); + bool exit() { return false; } + void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); + WindowBase* getProgressBar() { return &mProgressBar; } + void clear() { resetReference(); } protected: diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index cd1d29854..8a360435c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -75,8 +75,6 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); - - mProgressBar.setVisible (false); } void WaitDialog::setPtr(const MWWorld::Ptr &ptr) @@ -86,11 +84,22 @@ namespace MWGui bool WaitDialog::exit() { - return (!mProgressBar.isVisible()); //Only exit if not currently waiting + return (!mTimeAdvancer.isRunning()); //Only exit if not currently waiting } void WaitDialog::onOpen() { + if (mTimeAdvancer.isRunning()) + { + mProgressBar.setVisible(true); + setVisible(false); + return; + } + else + { + mProgressBar.setVisible(false); + } + if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { MWBase::Environment::get().getWindowManager()->popGuiMode (); @@ -262,11 +271,6 @@ namespace MWGui } } - void WaitDialog::clear() - { - mProgressBar.setVisible(false); - } - void WaitDialog::stopWaiting () { MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 6bd90473f..c7ccee025 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -34,12 +34,13 @@ namespace MWGui virtual bool exit(); void onFrame(float dt); - void clear(); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); + WindowBase* getProgressBar() { return &mProgressBar; } + protected: MyGUI::TextBox* mDateTimeText; MyGUI::TextBox* mRestText; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6c69dffbc..c572bce54 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -414,7 +414,7 @@ namespace MWGui mWaitDialog = new WaitDialog(); mWindows.push_back(mWaitDialog); - mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); + mGuiModeStates[GM_Rest] = GuiModeState({mWaitDialog->getProgressBar(), mWaitDialog}); SpellCreationDialog* spellCreationDialog = new SpellCreationDialog(); mWindows.push_back(spellCreationDialog); @@ -426,7 +426,7 @@ namespace MWGui TrainingWindow* trainingWindow = new TrainingWindow(); mWindows.push_back(trainingWindow); - mGuiModeStates[GM_Training] = GuiModeState(trainingWindow); + mGuiModeStates[GM_Training] = GuiModeState({trainingWindow->getProgressBar(), trainingWindow}); MerchantRepair* merchantRepair = new MerchantRepair(); mWindows.push_back(merchantRepair); From 8ae7e4c958a0b59a0b555b9c60a227521f5da327 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:05:52 +0200 Subject: [PATCH 064/150] Make Enter on a name edit accept the dialog --- apps/openmw/mwgui/alchemywindow.cpp | 9 +++++++++ apps/openmw/mwgui/alchemywindow.hpp | 1 + apps/openmw/mwgui/enchantingdialog.cpp | 8 ++++++++ apps/openmw/mwgui/enchantingdialog.hpp | 3 ++- apps/openmw/mwgui/spellcreationdialog.cpp | 6 ++++++ apps/openmw/mwgui/spellcreationdialog.hpp | 1 + 6 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 5b1489821..0140653a1 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -54,9 +54,16 @@ namespace MWGui mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked); + mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept); + center(); } + void AlchemyWindow::onAccept(MyGUI::EditBox* sender) + { + onCreateButtonClicked(sender); + } + void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); @@ -128,6 +135,8 @@ namespace MWGui } update(); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); } void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index a27d9c749..2d13a346a 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -44,6 +44,7 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* _sender); void onCreateButtonClicked(MyGUI::Widget* _sender); void onIngredientSelected(MyGUI::Widget* _sender); + void onAccept(MyGUI::EditBox*); void onSelectedItem(int index); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 88973bd46..74d80d292 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -53,6 +54,7 @@ namespace MWGui mSoulBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectSoul); mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onBuyButtonClicked); mTypeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onTypeButtonClicked); + mName->eventEditSelectAccept += MyGUI::newDelegate(this, &EnchantingDialog::onAccept); } EnchantingDialog::~EnchantingDialog() @@ -63,6 +65,7 @@ namespace MWGui void EnchantingDialog::onOpen() { center(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mName); } void EnchantingDialog::setSoulGem(const MWWorld::Ptr &gem) @@ -284,6 +287,11 @@ namespace MWGui updateEffectsView(); } + void EnchantingDialog::onAccept(MyGUI::EditBox *sender) + { + onBuyButtonClicked(sender); + } + void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) { if (mEffects.size() <= 0) diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 39614ebd1..4906de919 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -48,6 +48,7 @@ namespace MWGui void onBuyButtonClicked(MyGUI::Widget* sender); void updateLabels(); void onTypeButtonClicked(MyGUI::Widget* sender); + void onAccept(MyGUI::EditBox* sender); ItemSelectionDialog* mItemSelectionDialog; @@ -60,7 +61,7 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; - MyGUI::TextBox* mName; + MyGUI::EditBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index d5dee1139..4aa208d8f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -349,6 +349,7 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onCancelButtonClicked); mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onBuyButtonClicked); + mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SpellCreationDialog::onAccept); setWidgets(mAvailableEffectsList, mUsedEffectsView); } @@ -416,6 +417,11 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } + void SpellCreationDialog::onAccept(MyGUI::EditBox *sender) + { + onBuyButtonClicked(sender); + } + void SpellCreationDialog::onOpen() { center(); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 855016666..ec90fa3ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -162,6 +162,7 @@ namespace MWGui void onCancelButtonClicked (MyGUI::Widget* sender); void onBuyButtonClicked (MyGUI::Widget* sender); + void onAccept(MyGUI::EditBox* sender); virtual void notifyEffectsChanged (); From 67dc4e019acb554b6d36f02eb73f3ef7b190848d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:10:50 +0200 Subject: [PATCH 065/150] Make Enter on trade window price attempt the trade --- apps/openmw/mwgui/tradewindow.cpp | 8 ++++++++ apps/openmw/mwgui/tradewindow.hpp | 1 + 2 files changed, 9 insertions(+) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index feccfd942..c2e58b81f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -96,6 +96,7 @@ namespace MWGui mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); mTotalBalance->eventValueChanged += MyGUI::newDelegate(this, &TradeWindow::onBalanceValueChanged); + mTotalBalance->eventEditSelectAccept += MyGUI::newDelegate(this, &TradeWindow::onAccept); mTotalBalance->setMinValue(INT_MIN+1); // disallow INT_MIN since abs(INT_MIN) is undefined setCoord(400, 0, 400, 300); @@ -140,6 +141,8 @@ namespace MWGui setTitle(actor.getClass().getName(actor)); onFilterChanged(mFilterAll); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTotalBalance); } void TradeWindow::onFrame(float dt) @@ -364,6 +367,11 @@ namespace MWGui restock(); } + void TradeWindow::onAccept(MyGUI::EditBox *sender) + { + onOfferButtonClicked(sender); + } + void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { exit(); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 00f38024d..fc692a55a 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -84,6 +84,7 @@ namespace MWGui void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); + void onAccept(MyGUI::EditBox* sender); void onCancelButtonClicked(MyGUI::Widget* _sender); void onMaxSaleButtonClicked(MyGUI::Widget* _sender); void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); From 76ddf8d794dc9cc847297c7f994635028ffb1fcb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:17:08 +0200 Subject: [PATCH 066/150] Support Up/DownArrow keys to change NumericEditBox value --- components/widgets/numericeditbox.cpp | 16 ++++++++++++++++ components/widgets/numericeditbox.hpp | 1 + 2 files changed, 17 insertions(+) diff --git a/components/widgets/numericeditbox.cpp b/components/widgets/numericeditbox.cpp index 828a84589..6e884a091 100644 --- a/components/widgets/numericeditbox.cpp +++ b/components/widgets/numericeditbox.cpp @@ -75,4 +75,20 @@ namespace Gui setCaption(MyGUI::utility::toString(mValue)); } + void NumericEditBox::onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + { + setValue(std::min(mValue+1, mMaxValue)); + eventValueChanged(mValue); + } + else if (key == MyGUI::KeyCode::ArrowDown) + { + setValue(std::max(mValue-1, mMinValue)); + eventValueChanged(mValue); + } + else + Base::onKeyButtonPressed(key, character); + } + } diff --git a/components/widgets/numericeditbox.hpp b/components/widgets/numericeditbox.hpp index 20000b3d3..ca7674f22 100644 --- a/components/widgets/numericeditbox.hpp +++ b/components/widgets/numericeditbox.hpp @@ -33,6 +33,7 @@ namespace Gui private: void onEditTextChange(MyGUI::EditBox* sender); void onKeyLostFocus(MyGUI::Widget* _new); + void onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char character); int mValue; From ca3b08b85202ed40845e93bed9800d02f0d86859 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:49:35 +0200 Subject: [PATCH 067/150] Make Activate key accept GUI buttons --- apps/openmw/mwinput/inputmanagerimp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c5b18ff17..79c689561 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -162,14 +162,13 @@ namespace MWInput void InputManager::setPlayerControlsEnabled(bool enabled) { - int nPlayerChannels = 18; - int playerChannels[] = {A_Activate, A_AutoMove, A_AlwaysRun, A_ToggleWeapon, + int playerChannels[] = {A_AutoMove, A_AlwaysRun, A_ToggleWeapon, A_ToggleSpell, A_Rest, A_QuickKey1, A_QuickKey2, A_QuickKey3, A_QuickKey4, A_QuickKey5, A_QuickKey6, A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10, A_Use, A_Journal}; - for(int i = 0; i < nPlayerChannels; i++) { + for(size_t i = 0; i < sizeof(playerChannels)/sizeof(playerChannels[0]); i++) { int pc = playerChannels[i]; mInputBinder->getChannel(pc)->setEnabled(enabled); } @@ -234,8 +233,7 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - activate(); + activate(); break; case A_Journal: toggleJournal (); @@ -1080,7 +1078,9 @@ namespace MWInput void InputManager::activate() { - if (mControlSwitch["playercontrols"]) + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + else if (mControlSwitch["playercontrols"]) mPlayer->activate(); } From 94b538ac829553ba994054206b50aa90a6299785 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:57:09 +0200 Subject: [PATCH 068/150] Fix crash due to not calling WindowModal::onClose() --- apps/openmw/mwgui/race.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 2b407ac93..64609cbe6 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -187,6 +187,8 @@ namespace MWGui void RaceDialog::onClose() { + WindowModal::onClose(); + mPreviewImage->setRenderItemTexture(NULL); mPreviewTexture.reset(NULL); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c572bce54..d734d7540 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1738,9 +1738,12 @@ namespace MWGui // Only remove the top if it matches the current pointer. A lot of things hide their visibility before showing it, //so just popping the top would cause massive issues. if(!mCurrentModals.empty()) + { if(input == mCurrentModals.top()) mCurrentModals.pop(); - + else + std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; + } if (mCurrentModals.empty()) mKeyboardNavigation->restoreFocus(getMode()); } From ad8d0c53024d82464cf7a2861ce2908f3252efad Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 15:32:44 +0200 Subject: [PATCH 069/150] Use keypad to control the camera --- apps/openmw/mwinput/inputmanagerimp.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 79c689561..b1f80cae6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1215,6 +1215,17 @@ namespace MWInput control->setInitialValue(0.0f); mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } + + if (i == A_LookLeftRight && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_4) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_6)) + { + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_6, ICS::Control::INCREASE); + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_4, ICS::Control::DECREASE); + } + if (i == A_LookUpDown && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_8) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_2)) + { + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_2, ICS::Control::INCREASE); + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_8, ICS::Control::DECREASE); + } } } } From c035548f3737a24e1b699b770c4bba753d806641 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 19:00:51 +0200 Subject: [PATCH 070/150] Make Tab work if selected widget is marked as not needing keyfocus --- apps/openmw/mwgui/keyboardnavigation.cpp | 26 ++++++++---------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index ddfd8f662..da99c72d0 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -63,12 +63,6 @@ void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) w.second = nullptr; } -bool isButtonFocus() -{ - MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - return focus->getTypeName().find("Button") != std::string::npos; -} - enum Direction { D_Left, @@ -106,7 +100,13 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - if (!focus && (direction == D_Next || direction == D_Prev)) + if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) + return false; + + if (focus && (direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + return false; + + if ((!focus || !focus->getNeedKeyFocus()) && (direction == D_Next || direction == D_Prev)) { // if nothing is selected, select the first widget MyGUI::VectorWidgetPtr keyFocusList; @@ -120,20 +120,12 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) return true; } } - if (!focus) return false; - if (!isButtonFocus() && direction != D_Prev && direction != D_Next) - return false; - - if ((direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") - return false; - - MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - while (window->getParent()) + MyGUI::Widget* window = focus; + while (window && window->getParent()) window = window->getParent(); - MyGUI::VectorWidgetPtr keyFocusList; getKeyFocusWidgets(window, keyFocusList); From d78e8228331826976f17f8a37801c8eed7488232 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 19:15:39 +0200 Subject: [PATCH 071/150] Add 'delay' argument for screen fading operations --- apps/openmw/mwbase/windowmanager.hpp | 6 +++--- apps/openmw/mwgui/screenfader.cpp | 29 ++++++++++++++++---------- apps/openmw/mwgui/screenfader.hpp | 11 +++++----- apps/openmw/mwgui/trainingwindow.cpp | 11 +--------- apps/openmw/mwgui/trainingwindow.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++------ apps/openmw/mwgui/windowmanagerimp.hpp | 6 +++--- 7 files changed, 37 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 43d99b6b3..2df3113b3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -317,11 +317,11 @@ namespace MWBase virtual void pinWindow (MWGui::GuiWindow window) = 0; /// Fade the screen in, over \a time seconds - virtual void fadeScreenIn(const float time, bool clearQueue=true) = 0; + virtual void fadeScreenIn(const float time, bool clearQueue=true, float delay=0.f) = 0; /// Fade the screen out to black, over \a time seconds - virtual void fadeScreenOut(const float time, bool clearQueue=true) = 0; + virtual void fadeScreenOut(const float time, bool clearQueue=true, float delay=0.f) = 0; /// Fade the screen to a specified percentage of black, over \a time seconds - virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true) = 0; + virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true, float delay=0.f) = 0; /// Darken the screen to a specified percentage virtual void setBlindness(const int percent) = 0; diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 76e79a348..d1118848b 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -6,12 +6,13 @@ namespace MWGui { - FadeOp::FadeOp(ScreenFader * fader, float time, float targetAlpha) + FadeOp::FadeOp(ScreenFader * fader, float time, float targetAlpha, float delay) : mFader(fader), - mRemainingTime(time), + mRemainingTime(time+delay), mTargetTime(time), mTargetAlpha(targetAlpha), mStartAlpha(0.f), + mDelay(delay), mRunning(false) { } @@ -26,7 +27,7 @@ namespace MWGui if (mRunning) return; - mRemainingTime = mTargetTime; + mRemainingTime = mTargetTime + mDelay; mStartAlpha = mFader->getCurrentAlpha(); mRunning = true; } @@ -42,6 +43,12 @@ namespace MWGui return; } + if (mRemainingTime > mTargetTime) + { + mRemainingTime -= dt; + return; + } + float currentAlpha = mFader->getCurrentAlpha(); if (mStartAlpha > mTargetAlpha) { @@ -103,19 +110,19 @@ namespace MWGui mMainWidget->setAlpha(1.f-((1.f-mCurrentAlpha) * mFactor)); } - void ScreenFader::fadeIn(float time) + void ScreenFader::fadeIn(float time, float delay) { - queue(time, 1.f); + queue(time, 1.f, delay); } - void ScreenFader::fadeOut(const float time) + void ScreenFader::fadeOut(const float time, float delay) { - queue(time, 0.f); + queue(time, 0.f, delay); } - void ScreenFader::fadeTo(const int percent, const float time) + void ScreenFader::fadeTo(const int percent, const float time, float delay) { - queue(time, percent/100.f); + queue(time, percent/100.f, delay); } void ScreenFader::clear() @@ -135,7 +142,7 @@ namespace MWGui mRepeat = repeat; } - void ScreenFader::queue(float time, float targetAlpha) + void ScreenFader::queue(float time, float targetAlpha, float delay) { if (time < 0.f) return; @@ -147,7 +154,7 @@ namespace MWGui return; } - mQueue.push_back(FadeOp::Ptr(new FadeOp(this, time, targetAlpha))); + mQueue.push_back(FadeOp::Ptr(new FadeOp(this, time, targetAlpha, delay))); } bool ScreenFader::isEmpty() diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 19468de3c..88dd0c57b 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -14,7 +14,7 @@ namespace MWGui public: typedef std::shared_ptr Ptr; - FadeOp(ScreenFader * fader, float time, float targetAlpha); + FadeOp(ScreenFader * fader, float time, float targetAlpha, float delay); bool isRunning(); @@ -28,6 +28,7 @@ namespace MWGui float mTargetTime; float mTargetAlpha; float mStartAlpha; + float mDelay; bool mRunning; }; @@ -38,16 +39,16 @@ namespace MWGui void update(float dt); - void fadeIn(const float time); - void fadeOut(const float time); - void fadeTo(const int percent, const float time); + void fadeIn(const float time, float delay=0); + void fadeOut(const float time, float delay=0); + void fadeTo(const int percent, const float time, float delay=0); void clear(); void setFactor (float factor); void setRepeat(bool repeat); - void queue(float time, float targetAlpha); + void queue(float time, float targetAlpha, float delay); bool isEmpty(); void clearQueue(); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 13a0a6883..120ab5cba 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,6 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") - , mFadeTimeRemaining(0) , mTimeAdvancer(0.05f) { getWidget(mTrainingOptions, "TrainingOptions"); @@ -183,7 +182,7 @@ namespace MWGui mTimeAdvancer.run(2); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25); - mFadeTimeRemaining = 0.5; + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.25, false, 0.25); } void TrainingWindow::onTrainingProgressChanged(int cur, int total) @@ -204,13 +203,5 @@ namespace MWGui { checkReferenceAvailable(); mTimeAdvancer.onFrame(dt); - - if (mFadeTimeRemaining <= 0) - return; - - mFadeTimeRemaining -= dt; - - if (mFadeTimeRemaining <= 0) - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.25); } } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index fb7b10deb..69a013059 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -39,8 +39,6 @@ namespace MWGui MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - float mFadeTimeRemaining; - WaitDialogProgressBar mProgressBar; TimeAdvancer mTimeAdvancer; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d734d7540..6be754109 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1788,25 +1788,25 @@ namespace MWGui updateVisible(); } - void WindowManager::fadeScreenIn(const float time, bool clearQueue) + void WindowManager::fadeScreenIn(const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeOut(time); + mScreenFader->fadeOut(time, delay); } - void WindowManager::fadeScreenOut(const float time, bool clearQueue) + void WindowManager::fadeScreenOut(const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeIn(time); + mScreenFader->fadeIn(time, delay); } - void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue) + void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeTo(percent, time); + mScreenFader->fadeTo(percent, time, delay); } void WindowManager::setBlindness(const int percent) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f315bb906..56e7d9b7b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -344,11 +344,11 @@ namespace MWGui virtual void pinWindow (MWGui::GuiWindow window); /// Fade the screen in, over \a time seconds - virtual void fadeScreenIn(const float time, bool clearQueue); + virtual void fadeScreenIn(const float time, bool clearQueue, float delay); /// Fade the screen out to black, over \a time seconds - virtual void fadeScreenOut(const float time, bool clearQueue); + virtual void fadeScreenOut(const float time, bool clearQueue, float delay); /// Fade the screen to a specified percentage of black, over \a time seconds - virtual void fadeScreenTo(const int percent, const float time, bool clearQueue); + virtual void fadeScreenTo(const int percent, const float time, bool clearQueue, float delay); /// Darken the screen to a specified percentage virtual void setBlindness(const int percent); From e4c9d8466628061da92779695c0d0eb08746eff6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 01:03:16 +0200 Subject: [PATCH 072/150] Disable NeedKey for ScrollView skins The widget is set to accept key focus by default for no reason I can tell. Fix in MyGUI TBD --- files/mygui/openmw_map_window.skin.xml | 1 + files/mygui/openmw_scroll.skin.xml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/files/mygui/openmw_map_window.skin.xml b/files/mygui/openmw_map_window.skin.xml index 31a70191f..f6c099630 100644 --- a/files/mygui/openmw_map_window.skin.xml +++ b/files/mygui/openmw_map_window.skin.xml @@ -2,6 +2,7 @@ + diff --git a/files/mygui/openmw_scroll.skin.xml b/files/mygui/openmw_scroll.skin.xml index 415c2479a..cff0ad7eb 100644 --- a/files/mygui/openmw_scroll.skin.xml +++ b/files/mygui/openmw_scroll.skin.xml @@ -3,11 +3,13 @@ + + From 82a211ba030bce61618d6820b9db2787d0a6b936 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 17:47:30 +0200 Subject: [PATCH 073/150] Fix duplicate code --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 14 +------------- components/esm/loadnpc.hpp | 2 +- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index fb4ba1016..bacbd7b2b 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -365,19 +365,7 @@ namespace MWDialogue } // check the available services of this actor - int services = 0; - if (mActor.getTypeName() == typeid(ESM::NPC).name()) - { - MWWorld::LiveCellRef* ref = mActor.get(); - if (ref->mBase->mHasAI) - services = ref->mBase->mAiData.mServices; - } - else if (mActor.getTypeName() == typeid(ESM::Creature).name()) - { - MWWorld::LiveCellRef* ref = mActor.get(); - if (ref->mBase->mHasAI) - services = ref->mBase->mAiData.mServices; - } + int services = mActor.getClass().getServices(mActor); int windowServices = 0; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 5b89f4055..019baa297 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -46,7 +46,7 @@ struct NPC // Other services Spells = 0x00800, MagicItems = 0x01000, - Training = 0x04000, // What skills? + Training = 0x04000, Spellmaking = 0x08000, Enchanting = 0x10000, Repair = 0x20000 From b7752ec52de5489583fe174f2df2381c5777b06c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 18:07:49 +0200 Subject: [PATCH 074/150] Make TradeWindow not depend on DialogueWindow --- apps/openmw/mwgui/dialogue.cpp | 5 +++++ apps/openmw/mwgui/dialogue.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 4 +--- apps/openmw/mwgui/tradewindow.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ec6dcb2cb..86aa64e8b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -270,6 +270,11 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } + void DialogueWindow::onTradeComplete() + { + addResponse(MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); + } + bool DialogueWindow::exit() { if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 224ecba66..dbb33969f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -99,6 +99,8 @@ namespace MWGui public: DialogueWindow(); + void onTradeComplete(); + virtual bool exit(); // Events diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index c2e58b81f..341167ab7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -27,7 +27,6 @@ #include "containeritemmodel.hpp" #include "tradeitemmodel.hpp" #include "countdialog.hpp" -#include "dialogue.hpp" #include "controllers.hpp" namespace @@ -358,8 +357,7 @@ namespace MWGui mPtr.getClass().getCreatureStats(mPtr).getGoldPool() - mCurrentBalance ); } - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse( - MWBase::Environment::get().getWorld()->getStore().get().find("sBarterDialog5")->getString()); + eventTradeDone(); MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up"); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index fc692a55a..514d24022 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -41,6 +41,9 @@ namespace MWGui virtual void resetReference(); + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_TradeDone; + EventHandle_TradeDone eventTradeDone; + private: ItemView* mItemView; SortFilterItemModel* mSortModel; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6be754109..76f0b029d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -337,7 +337,6 @@ namespace MWGui mTradeWindow = new TradeWindow(); mWindows.push_back(mTradeWindow); trackWindow(mTradeWindow, "barter"); - mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); mConsole = new Console(w,h, mConsoleOnlyScripts); @@ -366,6 +365,7 @@ namespace MWGui mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); + mTradeWindow->eventTradeDone += MyGUI::newDelegate(mDialogueWindow, &DialogueWindow::onTradeComplete); ContainerWindow* containerWindow = new ContainerWindow(mDragAndDrop); mWindows.push_back(containerWindow); From f8ffd851461219cd5b7909b91dbf807f36b17a30 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 18:50:24 +0200 Subject: [PATCH 075/150] Topic passed to keywordSelected() no longer has to be lower case Remove redundant mDialogueMap --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 42 ++++++++----------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 3 +- apps/openmw/mwgui/dialogue.cpp | 23 ++-------- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index bacbd7b2b..c29476c7f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -60,15 +60,6 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; mCompilerContext.setExtensions (&extensions); - - const MWWorld::Store &dialogs = - MWBase::Environment::get().getWorld()->getStore().get(); - - MWWorld::Store::iterator it = dialogs.begin(); - for (; it != dialogs.end(); ++it) - { - mDialogueMap[Misc::StringUtils::lowerCase(it->mId)] = *it; - } } void DialogueManager::clear() @@ -171,7 +162,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), "", false); executeScript (info->mResultScript, mActor); - mLastTopic = Misc::StringUtils::lowerCase(it->mId); + mLastTopic = it->mId; // update topics again to accommodate changes resulting from executeScript updateTopics(); @@ -310,7 +301,7 @@ namespace MWDialogue { if (iter->mId == info->mId) { - MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor); + MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(topic), info->mId, mActor); break; } } @@ -327,6 +318,11 @@ namespace MWDialogue } } + const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id) + { + return MWBase::Environment::get().getWorld()->getStore().get().search(id); + } + void DialogueManager::updateGlobals() { MWBase::Environment::get().getWorld()->updateDialogueGlobals(); @@ -416,12 +412,10 @@ namespace MWDialogue { if(!mIsInChoice) { - if(mDialogueMap.find(keyword) != mDialogueMap.end()) + const ESM::Dialogue* dialogue = searchDialogue(keyword); + if (dialogue && dialogue->mType == ESM::Dialogue::Topic) { - if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic) - { - executeTopic (keyword); - } + executeTopic (keyword); } } @@ -456,14 +450,14 @@ namespace MWDialogue { mChoice = answer; - if (mDialogueMap.find(mLastTopic) != mDialogueMap.end()) + const ESM::Dialogue* dialogue = searchDialogue(mLastTopic); + if (dialogue) { Filter filter (mActor, mChoice, mTalkedTo); - if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic - || mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting) + if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting) { - if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true)) + if (const ESM::DialInfo *info = filter.search (*dialogue, true)) { std::string text = info->mResponse; parseText (text); @@ -477,12 +471,12 @@ namespace MWDialogue // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. - for (ESM::Dialogue::InfoContainer::const_iterator iter = mDialogueMap[mLastTopic].mInfo.begin(); - iter!=mDialogueMap[mLastTopic].mInfo.end(); ++iter) + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin(); + iter!=dialogue->mInfo.end(); ++iter) { if (iter->mId == info->mId) { - MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor); + MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(mLastTopic), info->mId, mActor); break; } } @@ -737,7 +731,7 @@ namespace MWDialogue if (actor == mActor && !mLastTopic.empty()) { MWBase::Environment::get().getJournal()->removeLastAddedTopicResponse( - mLastTopic, actor.getClass().getName(actor)); + Misc::StringUtils::lowerCase(mLastTopic), actor.getClass().getName(actor)); } } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 40a24a1f8..81bd2f2b9 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -22,7 +22,6 @@ namespace MWDialogue { class DialogueManager : public MWBase::DialogueManager { - std::map mDialogueMap; std::set mKnownTopics;// Those are the topics the player knows. // Modified faction reactions. > @@ -56,6 +55,8 @@ namespace MWDialogue void executeTopic (const std::string& topic); + const ESM::Dialogue* searchDialogue(const std::string& id); + public: DialogueManager (const Compiler::Extensions& extensions, Translation::Storage& translationDataStorage); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 86aa64e8b..95fa042cf 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -223,7 +223,7 @@ namespace MWGui { MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId)); + MWBase::Environment::get().getDialogueManager()->keywordSelected(mTopicId); } void Goodbye::activated() @@ -328,7 +328,7 @@ namespace MWGui } if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(topic)); + MWBase::Environment::get().getDialogueManager()->keywordSelected(topic); else { const MWWorld::Store &gmst = @@ -552,24 +552,7 @@ namespace MWGui void DialogueWindow::addResponse(const std::string &text, const std::string &title, bool needMargin) { - // This is called from the dialogue manager, so text is - // case-smashed - thus we have to retrieve the correct case - // of the title through the topic list. - std::string realTitle = title; - if (realTitle != "") - { - for (size_t i=0; igetItemCount(); ++i) - { - std::string item = mTopicsList->getItemNameAt(i); - if (Misc::StringUtils::ciEqual(item, title)) - { - realTitle = item; - break; - } - } - } - - mHistoryContents.push_back(new Response(text, realTitle, needMargin)); + mHistoryContents.push_back(new Response(text, title, needMargin)); updateHistory(); } From 19e07fad30bb43f0d474f9326fadbc44ab8b894a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:52:20 +0200 Subject: [PATCH 076/150] Remove redundant Services enum --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 39 ------------------- apps/openmw/mwgui/dialogue.cpp | 20 ++++++---- apps/openmw/mwgui/dialogue.hpp | 16 -------- components/esm/loadnpc.hpp | 2 + 4 files changed, 14 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c29476c7f..dea942349 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -360,47 +360,8 @@ namespace MWDialogue } } - // check the available services of this actor - int services = mActor.getClass().getServices(mActor); - - int windowServices = 0; - - if (services & ESM::NPC::Weapon - || services & ESM::NPC::Armor - || services & ESM::NPC::Clothing - || services & ESM::NPC::Books - || services & ESM::NPC::Ingredients - || services & ESM::NPC::Picks - || services & ESM::NPC::Probes - || services & ESM::NPC::Lights - || services & ESM::NPC::Apparatus - || services & ESM::NPC::RepairItem - || services & ESM::NPC::Misc) - windowServices |= MWGui::DialogueWindow::Service_Trade; - - if((mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->getTransport().empty()) - || (mActor.getTypeName() == typeid(ESM::Creature).name() && !mActor.get()->mBase->getTransport().empty())) - windowServices |= MWGui::DialogueWindow::Service_Travel; - - if (services & ESM::NPC::Spells) - windowServices |= MWGui::DialogueWindow::Service_BuySpells; - - if (services & ESM::NPC::Spellmaking) - windowServices |= MWGui::DialogueWindow::Service_CreateSpells; - - if (services & ESM::NPC::Training) - windowServices |= MWGui::DialogueWindow::Service_Training; - - if (services & ESM::NPC::Enchanting) - windowServices |= MWGui::DialogueWindow::Service_Enchant; - - if (services & ESM::NPC::Repair) - windowServices |= MWGui::DialogueWindow::Service_Repair; - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->setServices (windowServices); - // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); win->setKeywords(keywordList); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 95fa042cf..e4d0af424 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -237,7 +237,6 @@ namespace MWGui DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") - , mServices(0) , mEnabled(false) , mGoodbye(false) , mPersuasionDialog() @@ -411,6 +410,11 @@ namespace MWGui mTopicLinks.clear(); mKeywordSearch.clear(); + int services = mPtr.getClass().getServices(mPtr); + + bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get()->mBase->getTransport().empty()) + || (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get()->mBase->getTransport().empty()); + bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); @@ -420,25 +424,25 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name()) mTopicsList->addItem(gmst.find("sPersuasion")->getString()); - if (mServices & Service_Trade) + if (services & ESM::NPC::AllItems) mTopicsList->addItem(gmst.find("sBarter")->getString()); - if (mServices & Service_BuySpells) + if (services & ESM::NPC::Spells) mTopicsList->addItem(gmst.find("sSpells")->getString()); - if (mServices & Service_Travel) + if (services & travel) mTopicsList->addItem(gmst.find("sTravel")->getString()); - if (mServices & Service_CreateSpells) + if (services & ESM::NPC::Spellmaking) mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); - if (mServices & Service_Enchant) + if (services & ESM::NPC::Enchanting) mTopicsList->addItem(gmst.find("sEnchanting")->getString()); - if (mServices & Service_Training) + if (services & ESM::NPC::Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); - if (mServices & Service_Repair) + if (services & ESM::NPC::Repair) mTopicsList->addItem(gmst.find("sRepair")->getString()); if (isCompanion) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index dbb33969f..af5fe5efc 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -122,20 +122,6 @@ namespace MWGui void onFrame(float dt); void clear() { resetReference(); } - // make sure to call these before setKeywords() - void setServices(int services) { mServices = services; } - - enum Services - { - Service_Trade = 0x01, - Service_BuySpells = 0x02, - Service_CreateSpells = 0x04, - Service_Enchant = 0x08, - Service_Training = 0x10, - Service_Travel = 0x20, - Service_Repair = 0x40 - }; - protected: void onSelectTopic(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); @@ -152,8 +138,6 @@ namespace MWGui void updateOptions(); void restock(); - int mServices; - bool mEnabled; bool mGoodbye; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 019baa297..d7f30e079 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -43,6 +43,8 @@ struct NPC Misc = 0x00400, Potions = 0x02000, + AllItems = Weapon|Armor|Clothing|Books|Ingredients|Picks|Probes|Lights|Apparatus|RepairItem|Misc|Potions, + // Other services Spells = 0x00800, MagicItems = 0x01000, From e14573fa8c05f6e41cbfa74cb6c3a31c4d0f990c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:53:42 +0200 Subject: [PATCH 077/150] Add missing null check --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e4d0af424..920183c61 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -625,7 +625,7 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); - if(mPtr.getTypeName() == typeid(ESM::NPC).name()) + if(!mPtr.isEmpty() && mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); From 717e68fab21b4243118b06e61f74756cbdc1a130 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:58:34 +0200 Subject: [PATCH 078/150] Remove redundant resetHistory argument --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 5 +---- apps/openmw/mwgui/dialogue.cpp | 5 +++-- apps/openmw/mwgui/dialogue.hpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index dea942349..29bb49ca0 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -127,9 +127,6 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - // If the dialogue window was already open, keep the existing history - bool resetHistory = (!MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue)); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -145,7 +142,7 @@ namespace MWDialogue { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); + win->startDialogue(actor, actor.getClass().getName (actor)); creatureStats.talkedToPlayer(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 920183c61..4ec3da50b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -283,6 +283,7 @@ namespace MWGui } else { + resetReference(); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); mTopicsList->scrollToTop(); return true; @@ -357,7 +358,7 @@ namespace MWGui } } - void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory) + void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) { MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); @@ -372,7 +373,7 @@ namespace MWGui mTopicsList->clear(); - if (resetHistory || !sameActor) + if (!sameActor) { for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) delete (*it); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index af5fe5efc..b854e6c1a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -108,7 +108,7 @@ namespace MWGui void notifyLinkClicked (TypesetBook::InteractiveId link); - void startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory); + void startDialogue(MWWorld::Ptr actor, std::string npcName); void setKeywords(std::list keyWord); void addResponse (const std::string& text, const std::string& title="", bool needMargin = true); From 36c192a1ddf98efb6ee4cf551353708316c91ae8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:03:52 +0200 Subject: [PATCH 079/150] Undo the console portion of 84657271c760 because it results in the console forgetting its object on opening --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/console.cpp | 6 +++--- apps/openmw/mwgui/console.hpp | 5 +---- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 2df3113b3..51a17d380 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -151,6 +151,8 @@ namespace MWBase virtual void updateSpellWindow() = 0; + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; + /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 182b6ef97..6094111f8 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -417,7 +417,7 @@ namespace MWGui setCoord(10,10, width-10, height/2); } - void Console::setPtr(const MWWorld::Ptr& object) + void Console::setSelectedObject(const MWWorld::Ptr& object) { if (!object.isEmpty()) { @@ -443,12 +443,12 @@ namespace MWGui void Console::onReferenceUnavailable() { - setPtr(MWWorld::Ptr()); + setSelectedObject(MWWorld::Ptr()); } void Console::resetReference() { ReferenceInterface::resetReference(); - setPtr(MWWorld::Ptr()); + setSelectedObject(MWWorld::Ptr()); } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index f243b8387..f5647e9ea 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -25,7 +25,7 @@ namespace MWGui { public: /// Set the implicit object for script execution - void setPtr(const MWWorld::Ptr& object); + void setSelectedObject(const MWWorld::Ptr& object); MyGUI::EditBox* mCommandLine; MyGUI::EditBox* mHistory; @@ -42,12 +42,9 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); - void onFrame(float dt) { checkReferenceAvailable(); } - void setFont(const std::string &fntName); void onResChange(int width, int height); - void clear() { resetReference(); } // Print a message to the console, in specified color. void print(const std::string &msg, const std::string& color = "#FFFFFF"); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 779e358d3..1db2691f4 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -260,7 +260,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Console, object); + MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 76f0b029d..85f57a75e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1884,6 +1884,11 @@ namespace MWGui mSpellWindow->updateSpells(); } + void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) + { + mConsole->setSelectedObject(object); + } + std::string WindowManager::correctIconPath(const std::string& path) { return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 56e7d9b7b..53b2dc33a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -190,6 +190,8 @@ namespace MWGui virtual void updateSpellWindow(); + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); + ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); From e8c6a3b225828fac735ba7b409ddccc9446e7640 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:21:51 +0200 Subject: [PATCH 080/150] Fix crash in dialogue filter if local variables are not configured This could happen e.g. by 'some_npc_in_remote_cell->forcegreeting' --- apps/openmw/mwdialogue/filter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 67bb53e71..e8757e4a3 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -193,7 +193,8 @@ bool MWDialogue::Filter::testFunctionLocal(const MWDialogue::SelectWrapper& sele return false; // shouldn't happen, we checked that variable has a type above, so must exist const MWScript::Locals& locals = mActor.getRefData().getLocals(); - + if (locals.isEmpty()) + return select.selectCompare(0); switch (type) { case 's': return select.selectCompare (static_cast (locals.mShorts[index])); From c5613e384ea3dae8af6c6d8521e102a65424fb9c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:29:06 +0200 Subject: [PATCH 081/150] Remove duplicate disposition code --- apps/openmw/mwgui/dialogue.cpp | 17 ++++------------- apps/openmw/mwgui/dialogue.hpp | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 4ec3da50b..869b83928 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -384,7 +384,7 @@ namespace MWGui delete (*it); mLinks.clear(); - updateOptions(); + updateDisposition(); restock(); } @@ -579,13 +579,10 @@ namespace MWGui updateHistory(); } - void DialogueWindow::updateOptions() + void DialogueWindow::updateDisposition() { - //Clear the list of topics - mTopicsList->clear(); - bool dispositionVisible = false; - if (mPtr.getClass().isNpc()) + if (!mPtr.isEmpty() && mPtr.getClass().isNpc()) { dispositionVisible = true; mDispositionBar->setProgressRange(100); @@ -626,12 +623,6 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); - if(!mPtr.isEmpty() && mPtr.getTypeName() == typeid(ESM::NPC).name()) - { - int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(disp); - mDispositionText->setCaption(MyGUI::utility::toString(disp)+std::string("/100")); - } + updateDisposition(); } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index b854e6c1a..83f1eb1de 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -135,7 +135,7 @@ namespace MWGui virtual void onReferenceUnavailable(); private: - void updateOptions(); + void updateDisposition(); void restock(); bool mEnabled; From 476bec41c5c80c98981b491a6ca9593146c07901 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:47:35 +0200 Subject: [PATCH 082/150] Remove redundant code --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 29bb49ca0..ffa26e211 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -330,14 +330,12 @@ namespace MWDialogue updateGlobals(); std::list keywordList; - int choice = mChoice; - mChoice = -1; mActorKnownTopics.clear(); const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); - Filter filter (mActor, mChoice, mTalkedTo); + Filter filter (mActor, -1, mTalkedTo); for (MWWorld::Store::iterator iter = dialogs.begin(); iter != dialogs.end(); ++iter) { @@ -362,8 +360,6 @@ namespace MWDialogue // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); win->setKeywords(keywordList); - - mChoice = choice; } void DialogueManager::keywordSelected (const std::string& keyword) From 2ce79e07a461d4be141a4c5574474d7b9116467b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:38:38 +0200 Subject: [PATCH 083/150] Refactor dialogue GUI to talk to the dialogue manager, not the other way around and not both ways. - Fix memory leaks in DialogueWindow - Fix Link objects being deleted from their own event handler --- apps/openmw/mwbase/dialoguemanager.hpp | 21 ++- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 125 +++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 24 ++- apps/openmw/mwgui/dialogue.cpp | 152 ++++++++++++------ apps/openmw/mwgui/dialogue.hpp | 39 +++-- apps/openmw/mwgui/enchantingdialog.cpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 1 + apps/openmw/mwgui/trainingwindow.cpp | 1 + apps/openmw/mwgui/travelwindow.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.hpp | 1 - apps/openmw/mwscript/dialogueextensions.cpp | 5 +- apps/openmw/mwworld/actiontalk.cpp | 4 +- 14 files changed, 229 insertions(+), 148 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index 18f249e56..c928fa940 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -2,6 +2,8 @@ #define GAME_MWBASE_DIALOGUEMANAGER_H #include +#include +#include #include @@ -42,24 +44,29 @@ namespace MWBase virtual bool isInChoice() const = 0; - virtual void startDialogue (const MWWorld::Ptr& actor) = 0; + typedef std::pair Response; // title, text + virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response) = 0; virtual void addTopic (const std::string& topic) = 0; - virtual void askQuestion (const std::string& question,int choice) = 0; + virtual void addChoice (const std::string& text,int choice) = 0; + virtual const std::vector >& getChoices() = 0; + + virtual bool isGoodbye() = 0; virtual void goodbye() = 0; virtual void say(const MWWorld::Ptr &actor, const std::string &topic) = 0; - //calbacks for the GUI - virtual void keywordSelected (const std::string& keyword) = 0; + virtual Response keywordSelected (const std::string& keyword) = 0; virtual void goodbyeSelected() = 0; - virtual void questionAnswered (int answer) = 0; + virtual Response questionAnswered (int answer) = 0; + + virtual std::list getAvailableTopics() = 0; - virtual bool checkServiceRefused () = 0; + virtual bool checkServiceRefused (Response& response) = 0; - virtual void persuade (int type) = 0; + virtual Response persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 51a17d380..d8bce67e4 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -140,7 +140,6 @@ namespace MWBase virtual bool isAllowed (MWGui::GuiWindow wnd) const = 0; /// \todo investigate, if we really need to expose every single lousy UI element to the outside world - virtual MWGui::DialogueWindow* getDialogueWindow() = 0; virtual MWGui::InventoryWindow* getInventoryWindow() = 0; virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index ffa26e211..4ed3b82a9 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -33,8 +34,6 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwgui/dialogue.hpp" - #include "../mwscript/compilercontext.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwscript/extensions.hpp" @@ -59,6 +58,7 @@ namespace MWDialogue { mChoice = -1; mIsInChoice = false; + mGoodbye = false; mCompilerContext.setExtensions (&extensions); } @@ -99,17 +99,15 @@ namespace MWDialogue if (mActorKnownTopics.count( topicId )) mKnownTopics.insert( topicId ); } - - updateTopics(); } - void DialogueManager::startDialogue (const MWWorld::Ptr& actor) + bool DialogueManager::startDialogue (const MWWorld::Ptr& actor, Response& response) { updateGlobals(); // Dialogue with dead actor (e.g. through script) should not be allowed. if (actor.getClass().getCreatureStats(actor).isDead()) - return; + return false; mLastTopic = ""; mPermanentDispositionChange = 0; @@ -117,6 +115,8 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; + mGoodbye = false; + mChoices.clear(); mActor = actor; @@ -125,8 +125,6 @@ namespace MWDialogue mActorKnownTopics.clear(); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -140,10 +138,6 @@ namespace MWDialogue // Search a response (we do not accept a fallback to "Info refusal" here) if (const ESM::DialInfo *info = filter.search (*it, false)) { - //initialise the GUI - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - win->startDialogue(actor, actor.getClass().getName (actor)); - creatureStats.talkedToPlayer(); if (!info->mSound.empty()) @@ -152,29 +146,23 @@ namespace MWDialogue } // first topics update so that parseText knows the keywords to highlight - updateTopics(); + updateActorKnownTopics(); parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), "", false); + response = Response ("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); mLastTopic = it->mId; // update topics again to accommodate changes resulting from executeScript - updateTopics(); + updateActorKnownTopics(); - return; + return true; } } } - - // No greetings found. The dialogue window should not be shown. - // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). - bool isCompanion = !mActor.getClass().getScript(mActor).empty() - && mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion"); - if (isCompanion) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mActor); + return false; } bool DialogueManager::compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor) @@ -252,8 +240,9 @@ namespace MWDialogue } } - void DialogueManager::executeTopic (const std::string& topic) + DialogueManager::Response DialogueManager::executeTopic (const std::string& topic) { + DialogueManager::Response response; Filter filter (mActor, mChoice, mTalkedTo); const MWWorld::Store &dialogues = @@ -261,8 +250,6 @@ namespace MWDialogue const ESM::Dialogue& dialogue = *dialogues.find (topic); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - const ESM::DialInfo* info = filter.search(dialogue, true); if (info) { @@ -287,7 +274,7 @@ namespace MWDialogue title = topic; MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title); + response = Response(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); if (dialogue.mType == ESM::Dialogue::Topic) { @@ -308,11 +295,7 @@ namespace MWDialogue mLastTopic = topic; } - else - { - // no response found, print a fallback text - win->addResponse ("…", topic); - } + return response; } const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id) @@ -325,11 +308,10 @@ namespace MWDialogue MWBase::Environment::get().getWorld()->updateDialogueGlobals(); } - void DialogueManager::updateTopics() + void DialogueManager::updateActorKnownTopics() { updateGlobals(); - std::list keywordList; mActorKnownTopics.clear(); const MWWorld::Store &dialogs = @@ -345,35 +327,42 @@ namespace MWDialogue { std::string lower = Misc::StringUtils::lowerCase(iter->mId); mActorKnownTopics.insert (lower); - - //does the player know the topic? - if (mKnownTopics.count(lower)) - { - keywordList.push_back (iter->mId); - } } } } - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + } + + std::list DialogueManager::getAvailableTopics() + { + updateActorKnownTopics(); + + std::list keywordList; + + for (const std::string& topic : mActorKnownTopics) + { + //does the player know the topic? + if (mKnownTopics.count(Misc::StringUtils::lowerCase(topic))) + keywordList.push_back(topic); + } // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); - win->setKeywords(keywordList); + return keywordList; } - void DialogueManager::keywordSelected (const std::string& keyword) + DialogueManager::Response DialogueManager::keywordSelected (const std::string& keyword) { + Response response; if(!mIsInChoice) { const ESM::Dialogue* dialogue = searchDialogue(keyword); if (dialogue && dialogue->mType == ESM::Dialogue::Topic) { - executeTopic (keyword); + response = executeTopic (keyword); } } - - updateTopics(); + return response; } bool DialogueManager::isInChoice() const @@ -383,8 +372,6 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - // Apply disposition change to NPC's base disposition if (mActor.getClass().isNpc()) { @@ -400,9 +387,10 @@ namespace MWDialogue mTemporaryDispositionChange = 0; } - void DialogueManager::questionAnswered (int answer) + DialogueManager::Response DialogueManager::questionAnswered (int answer) { mChoice = answer; + DialogueManager::Response response; const ESM::Dialogue* dialogue = searchDialogue(mLastTopic); if (dialogue) @@ -418,10 +406,10 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices(); + mChoices.clear(); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext)); + response = Response("", Interpreter::fixDefinesDialog(text, interpreterContext)); // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. @@ -441,32 +429,39 @@ namespace MWDialogue { mChoice = -1; mIsInChoice = false; - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices(); + mChoices.clear(); } } } - updateTopics(); + updateActorKnownTopics(); + return response; } - void DialogueManager::askQuestion (const std::string& question, int choice) + void DialogueManager::addChoice (const std::string& text, int choice) { mIsInChoice = true; - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->addChoice(question, choice); + mChoices.push_back(std::make_pair(text, choice)); } - void DialogueManager::goodbye() + const std::vector >& DialogueManager::getChoices() { - mIsInChoice = true; + return mChoices; + } - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + bool DialogueManager::isGoodbye() + { + return mGoodbye; + } - win->goodbye(); + void DialogueManager::goodbye() + { + mIsInChoice = false; + mGoodbye = true; } - void DialogueManager::persuade(int type) + DialogueManager::Response DialogueManager::persuade(int type) { bool success; float temp, perm; @@ -515,7 +510,7 @@ namespace MWDialogue text = "Bribe"; } - executeTopic (text + (success ? " Success" : " Fail")); + return executeTopic (text + (success ? " Success" : " Fail")); } int DialogueManager::getTemporaryDispositionChange() const @@ -528,7 +523,7 @@ namespace MWDialogue mTemporaryDispositionChange += delta; } - bool DialogueManager::checkServiceRefused() + bool DialogueManager::checkServiceRefused(Response& response) { Filter filter (mActor, mChoice, mTalkedTo); @@ -536,7 +531,6 @@ namespace MWDialogue MWBase::Environment::get().getWorld()->getStore().get(); const ESM::Dialogue& dialogue = *dialogues.find ("Service Refusal"); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); std::vector infos = filter.list (dialogue, false, false, true); if (!infos.empty()) @@ -550,8 +544,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), - gmsts.find ("sServiceRefusal")->getString()); + response = Response(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); return true; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 81bd2f2b9..d9c622120 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -41,19 +41,22 @@ namespace MWDialogue int mChoice; std::string mLastTopic; // last topic ID, lowercase bool mIsInChoice; + bool mGoodbye; + + std::vector > mChoices; float mTemporaryDispositionChange; float mPermanentDispositionChange; void parseText (const std::string& text); - void updateTopics(); + void updateActorKnownTopics(); void updateGlobals(); bool compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor); void executeScript (const std::string& script, const MWWorld::Ptr& actor); - void executeTopic (const std::string& topic); + Response executeTopic (const std::string& topic); const ESM::Dialogue* searchDialogue(const std::string& id); @@ -65,24 +68,29 @@ namespace MWDialogue virtual bool isInChoice() const; - virtual void startDialogue (const MWWorld::Ptr& actor); + virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response); + + std::list getAvailableTopics(); virtual void addTopic (const std::string& topic); - virtual void askQuestion (const std::string& question,int choice); + virtual void addChoice (const std::string& text,int choice); + const std::vector >& getChoices(); + + virtual bool isGoodbye(); virtual void goodbye(); - virtual bool checkServiceRefused (); + virtual bool checkServiceRefused (Response& response); virtual void say(const MWWorld::Ptr &actor, const std::string &topic); //calbacks for the GUI - virtual void keywordSelected (const std::string& keyword); + virtual Response keywordSelected (const std::string& keyword); virtual void goodbyeSelected(); - virtual void questionAnswered (int answer); + virtual Response questionAnswered (int answer); - virtual void persuade (int type); + virtual Response persuade (int type); virtual int getTemporaryDispositionChange () const; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 869b83928..a7f18561e 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -68,7 +68,9 @@ namespace MWGui else /*if (sender == mBribe1000Button)*/ type = MWBase::MechanicsManager::PT_Bribe1000; - MWBase::Environment::get().getDialogueManager()->persuade(type); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->persuade(type); + + eventPersuadeMsg(response.first, response.second); setVisible(false); } @@ -214,30 +216,26 @@ namespace MWGui void Choice::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId); + eventChoiceActivated(mChoiceId); } void Topic::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->keywordSelected(mTopicId); + eventTopicActivated(mTopicId); } void Goodbye::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + eventActivated(); } // -------------------------------------------------------------------------------------------------- DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") - , mEnabled(false) , mGoodbye(false) , mPersuasionDialog() { @@ -245,13 +243,14 @@ namespace MWGui center(); mPersuasionDialog.setVisible(false); + mPersuasionDialog.eventPersuadeMsg += MyGUI::newDelegate(this, &DialogueWindow::onPersuadeResult); //History view getWidget(mHistory, "History"); //Topics list getWidget(mTopicsList, "TopicsList"); - mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectListItem); getWidget(mGoodbyeButton, "ByeButton"); mGoodbyeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); @@ -269,15 +268,27 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } + DialogueWindow::~DialogueWindow() + { + mPersuasionDialog.eventPersuadeMsg.clear(); + + deleteLater(); + for (Link* link : mLinks) + delete link; + for (auto link : mTopicLinks) + delete link.second; + for (auto history : mHistoryContents) + delete history; + } + void DialogueWindow::onTradeComplete() { - addResponse(MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); + addResponse("", MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); } bool DialogueWindow::exit() { - if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) - && !mGoodbye) + if ((MWBase::Environment::get().getDialogueManager()->isInChoice())) { return false; } @@ -315,9 +326,9 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } - void DialogueWindow::onSelectTopic(const std::string& topic, int id) + void DialogueWindow::onSelectListItem(const std::string& topic, int id) { - if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + if (mGoodbye || MWBase::Environment::get().getDialogueManager()->isInChoice()) return; int separatorPos = 0; @@ -328,17 +339,18 @@ namespace MWGui } if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(topic); + onTopicActivated(topic); else { const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + MWBase::DialogueManager::Response response; if (topic == gmst.find("sPersuasion")->getString()) mPersuasionDialog.setVisible(true); else if (topic == gmst.find("sCompanionShare")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); - else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(response)) { if (topic == gmst.find("sBarter")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); @@ -355,21 +367,30 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } + else + addResponse(response.first, response.second); } } - void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) + void DialogueWindow::setPtr(const MWWorld::Ptr& actor) { + MWBase::DialogueManager::Response response; + if (!MWBase::Environment::get().getDialogueManager()->startDialogue(actor, response)) + { + // No greetings found. The dialogue window should not be shown. + // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). + if (isCompanion()) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr); + return; + } + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); mGoodbye = false; - mEnabled = true; bool sameActor = (mPtr == actor); mPtr = actor; mTopicsList->setEnabled(true); - setTitle(npcName); - - clearChoices(); + setTitle(mPtr.getClass().getName(mPtr)); mTopicsList->clear(); @@ -381,12 +402,13 @@ namespace MWGui } for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) - delete (*it); + mDeleteLater.push_back(*it); // Links are not deleted right away to prevent issues with event handlers mLinks.clear(); updateDisposition(); - restock(); + + addResponse(response.first, response.second, false); } void DialogueWindow::restock() @@ -403,11 +425,18 @@ namespace MWGui } } + void DialogueWindow::deleteLater() + { + for (Link* link : mDeleteLater) + delete link; + mDeleteLater.clear(); + } + void DialogueWindow::setKeywords(std::list keyWords) { mTopicsList->clear(); for (std::map::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) - delete it->second; + mDeleteLater.push_back(it->second); mTopicLinks.clear(); mKeywordSearch.clear(); @@ -416,9 +445,6 @@ namespace MWGui bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get()->mBase->getTransport().empty()) || (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get()->mBase->getTransport().empty()); - bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -446,7 +472,7 @@ namespace MWGui if (services & ESM::NPC::Repair) mTopicsList->addItem(gmst.find("sRepair")->getString()); - if (isCompanion) + if (isCompanion()) mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); if (mTopicsList->getItemCount() > 0) @@ -458,6 +484,7 @@ namespace MWGui mTopicsList->addItem(*it); Topic* t = new Topic(*it); + t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated); mTopicLinks[Misc::StringUtils::lowerCase(*it)] = t; mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t)); @@ -491,9 +518,11 @@ namespace MWGui typesetter->sectionBreak(9); // choices const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); - for (std::vector >::iterator it = mChoices.begin(); it != mChoices.end(); ++it) + mChoices = MWBase::Environment::get().getDialogueManager()->getChoices(); + for (std::vector >::const_iterator it = mChoices.begin(); it != mChoices.end(); ++it) { Choice* link = new Choice(it->second); + link->eventChoiceActivated += MyGUI::newDelegate(this, &DialogueWindow::onChoiceActivated); mLinks.push_back(link); typesetter->lineBreak(); @@ -503,9 +532,11 @@ namespace MWGui typesetter->write(questionStyle, to_utf8_span(it->first.c_str())); } + mGoodbye = MWBase::Environment::get().getDialogueManager()->isGoodbye(); if (mGoodbye) { Goodbye* link = new Goodbye(); + link->eventActivated += MyGUI::newDelegate(this, &DialogueWindow::onGoodbyeActivated); mLinks.push_back(link); std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString(); BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver, @@ -550,32 +581,40 @@ namespace MWGui reinterpret_cast(link)->activated(); } - void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos) + void DialogueWindow::onTopicActivated(const std::string &topicId) { - mHistory->setPosition(0, static_cast(pos) * -1); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId); + addResponse(response.first, response.second); } - void DialogueWindow::addResponse(const std::string &text, const std::string &title, bool needMargin) + void DialogueWindow::onChoiceActivated(int id) { - mHistoryContents.push_back(new Response(text, title, needMargin)); - updateHistory(); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->questionAnswered(id); + addResponse(response.first, response.second); } - void DialogueWindow::addMessageBox(const std::string& text) + void DialogueWindow::onGoodbyeActivated() { - mHistoryContents.push_back(new Message(text)); - updateHistory(); + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + resetReference(); + } + + void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos) + { + mHistory->setPosition(0, static_cast(pos) * -1); } - void DialogueWindow::addChoice(const std::string& choice, int id) + void DialogueWindow::addResponse(const std::string &title, const std::string &text, bool needMargin) { - mChoices.push_back(std::make_pair(choice, id)); + mHistoryContents.push_back(new Response(text, title, needMargin)); updateHistory(); + updateTopics(); } - void DialogueWindow::clearChoices() + void DialogueWindow::addMessageBox(const std::string& text) { - mChoices.clear(); + mHistoryContents.push_back(new Message(text)); updateHistory(); } @@ -608,13 +647,6 @@ namespace MWGui } } - void DialogueWindow::goodbye() - { - mGoodbye = true; - mEnabled = false; - updateHistory(); - } - void DialogueWindow::onReferenceUnavailable() { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); @@ -623,6 +655,30 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); + if (mPtr.isEmpty()) + return; + updateDisposition(); + deleteLater(); + + if (mChoices != MWBase::Environment::get().getDialogueManager()->getChoices() + || mGoodbye != MWBase::Environment::get().getDialogueManager()->isGoodbye()) + updateHistory(); + } + + void DialogueWindow::updateTopics() + { + setKeywords(MWBase::Environment::get().getDialogueManager()->getAvailableTopics()); + } + + bool DialogueWindow::isCompanion() + { + return !mPtr.getClass().getScript(mPtr).empty() + && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); + } + + void DialogueWindow::onPersuadeResult(const std::string &title, const std::string &text) + { + addResponse(title, text); } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 83f1eb1de..c83906588 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -8,6 +8,8 @@ #include "../mwdialogue/keywordsearch.hpp" +#include + namespace Gui { class MWList; @@ -20,14 +22,14 @@ namespace MWGui namespace MWGui { - class DialogueHistoryViewModel; - class BookPage; - class PersuasionDialog : public WindowModal { public: PersuasionDialog(); + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_Result; + EventHandle_Result eventPersuadeMsg; + virtual void onOpen(); private: @@ -53,6 +55,8 @@ namespace MWGui struct Topic : Link { + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_TopicId; + EventHandle_TopicId eventTopicActivated; Topic(const std::string& id) : mTopicId(id) {} std::string mTopicId; virtual void activated (); @@ -60,6 +64,8 @@ namespace MWGui struct Choice : Link { + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_ChoiceId; + EventHandle_ChoiceId eventChoiceActivated; Choice(int id) : mChoiceId(id) {} int mChoiceId; virtual void activated (); @@ -67,6 +73,8 @@ namespace MWGui struct Goodbye : Link { + typedef MyGUI::delegates::CMultiDelegate0 Event_Activated; + Event_Activated eventActivated; virtual void activated (); }; @@ -98,6 +106,7 @@ namespace MWGui { public: DialogueWindow(); + ~DialogueWindow(); void onTradeComplete(); @@ -108,25 +117,29 @@ namespace MWGui void notifyLinkClicked (TypesetBook::InteractiveId link); - void startDialogue(MWWorld::Ptr actor, std::string npcName); + void setPtr(const MWWorld::Ptr& actor); + void setKeywords(std::list keyWord); - void addResponse (const std::string& text, const std::string& title="", bool needMargin = true); + void addResponse (const std::string& title, const std::string& text, bool needMargin = true); void addMessageBox(const std::string& text); - void addChoice(const std::string& choice, int id); - void clearChoices(); - - void goodbye(); void onFrame(float dt); void clear() { resetReference(); } protected: - void onSelectTopic(const std::string& topic, int id); + void updateTopics(); + bool isCompanion(); + + void onPersuadeResult(const std::string& title, const std::string& text); + void onSelectListItem(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onWindowResize(MyGUI::Window* _sender); + void onTopicActivated(const std::string& topicId); + void onChoiceActivated(int id); + void onGoodbyeActivated(); void onScrollbarMoved (MyGUI::ScrollBar* sender, size_t pos); @@ -137,17 +150,19 @@ namespace MWGui private: void updateDisposition(); void restock(); + void deleteLater(); bool mEnabled; - bool mGoodbye; - std::vector mHistoryContents; std::vector > mChoices; + bool mGoodbye; std::vector mLinks; std::map mTopicLinks; + std::vector mDeleteLater; + KeywordSearchT mKeywordSearch; BookPage* mHistory; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 74d80d292..6b0b33a0a 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -353,6 +353,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); return; } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 341167ab7..939f70b59 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -323,6 +323,7 @@ namespace MWGui onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); return; } } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 120ab5cba..1081ee81e 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -197,6 +197,7 @@ namespace MWGui // go back to game mode MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 02df6bd8e..c9f19ad92 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -178,6 +178,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 85f57a75e..f5825f08d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1288,7 +1288,6 @@ namespace MWGui mConsole->executeFile (path); } - MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 53b2dc33a..f6b2707ad 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -179,7 +179,6 @@ namespace MWGui virtual bool isAllowed(GuiWindow wnd) const; /// \todo investigate, if we really need to expose every single lousy UI element to the outside world - virtual MWGui::DialogueWindow* getDialogueWindow(); virtual MWGui::InventoryWindow* getInventoryWindow(); virtual MWGui::CountDialog* getCountDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog(); diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index fcb7e8f3b..21d8d469b 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" @@ -116,7 +117,7 @@ namespace MWScript runtime.pop(); arg0 = arg0 -1; } - dialogue->askQuestion(question,choice); + dialogue->addChoice(question,choice); } } }; @@ -133,7 +134,7 @@ namespace MWScript if (!ptr.getRefData().isEnabled()) return; - MWBase::Environment::get().getDialogueManager()->startDialogue (ptr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, ptr); } }; diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 051380ff5..c7bb6a26e 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -1,7 +1,7 @@ #include "actiontalk.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/windowmanager.hpp" namespace MWWorld { @@ -9,6 +9,6 @@ namespace MWWorld void ActionTalk::executeImp (const Ptr& actor) { - MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, getTarget()); } } From 9b91ea5d34413c674a637692a984046c0886b728 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 16:51:19 +0200 Subject: [PATCH 084/150] Exit drag-and-drop if dragged item is deleted (Fixes #3097) --- apps/openmw/mwgui/draganddrop.cpp | 6 ++++++ apps/openmw/mwgui/draganddrop.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 6 +----- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index fe0ad3374..d81b2ed00 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -121,6 +121,12 @@ void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView) mSourceView->update(); } +void DragAndDrop::onFrame() +{ + if (mIsOnDragAndDrop && mItem.mBase.getRefData().getCount() == 0) + finish(); +} + void DragAndDrop::finish() { mIsOnDragAndDrop = false; diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp index a356fe4e2..dff8cd73c 100644 --- a/apps/openmw/mwgui/draganddrop.hpp +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -29,6 +29,7 @@ namespace MWGui void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); void drop (ItemModel* targetModel, ItemView* targetView); + void onFrame(); void finish(); }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f5825f08d..7e3741ae6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -876,11 +876,7 @@ namespace MWGui MWBase::StateManager::State_NoGame) return; - if (mDragAndDrop->mIsOnDragAndDrop) - { - assert(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - } + mDragAndDrop->onFrame(); updateMap(); From 09e93319f5620278bfb2bd5957948118fe36faed Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:20:07 +0200 Subject: [PATCH 085/150] Restrict the 'fake mouse movement' workaround to where it's actually required (Fixes #3978) --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b1f80cae6..cf52cbd18 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -366,8 +366,6 @@ namespace MWInput mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); mInputManager->capture(disableEvents); - // inject some fake mouse movement to force updating MyGUI's widget states - MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); if (mControlsDisabled) { @@ -764,6 +762,8 @@ namespace MWInput mMouseWheel = int(arg.z); MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); + // FIXME: inject twice to force updating focused widget states (tooltips) resulting from changing the viewport by scroll wheel + MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); } if (mMouseLookEnabled && !mControlsDisabled) From fce9a14986e352af26270d814add9085c609c01c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:44:35 +0200 Subject: [PATCH 086/150] Hide the mouse cursor until it's used --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++++ apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d8bce67e4..d454067c8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -180,6 +180,7 @@ namespace MWBase virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0; virtual void setCursorVisible(bool visible) = 0; + virtual void setCursorActive(bool active) = 0; virtual void getMousePosition(int &x, int &y) = 0; virtual void getMousePosition(float &x, float &y) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7e3741ae6..8272568d3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -176,6 +176,7 @@ namespace MWGui , mWerewolfOverlayEnabled(Settings::Manager::getBool ("werewolf overlay", "GUI")) , mHudEnabled(true) , mCursorVisible(true) + , mCursorActive(false) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -1009,7 +1010,16 @@ namespace MWGui void WindowManager::setCursorVisible(bool visible) { + if (visible == mCursorVisible) + return; mCursorVisible = visible; + if (!visible) + mCursorActive = false; + } + + void WindowManager::setCursorActive(bool active) + { + mCursorActive = active; } void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) @@ -1518,7 +1528,7 @@ namespace MWGui bool WindowManager::getCursorVisible() { - return mCursorVisible; + return mCursorVisible && mCursorActive; } void WindowManager::trackWindow(Layout *layout, const std::string &name) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f6b2707ad..612470a7e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -320,6 +320,9 @@ namespace MWGui virtual bool getCursorVisible(); + /// Call when mouse cursor or buttons are used. + virtual void setCursorActive(bool active); + /// Clear all savegame-specific data virtual void clear(); @@ -447,6 +450,7 @@ namespace MWGui bool mWerewolfOverlayEnabled; bool mHudEnabled; bool mCursorVisible; + bool mCursorActive; void setCursorVisible(bool visible); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf52cbd18..6f0b3b1b4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -718,6 +718,7 @@ namespace MWInput MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); } } + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } setPlayerControlsEnabled(!guiMode); @@ -764,6 +765,8 @@ namespace MWInput MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); // FIXME: inject twice to force updating focused widget states (tooltips) resulting from changing the viewport by scroll wheel MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); + + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } if (mMouseLookEnabled && !mControlsDisabled) From c88c535e0ecf786384d7b209a2446d65a37b3aaf Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:59:45 +0200 Subject: [PATCH 087/150] Fix HBox/VBox not using Client widget with MyGUI <= 3.2.2 --- components/widgets/box.cpp | 16 ++++++++++++++++ components/widgets/box.hpp | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index eeddc22dd..a7bd573f4 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -238,6 +238,14 @@ namespace Gui align(); } + void HBox::initialiseOverride() + { + Base::initialiseOverride(); + MyGUI::Widget* client = 0; + assignWidget(client, "Client"); + setWidgetClient(client); + } + void HBox::onWidgetCreated(MyGUI::Widget* _widget) { align(); @@ -385,6 +393,14 @@ namespace Gui align(); } + void VBox::initialiseOverride() + { + Base::initialiseOverride(); + MyGUI::Widget* client = 0; + assignWidget(client, "Client"); + setWidgetClient(client); + } + MyGUI::IntSize VBox::getRequestedSize () { MyGUI::IntSize size(0,0); diff --git a/components/widgets/box.hpp b/components/widgets/box.hpp index 70f73ce42..467d4b82d 100644 --- a/components/widgets/box.hpp +++ b/components/widgets/box.hpp @@ -99,6 +99,8 @@ namespace Gui virtual void setCoord (const MyGUI::IntCoord &_value); protected: + virtual void initialiseOverride(); + virtual void align(); virtual MyGUI::IntSize getRequestedSize(); @@ -116,6 +118,8 @@ namespace Gui virtual void setCoord (const MyGUI::IntCoord &_value); protected: + virtual void initialiseOverride(); + virtual void align(); virtual MyGUI::IntSize getRequestedSize(); From 2514cc5cc8162e24b299ea9690562475bda57f42 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:20:24 +0200 Subject: [PATCH 088/150] Workaround key focus being reset in BookWindow when next/prev are hidden --- apps/openmw/mwgui/bookwindow.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ae20b8e43..a86146f2f 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,6 +1,7 @@ #include "bookwindow.hpp" #include +#include #include @@ -153,20 +154,16 @@ namespace MWGui mLeftPageNumber->setCaption( MyGUI::utility::toString(mCurrentPage*2 + 1) ); mRightPageNumber->setCaption( MyGUI::utility::toString(mCurrentPage*2 + 2) ); - //If it is the last page, hide the button "Next Page" - if ( (mCurrentPage+1)*2 == mPages.size() - || (mCurrentPage+1)*2 == mPages.size() + 1) - { - mNextPageButton->setVisible(false); - } else { - mNextPageButton->setVisible(true); - } - //If it is the fist page, hide the button "Prev Page" - if (mCurrentPage == 0) { - mPrevPageButton->setVisible(false); - } else { - mPrevPageButton->setVisible(true); - } + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool nextPageVisible = (mCurrentPage+1)*2 < mPages.size(); + mNextPageButton->setVisible(nextPageVisible); + bool prevPageVisible = mCurrentPage != 0; + mPrevPageButton->setVisible(prevPageVisible); + + if (focus == mNextPageButton && !nextPageVisible && prevPageVisible) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mPrevPageButton); + else if (focus == mPrevPageButton && !prevPageVisible && nextPageVisible) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mNextPageButton); if (mPages.empty()) return; From a0ee1c563049216350ae8ed5c5678806de0567b7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:24:43 +0200 Subject: [PATCH 089/150] Fix order of buttons in book window layout for key cycling --- files/mygui/openmw_book.layout | 77 +++++++++++++++++----------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 7c158af8d..a7bea5eb5 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -5,49 +5,50 @@ - - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - + + + From 010a7ea5b36ea6e412375fe94106ded92850fbf7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:33:32 +0200 Subject: [PATCH 090/150] Fix tooltip widgets being set to accept key focus --- apps/openmw/mwgui/tooltips.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9b89c3957..a611b1f06 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -422,18 +422,20 @@ namespace MWGui std::string realImage = MWBase::Environment::get().getWindowManager()->correctIconPath(image); MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); - captionWidget->setProperty("Static", "true"); + captionWidget->setEditStatic(true); + captionWidget->setNeedKeyFocus(false); captionWidget->setCaptionWithReplacing(caption); MyGUI::IntSize captionSize = captionWidget->getTextSize(); int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); MyGUI::EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), MyGUI::Align::Stretch, "ToolTipText"); - textWidget->setProperty("Static", "true"); - textWidget->setProperty("MultiLine", "true"); - textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); + textWidget->setEditStatic(true); + textWidget->setEditMultiLine(true); + textWidget->setEditWordWrap(info.wordWrap); textWidget->setCaptionWithReplacing(text); textWidget->setTextAlign(MyGUI::Align::HCenter | MyGUI::Align::Top); + textWidget->setNeedKeyFocus(false); MyGUI::IntSize textSize = textWidget->getTextSize(); captionSize += MyGUI::IntSize(imageSize, 0); // adjust for image From b9341925f2947b31562d7eca9a3c95d6edc20fb6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:33:41 +0200 Subject: [PATCH 091/150] Set AutoSizedEditBox as Static by default Would look very odd anyway to use it for editable text, with the widget resizing as you type. --- components/widgets/box.cpp | 7 +++++++ components/widgets/box.hpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index a7bd573f4..bf18cef5b 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -66,6 +66,13 @@ namespace Gui notifySizeChange (this); } + void AutoSizedEditBox::initialiseOverride() + { + Base::initialiseOverride(); + setNeedKeyFocus(false); + setEditStatic(true); + } + void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) { if (_key == "ExpandDirection") diff --git a/components/widgets/box.hpp b/components/widgets/box.hpp index 467d4b82d..66be00719 100644 --- a/components/widgets/box.hpp +++ b/components/widgets/box.hpp @@ -39,9 +39,12 @@ namespace Gui MYGUI_RTTI_DERIVED( AutoSizedEditBox ) public: + virtual MyGUI::IntSize getRequestedSize(); virtual void setCaption(const MyGUI::UString& _value); + virtual void initialiseOverride(); + protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); }; From 475ac46f3eb10bcb977387ccb1e084407229bdd3 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 19:22:23 +0200 Subject: [PATCH 092/150] Workaround keyfocus issues in current versions of MyGUI --- apps/openmw/mwgui/keyboardnavigation.cpp | 58 +++++++++++++++++++++++- apps/openmw/mwgui/keyboardnavigation.hpp | 4 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index da99c72d0..c9ad5a587 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -30,7 +31,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu } } +bool shouldAcceptKeyFocus(MyGUI::Widget* w) +{ + return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); +} + KeyboardNavigation::KeyboardNavigation() + : mCurrentFocus(nullptr) { MyGUI::WidgetManager::getInstance().registerUnlinker(this); } @@ -42,7 +49,11 @@ KeyboardNavigation::~KeyboardNavigation() void KeyboardNavigation::saveFocus(int mode) { - mKeyFocus[mode] = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (shouldAcceptKeyFocus(focus)) + mKeyFocus[mode] = focus; + else + mKeyFocus[mode] = mCurrentFocus; } void KeyboardNavigation::restoreFocus(int mode) @@ -61,6 +72,51 @@ void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) for (std::pair& w : mKeyFocus) if (w.second == widget) w.second = nullptr; + if (widget == mCurrentFocus) + mCurrentFocus = nullptr; +} + +void styleFocusedButton(MyGUI::Widget* w) +{ + if (w) + { + if (MyGUI::Button* b = w->castType(false)) + { + b->_setWidgetState("highlighted"); + } + } +} + +void KeyboardNavigation::onFrame() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + if (focus == mCurrentFocus) + { + styleFocusedButton(mCurrentFocus); + return; + } + + // workaround incorrect key focus resets (fix in MyGUI TBD) + if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus)) + { + MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); + focus = mCurrentFocus; + } + + // style highlighted button (won't be needed for MyGUI 3.2.3) + if (focus != mCurrentFocus) + { + if (mCurrentFocus) + { + if (MyGUI::Button* b = mCurrentFocus->castType(false)) + b->_setWidgetState("normal"); + } + + mCurrentFocus = focus; + } + + styleFocusedButton(mCurrentFocus); } enum Direction diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index fff36d862..15aa0d6a8 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -21,6 +21,8 @@ namespace MWGui void _unlinkWidget(MyGUI::Widget* widget); + void onFrame(); + private: bool switchFocus(int direction, bool wrap); @@ -28,6 +30,8 @@ namespace MWGui bool accept(); std::map mKeyFocus; + + MyGUI::Widget* mCurrentFocus; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8272568d3..950b1edc3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -866,6 +866,8 @@ namespace MWGui if (!mCurrentModals.empty()) mCurrentModals.top()->onFrame(frameDuration); + mKeyboardNavigation->onFrame(); + mMessageBoxManager->onFrame(frameDuration); mToolTips->onFrame(frameDuration); From 41fe16013b5f7908964d7837f306bb333446b461 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 19:37:33 +0200 Subject: [PATCH 093/150] Select first widget if we can't find the current widget --- apps/openmw/mwgui/keyboardnavigation.cpp | 38 ++++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index c9ad5a587..d4d0a8c43 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -152,6 +152,21 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) } } +bool selectFirstWidget() +{ + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + return false; +} + bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); @@ -159,22 +174,14 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) return false; - if (focus && (direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + bool isCycle = (direction == D_Prev || direction == D_Next); + if (focus && isCycle && focus->getUserString("AcceptTab") == "true") return false; - if ((!focus || !focus->getNeedKeyFocus()) && (direction == D_Next || direction == D_Prev)) + if ((!focus || !focus->getNeedKeyFocus()) && isCycle) { // if nothing is selected, select the first widget - MyGUI::VectorWidgetPtr keyFocusList; - MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); - while (enumerator.next()) - getKeyFocusWidgets(enumerator.current(), keyFocusList); - - if (!keyFocusList.empty()) - { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); - return true; - } + return selectFirstWidget(); } if (!focus) return false; @@ -190,7 +197,12 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) MyGUI::VectorWidgetPtr::iterator found = std::find(keyFocusList.begin(), keyFocusList.end(), focus); if (found == keyFocusList.end()) - return false; + { + if (isCycle) + return selectFirstWidget(); + else + return false; + } bool forward = (direction == D_Next || direction == D_Right || direction == D_Down); From 1714271a7692e884fa0337cc56ef9d5d5bf74236 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 22:21:30 +0200 Subject: [PATCH 094/150] Improve KeyboardNavigation to better handle modal windows It's no longer possible to cycle to widgets that aren't part of the current modal window. The window manager will remember the focused widget of a modal window on a limited basis (it'll be discarded when a different modal window opens). --- apps/openmw/mwgui/dialogue.cpp | 7 ++- apps/openmw/mwgui/dialogue.hpp | 2 + apps/openmw/mwgui/keyboardnavigation.cpp | 70 ++++++++++++++++++------ apps/openmw/mwgui/keyboardnavigation.hpp | 8 +++ apps/openmw/mwgui/windowbase.cpp | 5 +- apps/openmw/mwgui/windowbase.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++++ files/mygui/openmw_text.skin.xml | 1 + 8 files changed, 87 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index a7f18561e..b7da86f4e 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -77,7 +77,6 @@ namespace MWGui void PersuasionDialog::onOpen() { - WindowModal::onOpen(); center(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -88,6 +87,12 @@ namespace MWGui mBribe1000Button->setEnabled (playerGold >= 1000); mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); + WindowModal::onOpen(); + } + + MyGUI::Widget* PersuasionDialog::getDefaultKeyFocus() + { + return mAdmireButton; } // -------------------------------------------------------------------------------------------------- diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index c83906588..6535ad4b2 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -32,6 +32,8 @@ namespace MWGui virtual void onOpen(); + virtual MyGUI::Widget* getDefaultKeyFocus(); + private: MyGUI::Button* mCancelButton; MyGUI::Button* mAdmireButton; diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index d4d0a8c43..6e1113a4f 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -38,6 +38,7 @@ bool shouldAcceptKeyFocus(MyGUI::Widget* w) KeyboardNavigation::KeyboardNavigation() : mCurrentFocus(nullptr) + , mModalWindow(nullptr) { MyGUI::WidgetManager::getInstance().registerUnlinker(this); } @@ -51,9 +52,13 @@ void KeyboardNavigation::saveFocus(int mode) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); if (shouldAcceptKeyFocus(focus)) + { mKeyFocus[mode] = focus; + } else + { mKeyFocus[mode] = mCurrentFocus; + } } void KeyboardNavigation::restoreFocus(int mode) @@ -87,6 +92,13 @@ void styleFocusedButton(MyGUI::Widget* w) } } +bool isRootParent(MyGUI::Widget* widget, MyGUI::Widget* root) +{ + while (widget && widget->getParent()) + widget = widget->getParent(); + return widget == root; +} + void KeyboardNavigation::onFrame() { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); @@ -98,7 +110,7 @@ void KeyboardNavigation::onFrame() } // workaround incorrect key focus resets (fix in MyGUI TBD) - if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus)) + if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow))) { MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); focus = mCurrentFocus; @@ -119,6 +131,25 @@ void KeyboardNavigation::onFrame() styleFocusedButton(mCurrentFocus); } +void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *defaultFocus) +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus || !shouldAcceptKeyFocus(focus)) + { + MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + } + else + { + if (!isRootParent(focus, window)) + MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + } +} + +void KeyboardNavigation::setModalWindow(MyGUI::Widget *window) +{ + mModalWindow = window; +} + enum Direction { D_Left, @@ -152,29 +183,15 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) } } -bool selectFirstWidget() -{ - MyGUI::VectorWidgetPtr keyFocusList; - MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); - while (enumerator.next()) - getKeyFocusWidgets(enumerator.current(), keyFocusList); - - if (!keyFocusList.empty()) - { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); - return true; - } - return false; -} - bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) + bool isCycle = (direction == D_Prev || direction == D_Next); + + if ((focus && focus->getTypeName().find("Button") == std::string::npos) && !isCycle) return false; - bool isCycle = (direction == D_Prev || direction == D_Next); if (focus && isCycle && focus->getUserString("AcceptTab") == "true") return false; @@ -230,6 +247,23 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) return true; } +bool KeyboardNavigation::selectFirstWidget() +{ + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + if (mModalWindow) + enumerator = mModalWindow->getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + return false; +} + bool KeyboardNavigation::accept() { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index 15aa0d6a8..728f16a3d 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -23,15 +23,23 @@ namespace MWGui void onFrame(); + /// Set a key focus widget for this window, if one isn't already set. + void setDefaultFocus(MyGUI::Widget* window, MyGUI::Widget* defaultFocus); + + void setModalWindow(MyGUI::Widget* window); + private: bool switchFocus(int direction, bool wrap); + bool selectFirstWidget(); + /// Send button press event to focused button bool accept(); std::map mKeyFocus; MyGUI::Widget* mCurrentFocus; + MyGUI::Widget* mModalWindow; }; } diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index e563d9aa9..a0e7eedde 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -67,14 +67,17 @@ WindowModal::WindowModal(const std::string& parLayout) void WindowModal::onOpen() { - // Order important. We need to save the key focus widget before its unset MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); + MyGUI::InputManager::getInstance().setKeyFocusWidget(focus); } void WindowModal::onClose() { MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index f183c97fe..56901c95a 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -23,6 +23,8 @@ namespace MWGui public: WindowBase(const std::string& parLayout); + virtual MyGUI::Widget* getDefaultKeyFocus() { return NULL; } + // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 950b1edc3..0b51b2b3f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1738,6 +1738,10 @@ namespace MWGui mKeyboardNavigation->saveFocus(getMode()); mCurrentModals.push(input); + mKeyboardNavigation->restoreFocus(-1); + + mKeyboardNavigation->setModalWindow(input->mMainWidget); + mKeyboardNavigation->setDefaultFocus(input->mMainWidget, input->getDefaultKeyFocus()); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1747,12 +1751,20 @@ namespace MWGui if(!mCurrentModals.empty()) { if(input == mCurrentModals.top()) + { mCurrentModals.pop(); + mKeyboardNavigation->saveFocus(-1); + } else std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; } if (mCurrentModals.empty()) + { + mKeyboardNavigation->setModalWindow(NULL); mKeyboardNavigation->restoreFocus(getMode()); + } + else + mKeyboardNavigation->setModalWindow(mCurrentModals.top()->mMainWidget); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 163b9d134..edc103443 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -81,6 +81,7 @@ color_misc=0,205,205 # ???? + From 22929e53fad10f2be52b67ccf77ab8e5d90c00b9 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 22:25:10 +0200 Subject: [PATCH 095/150] Don't ignore my own advice Can't wait until MyGUI 3.2.2 is a build dependency, then we can use key focus events to handle the SDL text input. --- apps/openmw/mwgui/bookwindow.cpp | 4 ++-- apps/openmw/mwgui/keyboardnavigation.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index a86146f2f..c18548dad 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -161,9 +161,9 @@ namespace MWGui mPrevPageButton->setVisible(prevPageVisible); if (focus == mNextPageButton && !nextPageVisible && prevPageVisible) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mPrevPageButton); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mPrevPageButton); else if (focus == mPrevPageButton && !prevPageVisible && nextPageVisible) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mNextPageButton); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNextPageButton); if (mPages.empty()) return; diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 6e1113a4f..2b06de295 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -112,7 +112,7 @@ void KeyboardNavigation::onFrame() // workaround incorrect key focus resets (fix in MyGUI TBD) if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow))) { - MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCurrentFocus); focus = mCurrentFocus; } @@ -136,12 +136,12 @@ void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *d MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); if (!focus || !shouldAcceptKeyFocus(focus)) { - MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus); } else { if (!isRootParent(focus, window)) - MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus); } } From 44720bf41a1cae7a920dec6537abe7dfc15664dc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:26:40 +0200 Subject: [PATCH 096/150] Allow MWList items to retain key focus --- components/widgets/list.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index c5a459f22..9318e32ed 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -72,6 +72,7 @@ namespace Gui button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheelMoved); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); + button->setNeedKeyFocus(true); int height = button->getTextSize().height; button->setSize(MyGUI::IntSize(button->getSize().width, height)); From 7a64098da399e4853fe824f477b878eab01050c4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:27:00 +0200 Subject: [PATCH 097/150] Avoid rebuilding the dialogue topics pane unnecessarily Also retaining key focus. --- apps/openmw/mwgui/dialogue.cpp | 16 +++++++++++++++- apps/openmw/mwgui/dialogue.hpp | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b7da86f4e..b726bf0d9 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -241,6 +241,7 @@ namespace MWGui DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") + , mIsCompanion(false) , mGoodbye(false) , mPersuasionDialog() { @@ -404,6 +405,9 @@ namespace MWGui for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) delete (*it); mHistoryContents.clear(); + + mKeywords.clear(); + updateTopicsPane(); } for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) @@ -438,6 +442,16 @@ namespace MWGui } void DialogueWindow::setKeywords(std::list keyWords) + { + if (mKeywords == keyWords && isCompanion() == mIsCompanion) + return; + mIsCompanion = isCompanion(); + mKeywords = keyWords; + + updateTopicsPane(); + } + + void DialogueWindow::updateTopicsPane() { mTopicsList->clear(); for (std::map::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) @@ -484,7 +498,7 @@ namespace MWGui mTopicsList->addSeparator(); - for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) + for(std::list::iterator it = mKeywords.begin(); it != mKeywords.end(); ++it) { mTopicsList->addItem(*it); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 6535ad4b2..97a0e8b37 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -132,6 +132,7 @@ namespace MWGui protected: void updateTopics(); + void updateTopicsPane(); bool isCompanion(); void onPersuadeResult(const std::string& title, const std::string& text); @@ -156,6 +157,9 @@ namespace MWGui bool mEnabled; + bool mIsCompanion; + std::list mKeywords; + std::vector mHistoryContents; std::vector > mChoices; bool mGoodbye; From 8964fc93d60341deb22cdbf702ba3c114b4034a2 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:27:53 +0200 Subject: [PATCH 098/150] Fix dialogue window not being exited properly --- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 5 +---- apps/openmw/mwgui/spellbuyingwindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 5 ++--- apps/openmw/mwgui/trainingwindow.cpp | 4 +--- apps/openmw/mwgui/travelwindow.cpp | 6 ++---- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 90ef32ced..739acee48 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -164,7 +164,7 @@ void CompanionWindow::onMessageBoxButtonClicked(int button) { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); // Important for Calvus' contract script to work properly - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 6b0b33a0a..3616b8b62 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -9,7 +9,6 @@ #include #include -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -176,7 +175,6 @@ namespace MWGui void EnchantingDialog::onReferenceUnavailable () { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); resetReference(); } @@ -352,8 +350,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, item, mPtr, 1); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); return; } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index aeb5cfbe5..d9c3a5f16 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -187,7 +187,7 @@ namespace MWGui { // remove both Spells and Dialogue (since you always trade with the NPC/creature that you have previously talked to) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void SpellBuyingWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 939f70b59..2eeeafe0d 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -322,8 +322,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, it->mBase, mPtr, it->mCount); onCancelButtonClicked(mCancelButton); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); return; } } @@ -503,7 +502,7 @@ namespace MWGui { // remove both Trade and Dialogue (since you always trade with the NPC/creature that you have previously talked to) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } int TradeWindow::getMerchantGold() diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 1081ee81e..b6504d223 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -6,7 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -196,8 +195,7 @@ namespace MWGui // go back to game mode MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index c9f19ad92..7c7cdb63e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -8,7 +8,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" @@ -177,8 +176,7 @@ namespace MWGui } MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); @@ -208,7 +206,7 @@ namespace MWGui void TravelWindow::onReferenceUnavailable() { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) From 05814c092959ab9481c9453e7364216f2e278133 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:04:01 +0200 Subject: [PATCH 099/150] Add key focus handling for WaitDialog Default is 'until healed'. Up/Down arrows change the hour slider and implicitely change the button to 'Wait'. --- apps/openmw/mwgui/waitdialog.cpp | 22 ++++++++++++++++++++++ apps/openmw/mwgui/waitdialog.hpp | 1 + 2 files changed, 23 insertions(+) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 8a360435c..43c6f135a 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,6 +1,7 @@ #include "waitdialog.hpp" #include +#include #include @@ -72,6 +73,10 @@ namespace MWGui mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); + mCancelButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mWaitButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mUntilHealedButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); @@ -80,6 +85,11 @@ namespace MWGui void WaitDialog::setPtr(const MWWorld::Ptr &ptr) { setCanRest(!ptr.isEmpty() || MWBase::Environment::get().getWorld ()->canRest () == 0); + + if (mUntilHealedButton->getVisible()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mUntilHealedButton); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton); } bool WaitDialog::exit() @@ -195,6 +205,18 @@ namespace MWGui { mHourText->setCaptionWithReplacing (MyGUI::utility::toString(position+1) + " #{sRestMenu2}"); mManualHours = position+1; + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton); + } + + void WaitDialog::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowDown) + mHourSlider->setScrollPosition(std::min(mHourSlider->getScrollPosition()+1, mHourSlider->getScrollRange()-1)); + else if (key == MyGUI::KeyCode::ArrowUp) + mHourSlider->setScrollPosition(std::max(static_cast(mHourSlider->getScrollPosition())-1, 0)); + else + return; + onHourSliderChangedPosition(mHourSlider, mHourSlider->getScrollPosition()); } void WaitDialog::onWaitingProgressChanged(int cur, int total) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index c7ccee025..eb6a55640 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -65,6 +65,7 @@ namespace MWGui void onWaitButtonClicked(MyGUI::Widget* sender); void onCancelButtonClicked(MyGUI::Widget* sender); void onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); void onWaitingProgressChanged(int cur, int total); void onWaitingInterrupted(); From 7a3fbfb34ae918cf00badd32c3b0b45ac875c4ab Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:21:20 +0200 Subject: [PATCH 100/150] Slightly improve journal window keyboard navigation --- apps/openmw/mwgui/journalwindow.cpp | 40 ++++++++++++++++++++++++++--- files/mygui/openmw_journal.layout | 32 +++++++++++------------ 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3a67e857d..30a440b58 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -84,10 +85,16 @@ namespace void adviseButtonClick (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender)) { - getWidget (name) -> + getWidget (name) -> eventMouseButtonClick += newDelegate(this, Handler); } + void adviseKeyPress (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character)) + { + getWidget (name) -> + eventKeyButtonPressed += newDelegate(this, Handler); + } + MWGui::BookPage* getPage (char const * name) { return getWidget (name); @@ -111,6 +118,12 @@ namespace adviseButtonClick (ShowAllBTN, &JournalWindowImpl::notifyShowAll ); adviseButtonClick (ShowActiveBTN, &JournalWindowImpl::notifyShowActive); + adviseKeyPress (OptionsBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (PrevPageBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (NextPageBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (CloseBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (JournalBTN, &JournalWindowImpl::notifyKeyPress); + Gui::MWList* list = getWidget(QuestsList); list->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyQuestClicked); @@ -237,6 +250,8 @@ namespace --page; } updateShowingPages(); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget(CloseBTN)); } void onClose() @@ -348,8 +363,19 @@ namespace relPages = 0; } - setVisible (PrevPageBTN, page > 0); - setVisible (NextPageBTN, relPages > 2); + MyGUI::Widget* nextPageBtn = getWidget(NextPageBTN); + MyGUI::Widget* prevPageBtn = getWidget(PrevPageBTN); + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool nextPageVisible = relPages > 2; + nextPageBtn->setVisible(nextPageVisible); + bool prevPageVisible = page > 0; + prevPageBtn->setVisible(prevPageVisible); + + if (focus == nextPageBtn && !nextPageVisible && prevPageVisible) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(prevPageBtn); + else if (focus == prevPageBtn && !prevPageVisible && nextPageVisible) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nextPageBtn); setVisible (PageOneNum, relPages > 0); setVisible (PageTwoNum, relPages > 1); @@ -361,6 +387,14 @@ namespace setText (PageTwoNum, page + 2); } + void notifyKeyPress(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + notifyPrevPage(sender); + else if (key == MyGUI::KeyCode::ArrowDown) + notifyNextPage(sender); + } + void notifyTopicClicked (intptr_t linkId) { Book topicBook = createTopicBook (linkId); diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 1131b1bbc..964b5ea95 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -3,32 +3,27 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + @@ -36,11 +31,14 @@ + + + From 879da9c69a6e7828a3e0d0bf1913e69e97629cbc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:28:15 +0200 Subject: [PATCH 101/150] Add key focus for some more button skins --- files/mygui/openmw_text.skin.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index edc103443..5f96d0a57 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -66,6 +66,7 @@ color_misc=0,205,205 # ???? + @@ -97,6 +98,7 @@ color_misc=0,205,205 # ???? + @@ -104,6 +106,7 @@ color_misc=0,205,205 # ???? + From 87311d86b58193cc15018777585d45e1bf99a29c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 12:12:16 +0200 Subject: [PATCH 102/150] Fix what looks like a copy/paste error --- apps/openmw/mwgui/widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 744ef236f..45767bf01 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -105,7 +105,7 @@ namespace MWGui assignWidget(button, "StatValueButton"); if (button) { - mSkillNameWidget = button; + mSkillValueWidget = button; button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); } } From 3d2ad2d3391aaf887010742afa45ce092a2157c6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 12:40:47 +0200 Subject: [PATCH 103/150] Include cleanup --- apps/openmw/mwgui/alchemywindow.cpp | 3 +++ apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/companionwindow.cpp | 1 + apps/openmw/mwgui/companionwindow.hpp | 6 +++++- apps/openmw/mwgui/dialogue.cpp | 3 ++- apps/openmw/mwgui/recharge.cpp | 1 - apps/openmw/mwgui/repair.cpp | 2 -- apps/openmw/mwgui/savegamedialog.cpp | 1 - apps/openmw/mwgui/waitdialog.cpp | 3 +-- 9 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 0140653a1..80284e9b2 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,6 +1,8 @@ #include "alchemywindow.hpp" #include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -19,6 +21,7 @@ #include "sortfilteritemmodel.hpp" #include "itemview.hpp" #include "itemwidget.hpp" +#include "widgets.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 2d13a346a..d1e54241a 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,7 +5,6 @@ #include "../mwmechanics/alchemy.hpp" -#include "widgets.hpp" #include "windowbase.hpp" namespace MWMechanics diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 739acee48..ad71be7df 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -13,6 +13,7 @@ #include "companionitemmodel.hpp" #include "draganddrop.hpp" #include "countdialog.hpp" +#include "widgets.hpp" namespace { diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 891106853..8ca350617 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -1,12 +1,16 @@ #ifndef OPENMW_MWGUI_COMPANIONWINDOW_H #define OPENMW_MWGUI_COMPANIONWINDOW_H -#include "widgets.hpp" #include "windowbase.hpp" #include "referenceinterface.hpp" namespace MWGui { + namespace Widgets + { + class MWDynamicStat; + } + class MessageBoxManager; class ItemView; class DragAndDrop; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b726bf0d9..4e36fe117 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -20,7 +22,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "widgets.hpp" #include "bookpage.hpp" #include "textcolours.hpp" diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 32da7876c..26a364f72 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -21,7 +21,6 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "widgets.hpp" #include "itemwidget.hpp" #include "itemchargeview.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index a461f7b3d..11a8aece2 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -17,8 +17,6 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" -#include "widgets.hpp" - #include "itemwidget.hpp" #include "itemchargeview.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index e7c27b268..0e4ff1cf4 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -29,7 +29,6 @@ #include "../mwstate/character.hpp" #include "confirmationdialog.hpp" -#include "widgets.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 43c6f135a..a7ad687cb 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -24,8 +25,6 @@ #include "../mwstate/charactermanager.hpp" -#include "widgets.hpp" - namespace MWGui { From 74e806d9745e6f14be6cc4f04320586b3df3cace Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:14:26 +0200 Subject: [PATCH 104/150] Additionally use movement keys (default WASD) to navigate GUI buttons --- apps/openmw/mwinput/inputmanagerimp.cpp | 29 +++++++++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 1 + 2 files changed, 30 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6f0b3b1b4..0637b6d83 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -174,6 +174,29 @@ namespace MWInput } } + void InputManager::handleGuiArrowKey(int action) + { + MyGUI::KeyCode key; + switch (action) + { + case A_MoveLeft: + key = MyGUI::KeyCode::ArrowLeft; + break; + case A_MoveRight: + key = MyGUI::KeyCode::ArrowRight; + break; + case A_MoveForward: + key = MyGUI::KeyCode::ArrowUp; + break; + case A_MoveBackward: + default: + key = MyGUI::KeyCode::ArrowDown; + break; + } + + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0); + } + void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { resetIdleTime (); @@ -235,6 +258,12 @@ namespace MWInput resetIdleTime(); activate(); break; + case A_MoveLeft: + case A_MoveRight: + case A_MoveForward: + case A_MoveBackward: + handleGuiArrowKey(action); + break; case A_Journal: toggleJournal (); break; diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 8809f44cd..cba7fc743 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -214,6 +214,7 @@ namespace MWInput void updateIdleTime(float dt); void setPlayerControlsEnabled(bool enabled); + void handleGuiArrowKey(int action); void updateCursorMode(); From c7a82704c6344ee62fd4a4848144b5f250fbf804 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:32:46 +0200 Subject: [PATCH 105/150] Fix key focus resets in SaveGameDialog --- apps/openmw/mwgui/savegamedialog.cpp | 12 ++++++++++++ apps/openmw/mwgui/savegamedialog.hpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 0e4ff1cf4..eb7f158d7 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -105,6 +105,11 @@ namespace MWGui } } + void SaveGameDialog::onDeleteSlotCancel() + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender) { // This might have previously been a save slot from the list. If so, that is no longer the case @@ -225,6 +230,11 @@ namespace MWGui accept(true); } + void SaveGameDialog::onConfirmationCancel() + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::accept(bool reallySure) { // Remove for MyGUI 3.2.2 @@ -240,6 +250,7 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationCancel); return; } if (mSaveNameEdit->getCaption().empty()) @@ -260,6 +271,7 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationCancel); return; } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 39e3d310a..a51124705 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -37,10 +37,12 @@ namespace MWGui void onSlotMouseClick(MyGUI::ListBox* sender, size_t pos); void onDeleteSlotConfirmed(); + void onDeleteSlotCancel(); void onEditSelectAccept (MyGUI::EditBox* sender); void onSaveNameChanged (MyGUI::EditBox* sender); void onConfirmationGiven(); + void onConfirmationCancel(); void accept(bool reallySure=false); From 0ee57effcceaf6050a3b85c6b91cc63615c7400e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:43:33 +0200 Subject: [PATCH 106/150] Make 'Delete game' button not accept keyfocus, to prevent accidents --- apps/openmw/mwgui/savegamedialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index eb7f158d7..423dbb036 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -57,6 +57,9 @@ namespace MWGui mSaveList->eventKeyButtonPressed += MyGUI::newDelegate(this, &SaveGameDialog::onKeyButtonPressed); mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept); mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged); + + // To avoid accidental deletions + mDeleteButton->setNeedKeyFocus(false); } void SaveGameDialog::onSlotActivated(MyGUI::ListBox *sender, size_t pos) From 5c50506c83262bf82681a580e89a81ed7eb99eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 27 Sep 2017 17:13:21 +0200 Subject: [PATCH 107/150] water shader refactor plus basic rain ripples --- files/shaders/water_fragment.glsl | 113 +++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 19 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 9c8e56191..f7f87ce77 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -38,10 +38,85 @@ const float WIND_SPEED = 0.2f; const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); + + + + + + + + + + + + +const float RAIN_RIPPLE_GAPS = 5.0; +const float RAIN_RIPPLE_RADIUS = 0.1; + +int modulo(int v1, int v2) +{ + return v1 - v2 * int(floor(float(v1) / float(v2))); +} + +vec2 randOffset(vec2 c) +{ + return fract(vec2( + c.x * c.y / 8.0 + c.y * 0.3 + c.x * 0.2, + c.x * c.y / 14.0 + c.y * 0.5 + c.x * 0.7)); +} + +float randPhase(vec2 c) +{ + return fract((c.x * c.y) / (c.x + c.y + 0.1)); +} + +float circle(vec2 coords, vec2 i_part, float phase) +{ + float d = distance(vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0),coords); + float r = RAIN_RIPPLE_RADIUS * phase; + + if (d > r) + return 0.0; + + float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + + return (1.0 - abs(phase)) * pow(sinValue,3.0); +} + +float rain(vec2 uv, float time) +{ + vec2 i_part = floor(uv * RAIN_RIPPLE_GAPS); + vec2 f_part = fract(uv * RAIN_RIPPLE_GAPS); + return circle(f_part,i_part,fract(time * 1.2 + randPhase(i_part))); +} + +float rainCombined(vec2 uv, float time) +{ + return + rain(uv,time) + + rain(uv + vec2(10.5,5.7),time) + + rain(uv * 0.75 + vec2(3.7,18.9),time) + + rain(uv * 0.9 + vec2(5.7,30.1),time) + + rain(uv * 0.8 + vec2(1.2,3.0),time); +} + + + + + + + + + + + + + + // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) -{ + { float c = abs(dot(Incoming, Normal)); float g = eta * eta - 1.0 + c * c; float result; @@ -56,7 +131,12 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) result = 1.0; /* TIR (no refracted component) */ return result; -} + } + +vec2 normalCoords(vec2 uv, float scale, float speed, float time, float timer1, float timer2, vec3 previousNormal) + { + return uv * (WAVE_SCALE * scale) + WIND_DIR * time * (WIND_SPEED * speed) -(previousNormal.xy/previousNormal.zz) * WAVE_CHOPPYNESS + vec2(time * timer1,time * timer2); + } varying vec3 screenCoordsPassthrough; varying vec4 position; @@ -101,22 +181,12 @@ void main(void) #define waterTimer osg_SimulationTime - nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); - vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; - vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; - vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; - vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; - vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; - vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; - - + vec3 normal0 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.05, 0.04, waterTimer, -0.015, -0.005, vec3(0.0,0.0,0.0))).rgb - 1.0; + vec3 normal1 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.1, 0.08, waterTimer, 0.02, 0.015, normal0)).rgb - 1.0; + vec3 normal2 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.25, 0.07, waterTimer, -0.04, -0.03, normal1)).rgb - 1.0; + vec3 normal3 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.5, 0.09, waterTimer, 0.03, 0.04, normal2)).rgb - 1.0; + vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; + vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + @@ -126,6 +196,10 @@ void main(void) normal = vec3(-normal.x, -normal.y, normal.z); + float rainRipple = rainCombined(position.xy / 1000.0,osg_SimulationTime); + +//normal.y += 2 * rainRipple; + // normal for sunlight scattering vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + @@ -133,7 +207,6 @@ void main(void) lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); - vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz); vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; @@ -200,6 +273,8 @@ void main(void) float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); +gl_FragData[0].xyz += vec3(rainRipple) * 0.2; + #if REFRACTION gl_FragData[0].w = 1.0; #else From 4a332a180764af345d939c93b0ebda696b81c9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 27 Sep 2017 21:25:14 +0200 Subject: [PATCH 108/150] improve rain ripples --- files/shaders/water_fragment.glsl | 69 ++++++++++++------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index f7f87ce77..23bd688ab 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -38,17 +38,7 @@ const float WIND_SPEED = 0.2f; const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); - - - - - - - - - - - +// ---------------- rain ripples related stuff --------------------- const float RAIN_RIPPLE_GAPS = 5.0; const float RAIN_RIPPLE_RADIUS = 0.1; @@ -70,27 +60,32 @@ float randPhase(vec2 c) return fract((c.x * c.y) / (c.x + c.y + 0.1)); } -float circle(vec2 coords, vec2 i_part, float phase) +vec4 circle(vec2 coords, vec2 i_part, float phase) { - float d = distance(vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0),coords); + vec2 center = vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0); + vec2 toCenter = coords - center; + float d = length(toCenter); float r = RAIN_RIPPLE_RADIUS * phase; if (d > r) - return 0.0; + return vec4(0.0,0.0,1.0,0.0); float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + float height = (1.0 - abs(phase)) * pow(sinValue,3.0); + + vec3 normal = normalize(mix(vec3(0.0,0.0,1.0),vec3(normalize(toCenter),0.0),height)); - return (1.0 - abs(phase)) * pow(sinValue,3.0); + return vec4(normal,height); } -float rain(vec2 uv, float time) +vec4 rain(vec2 uv, float time) { vec2 i_part = floor(uv * RAIN_RIPPLE_GAPS); vec2 f_part = fract(uv * RAIN_RIPPLE_GAPS); return circle(f_part,i_part,fract(time * 1.2 + randPhase(i_part))); } -float rainCombined(vec2 uv, float time) +vec4 rainCombined(vec2 uv, float time) // returns ripple normal in xyz and ripple height in w { return rain(uv,time) + @@ -100,19 +95,6 @@ float rainCombined(vec2 uv, float time) rain(uv * 0.8 + vec2(1.2,3.0),time); } - - - - - - - - - - - - - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) @@ -188,22 +170,24 @@ void main(void) vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; + vec4 rainRipple = rainCombined(position.xy / 1000.0,waterTimer); + vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; + vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y + + rippleAdd); normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = vec3(-normal.x, -normal.y, normal.z); - float rainRipple = rainCombined(position.xy / 1000.0,osg_SimulationTime); - -//normal.y += 2 * rainRipple; - // normal for sunlight scattering vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1 + + rippleAdd).xyz; + lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); @@ -224,10 +208,10 @@ void main(void) float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); - vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); + vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); // fresnel - float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); // air to water; water to air float fresnel = fresnel_dielectric(vVec, normal, ior); fresnel = clamp(fresnel, 0.0, 1.0); @@ -243,12 +227,14 @@ void main(void) #else float shore = 1.0; #endif + vec2 screenCoordsOffset = ( (normal.xy + rainRipple.w * vec2(0.0,2.0)) * REFL_BUMP * shore); + // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; + vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb; // refraction #if REFRACTION - vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP*shore)).rgb; + vec3 refraction = texture2D(refractionMap, screenCoords - screenCoordsOffset).rgb; // brighten up the refraction underwater refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; @@ -268,12 +254,11 @@ void main(void) #else gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; #endif - // fog float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); -gl_FragData[0].xyz += vec3(rainRipple) * 0.2; + gl_FragData[0].xyz += vec3(rainRipple.w) * 0.2; #if REFRACTION gl_FragData[0].w = 1.0; From 0240a6c38b3b62ea35ed84ce0b2903a89b8b1115 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:30:12 +0200 Subject: [PATCH 109/150] Fix controls window regression --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0637b6d83..e6acbbd52 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -697,7 +697,7 @@ namespace MWInput SDL_StopTextInput(); bool consumed = false; - if (kc != OIS::KC_UNASSIGNED) + if (kc != OIS::KC_UNASSIGNED && !mInputBinder->detectingBindingState()) { consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); if (SDL_IsTextInputActive() && // Little trick to check if key is printable @@ -726,7 +726,8 @@ namespace MWInput mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); - setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + if (!mInputBinder->detectingBindingState()) + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); mInputBinder->keyReleased (arg); } From fb8306b61f66650bc5ce5421a17fa496c70822fe Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:30:31 +0200 Subject: [PATCH 110/150] Disable keyfocus for world map button Fixes 'Tab' no longer working as a keybinding for closing the inventory window. --- files/mygui/openmw_map_window.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_map_window.layout b/files/mygui/openmw_map_window.layout index b38097dce..8d45022f8 100644 --- a/files/mygui/openmw_map_window.layout +++ b/files/mygui/openmw_map_window.layout @@ -31,6 +31,7 @@ + From a0f5e32113352217a372b040774a9a3292c79208 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:38:15 +0200 Subject: [PATCH 111/150] Fix 'new game' from the main menu not removing menu afterwards --- apps/openmw/mwgui/mainmenu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 4e629403a..00e4e30a5 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -80,6 +80,7 @@ namespace MWGui void MainMenu::onNewGameConfirmed() { + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); MWBase::Environment::get().getStateManager()->newGame(); } From db650df416991bd9485634cedb0b03eb12a67790 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:40:59 +0200 Subject: [PATCH 112/150] Fix 'blocking' messageboxes not handling key focus properly --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + files/mygui/openmw_interactive_messagebox_notransp.layout | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0b51b2b3f..fbee52c82 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -773,6 +773,7 @@ namespace MWGui double dt = frameTimer.time_s(); frameTimer.setStartTick(); + mKeyboardNavigation->onFrame(); mMessageBoxManager->onFrame(dt); MWBase::Environment::get().getInputManager()->update(dt, true, false); diff --git a/files/mygui/openmw_interactive_messagebox_notransp.layout b/files/mygui/openmw_interactive_messagebox_notransp.layout index 6b79b9417..f5a462977 100644 --- a/files/mygui/openmw_interactive_messagebox_notransp.layout +++ b/files/mygui/openmw_interactive_messagebox_notransp.layout @@ -9,6 +9,7 @@ + From e9d81fdf5aa7bfa4f5f4c668473fb722e7f8050f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:00:20 +0200 Subject: [PATCH 113/150] Fix being able to escape interactive messageboxes --- apps/openmw/mwgui/messagebox.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 38e6590b7..53b277416 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -77,6 +77,8 @@ namespace MWGui void mousePressed (MyGUI::Widget* _widget); int readPressedButton (); + virtual bool exit() { return false; } + bool mMarkedToDelete; private: From 0deda69a272813423518c406ee0fb6ceac563f79 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:04:36 +0200 Subject: [PATCH 114/150] Fix wrong skin for levelup attribute values --- apps/openmw/mwgui/levelupdialog.cpp | 4 +--- files/mygui/openmw_levelup_dialog.layout | 16 ++++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index a068d71f3..286405f79 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -41,6 +41,7 @@ namespace MWGui { MyGUI::TextBox* t; getWidget(t, "AttribVal" + MyGUI::utility::toString(i)); + mAttributeValues.push_back(t); MyGUI::Button* b; getWidget(b, "Attrib" + MyGUI::utility::toString(i)); @@ -48,10 +49,7 @@ namespace MWGui b->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onAttributeClicked); mAttributes.push_back(b); - mAttributeValues.push_back(t); - getWidget(t, "AttribMultiplier" + MyGUI::utility::toString(i)); - mAttributeMultipliers.push_back(t); } diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index fc11ddfd7..66855373a 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -50,7 +50,7 @@ - + @@ -64,7 +64,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -149,7 +149,7 @@ - + From d53e7f8a3c836344176d8f7f5500dd3128d52b06 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:07:49 +0200 Subject: [PATCH 115/150] Remove redundant code Already worked around in WindowBase::setVisible --- apps/openmw/mwgui/console.cpp | 7 ------- apps/openmw/mwgui/console.hpp | 1 - 2 files changed, 8 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 6094111f8..2d016ddf1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -152,13 +152,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine); } - void Console::onClose() - { - // Apparently, hidden widgets can retain key focus - // Remove for MyGUI 3.2.2 - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); - } - void Console::setFont(const std::string &fntName) { mHistory->setFontName(fntName); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index f5647e9ea..7ee39770d 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -40,7 +40,6 @@ namespace MWGui Console(int w, int h, bool consoleOnlyScripts); virtual void onOpen(); - virtual void onClose(); void setFont(const std::string &fntName); From 0ae009eb21eb2f079379320edb34fd2deb0d3a2a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:18:47 +0200 Subject: [PATCH 116/150] Hide message box before deleting it Fixes a crash when closing the game window during the 'plugin mismatch' dialog. Modal windows have to be hidden before they are deleted to prevent a dangling pointer in WindowManager. --- apps/openmw/mwgui/messagebox.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index dd0495051..6c421de5e 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -36,8 +36,13 @@ namespace MWGui void MessageBoxManager::clear() { - delete mInterMessageBoxe; - mInterMessageBoxe = NULL; + if (mInterMessageBoxe) + { + mInterMessageBoxe->setVisible(false); + + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; + } std::vector::iterator it(mMessageBoxes.begin()); for (; it != mMessageBoxes.end(); ++it) From 6ec66fa95fb64be4510c1c80777d0d7dfb1d614b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 16:57:55 +0000 Subject: [PATCH 117/150] Restore keyfocus to goodbye when selecting a topic --- apps/openmw/mwgui/dialogue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 4e36fe117..27a5003db 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -346,7 +346,10 @@ namespace MWGui } if (id >= separatorPos) + { onTopicActivated(topic); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + } else { const MWWorld::Store &gmst = From 14c9e858c819adf667f7ef022a246c72fa6d9e60 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 17:00:07 +0000 Subject: [PATCH 118/150] Check to make sure button is enabled --- apps/openmw/mwgui/dialogue.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 27a5003db..95fa00469 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -348,7 +348,8 @@ namespace MWGui if (id >= separatorPos) { onTopicActivated(topic); - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + if (mGoodbyeButton->getEnabled()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); } else { From 8416feaf5b302c3222df110a4e9a50bbaba6c02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 19:04:31 +0200 Subject: [PATCH 119/150] link rain water ripple effect to actual rain --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwrender/sky.cpp | 19 +++++++++++++++++-- apps/openmw/mwrender/sky.hpp | 1 + files/shaders/water_fragment.glsl | 12 +++++++++++- 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3a66c264b..23fc4ec28 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -251,6 +251,10 @@ namespace MWRender sceneRoot->setNodeMask(Mask_Scene); sceneRoot->setName("Scene Root"); + mUniformRainIntensity = new osg::Uniform("rainIntensity",(float) 0.0); + + mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); + mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); @@ -799,6 +803,7 @@ namespace MWRender { mEffectManager->clear(); mWater->clearRipples(); + mUniformRainIntensity->set((float) 0.0); // for interiors } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0087e43d..1673003c4 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -85,6 +85,7 @@ namespace MWRender osg::Uniform* mUniformNear; osg::Uniform* mUniformFar; + osg::Uniform* mUniformRainIntensity; void preloadCommonAssets(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index e6aa013ec..5bf5dbcb3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1305,13 +1305,19 @@ public: std::vector > mAlphaFaders; }; -private: +protected: float mAlpha; }; class RainFader : public AlphaFader { public: + + RainFader(osg::Uniform *rainIntensityUniform): AlphaFader() + { + mRainIntensityUniform = rainIntensityUniform; + } + virtual void setDefaults(osg::StateSet* stateset) { osg::ref_ptr mat (new osg::Material); @@ -1320,6 +1326,15 @@ public: mat->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + AlphaFader::apply(stateset,nv); + mRainIntensityUniform->set((float) (mAlpha * 2.0)); // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity + } + +protected: + osg::Uniform* mRainIntensityUniform; }; void SkyManager::createRain() @@ -1375,7 +1390,7 @@ void SkyManager::createRain() mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); - mRainFader = new RainFader; + mRainFader = new RainFader(mRootNode->getParent(0)->getParent(0)->getStateSet()->getUniform("rainIntensity")); mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); mRainNode->setNodeMask(Mask_WeatherParticles); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 863ecc77d..8278c7101 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 23bd688ab..9da7abc01 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -65,12 +65,14 @@ vec4 circle(vec2 coords, vec2 i_part, float phase) vec2 center = vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0); vec2 toCenter = coords - center; float d = length(toCenter); + float r = RAIN_RIPPLE_RADIUS * phase; if (d > r) return vec4(0.0,0.0,1.0,0.0); float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + float height = (1.0 - abs(phase)) * pow(sinValue,3.0); vec3 normal = normalize(mix(vec3(0.0,0.0,1.0),vec3(normalize(toCenter),0.0),height)); @@ -138,6 +140,8 @@ uniform float near; uniform float far; uniform vec3 nodePosition; +uniform float rainIntensity; + float frustumDepth; float linearizeDepth(float depth) // takes <0,1> non-linear depth value and returns <0,1> linearized value @@ -170,7 +174,13 @@ void main(void) vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; - vec4 rainRipple = rainCombined(position.xy / 1000.0,waterTimer); + vec4 rainRipple; + + if (rainIntensity > 0.01) + rainRipple = rainCombined(position.xy / 1000.0,waterTimer) * clamp(rainIntensity,0.0,1.0); + else + rainRipple = vec4(0.0,0.0,0.0,0.0); + vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + From c9c6326d8726a6c11cd5bff04732a142fbd9c119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 19:23:37 +0200 Subject: [PATCH 120/150] fix non-refraction water rain ripples --- files/shaders/water_fragment.glsl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 9da7abc01..ee7ac6255 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -231,8 +231,7 @@ void main(void) float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x) * normalization; float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x) * normalization; float surfaceDepth = linearizeDepth(gl_FragCoord.z) * normalization; - float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum - + float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #else float shore = 1.0; @@ -268,11 +267,15 @@ void main(void) float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); +#if REFRACTION gl_FragData[0].xyz += vec3(rainRipple.w) * 0.2; +#else + gl_FragData[0].xyz += vec3(rainRipple.w) * 0.7; +#endif #if REFRACTION gl_FragData[0].w = 1.0; #else - gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); + gl_FragData[0].w = clamp(fresnel*6.0 + specular, 0.0, 1.0); //clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif } From 7bb0a76df2a2a2f1db5d92d0bf1f108d54b88745 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 19:42:16 +0200 Subject: [PATCH 121/150] Fix tooltips showing when cursor isn't visible --- apps/openmw/mwgui/tooltips.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a611b1f06..e6de9c42c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -97,6 +97,8 @@ namespace MWGui if (guiMode) { + if (!MWBase::Environment::get().getWindowManager()->getCursorVisible()) + return; const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) From 64793a55dc1ef9fc6faa2ad5bb62505a321d7595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 20:44:43 +0200 Subject: [PATCH 122/150] get rid of buggy shader trick --- files/shaders/water_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index ee7ac6255..931422d5e 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -236,7 +236,7 @@ void main(void) #else float shore = 1.0; #endif - vec2 screenCoordsOffset = ( (normal.xy + rainRipple.w * vec2(0.0,2.0)) * REFL_BUMP * shore); + vec2 screenCoordsOffset = normal.xy * REFL_BUMP * shore; // reflection vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb; From 5b10e3128eda8a2d914d2e46efd9f333caebfbf4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 29 Sep 2017 14:58:25 +0000 Subject: [PATCH 123/150] Use first resolution in fullscreen if current is not supported (Fixes #4113) --- apps/openmw/mwgui/settingswindow.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c239fc12f..9bf6e4385 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -353,24 +353,31 @@ namespace MWGui } bool supported = false; + int fallbackX = 0, fallbackY = 0; for (unsigned int i=0; igetItemCount(); ++i) { std::string resStr = mResolutionList->getItemNameAt(i); int resX, resY; parseResolution (resX, resY, resStr); + if (i == 0) + { + fallbackX = resX; + fallbackY = resY; + } + if (resX == Settings::Manager::getInt("resolution x", "Video") && resY == Settings::Manager::getInt("resolution y", "Video")) supported = true; } - if (!supported) + if (!supported && mResolutionList->getItemCount()) { - std::string msg = "This resolution is not supported in Fullscreen mode. Please select a resolution from the list."; - MWBase::Environment::get().getWindowManager()-> - messageBox(msg); - _sender->castType()->setCaption(off); - return; + if (fallbackX != 0 && fallbackY != 0) + { + Settings::Manager::setInt("resolution x", "Video", fallbackX); + Settings::Manager::setInt("resolution y", "Video", fallbackY); + } } mWindowBorderButton->setEnabled(!newState); From 4999c667b62654ba580bcd9cdb9ebeb784f5797d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 29 Sep 2017 19:56:16 +0200 Subject: [PATCH 124/150] fix rain ripple bug --- apps/openmw/mwrender/renderingmanager.cpp | 9 ++++++++- apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwrender/sky.cpp | 10 ++++++++++ apps/openmw/mwrender/sky.hpp | 4 ++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 23fc4ec28..3826fd5f6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -504,6 +504,9 @@ namespace MWRender mWater->update(dt); } + if (!mSky->isEnabled() || !mSky->hasRain()) + clearRainRipples(); + mCamera->update(dt, paused); osg::Vec3f focal, cameraPos; @@ -803,7 +806,11 @@ namespace MWRender { mEffectManager->clear(); mWater->clearRipples(); - mUniformRainIntensity->set((float) 0.0); // for interiors + } + + void RenderingManager::clearRainRipples() + { + mUniformRainIntensity->set((float) 0.0); } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1673003c4..43059ab6d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -160,6 +160,8 @@ namespace MWRender /// Clear all worldspace-specific data void notifyWorldSpaceChanged(); + void clearRainRipples(); + void update(float dt, bool paused); Animation* getAnimation(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5bf5dbcb3..178c753c6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1431,6 +1431,16 @@ int SkyManager::getSecundaPhase() const return mSecunda->getPhaseInt(); } +bool SkyManager::isEnabled() +{ + return mEnabled; +} + +bool SkyManager::hasRain() +{ + return mRainNode != NULL; +} + void SkyManager::update(float duration) { if (!mEnabled) return; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 8278c7101..59a8ddc4e 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -138,6 +138,10 @@ namespace MWRender void sunDisable(); + bool isEnabled(); + + bool hasRain(); + void setRainSpeed(float speed); void setStormDirection(const osg::Vec3f& direction); From 03daf2b9e3bf08737dd84614874ce2e43a09b982 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 29 Sep 2017 22:28:09 +0400 Subject: [PATCH 125/150] Fix a failed assert in the getCell() check during a new game start --- apps/openmw/mwworld/worldimp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2a25d5bbc..9c7fba9fa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2118,7 +2118,9 @@ namespace MWWorld pos.z() += heightRatio*2*mPhysics->getRenderingHalfExtents(object).z(); - return isUnderwater(object.getCell(), pos); + const CellStore *currCell = object.isInCell() ? object.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup + + return isUnderwater(currCell, pos); } bool World::isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const From dfcbee3ab162e5c7ff8809bb753dafc083848548 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 30 Sep 2017 00:04:52 -0400 Subject: [PATCH 126/150] Ignore case when comparing textures, also add new textures to lookup map. --- apps/opencs/model/world/idtable.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 54d65ac3f..bde5af3d9 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,7 @@ #include "idtable.hpp" +#include +#include #include #include #include @@ -346,8 +348,10 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import for (int i = 0; i < idCollection()->getSize(); ++i) { auto& record = static_cast&>(idCollection()->getRecord(i)); + std::string texture = record.get().mTexture; + std::transform(texture.begin(), texture.end(), texture.begin(), tolower); if (record.isModified()) - reverseLookupMap.emplace(record.get().mTexture, idCollection()->getId(i)); + reverseLookupMap.emplace(texture, idCollection()->getId(i)); } for (const std::string& id : ids) @@ -366,7 +370,9 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import // Look for a pre-existing record auto& record = static_cast&>(idCollection()->getRecord(oldRow)); - auto searchIt = reverseLookupMap.find(record.get().mTexture); + std::string texture = record.get().mTexture; + std::transform(texture.begin(), texture.end(), texture.begin(), tolower); + auto searchIt = reverseLookupMap.find(texture); if (searchIt != reverseLookupMap.end()) { results.recordMapping.push_back(std::make_pair(id, searchIt->second)); @@ -385,6 +391,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import cloneRecord(id, newId, UniversalId::Type_LandTexture); results.createdRecords.push_back(newId); results.recordMapping.push_back(std::make_pair(id, newId)); + reverseLookupMap.emplace(texture, newId); break; } From 097b9d90bc101a0a55eced4baed9acf423e611f1 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 30 Sep 2017 16:53:39 +0200 Subject: [PATCH 127/150] Fix travel service not showing --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 95fa00469..8dd027c4a 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -481,7 +481,7 @@ namespace MWGui if (services & ESM::NPC::Spells) mTopicsList->addItem(gmst.find("sSpells")->getString()); - if (services & travel) + if (travel) mTopicsList->addItem(gmst.find("sTravel")->getString()); if (services & ESM::NPC::Spellmaking) From 3c62a8c5c29fe5b1d0ed0531bee39a52f517735f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 30 Sep 2017 16:57:07 +0200 Subject: [PATCH 128/150] Fix console selected object persisting on a new game --- apps/openmw/mwgui/console.cpp | 5 +++++ apps/openmw/mwgui/console.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 2d016ddf1..e8ac33f6d 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -215,6 +215,11 @@ namespace MWGui } } + void Console::clear() + { + resetReference(); + } + void Console::keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 7ee39770d..bbff34c8d 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -60,6 +60,8 @@ namespace MWGui void executeFile (const std::string& path); + void clear(); + virtual void resetReference (); protected: From 04452b094963d8cbe1e453d9344d8407c4cf11f8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:11:53 +0400 Subject: [PATCH 129/150] Use a pickpocket crime instead of theft when pickpocketing was failed --- apps/openmw/mwgui/container.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 57c756762..a70d833c7 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -136,7 +136,7 @@ namespace MWGui bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); - if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) + if (mPtr.getClass().isNpc() && !loot) { // we are stealing stuff MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -271,9 +271,8 @@ namespace MWGui MWMechanics::Pickpocket pickpocket(player, mPtr); if (pickpocket.pick(item.mBase, count)) { - int value = item.mBase.getClass().getValue(item.mBase) * count; MWBase::Environment::get().getMechanicsManager()->commitCrime( - player, mPtr, MWBase::MechanicsManager::OT_Theft, value, true); + player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); mPickpocketDetected = true; return false; From 34895157f91e25f2990afa59e2d4572ff837db37 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:22:26 +0400 Subject: [PATCH 130/150] Consider taking items from unconscious NPC as a theft --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 23 +++++++++++++++---- .../mwmechanics/mechanicsmanagerimp.hpp | 4 ++-- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index d9068b285..398439ad8 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -238,7 +238,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) = 0; + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e6de9c42c..a9930db4f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -325,7 +325,7 @@ namespace MWGui } } - void ToolTips::setFocusObject(const MWWorld::ConstPtr& focus) + void ToolTips::setFocusObject(const MWWorld::Ptr& focus) { mFocusObject = focus; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index bb2affc63..2793e6544 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -59,7 +59,7 @@ namespace MWGui void setDelay(float delay); - void setFocusObject(const MWWorld::ConstPtr& focus); + void setFocusObject(const MWWorld::Ptr& focus); void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); ///< set the screen-space position of the tooltip for focused object @@ -96,7 +96,7 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - MWWorld::ConstPtr mFocusObject; + MWWorld::Ptr mFocusObject; MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fbee52c82..e96743b91 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1573,7 +1573,7 @@ namespace MWGui mMessageBoxManager->clear(); - mToolTips->setFocusObject(MWWorld::ConstPtr()); + mToolTips->setFocusObject(MWWorld::Ptr()); mSelectedSpell.clear(); mCustomMarkers.clear(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 574444a8f..950cf8a01 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -840,17 +840,30 @@ namespace MWMechanics mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) { - const MWWorld::CellRef& cellref = item.getCellRef(); + const MWWorld::CellRef& cellref = target.getCellRef(); // there is no harm to use unlocked doors - if (item.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) + if (target.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) return true; - // TODO: implement a better check to check if item is owned bed - if (item.getClass().isActivator() && item.getClass().getScript(item).compare(0, 3, "Bed") != 0) + // TODO: implement a better check to check if target is owned bed + if (target.getClass().isActivator() && target.getClass().getScript(target).compare(0, 3, "Bed") != 0) return true; + if (target.getClass().isNpc()) + { + if (target.getClass().getCreatureStats(target).isDead()) + return true; + + // check if a player tries to pickpocket a target NPC + if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak) + || target.getClass().getCreatureStats(target).getKnockedDown()) + return false; + + return true; + } + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 1bf3a8d22..ee4cf28af 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -204,8 +204,8 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); - /// @return is \a ptr allowed to take/use \a cellref or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim); + /// @return is \a ptr allowed to take/use \a target or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim); virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); From 3ebb18ce18b89407464f388c00fb36455500be36 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:31:06 +0400 Subject: [PATCH 131/150] Make unconscious actors do not report about crimes --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 950cf8a01..525749c38 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1097,6 +1097,10 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).isDead()) continue; + // Unconsious actor can not report about crime + if (it->getClass().getCreatureStats(*it).getKnockedDown()) + continue; + if ((*it == victim && victimAware) || (MWBase::Environment::get().getWorld()->getLOS(player, *it) && awarenessCheck(player, *it) ) // Murder crime can be reported even if no one saw it (hearing is enough, I guess). @@ -1208,12 +1212,16 @@ namespace MWMechanics // Tell everyone (including the original reporter) in alarm range for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { - if ( *it == player + if (*it == player || !it->getClass().isNpc() || it->getClass().getCreatureStats(*it).isDead()) continue; if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + // Unconsious actor can not report about crime and should not become hostile + if (it->getClass().getCreatureStats(*it).getKnockedDown()) + continue; + // Player's followers should not attack player, or try to arrest him if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) { From f26206b63026253e91993003a69bc29dbb9acb19 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:55:42 +0400 Subject: [PATCH 132/150] Make unconscious actors do not speak and do not track targets --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 ++++++ apps/openmw/mwmechanics/actors.cpp | 14 +++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 4ed3b82a9..6fac03e92 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -567,6 +567,12 @@ namespace MWDialogue return; } + if (actor.getClass().getCreatureStats(actor).getKnockedDown()) + { + // Unconscious actors can not speak + return; + } + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Dialogue *dial = store.get().find(topic); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cef429504..d0fe5a755 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1232,13 +1232,17 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; - for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + // Unconsious actor can not track target + if (!iter->first.getClass().getCreatureStats(iter->first).getKnockedDown()) { - if (it->first == iter->first) - continue; - updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); + for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + { + if (it->first == iter->first) + continue; + updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); + } + iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } - iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } if (iter->first.getClass().isNpc() && iter->first != player) From b8fd530ee1111372f34f6e084fd0b966eb7c9dd0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 21:20:38 +0400 Subject: [PATCH 133/150] Do not speak with unconscious creatures --- apps/openmw/mwclass/creature.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index d6926f11d..2e16b13aa 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -470,6 +470,9 @@ namespace MWClass if(stats.getAiSequence().isInCombat()) return std::shared_ptr(new MWWorld::FailedAction("")); + if(stats.getKnockedDown()) + return std::shared_ptr(new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } From c5fcb9684efe3c0b41a0d7901af4887d7b9ca003 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 21:29:02 +0400 Subject: [PATCH 134/150] Improve owned crosshair feature behaviour --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 525749c38..da98e7f5f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -856,6 +856,9 @@ namespace MWMechanics if (target.getClass().getCreatureStats(target).isDead()) return true; + if (target.getClass().getCreatureStats(target).getAiSequence().isInCombat()) + return true; + // check if a player tries to pickpocket a target NPC if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak) || target.getClass().getCreatureStats(target).getKnockedDown()) From 21b6bd176f2c40f1e953fd599030d5f64e8abae5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 1 Oct 2017 17:11:30 +0400 Subject: [PATCH 135/150] AI: Autoequip armor when bound armor spell expires --- apps/openmw/mwmechanics/actors.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cef429504..69ccdf9e4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -71,7 +71,9 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } else { - actor.getClass().getContainerStore(actor).remove(item, 1, actor); + MWWorld::Ptr itemPtr = actor.getClass().getInventoryStore(actor).search(item); + if (!itemPtr.isEmpty()) + actor.getClass().getInventoryStore(actor).remove(itemPtr, 1, actor, true); } } From 137ea872d34683c8e2631b7b96b4fe9d716a2ec3 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 2 Oct 2017 15:56:22 -0400 Subject: [PATCH 136/150] Hide base land textures. --- apps/opencs/CMakeLists.txt | 2 +- .../world/landtexturetableproxymodel.cpp | 21 ++++++++++++++++++ .../world/landtexturetableproxymodel.hpp | 22 +++++++++++++++++++ apps/opencs/view/world/table.cpp | 6 +++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/world/landtexturetableproxymodel.cpp create mode 100644 apps/opencs/model/world/landtexturetableproxymodel.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 36ff8cf67..f10525e08 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 resourcetable nestedtableproxymodel idtree infotableproxymodel + idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel landtexturetableproxymodel ) diff --git a/apps/opencs/model/world/landtexturetableproxymodel.cpp b/apps/opencs/model/world/landtexturetableproxymodel.cpp new file mode 100644 index 000000000..cf33fab9e --- /dev/null +++ b/apps/opencs/model/world/landtexturetableproxymodel.cpp @@ -0,0 +1,21 @@ +#include "landtexturetableproxymodel.hpp" + +#include "idtable.hpp" + +namespace CSMWorld +{ + LandTextureTableProxyModel::LandTextureTableProxyModel(QObject* parent) + : IdTableProxyModel(parent) + { + } + + bool LandTextureTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const + { + int columnIndex = mSourceModel->findColumnIndex(Columns::ColumnId_Modification); + QModelIndex index = mSourceModel->index(sourceRow, columnIndex); + if (mSourceModel->data(index).toInt() != RecordBase::State_ModifiedOnly) + return false; + + return IdTableProxyModel::filterAcceptsRow(sourceRow, sourceParent); + } +} diff --git a/apps/opencs/model/world/landtexturetableproxymodel.hpp b/apps/opencs/model/world/landtexturetableproxymodel.hpp new file mode 100644 index 000000000..bbedecb53 --- /dev/null +++ b/apps/opencs/model/world/landtexturetableproxymodel.hpp @@ -0,0 +1,22 @@ +#ifndef CSM_WORLD_LANDTEXTURETABLEPROXYMODEL_H +#define CSM_WORLD_LANDTEXTURETABLEPROXYMODEL_H + +#include "idtableproxymodel.hpp" + +namespace CSMWorld +{ + /// \brief Removes base records from filtered results. + class LandTextureTableProxyModel : public IdTableProxyModel + { + Q_OBJECT + public: + + LandTextureTableProxyModel(QObject* parent = nullptr); + + protected: + + bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const override; + }; +} + +#endif diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 3cccaaa22..34ecd57d0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -16,6 +16,7 @@ #include "../../model/world/idtableproxymodel.hpp" #include "../../model/world/idtablebase.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/landtexturetableproxymodel.hpp" #include "../../model/world/record.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/commanddispatcher.hpp" @@ -236,10 +237,15 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos || id.getType() == CSMWorld::UniversalId::Type_JournalInfos; + bool isLtexTable = (id.getType() == CSMWorld::UniversalId::Type_LandTextures); if (isInfoTable) { mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this); } + else if (isLtexTable) + { + mProxyModel = new CSMWorld::LandTextureTableProxyModel (this); + } else { mProxyModel = new CSMWorld::IdTableProxyModel (this); From 2f5449a68c6ff2b0c3f7345e0d9746dd59eba490 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 2 Oct 2017 16:13:40 -0400 Subject: [PATCH 137/150] Remove now unnecessary overrides. --- apps/opencs/model/world/idtable.cpp | 26 -------------------------- apps/opencs/model/world/idtable.hpp | 6 ------ 2 files changed, 32 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index bde5af3d9..fcfc8577e 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -313,32 +313,6 @@ CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, u { } -QVariant CSMWorld::LandTextureIdTable::data(const QModelIndex& index, int role) const -{ - if (role==Qt::EditRole && !idCollection()->getRecord(index.row()).isModified()) - return QVariant(); - - return IdTable::data(index, role); -} - -bool CSMWorld::LandTextureIdTable::setData(const QModelIndex& index, const QVariant& value, int role) -{ - if (!idCollection()->getRecord(index.row()).isModified()) - return false; - else - return IdTable::setData(index, value, role); -} - -Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) const -{ - Qt::ItemFlags flags = IdTable::flags(index); - - if (!idCollection()->getRecord(index.row()).isModified()) - flags &= ~Qt::ItemIsEnabled; - - return flags; -} - CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures(const std::vector& ids) { ImportResults results; diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ccc5ac404..4136061e4 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -118,12 +118,6 @@ namespace CSMWorld LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); - QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; - - bool setData(const QModelIndex& index, const QVariant& value, int role) override; - - Qt::ItemFlags flags (const QModelIndex & index) const override; - /// Finds and maps/recreates the specified ids. ImportResults importTextures(const std::vector& ids); }; From d7a5622485a03ef6324470fcb84976882f444af7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 3 Oct 2017 09:16:46 +0000 Subject: [PATCH 138/150] Fix book window buttons overlap --- files/mygui/openmw_book.layout | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index a7bea5eb5..c83c4982b 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -14,19 +14,15 @@ - - - - - - + + + + - - - - - - + + + + From c598f1313c4233af2aec6dcb92e4924408120961 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Tue, 3 Oct 2017 17:34:45 +0200 Subject: [PATCH 139/150] [macOS, CI] Update dependencies The following changes are included: - https://github.com/OpenMW/openmw-deps-mac/pull/37 - https://github.com/OpenMW/openmw-deps-mac/pull/38 --- CI/before_install.osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index 25e1c9517..86e8fb81b 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -6,5 +6,5 @@ brew outdated cmake || brew upgrade cmake brew outdated pkgconfig || brew upgrade pkgconfig brew install $macos_qt_formula -curl https://downloads.openmw.org/osx/dependencies/openmw-deps-5e144e2.zip -o ~/openmw-deps.zip +curl https://downloads.openmw.org/osx/dependencies/openmw-deps-c40905f.zip -o ~/openmw-deps.zip unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null From 433028e8d7395db109920e0b74309388ddec8984 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 3 Oct 2017 22:07:56 +0000 Subject: [PATCH 140/150] Fix GUI regressions --- apps/openmw/mwgui/dialogue.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8dd027c4a..e13e626ae 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -390,6 +390,7 @@ namespace MWGui { // No greetings found. The dialogue window should not be shown. // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); if (isCompanion()) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr); return; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e96743b91..fdf4da8a7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -606,7 +606,7 @@ namespace MWGui mMap->setVisible(false); mStatsWindow->setVisible(false); mSpellWindow->setVisible(false); - mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter); + mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter || getMode() == GM_Companion); } GuiMode mode = mGuiModes.back(); From 1cb7ed5db102117b595b8d026d49a51a6244d068 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 3 Oct 2017 09:59:31 +0400 Subject: [PATCH 141/150] Use owned tooltips for items in containers correctly --- apps/openmw/mwgui/container.cpp | 20 ++++++--- apps/openmw/mwgui/containeritemmodel.cpp | 16 +++++++ apps/openmw/mwgui/containeritemmodel.hpp | 1 + apps/openmw/mwgui/itemmodel.cpp | 10 +++++ apps/openmw/mwgui/itemmodel.hpp | 6 +++ apps/openmw/mwgui/pickpocketitemmodel.cpp | 5 +++ apps/openmw/mwgui/pickpocketitemmodel.hpp | 2 + apps/openmw/mwgui/sortfilteritemmodel.cpp | 5 +++ apps/openmw/mwgui/sortfilteritemmodel.hpp | 1 + apps/openmw/mwgui/tooltips.cpp | 44 +++++++++---------- apps/openmw/mwgui/tooltips.hpp | 4 +- apps/openmw/mwgui/tradeitemmodel.cpp | 5 +++ apps/openmw/mwgui/tradeitemmodel.hpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 3 ++ 14 files changed, 92 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index a70d833c7..74ed4fff9 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -22,6 +22,7 @@ #include "itemview.hpp" #include "itemwidget.hpp" #include "inventoryitemmodel.hpp" +#include "containeritemmodel.hpp" #include "sortfilteritemmodel.hpp" #include "pickpocketitemmodel.hpp" #include "draganddrop.hpp" @@ -136,15 +137,22 @@ namespace MWGui bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); - if (mPtr.getClass().isNpc() && !loot) + if (mPtr.getClass().hasInventoryStore(mPtr)) { - // we are stealing stuff - MWWorld::Ptr player = MWMechanics::getPlayer(); - mModel = new PickpocketItemModel(player, new InventoryItemModel(container), - !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); + if (mPtr.getClass().isNpc() && !loot) + { + // we are stealing stuff + MWWorld::Ptr player = MWMechanics::getPlayer(); + mModel = new PickpocketItemModel(player, new InventoryItemModel(container), + !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); + } + else + mModel = new InventoryItemModel(container); } else - mModel = new InventoryItemModel(container); + { + mModel = new ContainerItemModel(container); + } mDisposeCorpseButton->setVisible(loot); diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index d62cd16b0..479638672 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -6,8 +6,11 @@ #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { @@ -47,6 +50,19 @@ ContainerItemModel::ContainerItemModel (const MWWorld::Ptr& source) mItemSources.push_back(source); } +bool ContainerItemModel::allowedToUseItems() const +{ + if (mItemSources.size() == 0) + return true; + + MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::Ptr victim; + + // Check if the player is allowed to use items from opened container + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + return mm->isAllowedToUse(ptr, mItemSources[0], victim); +} + ItemStack ContainerItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index 7ced6ae34..c6ecafd46 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -17,6 +17,7 @@ namespace MWGui ContainerItemModel (const MWWorld::Ptr& source); + virtual bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 390bb0586..ffcf9075e 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -119,6 +119,11 @@ namespace MWGui return ret; } + bool ItemModel::allowedToUseItems() const + { + return true; + } + bool ItemModel::allowedToInsertItems() const { return true; @@ -135,6 +140,11 @@ namespace MWGui delete mSourceModel; } + bool ProxyItemModel::allowedToUseItems() const + { + return mSourceModel->allowedToUseItems(); + } + MWWorld::Ptr ProxyItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner) { return mSourceModel->copyItem (item, count, setNewOwner); diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 20955b206..bc6be8023 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -70,6 +70,9 @@ namespace MWGui virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0; virtual void removeItem (const ItemStack& item, size_t count) = 0; + /// Is the player allowed to use items from this item model? (default true) + virtual bool allowedToUseItems() const; + /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; @@ -85,6 +88,9 @@ namespace MWGui public: ProxyItemModel(); virtual ~ProxyItemModel(); + + bool allowedToUseItems() const; + virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 238fb5913..ec4b378a0 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -26,6 +26,11 @@ namespace MWGui } } + bool PickpocketItemModel::allowedToUseItems() const + { + return false; + } + ItemStack PickpocketItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index 61f0569b5..1b08ec485 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -11,6 +11,8 @@ namespace MWGui { public: PickpocketItemModel (const MWWorld::Ptr& thief, ItemModel* sourceModel, bool hideItems=true); + + virtual bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); virtual void update(); diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 45aa261df..e294ebe07 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -159,6 +159,11 @@ namespace MWGui mSourceModel = sourceModel; } + bool SortFilterItemModel::allowedToUseItems() const + { + return mSourceModel->allowedToUseItems(); + } + void SortFilterItemModel::addDragItem (const MWWorld::Ptr& dragItem, size_t count) { mDragItems.push_back(std::make_pair(dragItem, count)); diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 4731cbb8a..6ddb019b0 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -15,6 +15,7 @@ namespace MWGui bool filterAccepts (const ItemStack& item); + bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a9930db4f..af6bf4726 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -120,7 +120,7 @@ namespace MWGui if (info.caption.empty()) info.caption=mFocusObject.getCellRef().getRefId(); info.icon=""; - tooltipSize = createToolTip(info, true); + tooltipSize = createToolTip(info, checkOwned()); } else tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true); @@ -186,22 +186,24 @@ namespace MWGui ToolTipInfo info; info.text = data.caption; info.notes = data.notes; - tooltipSize = createToolTip(info, false); + tooltipSize = createToolTip(info); } else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); + bool isAllowedToUse = checkOwned(); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, !isAllowedToUse); } else if (type == "ItemModelIndex") { std::pair pair = *focus->getUserData >(); mFocusObject = pair.second->getItem(pair.first).mBase; - tooltipSize = getToolTipViaPtr(pair.second->getItem(pair.first).mCount, false); + bool isAllowedToUse = pair.second->allowedToUseItems(); + tooltipSize = getToolTipViaPtr(pair.second->getItem(pair.first).mCount, false, !isAllowedToUse); } else if (type == "ToolTipInfo") { - tooltipSize = createToolTip(*focus->getUserData(), false); + tooltipSize = createToolTip(*focus->getUserData()); } else if (type == "AvatarItemSelection") { @@ -244,7 +246,7 @@ namespace MWGui info.text = "#{sSchool}: " + sSchoolNames[school]; } info.effects = effects; - tooltipSize = createToolTip(info, false); + tooltipSize = createToolTip(info); } else if (type == "Layout") { @@ -298,7 +300,7 @@ namespace MWGui { if (!mFocusObject.isEmpty()) { - MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount()); + MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true, checkOwned()); setCoord(viewSize.width/2 - tooltipSize.width/2, std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), @@ -332,7 +334,7 @@ namespace MWGui update(mFrameDuration); } - MyGUI::IntSize ToolTips::getToolTipViaPtr (int count, bool image) + MyGUI::IntSize ToolTips::getToolTipViaPtr (int count, bool image, bool isOwned) { // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -351,7 +353,7 @@ namespace MWGui ToolTipInfo info = object.getToolTipInfo(mFocusObject, count); if (!image) info.icon = ""; - tooltipSize = createToolTip(info, true); + tooltipSize = createToolTip(info, isOwned); } return tooltipSize; @@ -359,27 +361,21 @@ namespace MWGui bool ToolTips::checkOwned() { - if(!mFocusObject.isEmpty()) - { - MWWorld::Ptr ptr = MWMechanics::getPlayer(); - MWWorld::Ptr victim; - - MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); - bool allowed = mm->isAllowedToUse(ptr, mFocusObject, victim); - - return !allowed; - } - else - { + if(mFocusObject.isEmpty()) return false; - } + + MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::Ptr victim; + + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + return !mm->isAllowedToUse(ptr, mFocusObject, victim); } - MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info, bool isFocusObject) + MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info, bool isOwned) { mDynamicToolTipBox->setVisible(true); - if((mShowOwned == 1 || mShowOwned == 3) && isFocusObject && checkOwned()) + if((mShowOwned == 1 || mShowOwned == 3) && isOwned) mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp_Owned" : "HUD_Box_Owned"); else mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp" : "HUD_Box"); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 2793e6544..1ef473b5a 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -98,10 +98,10 @@ namespace MWGui MWWorld::Ptr mFocusObject; - MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); + MyGUI::IntSize getToolTipViaPtr (int count, bool image = true, bool isOwned = false); ///< @return requested tooltip size - MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isFocusObject); + MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isOwned = false); ///< @return requested tooltip size /// @param isFocusObject Is the object this tooltips originates from mFocusObject? diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index ae3feb61c..a26294a0e 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -15,6 +15,11 @@ namespace MWGui mSourceModel = sourceModel; } + bool TradeItemModel::allowedToUseItems() const + { + return true; + } + ItemStack TradeItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/tradeitemmodel.hpp b/apps/openmw/mwgui/tradeitemmodel.hpp index 1bfee9b2a..cdb949c49 100644 --- a/apps/openmw/mwgui/tradeitemmodel.hpp +++ b/apps/openmw/mwgui/tradeitemmodel.hpp @@ -15,6 +15,8 @@ namespace MWGui public: TradeItemModel (ItemModel* sourceModel, const MWWorld::Ptr& merchant); + bool allowedToUseItems() const; + virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index da98e7f5f..2c7b6a500 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -842,6 +842,9 @@ namespace MWMechanics bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) { + if (target.isEmpty()) + return true; + const MWWorld::CellRef& cellref = target.getCellRef(); // there is no harm to use unlocked doors if (target.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) From 7c68ed04b2bb458d02fd6b57dd1f1b9a3187ab48 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:03:23 +0200 Subject: [PATCH 142/150] Don't require modal windows to be removed in the same order they were added --- apps/openmw/mwgui/windowmanagerimp.cpp | 24 ++++++++++++++---------- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fdf4da8a7..a9ca9bd19 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -865,7 +865,7 @@ namespace MWGui window->onFrame(frameDuration); } if (!mCurrentModals.empty()) - mCurrentModals.top()->onFrame(frameDuration); + mCurrentModals.back()->onFrame(frameDuration); mKeyboardNavigation->onFrame(); @@ -1727,9 +1727,9 @@ namespace MWGui { if (!mCurrentModals.empty()) { - if (!mCurrentModals.top()->exit()) + if (!mCurrentModals.back()->exit()) return; - mCurrentModals.top()->setVisible(false); + mCurrentModals.back()->setVisible(false); } } @@ -1738,7 +1738,7 @@ namespace MWGui if (mCurrentModals.empty()) mKeyboardNavigation->saveFocus(getMode()); - mCurrentModals.push(input); + mCurrentModals.push_back(input); mKeyboardNavigation->restoreFocus(-1); mKeyboardNavigation->setModalWindow(input->mMainWidget); @@ -1747,17 +1747,21 @@ namespace MWGui void WindowManager::removeCurrentModal(WindowModal* input) { - // Only remove the top if it matches the current pointer. A lot of things hide their visibility before showing it, - //so just popping the top would cause massive issues. if(!mCurrentModals.empty()) { - if(input == mCurrentModals.top()) + if(input == mCurrentModals.back()) { - mCurrentModals.pop(); + mCurrentModals.pop_back(); mKeyboardNavigation->saveFocus(-1); } else - std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; + { + auto found = std::find(mCurrentModals.begin(), mCurrentModals.end(), input); + if (found != mCurrentModals.end()) + mCurrentModals.erase(found); + else + std::cerr << " warning: can't find modal window " << input << std::endl; + } } if (mCurrentModals.empty()) { @@ -1765,7 +1769,7 @@ namespace MWGui mKeyboardNavigation->restoreFocus(getMode()); } else - mKeyboardNavigation->setModalWindow(mCurrentModals.top()->mMainWidget); + mKeyboardNavigation->setModalWindow(mCurrentModals.back()->mMainWidget); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 612470a7e..bdd2aa094 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -401,7 +401,7 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; - std::stack mCurrentModals; + std::vector mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). CustomMarkerCollection mCustomMarkers; From 49a0922f1b4b26c5dd421ab326fb6529b55d79eb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:08:09 +0200 Subject: [PATCH 143/150] Remove 'visibility mask' gui feature which did not end up being useful --- apps/openmw/mwgui/windowmanagerimp.cpp | 29 +++++++++++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a9ca9bd19..9a7a7437a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -613,18 +613,18 @@ namespace MWGui mInventoryWindow->setTrading(mode == GM_Barter); - // For the inventory mode, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed & ~mForceHidden; - mGuiModeStates[GM_Inventory].mVisibilityMask.resize(4); - mGuiModeStates[GM_Inventory].mVisibilityMask[0] = eff & GW_Map; - mGuiModeStates[GM_Inventory].mVisibilityMask[1] = eff & GW_Inventory; - mGuiModeStates[GM_Inventory].mVisibilityMask[2] = eff & GW_Magic; - mGuiModeStates[GM_Inventory].mVisibilityMask[3] = eff & GW_Stats; if (getMode() == GM_Inventory) - mGuiModeStates[GM_Inventory].update(true); + { + // For the inventory mode, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed & ~mForceHidden; + mMap->setVisible(eff & GW_Map); + mInventoryWindow->setVisible(eff & GW_Inventory); + mSpellWindow->setVisible(eff & GW_Magic); + mStatsWindow->setVisible(eff & GW_Stats); + } switch (mode) { @@ -2063,12 +2063,7 @@ namespace MWGui void WindowManager::GuiModeState::update(bool visible) { for (unsigned int i=0; isetVisible(visible && visibilityMask); - } + mWindows[i]->setVisible(visible); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index bdd2aa094..c8bc8d21e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -477,7 +477,6 @@ namespace MWGui void update(bool visible); std::vector mWindows; - std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. std::string mCloseSound; std::string mOpenSound; From e4f0f7157a796ccf647b6e841b06604ce8f0bf69 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:08:52 +0200 Subject: [PATCH 144/150] Fix pinned windows not being updated --- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9a7a7437a..eae706ec3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -864,6 +864,14 @@ namespace MWGui for (WindowBase* window : state.mWindows) window->onFrame(frameDuration); } + else + { + // update pinned windows if visible + for (WindowBase* window : mGuiModeStates[GM_Inventory].mWindows) + if (window->isVisible()) + window->onFrame(frameDuration); + } + if (!mCurrentModals.empty()) mCurrentModals.back()->onFrame(frameDuration); From a4737d84178e0f7ae58ed9364d648d1e9c4c687f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:26:23 +0200 Subject: [PATCH 145/150] Use MyGUI frame events for ScreenFader --- apps/openmw/mwgui/screenfader.cpp | 10 +++++++++- apps/openmw/mwgui/screenfader.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index d1118848b..9a9a1ae01 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace MWGui { @@ -80,6 +81,8 @@ namespace MWGui , mFactor(1.f) , mRepeat(false) { + MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate(this, &ScreenFader::onFrameStart); + mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); MyGUI::ImageBox* imageBox = mMainWidget->castType(false); @@ -94,7 +97,12 @@ namespace MWGui } } - void ScreenFader::update(float dt) + ScreenFader::~ScreenFader() + { + MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &ScreenFader::onFrameStart); + } + + void ScreenFader::onFrameStart(float dt) { if (!mQueue.empty()) { diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 88dd0c57b..79bea30e5 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -36,8 +36,9 @@ namespace MWGui { public: ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout", const MyGUI::FloatCoord& texCoordOverride = MyGUI::FloatCoord(0,0,1,1)); + ~ScreenFader(); - void update(float dt); + void onFrameStart(float dt); void fadeIn(const float time, float delay=0); void fadeOut(const float time, float delay=0); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eae706ec3..504bef964 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -894,12 +894,6 @@ namespace MWGui mHud->onFrame(frameDuration); - if (mWerewolfFader) - mWerewolfFader->update(frameDuration); - mBlindnessFader->update(frameDuration); - mHitFader->update(frameDuration); - mScreenFader->update(frameDuration); - mDebugWindow->onFrame(frameDuration); if (mCharGen) From 12510efab7bd2e29f23e5054356718a8847bf763 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:39:19 +0200 Subject: [PATCH 146/150] Fade screen out during loading screen (when travelling) --- apps/openmw/mwgui/loadingscreen.cpp | 12 ++++++++++-- apps/openmw/mwgui/loadingscreen.hpp | 1 + apps/openmw/mwgui/travelwindow.cpp | 2 ++ files/mygui/openmw_layers.xml | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f22d825dd..4753c39f2 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -50,6 +50,8 @@ namespace MWGui mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); + mSceneImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, + MyGUI::Align::Stretch, "Scene"); findSplashScreens(); } @@ -110,6 +112,7 @@ namespace MWGui { WindowBase::setVisible(visible); mBackgroundImage->setVisible(visible); + mSceneImage->setVisible(visible); } double LoadingScreen::getTargetFrameRate() const @@ -214,8 +217,11 @@ namespace MWGui // TODO: add option (filename pattern?) to use image aspect ratio instead of 4:3 // we can't do this by default, because the Morrowind splash screens are 1024x1024, but should be displayed as 4:3 bool stretch = Settings::Manager::getBool("stretch menu background", "GUI"); + mBackgroundImage->setVisible(true); mBackgroundImage->setBackgroundImage(randomSplash, true, stretch); } + mSceneImage->setBackgroundImage(""); + mSceneImage->setVisible(false); } void LoadingScreen::setProgressRange (size_t range) @@ -292,9 +298,11 @@ namespace MWGui mViewer->getCamera()->setInitialDrawCallback(new CopyFramebufferToTextureCallback(mTexture)); mBackgroundImage->setBackgroundImage(""); + mBackgroundImage->setVisible(false); - mBackgroundImage->setRenderItemTexture(mGuiTexture.get()); - mBackgroundImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + mSceneImage->setRenderItemTexture(mGuiTexture.get()); + mSceneImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + mSceneImage->setVisible(true); } void LoadingScreen::draw() diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 2f8831fdc..8536972a3 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -72,6 +72,7 @@ namespace MWGui MyGUI::TextBox* mLoadingText; MyGUI::ScrollBar* mProgressBar; BackgroundImage* mBackgroundImage; + BackgroundImage* mSceneImage; std::vector mSplashScreens; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 7c7cdb63e..7586bb66a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -178,6 +178,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); + // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); action.execute(player); diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index cd8a9f760..5e4a74978 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,6 +1,7 @@ + From d94235e3a727bcec1d800cd4184bd70da142d306 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:47:42 +0200 Subject: [PATCH 147/150] Update the saves list/preview image when character selection changes to make it more convenient to flip through characters with the keyboard --- apps/openmw/mwgui/savegamedialog.cpp | 13 ++++++++++--- apps/openmw/mwgui/savegamedialog.hpp | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 423dbb036..6a290bef1 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -50,7 +50,8 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked); mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked); - mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); + mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); + mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterAccept); mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected); mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick); mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated); @@ -132,6 +133,8 @@ namespace MWGui mSaveNameEdit->setCaption (""); if (mSaving) MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); center(); @@ -322,6 +325,12 @@ namespace MWGui fillSaveList(); } + void SaveGameDialog::onCharacterAccept(MyGUI::ComboBox* sender, size_t pos) + { + // Give key focus to save list so we can confirm the selection with Enter + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::fillSaveList() { mSaveList->removeAllItems(); @@ -336,8 +345,6 @@ namespace MWGui { mSaveList->setIndexSelected(0); onSlotSelected(mSaveList, 0); - // Give key focus to save list so we can confirm the selection with Enter - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); } else onSlotSelected(mSaveList, MyGUI::ITEM_NONE); diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index a51124705..0a87b6600 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -29,6 +29,7 @@ namespace MWGui void onOkButtonClicked (MyGUI::Widget* sender); void onDeleteButtonClicked (MyGUI::Widget* sender); void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos); + void onCharacterAccept(MyGUI::ComboBox* sender, size_t pos); // Slot selected (mouse click or arrow keys) void onSlotSelected (MyGUI::ListBox* sender, size_t pos); // Slot activated (double click or enter key) From cd437f094d9fbeb77850dbaa0d84fb25ca749151 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:35:09 +0200 Subject: [PATCH 148/150] Fix exiting savegamedialog with 'esc' when no game is running --- apps/openmw/mwgui/mainmenu.cpp | 5 +++++ apps/openmw/mwgui/mainmenu.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- apps/openmw/mwinput/inputmanagerimp.cpp | 4 +--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 00e4e30a5..5017b8893 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -210,6 +210,11 @@ namespace MWGui } } + bool MainMenu::exit() + { + return MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Running; + } + void MainMenu::updateMenu() { setCoord(0,0, mWidth, mHeight); diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 1beb9ee16..82553d22e 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -38,6 +38,8 @@ namespace MWGui void onFrame(float dt); + bool exit(); + private: const VFS::Manager* mVFS; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 504bef964..a81c3a614 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -750,8 +750,8 @@ namespace MWGui if (!window->exit()) { // unable to exit window, but give access to main menu - if (!MyGUI::InputManager::getInstance().isModalAny()) - pushGuiMode (MWGui::GM_MainMenu); + if (!MyGUI::InputManager::getInstance().isModalAny() && getMode() != GM_MainMenu) + pushGuiMode (GM_MainMenu); return; } } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e6acbbd52..06ebeb0b8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -241,9 +241,7 @@ namespace MWInput switch (action) { case A_GameMenu: - if(!(MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running - && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_MainMenu)) - toggleMainMenu (); + toggleMainMenu (); break; case A_Screenshot: screenshot(); From 8c0790580a80431d9f31d7beed07f8e61beae121 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:39:28 +0200 Subject: [PATCH 149/150] Add screen fading for exterior cell transitions --- apps/openmw/mwworld/scene.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c83165239..0a27cf257 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -580,10 +580,16 @@ namespace MWWorld MWBase::Environment::get().getWorld()->positionToIndex (position.pos[0], position.pos[1], x, y); + if (changeEvent) + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + changeCellGrid(x, y, changeEvent); CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); changePlayerCell(current, position, adjustPlayerPos); + + if (changeEvent) + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); } CellStore* Scene::getCurrentCell () From 842a42ee664b30dee6e9bd74c4a70de1bfca19ea Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:39:58 +0200 Subject: [PATCH 150/150] Fix non-top level Windows accepting key focus --- apps/openmw/mwgui/keyboardnavigation.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 2b06de295..d27185204 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -12,6 +12,11 @@ namespace MWGui { +bool shouldAcceptKeyFocus(MyGUI::Widget* w) +{ + return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); +} + /// Recursively get all child widgets that accept keyboard input void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) { @@ -24,18 +29,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu MyGUI::Widget* w = enumerator.current(); if (!w->getVisible() || !w->getEnabled()) continue; - if (w->getNeedKeyFocus()) + if (w->getNeedKeyFocus() && shouldAcceptKeyFocus(w)) results.push_back(w); else getKeyFocusWidgets(w, results); } } -bool shouldAcceptKeyFocus(MyGUI::Widget* w) -{ - return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); -} - KeyboardNavigation::KeyboardNavigation() : mCurrentFocus(nullptr) , mModalWindow(nullptr)