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));