Replace nonconst getId with setId, add template specialization and specialized derived classes for LandTexture

new-script-api
Kyle Cooley 7 years ago
parent 5d14a2afcc
commit 9e41f1340a

@ -70,7 +70,7 @@ opencs_units (view/world
cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
bodypartcreator bodypartcreator landtexturecreator
) )
opencs_units_noqt (view/world opencs_units_noqt (view/world

@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <functional> #include <functional>
#include <QVariant> #include <QVariant>
@ -13,8 +14,8 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include "columnbase.hpp" #include "columnbase.hpp"
#include "collectionbase.hpp" #include "collectionbase.hpp"
#include "landtexture.hpp"
namespace CSMWorld namespace CSMWorld
{ {
@ -22,15 +23,14 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct IdAccessor struct IdAccessor
{ {
std::string& getId (ESXRecordT& record); void setId(ESXRecordT& record, const std::string& id) const;
const std::string getId (const ESXRecordT& record) const; const std::string getId (const ESXRecordT& record) const;
}; };
template<typename ESXRecordT> template<typename ESXRecordT>
std::string& IdAccessor<ESXRecordT>::getId (ESXRecordT& record) void IdAccessor<ESXRecordT>::setId(ESXRecordT& record, const std::string& id) const
{ {
return record.mId; record.mId = id;
} }
template<typename ESXRecordT> template<typename ESXRecordT>
@ -39,6 +39,23 @@ namespace CSMWorld
return record.mId; return record.mId;
} }
template<>
inline void IdAccessor<LandTexture>::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<LandTexture>::getId (const LandTexture& record) const
{
return LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex);
}
/// \brief Single-type record collection /// \brief Single-type record collection
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> > template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
class Collection : public CollectionBase class Collection : public CollectionBase
@ -213,7 +230,7 @@ namespace CSMWorld
Record<ESXRecordT> copy; Record<ESXRecordT> copy;
copy.mModified = getRecord(origin).get(); copy.mModified = getRecord(origin).get();
copy.mState = RecordBase::State_ModifiedOnly; copy.mState = RecordBase::State_ModifiedOnly;
copy.get().mId = destination; IdAccessorT().setId(copy.get(), destination);
insertRecord(copy, getAppendIndex(destination, type)); insertRecord(copy, getAppendIndex(destination, type));
} }
@ -366,7 +383,7 @@ namespace CSMWorld
UniversalId::Type type) UniversalId::Type type)
{ {
ESXRecordT record; ESXRecordT record;
IdAccessorT().getId (record) = id; IdAccessorT().setId(record, id);
record.blank(); record.blank();
Record<ESXRecordT> record2; Record<ESXRecordT> record2;

@ -63,6 +63,13 @@ namespace CSMWorld
} }
}; };
template<>
inline QVariant StringIdColumn<LandTexture>::get(const Record<LandTexture>& 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<typename ESXRecordT> template<typename ESXRecordT>
struct RecordStateColumn : public Column<ESXRecordT> struct RecordStateColumn : public Column<ESXRecordT>
{ {
@ -2421,6 +2428,31 @@ namespace CSMWorld
} }
}; };
template<typename ESXRecordT>
struct TextureHandleColumn : public Column<ESXRecordT>
{
TextureHandleColumn()
: Column<ESXRecordT> (Columns::ColumnId_TextureHandle, ColumnBase::Display_String)
{}
QVariant get(const Record<ESXRecordT>& record) const override
{
return QString::fromUtf8(record.get().mId.c_str());
}
void set(Record<ESXRecordT>& 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<typename ESXRecordT> template<typename ESXRecordT>
struct TextureIndexColumn : public Column<ESXRecordT> struct TextureIndexColumn : public Column<ESXRecordT>
{ {
@ -2428,31 +2460,30 @@ namespace CSMWorld
: Column<ESXRecordT> (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) : Column<ESXRecordT> (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer)
{} {}
QVariant get (const Record<ESXRecordT>& record) const QVariant get(const Record<ESXRecordT>& record) const override
{ {
return record.get().mIndex; return record.get().mIndex;
} }
virtual bool isEditable() const bool isEditable() const override
{ {
return false; return false;
} }
}; };
// TODO remove
template<typename ESXRecordT> template<typename ESXRecordT>
struct PluginIndexColumn : public Column<ESXRecordT> struct PluginIndexColumn : public Column<ESXRecordT>
{ {
PluginIndexColumn() PluginIndexColumn()
: Column<ESXRecordT> (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) : Column<ESXRecordT> (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0)
{} {}
QVariant get (const Record<ESXRecordT>& record) const QVariant get(const Record<ESXRecordT>& record) const override
{ {
return -1; return -1;
} }
virtual bool isEditable() const virtual bool isEditable() const override
{ {
return false; return false;
} }

@ -330,6 +330,7 @@ namespace CSMWorld
{ ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_WeatherChance, "Percent Chance" },
{ ColumnId_Text, "Text" }, { ColumnId_Text, "Text" },
{ ColumnId_TextureHandle, "Texture Handle" },
{ ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_PluginIndex, "Plugin Index" },
{ ColumnId_TextureIndex, "Texture Index" }, { ColumnId_TextureIndex, "Texture Index" },

@ -329,8 +329,9 @@ namespace CSMWorld
ColumnId_Text = 297, ColumnId_Text = 297,
ColumnId_PluginIndex = 298, ColumnId_TextureHandle = 298,
ColumnId_TextureIndex = 299, ColumnId_PluginIndex = 299,
ColumnId_TextureIndex = 300,
// Allocated to a separate value range, so we don't get a collision should we ever need // Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values. // to extend the number of use values.

@ -417,9 +417,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land)); mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land));
mLand.addColumn (new PluginIndexColumn<Land>); mLand.addColumn (new PluginIndexColumn<Land>);
mLandTextures.addColumn (new StringIdColumn<LandTexture>); mLandTextures.addColumn (new StringIdColumn<LandTexture>(true));
mLandTextures.addColumn (new RecordStateColumn<LandTexture>); mLandTextures.addColumn (new RecordStateColumn<LandTexture>);
mLandTextures.addColumn (new FixedRecordTypeColumn<LandTexture>(UniversalId::Type_LandTexture)); mLandTextures.addColumn (new FixedRecordTypeColumn<LandTexture>(UniversalId::Type_LandTexture));
mLandTextures.addColumn (new TextureHandleColumn<LandTexture>);
mLandTextures.addColumn (new PluginIndexColumn<LandTexture>); mLandTextures.addColumn (new PluginIndexColumn<LandTexture>);
mLandTextures.addColumn (new TextureIndexColumn<LandTexture>); mLandTextures.addColumn (new TextureIndexColumn<LandTexture>);
mLandTextures.addColumn (new TextureColumn<LandTexture>); mLandTextures.addColumn (new TextureColumn<LandTexture>);
@ -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 (&mSoundGens), UniversalId::Type_SoundGen);
addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect);
addModel (new IdTable (&mLand), UniversalId::Type_Land); 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 IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid);
addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript);
addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview),

