mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 03:15:32 +00:00
Merge remote-tracking branch 'upstream/master' into osgshadow-test
This commit is contained in:
commit
b94bbe00cb
87 changed files with 2108 additions and 227 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
|
||||
|
@ -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 landcreator
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/world
|
||||
|
|
|
@ -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());
|
||||
|
@ -276,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());
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include <QVariant>
|
||||
|
@ -13,8 +14,9 @@
|
|||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "columnbase.hpp"
|
||||
|
||||
#include "collectionbase.hpp"
|
||||
#include "land.hpp"
|
||||
#include "landtexture.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
|
@ -22,15 +24,14 @@ namespace CSMWorld
|
|||
template<typename ESXRecordT>
|
||||
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<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>
|
||||
|
@ -39,6 +40,39 @@ namespace CSMWorld
|
|||
return record.mId;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void IdAccessor<Land>::setId (Land& record, const std::string& id) const
|
||||
{
|
||||
int x=0, y=0;
|
||||
|
||||
Land::parseUniqueRecordId(id, x, y);
|
||||
record.mX = x;
|
||||
record.mY = y;
|
||||
}
|
||||
|
||||
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<Land>::getId (const Land& record) const
|
||||
{
|
||||
return Land::createUniqueRecordId(record.mX, record.mY);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const std::string IdAccessor<LandTexture>::getId (const LandTexture& record) const
|
||||
{
|
||||
return LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex);
|
||||
}
|
||||
|
||||
/// \brief Single-type record collection
|
||||
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
|
||||
class Collection : public CollectionBase
|
||||
|
@ -69,6 +103,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();
|
||||
|
@ -108,6 +149,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)
|
||||
|
@ -206,16 +251,71 @@ namespace CSMWorld
|
|||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
|
||||
const std::string& destination,
|
||||
const UniversalId::Type type)
|
||||
int Collection<ESXRecordT, IdAccessorT>::cloneRecordImp(const std::string& origin,
|
||||
const std::string& destination, UniversalId::Type type)
|
||||
{
|
||||
Record<ESXRecordT> copy;
|
||||
copy.mModified = getRecord(origin).get();
|
||||
copy.mState = RecordBase::State_ModifiedOnly;
|
||||
copy.get().mId = destination;
|
||||
Record<ESXRecordT> 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<typename ESXRecordT, typename IdAccessorT>
|
||||
int Collection<ESXRecordT, IdAccessorT>::touchRecordImp(const std::string& id)
|
||||
{
|
||||
int index = getIndex(id);
|
||||
Record<ESXRecordT>& record = mRecords.at(index);
|
||||
if (record.isDeleted())
|
||||
{
|
||||
throw std::runtime_error("attempt to touch deleted record");
|
||||
}
|
||||
|
||||
if (!record.isModified())
|
||||
{
|
||||
record.setModified(record.get());
|
||||
return index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
|
||||
const std::string& destination, const UniversalId::Type type)
|
||||
{
|
||||
cloneRecordImp(origin, destination, type);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void Collection<Land, IdAccessor<Land> >::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<typename ESXRecordT, typename IdAccessorT>
|
||||
bool Collection<ESXRecordT, IdAccessorT>::touchRecord(const std::string& id)
|
||||
{
|
||||
return touchRecordImp(id) != -1;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Collection<Land, IdAccessor<Land> >::touchRecord(const std::string& id)
|
||||
{
|
||||
int index = touchRecordImp(id);
|
||||
if (index >= 0)
|
||||
{
|
||||
mRecords.at(index).get().mPlugin = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
|
@ -366,7 +466,7 @@ namespace CSMWorld
|
|||
UniversalId::Type type)
|
||||
{
|
||||
ESXRecordT record;
|
||||
IdAccessorT().getId (record) = id;
|
||||
IdAccessorT().setId(record, id);
|
||||
record.blank();
|
||||
|
||||
Record<ESXRecordT> record2;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,28 +1,341 @@
|
|||
#include "columnimp.hpp"
|
||||
|
||||
CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn<ESM::BodyPart> *meshType)
|
||||
: mMeshType(meshType)
|
||||
{}
|
||||
#include <stdexcept>
|
||||
#include <QVector>
|
||||
|
||||
QVariant CSMWorld::BodyPartRaceColumn::get(const Record<ESM::BodyPart> &record) const
|
||||
namespace CSMWorld
|
||||
{
|
||||
if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin)
|
||||
/* LandTextureNicknameColumn */
|
||||
LandTextureNicknameColumn::LandTextureNicknameColumn()
|
||||
: Column<LandTexture>(Columns::ColumnId_TextureNickname, ColumnBase::Display_String)
|
||||
{
|
||||
return QString::fromUtf8(record.get().mRace.c_str());
|
||||
}
|
||||
return QVariant(QVariant::UserType);
|
||||
}
|
||||
|
||||
void CSMWorld::BodyPartRaceColumn::set(Record<ESM::BodyPart> &record, const QVariant &data)
|
||||
{
|
||||
ESM::BodyPart record2 = record.get();
|
||||
|
||||
record2.mRace = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified(record2);
|
||||
}
|
||||
|
||||
bool CSMWorld::BodyPartRaceColumn::isEditable() const
|
||||
{
|
||||
return true;
|
||||
|
||||
QVariant LandTextureNicknameColumn::get(const Record<LandTexture>& record) const
|
||||
{
|
||||
return QString::fromUtf8(record.get().mId.c_str());
|
||||
}
|
||||
|
||||
void LandTextureNicknameColumn::set(Record<LandTexture>& 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<LandTexture>(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LandTextureIndexColumn::get(const Record<LandTexture>& record) const
|
||||
{
|
||||
return record.get().mIndex;
|
||||
}
|
||||
|
||||
bool LandTextureIndexColumn::isEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* LandPluginIndexColumn */
|
||||
LandPluginIndexColumn::LandPluginIndexColumn()
|
||||
: Column<Land>(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LandPluginIndexColumn::get(const Record<Land>& record) const
|
||||
{
|
||||
return record.get().mPlugin;
|
||||
}
|
||||
|
||||
bool LandPluginIndexColumn::isEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* LandTexturePluginIndexColumn */
|
||||
LandTexturePluginIndexColumn::LandTexturePluginIndexColumn()
|
||||
: Column<LandTexture>(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LandTexturePluginIndexColumn::get(const Record<LandTexture>& record) const
|
||||
{
|
||||
return record.get().mPluginIndex;
|
||||
}
|
||||
|
||||
bool LandTexturePluginIndexColumn::isEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* LandMapLodColumn */
|
||||
LandMapLodColumn::LandMapLodColumn()
|
||||
: Column<Land>(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LandMapLodColumn::get(const Record<Land>& record) const
|
||||
{
|
||||
const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE;
|
||||
const Land& land = record.get();
|
||||
|
||||
DataType values(Size, 0);
|
||||
|
||||
if (land.isDataLoaded(Land::DATA_WNAM))
|
||||
{
|
||||
for (int i = 0; i < Size; ++i)
|
||||
values[i] = land.mWnam[i];
|
||||
}
|
||||
|
||||
QVariant variant;
|
||||
variant.setValue(values);
|
||||
return variant;
|
||||
}
|
||||
|
||||
void LandMapLodColumn::set(Record<Land>& record, const QVariant& data)
|
||||
{
|
||||
DataType values = data.value<DataType>();
|
||||
|
||||
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 < values.size(); ++i)
|
||||
{
|
||||
copy.mWnam[i] = values[i];
|
||||
}
|
||||
|
||||
record.setModified(copy);
|
||||
}
|
||||
|
||||
bool LandMapLodColumn::isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* LandNormalsColumn */
|
||||
LandNormalsColumn::LandNormalsColumn()
|
||||
: Column<Land>(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LandNormalsColumn::get(const Record<Land>& record) const
|
||||
{
|
||||
const int Size = Land::LAND_NUM_VERTS * 3;
|
||||
const Land& land = record.get();
|
||||
|
||||
DataType values(Size, 0);
|
||||
|
||||
if (land.isDataLoaded(Land::DATA_VNML))
|
||||
{
|
||||
for (int i = 0; i < Size; ++i)
|
||||
values[i] = land.getLandData()->mNormals[i];
|
||||
}
|
||||
|
||||
QVariant variant;
|
||||
variant.setValue(values);
|
||||
return variant;
|
||||
}
|
||||
|
||||
void LandNormalsColumn::set(Record<Land>& record, const QVariant& data)
|
||||
{
|
||||
DataType values = data.value<DataType>();
|
||||
|
||||
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 < values.size(); ++i)
|
||||
{
|
||||
copy.getLandData()->mNormals[i] = values[i];
|
||||
}
|
||||
|
||||
record.setModified(copy);
|
||||
}
|
||||
|
||||
bool LandNormalsColumn::isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* LandHeightsColumn */
|
||||
LandHeightsColumn::LandHeightsColumn()
|
||||
: Column<Land>(Columns::ColumnId_LandHeightsIndex, ColumnBase::Display_String, 0)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LandHeightsColumn::get(const Record<Land>& record) const
|
||||
{
|
||||
const int Size = Land::LAND_NUM_VERTS;
|
||||
const Land& land = record.get();
|
||||
|
||||
DataType values(Size, 0);
|
||||
|
||||
if (land.isDataLoaded(Land::DATA_VHGT))
|
||||
{
|
||||
for (int i = 0; i < Size; ++i)
|
||||
values[i] = land.getLandData()->mHeights[i];
|
||||
}
|
||||
|
||||
QVariant variant;
|
||||
variant.setValue(values);
|
||||
return variant;
|
||||
}
|
||||
|
||||
void LandHeightsColumn::set(Record<Land>& record, const QVariant& data)
|
||||
{
|
||||
DataType values = data.value<DataType>();
|
||||
|
||||
if (values.size() != Land::LAND_NUM_VERTS)
|
||||
throw std::runtime_error("invalid land heights data");
|
||||
|
||||
Land copy = record.get();
|
||||
copy.setDataLoaded(Land::DATA_VHGT);
|
||||
|
||||
for (int i = 0; i < values.size(); ++i)
|
||||
{
|
||||
copy.getLandData()->mHeights[i] = values[i];
|
||||
}
|
||||
|
||||
record.setModified(copy);
|
||||
}
|
||||
|
||||
bool LandHeightsColumn::isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* LandColoursColumn */
|
||||
LandColoursColumn::LandColoursColumn()
|
||||
: Column<Land>(Columns::ColumnId_LandColoursIndex, ColumnBase::Display_String, 0)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LandColoursColumn::get(const Record<Land>& record) const
|
||||
{
|
||||
const int Size = Land::LAND_NUM_VERTS * 3;
|
||||
const Land& land = record.get();
|
||||
|
||||
DataType values(Size, 0);
|
||||
|
||||
if (land.isDataLoaded(Land::DATA_VCLR))
|
||||
{
|
||||
for (int i = 0; i < Size; ++i)
|
||||
values[i] = land.getLandData()->mColours[i];
|
||||
}
|
||||
|
||||
QVariant variant;
|
||||
variant.setValue(values);
|
||||
return variant;
|
||||
}
|
||||
|
||||
void LandColoursColumn::set(Record<Land>& record, const QVariant& data)
|
||||
{
|
||||
DataType values = data.value<DataType>();
|
||||
|
||||
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 < values.size(); ++i)
|
||||
{
|
||||
copy.getLandData()->mColours[i] = values[i];
|
||||
}
|
||||
|
||||
record.setModified(copy);
|
||||
}
|
||||
|
||||
bool LandColoursColumn::isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* LandTexturesColumn */
|
||||
LandTexturesColumn::LandTexturesColumn()
|
||||
: Column<Land>(Columns::ColumnId_LandTexturesIndex, ColumnBase::Display_String, 0)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant LandTexturesColumn::get(const Record<Land>& record) const
|
||||
{
|
||||
const int Size = Land::LAND_NUM_TEXTURES;
|
||||
const Land& land = record.get();
|
||||
|
||||
DataType values(Size, 0);
|
||||
|
||||
if (land.isDataLoaded(Land::DATA_VTEX))
|
||||
{
|
||||
for (int i = 0; i < Size; ++i)
|
||||
values[i] = land.getLandData()->mTextures[i];
|
||||
}
|
||||
|
||||
QVariant variant;
|
||||
variant.setValue(values);
|
||||
return variant;
|
||||
}
|
||||
|
||||
void LandTexturesColumn::set(Record<Land>& record, const QVariant& data)
|
||||
{
|
||||
DataType values = data.value<DataType>();
|
||||
|
||||
if (values.size() != Land::LAND_NUM_TEXTURES)
|
||||
throw std::runtime_error("invalid land textures data");
|
||||
|
||||
Land copy = record.get();
|
||||
copy.setDataLoaded(Land::DATA_VTEX);
|
||||
|
||||
for (int i = 0; i < values.size(); ++i)
|
||||
{
|
||||
copy.getLandData()->mTextures[i] = values[i];
|
||||
}
|
||||
|
||||
record.setModified(copy);
|
||||
}
|
||||
|
||||
bool LandTexturesColumn::isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* BodyPartRaceColumn */
|
||||
BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn<ESM::BodyPart> *meshType)
|
||||
: mMeshType(meshType)
|
||||
{}
|
||||
|
||||
QVariant BodyPartRaceColumn::get(const Record<ESM::BodyPart> &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<ESM::BodyPart> &record, const QVariant &data)
|
||||
{
|
||||
ESM::BodyPart record2 = record.get();
|
||||
|
||||
record2.mRace = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified(record2);
|
||||
}
|
||||
|
||||
bool BodyPartRaceColumn::isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
#define CSM_WOLRD_COLUMNIMP_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <QColor>
|
||||
#include <QVector>
|
||||
|
||||
#include <components/esm/loadbody.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
@ -15,6 +17,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.
|
||||
|
@ -60,6 +65,20 @@ namespace CSMWorld
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
inline QVariant StringIdColumn<Land>::get(const Record<Land>& record) const
|
||||
{
|
||||
const Land& land = record.get();
|
||||
return QString::fromUtf8(Land::createUniqueRecordId(land.mX, land.mY).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
inline QVariant StringIdColumn<LandTexture>::get(const Record<LandTexture>& record) const
|
||||
{
|
||||
const LandTexture& ltex = record.get();
|
||||
return QString::fromUtf8(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str());
|
||||
}
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct RecordStateColumn : public Column<ESXRecordT>
|
||||
{
|
||||
|
@ -673,32 +692,23 @@ namespace CSMWorld
|
|||
}
|
||||
};
|
||||
|
||||
/// \todo QColor is a GUI class and should not be in model. Need to think of an alternative
|
||||
/// solution.
|
||||
template<typename ESXRecordT>
|
||||
struct MapColourColumn : public Column<ESXRecordT>
|
||||
{
|
||||
/// \todo Replace Display_Integer with something that displays the colour value more directly.
|
||||
MapColourColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_MapColour, ColumnBase::Display_Colour)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
int colour = record.get().mMapColor;
|
||||
|
||||
return QColor (colour & 0xff, (colour>>8) & 0xff, (colour>>16) & 0xff);
|
||||
return record.get().mMapColor;
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
QColor colour = data.value<QColor>();
|
||||
|
||||
record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red();
|
||||
|
||||
record.setModified (record2);
|
||||
ESXRecordT copy = record.get();
|
||||
copy.mMapColor = data.toInt();
|
||||
record.setModified (copy);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
|
@ -1499,9 +1509,9 @@ namespace CSMWorld
|
|||
template<typename ESXRecordT>
|
||||
struct TopicColumn : public Column<ESXRecordT>
|
||||
{
|
||||
TopicColumn (bool journal)
|
||||
TopicColumn (bool journal)
|
||||
: Column<ESXRecordT> (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<ESXRecordT>& record) const
|
||||
|
@ -1755,7 +1765,7 @@ namespace CSMWorld
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct GenderNpcColumn : public Column<ESXRecordT>
|
||||
{
|
||||
|
@ -2198,8 +2208,8 @@ namespace CSMWorld
|
|||
struct EffectTextureColumn : public Column<ESXRecordT>
|
||||
{
|
||||
EffectTextureColumn (Columns::ColumnId columnId)
|
||||
: Column<ESXRecordT> (columnId,
|
||||
columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture
|
||||
: Column<ESXRecordT> (columnId,
|
||||
columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture
|
||||
: ColumnBase::Display_Icon)
|
||||
{
|
||||
assert (this->mColumnId==Columns::ColumnId_Icon ||
|
||||
|
@ -2417,7 +2427,95 @@ namespace CSMWorld
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct LandTextureNicknameColumn : public Column<LandTexture>
|
||||
{
|
||||
LandTextureNicknameColumn();
|
||||
|
||||
QVariant get(const Record<LandTexture>& record) const override;
|
||||
void set(Record<LandTexture>& record, const QVariant& data) override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct LandTextureIndexColumn : public Column<LandTexture>
|
||||
{
|
||||
LandTextureIndexColumn();
|
||||
|
||||
QVariant get(const Record<LandTexture>& record) const override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct LandPluginIndexColumn : public Column<Land>
|
||||
{
|
||||
LandPluginIndexColumn();
|
||||
|
||||
QVariant get(const Record<Land>& record) const override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct LandTexturePluginIndexColumn : public Column<LandTexture>
|
||||
{
|
||||
LandTexturePluginIndexColumn();
|
||||
|
||||
QVariant get(const Record<LandTexture>& record) const override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct LandMapLodColumn : public Column<Land>
|
||||
{
|
||||
using DataType = QVector<signed char>;
|
||||
|
||||
LandMapLodColumn();
|
||||
|
||||
QVariant get(const Record<Land>& record) const override;
|
||||
void set(Record<Land>& record, const QVariant& data) override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct LandNormalsColumn : public Column<Land>
|
||||
{
|
||||
using DataType = QVector<signed char>;
|
||||
|
||||
LandNormalsColumn();
|
||||
|
||||
QVariant get(const Record<Land>& record) const override;
|
||||
void set(Record<Land>& record, const QVariant& data) override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct LandHeightsColumn : public Column<Land>
|
||||
{
|
||||
using DataType = QVector<float>;
|
||||
|
||||
LandHeightsColumn();
|
||||
|
||||
QVariant get(const Record<Land>& record) const override;
|
||||
void set(Record<Land>& record, const QVariant& data) override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct LandColoursColumn : public Column<Land>
|
||||
{
|
||||
using DataType = QVector<unsigned char>;
|
||||
|
||||
LandColoursColumn();
|
||||
|
||||
QVariant get(const Record<Land>& record) const override;
|
||||
void set(Record<Land>& record, const QVariant& data) override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct LandTexturesColumn : public Column<Land>
|
||||
{
|
||||
using DataType = QVector<uint16_t>;
|
||||
|
||||
LandTexturesColumn();
|
||||
|
||||
QVariant get(const Record<Land>& record) const override;
|
||||
void set(Record<Land>& record, const QVariant& data) override;
|
||||
bool isEditable() const override;
|
||||
};
|
||||
|
||||
struct BodyPartRaceColumn : public RaceColumn<ESM::BodyPart>
|
||||
{
|
||||
const MeshTypeColumn<ESM::BodyPart> *mMeshType;
|
||||
|
@ -2430,4 +2528,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
|
||||
|
|
|
@ -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,14 @@ namespace CSMWorld
|
|||
{ ColumnId_WeatherChance, "Percent Chance" },
|
||||
|
||||
{ ColumnId_Text, "Text" },
|
||||
{ ColumnId_TextureNickname, "Texture Nickname" },
|
||||
{ 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" },
|
||||
|
|
|
@ -329,6 +329,15 @@ namespace CSMWorld
|
|||
|
||||
ColumnId_Text = 297,
|
||||
|
||||
ColumnId_TextureNickname = 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.
|
||||
ColumnId_UseValue1 = 0x10000,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
|
@ -15,6 +16,175 @@
|
|||
#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::ImportLandTexturesCommand::ImportLandTexturesCommand(IdTable& landTable,
|
||||
IdTable& ltexTable, QUndoCommand* parent)
|
||||
: QUndoCommand(parent)
|
||||
, mLands(landTable)
|
||||
, mLtexs(ltexTable)
|
||||
, mOldState(0)
|
||||
{
|
||||
setText("Copy land textures to current plugin");
|
||||
}
|
||||
|
||||
void CSMWorld::ImportLandTexturesCommand::redo()
|
||||
{
|
||||
int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex);
|
||||
int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt();
|
||||
|
||||
// Original data
|
||||
int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex);
|
||||
mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).value<DataType>();
|
||||
|
||||
// Need to make a copy so the old values can be looked up
|
||||
DataType copy(mOld);
|
||||
|
||||
// Perform touch/copy/etc...
|
||||
onRedo();
|
||||
|
||||
// Find all indices used
|
||||
std::unordered_set<int> texIndices;
|
||||
for (int i = 0; i < mOld.size(); ++i)
|
||||
{
|
||||
// All indices are offset by 1 for a default texture
|
||||
if (mOld[i] > 0)
|
||||
texIndices.insert(mOld[i] - 1);
|
||||
}
|
||||
|
||||
std::vector<std::string> oldTextures;
|
||||
for (int index : texIndices)
|
||||
{
|
||||
oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index));
|
||||
}
|
||||
|
||||
// Import the textures, replace old values
|
||||
LandTextureIdTable::ImportResults results = dynamic_cast<LandTextureIdTable&>(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 (mOld[i] == oldIndex + 1)
|
||||
copy[i] = newIndex + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply modification
|
||||
int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification);
|
||||
mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt();
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
// Undo copy/touch/etc...
|
||||
onUndo();
|
||||
|
||||
for (const std::string& id : mCreatedTextures)
|
||||
{
|
||||
int row = mLtexs.getModelIndex(id, 0).row();
|
||||
mLtexs.removeRows(row, 1);
|
||||
}
|
||||
mCreatedTextures.clear();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <QVariant>
|
||||
#include <QUndoCommand>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include "columnimp.hpp"
|
||||
#include "universalid.hpp"
|
||||
#include "nestedtablewrapper.hpp"
|
||||
|
||||
|
@ -24,6 +26,91 @@ namespace CSMWorld
|
|||
struct RecordBase;
|
||||
struct NestedTableWrapperBase;
|
||||
|
||||
class TouchCommand : public QUndoCommand
|
||||
{
|
||||
public:
|
||||
|
||||
TouchCommand(IdTable& model, const std::string& id, QUndoCommand* parent=nullptr);
|
||||
|
||||
void redo() override;
|
||||
void undo() override;
|
||||
|
||||
private:
|
||||
|
||||
IdTable& mTable;
|
||||
std::string mId;
|
||||
std::unique_ptr<RecordBase> mOld;
|
||||
|
||||
bool mChanged;
|
||||
};
|
||||
|
||||
class ImportLandTexturesCommand : public QUndoCommand
|
||||
{
|
||||
public:
|
||||
|
||||
ImportLandTexturesCommand(IdTable& landTable, IdTable& ltexTable,
|
||||
QUndoCommand* parent);
|
||||
|
||||
void redo() override;
|
||||
void undo() override;
|
||||
|
||||
protected:
|
||||
|
||||
using DataType = LandTexturesColumn::DataType;
|
||||
|
||||
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;
|
||||
DataType mOld;
|
||||
int mOldState;
|
||||
std::vector<std::string> 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<RecordBase> mOld;
|
||||
|
||||
bool mChanged;
|
||||
};
|
||||
|
||||
class ModifyCommand : public QUndoCommand
|
||||
{
|
||||
QAbstractItemModel *mModel;
|
||||
|
|
|
@ -412,6 +412,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
|||
Columns::ColumnId_NegativeLight, ESM::MagicEffect::NegativeLight));
|
||||
mMagicEffects.addColumn (new DescriptionColumn<ESM::MagicEffect>);
|
||||
|
||||
mLand.addColumn (new StringIdColumn<Land>);
|
||||
mLand.addColumn (new RecordStateColumn<Land>);
|
||||
mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land));
|
||||
mLand.addColumn (new LandPluginIndexColumn);
|
||||
mLand.addColumn (new LandMapLodColumn);
|
||||
mLand.addColumn (new LandNormalsColumn);
|
||||
mLand.addColumn (new LandHeightsColumn);
|
||||
mLand.addColumn (new LandColoursColumn);
|
||||
mLand.addColumn (new LandTexturesColumn);
|
||||
|
||||
mLandTextures.addColumn (new StringIdColumn<LandTexture>(true));
|
||||
mLandTextures.addColumn (new RecordStateColumn<LandTexture>);
|
||||
mLandTextures.addColumn (new FixedRecordTypeColumn<LandTexture>(UniversalId::Type_LandTexture));
|
||||
mLandTextures.addColumn (new LandTextureNicknameColumn);
|
||||
mLandTextures.addColumn (new LandTexturePluginIndexColumn);
|
||||
mLandTextures.addColumn (new LandTextureIndexColumn);
|
||||
mLandTextures.addColumn (new TextureColumn<LandTexture>);
|
||||
|
||||
mPathgrids.addColumn (new StringIdColumn<Pathgrid>);
|
||||
mPathgrids.addColumn (new RecordStateColumn<Pathgrid>);
|
||||
mPathgrids.addColumn (new FixedRecordTypeColumn<Pathgrid> (UniversalId::Type_Pathgrid));
|
||||
|
@ -531,6 +549,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, 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);
|
||||
addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview),
|
||||
|
@ -993,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:
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
#include "collection.hpp"
|
||||
#include "land.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
|
@ -39,6 +40,22 @@ namespace CSMWorld
|
|||
record.load (reader, isDeleted);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void IdCollection<Land, IdAccessor<Land> >::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<typename ESXRecordT, typename IdAccessorT>
|
||||
int IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
|
||||
{
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
#include "idtable.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/cellid.hpp>
|
||||
|
||||
#include "collectionbase.hpp"
|
||||
#include "columnbase.hpp"
|
||||
#include "landtexture.hpp"
|
||||
|
||||
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features)
|
||||
: IdTableBase (features), mIdCollection (idCollection)
|
||||
|
@ -179,6 +185,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
|
||||
{
|
||||
|
@ -281,3 +307,72 @@ CSMWorld::CollectionBase *CSMWorld::IdTable::idCollection() const
|
|||
{
|
||||
return mIdCollection;
|
||||
}
|
||||
|
||||
CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, unsigned int features)
|
||||
: IdTable(idCollection, features)
|
||||
{
|
||||
}
|
||||
|
||||
CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures(const std::vector<std::string>& ids)
|
||||
{
|
||||
ImportResults results;
|
||||
|
||||
// Map existing textures to ids
|
||||
std::map<std::string, std::string> reverseLookupMap;
|
||||
for (int i = 0; i < idCollection()->getSize(); ++i)
|
||||
{
|
||||
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(i));
|
||||
std::string texture = record.get().mTexture;
|
||||
std::transform(texture.begin(), texture.end(), texture.begin(), tolower);
|
||||
if (record.isModified())
|
||||
reverseLookupMap.emplace(texture, idCollection()->getId(i));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Look for a pre-existing record
|
||||
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(oldRow));
|
||||
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));
|
||||
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);
|
||||
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));
|
||||
reverseLookupMap.emplace(texture, newId);
|
||||
break;
|
||||
}
|
||||
|
||||
const size_t MaxIndex = std::numeric_limits<uint16_t>::max() - 1;
|
||||
index = (index + 1) % MaxIndex;
|
||||
} while (index != startIndex);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -93,6 +98,29 @@ namespace CSMWorld
|
|||
|
||||
virtual CollectionBase *idCollection() const;
|
||||
};
|
||||
|
||||
/// An IdTable customized to handle the more unique needs of LandTextureId's which behave
|
||||
/// 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<std::string,std::string>;
|
||||
|
||||
/// The newly added records
|
||||
std::vector<std::string> createdRecords;
|
||||
/// The 1st string is the original id, the 2nd is the mapped id
|
||||
std::vector<StringPair> recordMapping;
|
||||
};
|
||||
|
||||
LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0);
|
||||
|
||||
/// Finds and maps/recreates the specified ids.
|
||||
ImportResults importTextures(const std::vector<std::string>& ids);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,15 +1,30 @@
|
|||
#include "land.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
void Land::load(ESM::ESMReader &esm, bool &isDeleted)
|
||||
{
|
||||
ESM::Land::load(esm, isDeleted);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,11 @@ 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);
|
||||
|
||||
static std::string createUniqueRecordId(int x, int y);
|
||||
static void parseUniqueRecordId(const std::string& id, int& x, int& y);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "landtexture.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
|
@ -11,4 +14,21 @@ namespace CSMWorld
|
|||
mPluginIndex = esm.getIndex();
|
||||
}
|
||||
|
||||
std::string LandTexture::createUniqueRecordId(int plugin, int index)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << 'L' << plugin << '#' << index;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
21
apps/opencs/model/world/landtexturetableproxymodel.cpp
Normal file
21
apps/opencs/model/world/landtexturetableproxymodel.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
22
apps/opencs/model/world/landtexturetableproxymodel.hpp
Normal file
22
apps/opencs/model/world/landtexturetableproxymodel.hpp
Normal file
|
@ -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
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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::Type> 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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -224,6 +224,10 @@ namespace CSVDoc
|
|||
|
||||
void addRunLogSubView();
|
||||
|
||||
void addLandsSubView();
|
||||
|
||||
void addLandTexturesSubView();
|
||||
|
||||
void addPathgridSubView();
|
||||
|
||||
void addStartScriptsSubView();
|
||||
|
|
|
@ -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<CellNodeContainer*>(node->getUserData());
|
||||
container->getCell()->updateLand();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool CSVRender::Cell::removeObject (const std::string& id)
|
||||
{
|
||||
std::map<std::string, Object *>::iterator iter =
|
||||
|
@ -75,10 +102,69 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
|||
return modified;
|
||||
}
|
||||
|
||||
void CSVRender::Cell::updateLand()
|
||||
{
|
||||
if (!mUpdateLand || mLandDeleted)
|
||||
return;
|
||||
|
||||
mUpdateLand = false;
|
||||
|
||||
// Cell is deleted
|
||||
if (mDeleted)
|
||||
{
|
||||
unloadLand();
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup land if available
|
||||
const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand();
|
||||
int landIndex = land.searchId(mId);
|
||||
if (landIndex != -1 && !land.getRecord(mId).isDeleted())
|
||||
{
|
||||
const ESM::Land& esmLand = land.getRecord(mId).get();
|
||||
|
||||
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
|
||||
{
|
||||
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);
|
||||
|
||||
if (!mCellBorder)
|
||||
mCellBorder.reset(new CellBorder(mCellNode, mCoordinates));
|
||||
|
||||
mCellBorder->buildShape(esmLand);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No land data
|
||||
mLandDeleted = true;
|
||||
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,
|
||||
bool deleted)
|
||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0),
|
||||
mSubModeElementMask (0)
|
||||
mSubModeElementMask (0), mUpdateLand(true), mLandDeleted(false)
|
||||
{
|
||||
std::pair<CSMWorld::CellCoordinates, bool> result = CSMWorld::CellCoordinates::fromId (id);
|
||||
|
||||
|
@ -86,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();
|
||||
|
@ -99,22 +187,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
|
|||
|
||||
addObjects (0, rows-1);
|
||||
|
||||
const CSMWorld::IdCollection<CSMWorld::Land>& 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);
|
||||
}
|
||||
}
|
||||
updateLand();
|
||||
|
||||
mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates));
|
||||
mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates));
|
||||
|
@ -285,6 +358,38 @@ void CSVRender::Cell::pathgridRemoved()
|
|||
mPathgrid->removeGeometry();
|
||||
}
|
||||
|
||||
void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||
{
|
||||
mUpdateLand = true;
|
||||
}
|
||||
|
||||
void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
mLandDeleted = true;
|
||||
unloadLand();
|
||||
}
|
||||
|
||||
void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
mUpdateLand = true;
|
||||
mLandDeleted = false;
|
||||
}
|
||||
|
||||
void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||
{
|
||||
mUpdateLand = true;
|
||||
}
|
||||
|
||||
void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
mUpdateLand = true;
|
||||
}
|
||||
|
||||
void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
mUpdateLand = true;
|
||||
}
|
||||
|
||||
void CSVRender::Cell::reloadAssets()
|
||||
{
|
||||
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
@ -72,6 +73,9 @@ namespace CSVRender
|
|||
/// \return Have any objects been added?
|
||||
bool addObjects (int start, int end);
|
||||
|
||||
void updateLand();
|
||||
void unloadLand();
|
||||
|
||||
public:
|
||||
|
||||
enum Selection
|
||||
|
@ -118,6 +122,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);
|
||||
|
@ -145,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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -351,6 +351,72 @@ 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);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
||||
{
|
||||
|
@ -475,6 +541,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()));
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<const ESMTerrain::LandObject> 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();
|
||||
int row = mData.getLandTextures().searchId(CSMWorld::LandTexture::createUniqueRecordId(plugin, index));
|
||||
if (row == -1)
|
||||
return nullptr;
|
||||
|
||||
for (int i=0; i<numRecords; ++i)
|
||||
{
|
||||
const CSMWorld::LandTexture* ltex = &mData.getLandTextures().getRecord(i).get();
|
||||
if (ltex->mIndex == index && ltex->mPluginIndex == plugin)
|
||||
return ltex;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return &mData.getLandTextures().getRecord(row).get();
|
||||
}
|
||||
|
||||
void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY)
|
||||
|
|
|
@ -5,29 +5,32 @@
|
|||
|
||||
#include "../widget/coloreditor.hpp"
|
||||
|
||||
CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
|
||||
CSMDoc::Document& document,
|
||||
CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
|
||||
CSMDoc::Document& document,
|
||||
QObject *parent)
|
||||
: CommandDelegate(dispatcher, document, parent)
|
||||
{}
|
||||
|
||||
void CSVWorld::ColorDelegate::paint(QPainter *painter,
|
||||
void CSVWorld::ColorDelegate::paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
int colorInt = index.data().toInt();
|
||||
QColor color(colorInt & 0xff, (colorInt >> 8) & 0xff, (colorInt >> 16) & 0xff);
|
||||
|
||||
QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0),
|
||||
option.rect.y() + qRound(option.rect.height() / 4.0),
|
||||
option.rect.width() / 2,
|
||||
option.rect.height() / 2);
|
||||
painter->save();
|
||||
painter->fillRect(coloredRect, index.data().value<QColor>());
|
||||
painter->fillRect(coloredRect, color);
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawRect(coloredRect);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
|
||||
CSMDoc::Document &document,
|
||||
CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
|
||||
CSMDoc::Document &document,
|
||||
QObject *parent) const
|
||||
{
|
||||
return new ColorDelegate(dispatcher, document, parent);
|
||||
|
|
|
@ -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<CSMWorld::UniversalId>& ids) = 0;
|
||||
|
||||
virtual void setEditLock (bool locked) = 0;
|
||||
|
||||
virtual void toggleWidgets(bool active = true) = 0;
|
||||
|
|
|
@ -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;
|
||||
|
@ -254,6 +259,22 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId,
|
|||
mClonedType = type;
|
||||
}
|
||||
|
||||
void CSVWorld::GenericCreator::touch(const std::vector<CSMWorld::UniversalId>& ids)
|
||||
{
|
||||
// Combine multiple touch commands into one "macro" command
|
||||
mUndoStack.beginMacro("Touch Records");
|
||||
|
||||
CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&>(*mData.getTableModel(mListId));
|
||||
for (const CSMWorld::UniversalId& uid : ids)
|
||||
{
|
||||
CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId());
|
||||
mUndoStack.push(touchCmd);
|
||||
}
|
||||
|
||||
// Execute
|
||||
mUndoStack.endMacro();
|
||||
}
|
||||
|
||||
void CSVWorld::GenericCreator::toggleWidgets(bool active)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -103,6 +105,8 @@ namespace CSVWorld
|
|||
virtual void cloneMode(const std::string& originId,
|
||||
const CSMWorld::UniversalId::Type type);
|
||||
|
||||
virtual void touch(const std::vector<CSMWorld::UniversalId>& 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.
|
||||
|
|
120
apps/opencs/view/world/landcreator.cpp
Normal file
120
apps/opencs/view/world/landcreator.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include "landcreator.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QSpinBox>
|
||||
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#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<int>::max();
|
||||
const int MinInt = std::numeric_limits<int>::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::touch(const std::vector<CSMWorld::UniversalId>& ids)
|
||||
{
|
||||
// Combine multiple touch commands into one "macro" command
|
||||
getUndoStack().beginMacro("Touch records");
|
||||
|
||||
CSMWorld::IdTable& lands = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands));
|
||||
CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
|
||||
for (const CSMWorld::UniversalId& uid : ids)
|
||||
{
|
||||
CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId());
|
||||
getUndoStack().push(touchCmd);
|
||||
}
|
||||
|
||||
// Execute
|
||||
getUndoStack().endMacro();
|
||||
}
|
||||
|
||||
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::pushCommand(std::unique_ptr<CSMWorld::CreateCommand> command, const std::string& id)
|
||||
{
|
||||
if (mCloneMode)
|
||||
{
|
||||
CSMWorld::IdTable& lands = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands));
|
||||
CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&>(*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();
|
||||
}
|
||||
}
|
47
apps/opencs/view/world/landcreator.hpp
Normal file
47
apps/opencs/view/world/landcreator.hpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef CSV_WORLD_LANDCREATOR_H
|
||||
#define CSV_WORLD_LANDCREATOR_H
|
||||
|
||||
#include "genericcreator.hpp"
|
||||
|
||||
class QLabel;
|
||||
class QSpinBox;
|
||||
|
||||
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 touch(const std::vector<CSMWorld::UniversalId>& ids) override;
|
||||
|
||||
void focus() override;
|
||||
|
||||
void reset() override;
|
||||
|
||||
std::string getErrors() const override;
|
||||
|
||||
protected:
|
||||
|
||||
std::string getId() const override;
|
||||
|
||||
void pushCommand(std::unique_ptr<CSMWorld::CreateCommand> command,
|
||||
const std::string& id) override;
|
||||
|
||||
private slots:
|
||||
|
||||
void coordChanged(int value);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
101
apps/opencs/view/world/landtexturecreator.cpp
Normal file
101
apps/opencs/view/world/landtexturecreator.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include "landtexturecreator.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
|
||||
#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);
|
||||
|
||||
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(mIndexBox, SIGNAL(valueChanged(int)), this, SLOT(indexChanged(int)));
|
||||
}
|
||||
|
||||
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_TextureNickname);
|
||||
mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString()));
|
||||
|
||||
column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex);
|
||||
mIndexBox->setValue((table.data(table.getModelIndex(originId, column)).toInt()));
|
||||
}
|
||||
|
||||
void LandTextureCreator::focus()
|
||||
{
|
||||
mIndexBox->setFocus();
|
||||
}
|
||||
|
||||
void LandTextureCreator::reset()
|
||||
{
|
||||
GenericCreator::reset();
|
||||
mNameEdit->setText("");
|
||||
mIndexBox->setValue(0);
|
||||
}
|
||||
|
||||
std::string LandTextureCreator::getErrors() const
|
||||
{
|
||||
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_TextureNickname);
|
||||
command.addValue(column, mName.c_str());
|
||||
}
|
||||
|
||||
std::string LandTextureCreator::getId() const
|
||||
{
|
||||
return CSMWorld::LandTexture::createUniqueRecordId(0, mIndexBox->value());
|
||||
}
|
||||
|
||||
void LandTextureCreator::nameChanged(const QString& value)
|
||||
{
|
||||
mName = value.toUtf8().constData();
|
||||
update();
|
||||
}
|
||||
|
||||
void LandTextureCreator::indexChanged(int value)
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
49
apps/opencs/view/world/landtexturecreator.hpp
Normal file
49
apps/opencs/view/world/landtexturecreator.hpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#ifndef CSV_WORLD_LANDTEXTURECREATOR_H
|
||||
#define CSV_WORLD_LANDTEXTURECREATOR_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "genericcreator.hpp"
|
||||
|
||||
class QLineEdit;
|
||||
class QSpinBox;
|
||||
|
||||
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(int val);
|
||||
|
||||
private:
|
||||
|
||||
QLineEdit* mNameEdit;
|
||||
QSpinBox* mIndexBox;
|
||||
|
||||
std::string mName;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -18,6 +18,8 @@
|
|||
#include "pathgridcreator.hpp"
|
||||
#include "previewsubview.hpp"
|
||||
#include "bodypartcreator.hpp"
|
||||
#include "landcreator.hpp"
|
||||
#include "landtexturecreator.hpp"
|
||||
|
||||
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||
{
|
||||
|
@ -81,6 +83,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
|||
manager.add (CSMWorld::UniversalId::Type_Pathgrids,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, PathgridCreatorFactory>);
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Lands,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandCreator> >);
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_LandTextures,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandTextureCreator> >);
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Globals,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GlobalCreator> >);
|
||||
|
||||
|
@ -181,6 +189,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
|||
manager.add (CSMWorld::UniversalId::Type_Pathgrid,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, PathgridCreatorFactory> (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Land,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandCreator> >(false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_LandTexture,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandTextureCreator> >(false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_DebugProfile,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
@ -60,6 +61,9 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
|||
menu.addAction(mCloneAction);
|
||||
}
|
||||
|
||||
if (mTouchAction)
|
||||
menu.addAction (mTouchAction);
|
||||
|
||||
if (mCreateAction)
|
||||
menu.addAction (mCreateAction);
|
||||
|
||||
|
@ -226,17 +230,22 @@ 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<CSMWorld::IdTableBase&> (*mDocument.getData().getTableModel (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);
|
||||
|
@ -302,6 +311,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 +460,22 @@ void CSVWorld::Table::cloneRecord()
|
|||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::touchRecord()
|
||||
{
|
||||
if (!mEditLock && mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch)
|
||||
{
|
||||
std::vector<CSMWorld::UniversalId> touchIds;
|
||||
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it)
|
||||
{
|
||||
touchIds.push_back(getUniversalId(it->row()));
|
||||
}
|
||||
|
||||
emit touchRequest(touchIds);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::moveUpRecord()
|
||||
{
|
||||
if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant))
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace CSVWorld
|
|||
QAction *mEditAction;
|
||||
QAction *mCreateAction;
|
||||
QAction *mCloneAction;
|
||||
QAction *mTouchAction;
|
||||
QAction *mRevertAction;
|
||||
QAction *mDeleteAction;
|
||||
QAction *mMoveUpAction;
|
||||
|
@ -115,6 +116,8 @@ namespace CSVWorld
|
|||
|
||||
void cloneRequest(const CSMWorld::UniversalId&);
|
||||
|
||||
void touchRequest(const std::vector<CSMWorld::UniversalId>& ids);
|
||||
|
||||
void closeRequest();
|
||||
|
||||
void extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds);
|
||||
|
@ -129,6 +132,8 @@ namespace CSVWorld
|
|||
|
||||
void cloneRecord();
|
||||
|
||||
void touchRecord();
|
||||
|
||||
void moveUpRecord();
|
||||
|
||||
void moveDownRecord();
|
||||
|
|
|
@ -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<CSMWorld::UniversalId>& ids)
|
||||
{
|
||||
mCreator->touch(ids);
|
||||
}
|
||||
|
||||
void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds)
|
||||
{
|
||||
extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds);
|
||||
|
|
|
@ -102,6 +102,7 @@ namespace CSVWorld
|
|||
void createRequest();
|
||||
void cloneRequest(const std::string& id,
|
||||
const CSMWorld::UniversalId::Type type);
|
||||
void touchRequest(const std::vector<CSMWorld::UniversalId>&);
|
||||
|
||||
void extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds);
|
||||
void extendedRevertConfigRequest(const std::vector<std::string> &selectedIds);
|
||||
|
|
|
@ -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<CSMWorld::UniversalId>&)),
|
||||
mBottom, SLOT(touchRequest(const std::vector<CSMWorld::UniversalId>&)));
|
||||
|
||||
connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector<std::string> &)),
|
||||
mBottom, SLOT(extendedDeleteConfigRequest(const std::vector<std::string> &)));
|
||||
connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector<std::string> &)),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
namespace MWGui
|
||||
{
|
||||
|
||||
bool shouldAcceptKeyFocus(MyGUI::Widget* w)
|
||||
{
|
||||
return w && !w->castType<MyGUI::Window>(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<MyGUI::Widget*>& results)
|
||||
{
|
||||
|
@ -24,18 +29,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector<MyGUI::Widget*>& 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<MyGUI::Window>(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled();
|
||||
}
|
||||
|
||||
KeyboardNavigation::KeyboardNavigation()
|
||||
: mCurrentFocus(nullptr)
|
||||
, mModalWindow(nullptr)
|
||||
|
|
|
@ -50,6 +50,8 @@ namespace MWGui
|
|||
|
||||
mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal<BackgroundImage>("ImageBox", 0,0,1,1,
|
||||
MyGUI::Align::Stretch, "Menu");
|
||||
mSceneImage = MyGUI::Gui::getInstance().createWidgetReal<BackgroundImage>("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()
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace MWGui
|
|||
MyGUI::TextBox* mLoadingText;
|
||||
MyGUI::ScrollBar* mProgressBar;
|
||||
BackgroundImage* mBackgroundImage;
|
||||
BackgroundImage* mSceneImage;
|
||||
|
||||
std::vector<std::string> mSplashScreens;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace MWGui
|
|||
|
||||
void onFrame(float dt);
|
||||
|
||||
bool exit();
|
||||
|
||||
private:
|
||||
const VFS::Manager* mVFS;
|
||||
|
||||
|
|
|
@ -26,6 +26,11 @@ namespace MWGui
|
|||
}
|
||||
}
|
||||
|
||||
bool PickpocketItemModel::allowedToUseItems() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemStack PickpocketItemModel::getItem (ModelIndex index)
|
||||
{
|
||||
if (index < 0)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <MyGUI_RenderManager.h>
|
||||
#include <MyGUI_ImageBox.h>
|
||||
#include <MyGUI_Gui.h>
|
||||
|
||||
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<MyGUI::ImageBox>(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())
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace MWGui
|
|||
|
||||
bool filterAccepts (const ItemStack& item);
|
||||
|
||||
bool allowedToUseItems() const;
|
||||
virtual ItemStack getItem (ModelIndex index);
|
||||
virtual size_t getItemCount();
|
||||
|
||||
|
|
|
@ -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,23 @@ 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<MWWorld::Ptr>();
|
||||
tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false);
|
||||
tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, checkOwned());
|
||||
}
|
||||
else if (type == "ItemModelIndex")
|
||||
{
|
||||
std::pair<ItemModel::ModelIndex, ItemModel*> pair = *focus->getUserData<std::pair<ItemModel::ModelIndex, ItemModel*> >();
|
||||
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<MWGui::ToolTipInfo>(), false);
|
||||
tooltipSize = createToolTip(*focus->getUserData<MWGui::ToolTipInfo>());
|
||||
}
|
||||
else if (type == "AvatarItemSelection")
|
||||
{
|
||||
|
@ -244,7 +245,7 @@ namespace MWGui
|
|||
info.text = "#{sSchool}: " + sSchoolNames[school];
|
||||
}
|
||||
info.effects = effects;
|
||||
tooltipSize = createToolTip(info, false);
|
||||
tooltipSize = createToolTip(info);
|
||||
}
|
||||
else if (type == "Layout")
|
||||
{
|
||||
|
@ -298,7 +299,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 +333,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 +352,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 +360,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");
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
|
@ -15,6 +15,11 @@ namespace MWGui
|
|||
mSourceModel = sourceModel;
|
||||
}
|
||||
|
||||
bool TradeItemModel::allowedToUseItems() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ItemStack TradeItemModel::getItem (ModelIndex index)
|
||||
{
|
||||
if (index < 0)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -606,25 +606,25 @@ 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();
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -864,8 +864,16 @@ 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.top()->onFrame(frameDuration);
|
||||
mCurrentModals.back()->onFrame(frameDuration);
|
||||
|
||||
mKeyboardNavigation->onFrame();
|
||||
|
||||
|
@ -886,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)
|
||||
|
@ -1727,9 +1729,10 @@ namespace MWGui
|
|||
{
|
||||
if (!mCurrentModals.empty())
|
||||
{
|
||||
if (!mCurrentModals.top()->exit())
|
||||
WindowModal* window = mCurrentModals.back();
|
||||
if (!window->exit())
|
||||
return;
|
||||
mCurrentModals.top()->setVisible(false);
|
||||
window->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1738,7 +1741,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 +1750,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 +1772,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)
|
||||
|
@ -2059,12 +2066,7 @@ namespace MWGui
|
|||
void WindowManager::GuiModeState::update(bool visible)
|
||||
{
|
||||
for (unsigned int i=0; i<mWindows.size(); ++i)
|
||||
{
|
||||
bool visibilityMask = true;
|
||||
if (i < mVisibilityMask.size())
|
||||
visibilityMask = mVisibilityMask[i];
|
||||
mWindows[i]->setVisible(visible && visibilityMask);
|
||||
}
|
||||
mWindows[i]->setVisible(visible);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -401,7 +401,7 @@ namespace MWGui
|
|||
MWWorld::Ptr mSelectedEnchantItem;
|
||||
MWWorld::Ptr mSelectedWeapon;
|
||||
|
||||
std::stack<WindowModal*> mCurrentModals;
|
||||
std::vector<WindowModal*> mCurrentModals;
|
||||
|
||||
// Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window).
|
||||
CustomMarkerCollection mCustomMarkers;
|
||||
|
@ -477,7 +477,6 @@ namespace MWGui
|
|||
void update(bool visible);
|
||||
|
||||
std::vector<WindowBase*> mWindows;
|
||||
std::vector<bool> mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode.
|
||||
|
||||
std::string mCloseSound;
|
||||
std::string mOpenSound;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -70,11 +70,7 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr itemPtr = actor.getClass().getInventoryStore(actor).search(item);
|
||||
if (!itemPtr.isEmpty())
|
||||
actor.getClass().getInventoryStore(actor).remove(itemPtr, 1, actor, true);
|
||||
}
|
||||
actor.getClass().getInventoryStore(actor).remove(item, 1, actor, true);
|
||||
}
|
||||
|
||||
class CheckActorCommanded : public MWMechanics::EffectSourceVisitor
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -654,11 +654,30 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem(
|
|||
return mSelectedEnchantItem;
|
||||
}
|
||||
|
||||
int MWWorld::InventoryStore::remove(const std::string& itemId, int count, const Ptr& actor)
|
||||
{
|
||||
return remove(itemId, count, actor, false);
|
||||
}
|
||||
|
||||
int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor)
|
||||
{
|
||||
return remove(item, count, actor, false);
|
||||
}
|
||||
|
||||
int MWWorld::InventoryStore::remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement)
|
||||
{
|
||||
int toRemove = count;
|
||||
|
||||
for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter)
|
||||
if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId))
|
||||
toRemove -= remove(*iter, toRemove, actor, equipReplacement);
|
||||
|
||||
flagAsModified();
|
||||
|
||||
// number of removed items
|
||||
return count - toRemove;
|
||||
}
|
||||
|
||||
int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement)
|
||||
{
|
||||
int retCount = ContainerStore::remove(item, count, actor);
|
||||
|
|
|
@ -177,6 +177,9 @@ namespace MWWorld
|
|||
virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const;
|
||||
///< @return true if the two specified objects can stack with each other
|
||||
|
||||
virtual int remove(const std::string& itemId, int count, const Ptr& actor);
|
||||
virtual int remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement);
|
||||
|
||||
virtual int remove(const Ptr& item, int count, const Ptr& actor);
|
||||
virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement);
|
||||
///< Remove \a count item(s) designated by \a item from this inventory.
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -175,6 +175,45 @@ namespace ESM
|
|||
|
||||
}
|
||||
|
||||
void Land::blank()
|
||||
{
|
||||
mPlugin = 0;
|
||||
|
||||
for (int i = 0; i < LAND_GLOBAL_MAP_LOD_SIZE; ++i)
|
||||
mWnam[0] = 0;
|
||||
|
||||
if (!mLandData)
|
||||
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] = 0;
|
||||
mLandData->mNormals[i*3+2] = 127;
|
||||
}
|
||||
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;
|
||||
|
||||
// No file associated with the land now
|
||||
mContext.filename.clear();
|
||||
}
|
||||
|
||||
void Land::loadData(int flags, LandData* target) const
|
||||
{
|
||||
// Create storage if nothing is loaded
|
||||
|
@ -193,6 +232,16 @@ namespace ESM
|
|||
return;
|
||||
}
|
||||
|
||||
// Copy data to target if no file
|
||||
if (mContext.filename.empty())
|
||||
{
|
||||
// Make sure there is data, and that it doesn't point to the same object.
|
||||
if (mLandData && mLandData != target)
|
||||
*target = *mLandData;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ESM::ESMReader reader;
|
||||
reader.restoreContext(mContext);
|
||||
|
||||
|
@ -269,6 +318,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),
|
||||
|
|
|
@ -31,6 +31,8 @@ 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;
|
||||
|
||||
int mDataTypes;
|
||||
|
@ -64,6 +66,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,12 +113,12 @@ 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;
|
||||
|
||||
void blank() {}
|
||||
void blank();
|
||||
|
||||
/**
|
||||
* Actually loads data into target
|
||||
|
@ -131,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);
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace ESM
|
|||
|
||||
void LandTexture::blank()
|
||||
{
|
||||
mId.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.
|
||||
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
|
||||
|
|
|
@ -75,4 +75,9 @@ void World::updateTextureFiltering()
|
|||
mTextureManager->updateTextureFiltering();
|
||||
}
|
||||
|
||||
void World::clearAssociatedCaches()
|
||||
{
|
||||
mChunkManager->clearCache();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -14,19 +14,15 @@
|
|||
<Property key="ImagePushed" value="textures\tx_menubook_take_pressed.dds"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="Widget" position="0 0 292 398">
|
||||
<Widget type="ImageButton" skin="ImageBox" position="205 358 48 32" name="PrevPageBTN">
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="ImageButton" skin="ImageBox" position="205 358 48 32" name="PrevPageBTN">
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="Widget" position="292 0 292 398">
|
||||
<Widget type="ImageButton" skin="ImageBox" position="38 358 48 32" name="NextPageBTN">
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="ImageButton" skin="ImageBox" position="330 358 48 32" name="NextPageBTN">
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ImageButton" skin="ImageBox" position="488 358 48 32" name="CloseButton">
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<MyGUI type="Layer" version="1.0">
|
||||
<Layer name="Scene" overlapped="false" pick="false"/>
|
||||
<Layer name="Overlay" overlapped="false" pick="false"/>
|
||||
<Layer name="AdditiveOverlay" type="AdditiveLayer" pick="false"/>
|
||||
<Layer name="HUD" overlapped="false" pick="true"/>
|
||||
|
|
Loading…
Reference in a new issue