@ -281,3 +281,34 @@ CSMWorld::CollectionBase *CSMWorld::IdTable::idCollection() const
{ {
return mIdCollection; 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;
}

@ -93,6 +93,21 @@ namespace CSMWorld
virtual CollectionBase *idCollection() const; 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 #endif

@ -1,5 +1,7 @@
#include "landtexture.hpp" #include "landtexture.hpp"
#include <string>
#include <components/esm/esmreader.hpp> #include <components/esm/esmreader.hpp>
namespace CSMWorld namespace CSMWorld
@ -11,4 +13,19 @@ namespace CSMWorld
mPluginIndex = esm.getIndex(); 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));
}
} }

@ -13,6 +13,11 @@ namespace CSMWorld
int mPluginIndex; int mPluginIndex;
void load (ESM::ESMReader &esm, bool &isDeleted); 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);
}; };
} }

@ -0,0 +1,106 @@
#include "landtexturecreator.hpp"
#include <cstdint>
#include <limits>
#include <QIntValidator>
#include <QLabel>
#include <QLineEdit>
#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<uint16_t>::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<CSMWorld::IdTable&>(*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<CSMWorld::IdTable&>(*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();
}
}

@ -0,0 +1,49 @@
#ifndef CSV_WORLD_LANDTEXTURECREATOR_H
#define CSV_WORLD_LANDTEXTURECREATOR_H
#include <string>
#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

@ -18,6 +18,7 @@
#include "pathgridcreator.hpp" #include "pathgridcreator.hpp"
#include "previewsubview.hpp" #include "previewsubview.hpp"
#include "bodypartcreator.hpp" #include "bodypartcreator.hpp"
#include "landtexturecreator.hpp"
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
{ {
@ -43,8 +44,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Spells,
CSMWorld::UniversalId::Type_Enchantments, CSMWorld::UniversalId::Type_Enchantments,
CSMWorld::UniversalId::Type_SoundGens, CSMWorld::UniversalId::Type_SoundGens,
CSMWorld::UniversalId::Type_Lands,
CSMWorld::UniversalId::Type_LandTextures,
CSMWorld::UniversalId::Type_None // end marker CSMWorld::UniversalId::Type_None // end marker
}; };
@ -83,6 +82,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Pathgrids, manager.add (CSMWorld::UniversalId::Type_Pathgrids,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, PathgridCreatorFactory>); new CSVDoc::SubViewFactoryWithCreator<TableSubView, PathgridCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_Lands,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator> >);
manager.add (CSMWorld::UniversalId::Type_LandTextures,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandTextureCreator> >);
manager.add (CSMWorld::UniversalId::Type_Globals, manager.add (CSMWorld::UniversalId::Type_Globals,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GlobalCreator> >); new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GlobalCreator> >);
@ -183,6 +188,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Pathgrid, manager.add (CSMWorld::UniversalId::Type_Pathgrid,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, PathgridCreatorFactory> (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, PathgridCreatorFactory> (false));
manager.add (CSMWorld::UniversalId::Type_Land,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> >(false));
manager.add (CSMWorld::UniversalId::Type_LandTexture,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandTextureCreator> >(false));
manager.add (CSMWorld::UniversalId::Type_DebugProfile, manager.add (CSMWorld::UniversalId::Type_DebugProfile,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));

@ -59,7 +59,7 @@ namespace ESM
void LandTexture::blank() void LandTexture::blank()
{ {
mId.clear();
mTexture.clear(); mTexture.clear();
mIndex = -1;
} }
} }

@ -31,14 +31,15 @@ struct LandTexture
/// Return a string descriptor for this record type. Currently used for debugging / error logs only. /// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "LandTexture"; } static std::string getRecordType() { return "LandTexture"; }
// mId is merely a user friendly name for the texture in the editor.
std::string mId, mTexture; std::string mId, mTexture;
int mIndex; int mIndex;
void load(ESMReader &esm, bool &isDeleted); void load(ESMReader &esm, bool &isDeleted);
void save(ESMWriter &esm, bool isDeleted = false) const; 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(); void blank();
///< Set record to default state (does not touch the ID).
}; };
} }
#endif #endif

Loading…
Cancel
Save