Added Editor Properties widget at the top of every World Editor tab, made tons of backend changes to get it to work properly

This commit is contained in:
parax0 2016-02-07 23:48:43 -07:00
parent 8e1b66fa5a
commit a46cd5446f
49 changed files with 930 additions and 299 deletions

View File

@ -218,7 +218,6 @@ SOURCES += \
Resource/Model/CStaticModel.cpp \
Resource/Model/SSurface.cpp \
Resource/Script/CMasterTemplate.cpp \
Resource/Script/CScriptLayer.cpp \
Resource/Script/CScriptObject.cpp \
Resource/Script/CScriptTemplate.cpp \
Resource/CAnimationParameters.cpp \

View File

@ -116,11 +116,11 @@ void CScriptCooker::WriteLayerMP1(CScriptLayer *pLayer)
{
u32 LayerStart = mpSCLY->Tell();
mpSCLY->WriteByte(0); // Unknown value
mpSCLY->WriteLong(pLayer->GetNumObjects());
mpSCLY->WriteLong(pLayer->NumInstances());
for (u32 iInst = 0; iInst < pLayer->GetNumObjects(); iInst++)
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{
CScriptObject *pInstance = pLayer->ObjectByIndex(iInst);
CScriptObject *pInstance = pLayer->InstanceByIndex(iInst);
WriteInstanceMP1(pInstance);
}

View File

@ -572,7 +572,7 @@ void CAreaLoader::SetUpObjects()
if (!pLayer) break;
}
for (u32 iObj = 0; iObj < pLayer->GetNumObjects(); iObj++)
for (u32 iObj = 0; iObj < pLayer->NumInstances(); iObj++)
{
// Add object to object map
CScriptObject *pObj = (*pLayer)[iObj];

View File

@ -123,11 +123,11 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY)
case eArrayProperty: {
CArrayProperty *pArrayCast = static_cast<CArrayProperty*>(pProp);
u32 Size = SCLY.ReadLong();
int Size = SCLY.ReadLong();
pArrayCast->Resize(Size);
for (u32 iElem = 0; iElem < Size; iElem++)
for (int iElem = 0; iElem < Size; iElem++)
{
if (mVersion < eEchoesDemo)
LoadStructMP1(SCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
@ -243,7 +243,7 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream &SCLY)
{
CScriptObject *pObj = LoadObjectMP1(SCLY);
if (pObj)
mpLayer->AddObject(pObj);
mpLayer->AddInstance(pObj);
}
// Layer sizes are always a multiple of 32 - skip end padding before returning
@ -391,7 +391,7 @@ CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY)
{
CScriptObject *pObj = LoadObjectMP2(SCLY);
if (pObj)
mpLayer->AddObject(pObj);
mpLayer->AddInstance(pObj);
}
if (IsSCGN)

View File

@ -1,95 +0,0 @@
#include "CScriptLayer.h"
CScriptLayer::CScriptLayer()
{
mLayerName = "New Layer";
mActive = true;
mVisible = true;
}
CScriptLayer::~CScriptLayer()
{
for (auto it = mObjects.begin(); it != mObjects.end(); it++)
delete *it;
}
// ************* DATA MANIPULATION *************
void CScriptLayer::AddObject(CScriptObject* object)
{
mObjects.push_back(object);
}
void CScriptLayer::DeleteObjectByIndex(u32 index)
{
delete mObjects[index];
mObjects.erase(mObjects.begin() + index, mObjects.begin() + index);
}
void CScriptLayer::DeleteObjectByID(u32 ID)
{
for (auto it = mObjects.begin(); it != mObjects.end(); it++)
{
if ((*it)->InstanceID() == ID)
{
delete *it;
mObjects.erase(it, it);
break;
}
}
}
void CScriptLayer::Reserve(u32 amount)
{
mObjects.reserve(amount);
}
// ************* GETTERS *************
TString CScriptLayer::Name()
{
return mLayerName;
}
bool CScriptLayer::IsActive()
{
return mActive;
}
bool CScriptLayer::IsVisible()
{
return mVisible;
}
u32 CScriptLayer::GetNumObjects()
{
return mObjects.size();
}
CScriptObject* CScriptLayer::ObjectByIndex(u32 index)
{
return mObjects[index];
}
CScriptObject* CScriptLayer::ObjectByID(u32 ID)
{
for (auto it = mObjects.begin(); it != mObjects.end(); it++)
if ((*it)->InstanceID() == ID)
return *it;
return nullptr;
}
// ************* SETTERS *************
void CScriptLayer::SetName(const TString& name)
{
mLayerName = name;
}
void CScriptLayer::SetActive(bool active)
{
mActive = active;
}
void CScriptLayer::SetVisible(bool visible)
{
mVisible = visible;
}

View File

@ -1,5 +1,5 @@
#ifndef SSCRIPTLAYER_H
#define SSCRIPTLAYER_H
#ifndef CSCRIPTLAYER_H
#define CSCRIPTLAYER_H
#include "CScriptObject.h"
#include <Common/types.h>
@ -11,38 +11,85 @@ class CScriptLayer
TString mLayerName;
bool mActive;
bool mVisible;
std::vector<CScriptObject*> mObjects;
std::vector<CScriptObject*> mInstances;
public:
CScriptLayer();
~CScriptLayer();
CScriptLayer()
: mLayerName("New Layer")
, mActive(true)
, mVisible(true)
{
}
~CScriptLayer()
{
for (auto it = mInstances.begin(); it != mInstances.end(); it++)
delete *it;
}
// Data Manipulation
void AddObject(CScriptObject* object);
void DeleteObjectByIndex(u32 index);
void DeleteObjectByID(u32 ID);
void Reserve(u32 amount);
void AddInstance(CScriptObject *pObject)
{
mInstances.push_back(pObject);
}
// Getters and Setters
TString Name();
bool IsActive();
bool IsVisible();
u32 GetNumObjects();
CScriptObject* ObjectByIndex(u32 index);
CScriptObject* ObjectByID(u32 ID);
void RemoveInstance(CScriptObject *pInstance)
{
for (auto it = mInstances.begin(); it != mInstances.end(); it++)
{
if (*it == pInstance)
{
mInstances.erase(it);
break;
}
}
}
void SetName(const TString& name);
void SetActive(bool active);
void SetVisible(bool visible);
void RemoveInstanceByIndex(u32 Index)
{
mInstances.erase(mInstances.begin() + Index);
}
void RemoveInstanceByID(u32 ID)
{
for (auto it = mInstances.begin(); it != mInstances.end(); it++)
{
if ((*it)->InstanceID() == ID)
{
mInstances.erase(it);
break;
}
}
}
void Reserve(u32 Amount)
{
mInstances.reserve(Amount);
}
// Accessors
inline TString Name() const { return mLayerName; }
inline bool IsActive() const { return mActive; }
inline bool IsVisible() const { return mVisible; }
inline u32 NumInstances() const { return mInstances.size(); }
inline CScriptObject* InstanceByIndex(u32 Index) const { return mInstances[Index]; }
inline CScriptObject* InstanceByID(u32 ID) const
{
for (auto it = mInstances.begin(); it != mInstances.end(); it++)
{
if ((*it)->InstanceID() == ID)
return *it;
}
return nullptr;
}
inline void SetName(const TString& rkName) { mLayerName = rkName; }
inline void SetActive(bool Active) { mActive = Active; }
inline void SetVisible(bool Visible) { mVisible = Visible; }
// Operators
CScriptObject* operator[](u32 index);
CScriptObject* operator[](u32 Index) { return InstanceByIndex(Index); }
};
// ************* INLINE FUNCTIONS *************
inline CScriptObject* CScriptLayer::operator[](u32 index)
{
return mObjects[index];
}
#endif // SSCRIPTLAYER_H
#endif // CSCRIPTLAYER_H

View File

@ -1,4 +1,5 @@
#include "CScriptObject.h"
#include "CScriptLayer.h"
#include "CMasterTemplate.h"
#include "Core/Resource/CAnimSet.h"
@ -69,6 +70,16 @@ bool CScriptObject::IsEditorProperty(IProperty *pProp)
);
}
void CScriptObject::SetLayer(CScriptLayer *pLayer)
{
if (pLayer != mpLayer)
{
mpLayer->RemoveInstance(this);
mpLayer = pLayer;
mpLayer->AddInstance(this);
}
}
// ************ GETTERS ************
IProperty* CScriptObject::PropertyByIndex(u32 index) const
{

View File

@ -50,6 +50,7 @@ public:
void EvaluateCollisionModel();
void EvaluateVolume();
bool IsEditorProperty(IProperty *pProp);
void SetLayer(CScriptLayer *pLayer);
CScriptTemplate* Template() const;
CMasterTemplate* MasterTemplate() const;
@ -84,6 +85,12 @@ public:
CCollisionMeshGroup* GetCollision() const;
EVolumeShape VolumeShape() const;
float VolumeScale() const;
TStringProperty* InstanceNameProperty() const { return mpInstanceName; }
TVector3Property* PositionProperty() const { return mpPosition; }
TVector3Property* RotationProperty() const { return mpRotation; }
TVector3Property* ScaleProperty() const { return mpScale; }
TBoolProperty* ActiveProperty() const { return mpActive; }
};
#endif // CSCRIPTOBJECT_H

View File

@ -2,6 +2,11 @@
#include "IPropertyTemplate.h"
// ************ IProperty ************
CPropertyStruct* IProperty::RootStruct()
{
return (mpParent ? mpParent->RootStruct() : Type() == eStructProperty ? static_cast<CPropertyStruct*>(this) : nullptr);
}
IPropertyTemplate* IProperty::Template() const
{
return mpTemplate;
@ -111,23 +116,23 @@ CPropertyStruct* CPropertyStruct::StructByIDString(const TIDString& rkStr) const
}
// ************ CArrayProperty ************
void CArrayProperty::Resize(u32 Size)
void CArrayProperty::Resize(int Size)
{
u32 OldSize = mProperties.size();
int OldSize = mProperties.size();
if (OldSize == Size) return;
if (Size < OldSize)
{
for (u32 i = mProperties.size() - 1; i >= Size; i--)
delete mProperties[i];
for (int iProp = mProperties.size() - 1; iProp >= Size; iProp--)
delete mProperties[iProp];
}
mProperties.resize(Size);
if (Size > OldSize)
{
for (u32 i = OldSize; i < Size; i++)
mProperties[i] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct(this);
for (int iProp = OldSize; iProp < Size; iProp++)
mProperties[iProp] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct(this);
}
}

View File

@ -47,6 +47,8 @@ public:
inline CPropertyStruct* Parent() const { return mpParent; }
inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; }
CPropertyStruct* RootStruct();
// These functions can't be in the header to avoid circular includes with IPropertyTemplate.h
IPropertyTemplate* Template() const;
TString Name() const;
@ -178,7 +180,7 @@ public:
inline void Reserve(u32 amount) { mProperties.reserve(amount); }
// Functions
void Resize(u32 Size);
void Resize(int Size);
CStructTemplate* SubStructTemplate() const;
TString ElementName() const;
};

View File

@ -116,12 +116,12 @@ void CScene::SetActiveArea(CGameArea *pArea)
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
{
CScriptLayer *pLayer = mpArea->GetScriptLayer(iLyr);
u32 NumObjects = pLayer->GetNumObjects();
u32 NumObjects = pLayer->NumInstances();
mNodes[eScriptNode].reserve(mNodes[eScriptNode].size() + NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++)
{
CScriptObject *pObj = pLayer->ObjectByIndex(iObj);
CScriptObject *pObj = pLayer->InstanceByIndex(iObj);
CScriptNode *pNode = CreateScriptNode(pObj);
pNode->BuildLightList(mpArea);
@ -142,9 +142,9 @@ void CScene::SetActiveArea(CGameArea *pArea)
CScriptLayer *pGenLayer = mpArea->GetGeneratorLayer();
if (pGenLayer)
{
for (u32 iObj = 0; iObj < pGenLayer->GetNumObjects(); iObj++)
for (u32 iObj = 0; iObj < pGenLayer->NumInstances(); iObj++)
{
CScriptObject *pObj = pGenLayer->ObjectByIndex(iObj);
CScriptObject *pObj = pGenLayer->InstanceByIndex(iObj);
CScriptNode *pNode = CreateScriptNode(pObj);
// Add to map

View File

@ -191,6 +191,8 @@ void CScriptNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewIn
{
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ZERO);
glDepthMask(GL_TRUE);
CGraphics::UpdateVertexBlock();
CGraphics::UpdatePixelBlock();
CDrawUtil::DrawShadedCube(CColor::skTransparentPurple * TintColor(ViewInfo));
}
}

View File

@ -137,7 +137,9 @@ HEADERS += \
Undo/CEditScriptPropertyCommand.h \
Undo/CResizeScriptArrayCommand.h \
Undo/CBasicPropertyCommand.h \
Undo/IUndoCommand.h
Undo/IUndoCommand.h \
WorldEditor/WEditorProperties.h \
Undo/CChangeLayerCommand.h
# Source Files
SOURCES += \
@ -191,7 +193,9 @@ SOURCES += \
WorldEditor/CInstancesModel.cpp \
Undo/CEditScriptPropertyCommand.cpp \
Undo/CResizeScriptArrayCommand.cpp \
Undo/CBasicPropertyCommand.cpp
Undo/CBasicPropertyCommand.cpp \
WorldEditor/WEditorProperties.cpp \
Undo/CChangeLayerCommand.cpp
# UI Files
FORMS += \

View File

@ -21,7 +21,7 @@
#define CONNECT_RELAY(Widget, Index, Signal) \
CPropertyRelay *pRelay = new CPropertyRelay(Widget, Index); \
connect(Widget, SIGNAL(Signal), pRelay, SLOT(OnWidgetEdited())); \
connect(pRelay, SIGNAL(WidgetEdited(QWidget*, const QModelIndex&)), this, SLOT(WidgetEdited(QWidget*, const QModelIndex&)));
connect(pRelay, SIGNAL(WidgetEdited(QWidget*, const QModelIndex&)), this, SLOT(WidgetEdited(QWidget*, const QModelIndex&)))
CPropertyDelegate::CPropertyDelegate(QObject *pParent /*= 0*/)
: QStyledItemDelegate(pParent)
@ -57,7 +57,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
case eBoolProperty:
{
QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool));
pOut = pCheckBox;
break;
}
@ -67,7 +67,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT16_MIN);
pSpinBox->setMaximum(INT16_MAX);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
pOut = pSpinBox;
break;
}
@ -77,7 +77,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT32_MIN);
pSpinBox->setMaximum(INT32_MAX);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
pOut = pSpinBox;
break;
}
@ -86,15 +86,15 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
{
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
pSpinBox->setSingleStep(0.1);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double));
pOut = pSpinBox;
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
break;
}
case eColorProperty:
{
WColorPicker *pColorPicker = new WColorPicker(pParent);
CONNECT_RELAY(pColorPicker, rkIndex, colorChanged(QColor))
CONNECT_RELAY(pColorPicker, rkIndex, colorChanged(QColor));
pOut = pColorPicker;
break;
}
@ -102,7 +102,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
case eStringProperty:
{
QLineEdit *pLineEdit = new QLineEdit(pParent);
CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString))
CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString));
pOut = pLineEdit;
break;
}
@ -116,7 +116,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++)
pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum)));
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int));
pOut = pComboBox;
break;
}
@ -128,7 +128,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
pSelector->SetAllowedExtensions(pTemp->Extensions());
pSelector->setFont(qobject_cast<QWidget*>(parent())->font()); // bit of a hack to stop the resource selector font from changing
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString))
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString));
pOut = pSelector;
break;
}
@ -159,7 +159,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
else if (pProp->Type() == eBitfieldProperty)
{
QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool));
pOut = pCheckBox;
}
@ -178,7 +178,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
pSpinBox->setMaximum(1.0);
}
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double));
pOut = pSpinBox;
}
}
@ -194,6 +194,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkIndex) const
{
BlockRelays(true);
mEditInProgress = false; // fixes case where user does undo mid-edit
if (pEditor)
{
@ -433,11 +434,11 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
u32 NewCount = pSpinBox->value();
int NewCount = pSpinBox->value();
if (pArray->Count() != NewCount)
{
CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(mpModel, rkIndex, NewCount);
CResizeScriptArrayCommand *pCmd = new CResizeScriptArrayCommand(pProp, mpEditor, mpModel, NewCount);
mpEditor->UndoStack()->push(pCmd);
}
break;
@ -517,7 +518,8 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
// Create undo command
if (!Matches || EditInProgress)
{
CEditScriptPropertyCommand *pCommand = new CEditScriptPropertyCommand(mpModel, rkIndex, pOldValue, !mEditInProgress);
// Always consider the edit done for bool properties
CEditScriptPropertyCommand *pCommand = new CEditScriptPropertyCommand(pProp, mpEditor, pOldValue, (!mEditInProgress || pProp->Type() == eBoolProperty));
mpEditor->UndoStack()->push(pCommand);
}
@ -563,7 +565,7 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
else
pSelector->SetAllowedExtensions("CHAR");
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString))
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString));
return pSelector;
}
@ -579,14 +581,14 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
pComboBox->addItem(TO_QSTRING(pAnimSet->getNodeName(iChr)));
}
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int));
return pComboBox;
}
if (Type == eLongProperty)
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
return pSpinBox;
}

View File

@ -35,6 +35,48 @@ IProperty* CPropertyModel::PropertyForIndex(const QModelIndex& rkIndex, bool Han
return static_cast<IProperty*>(rkIndex.internalPointer());
}
QModelIndex CPropertyModel::IndexForProperty(IProperty *pProp) const
{
if (pProp == mpBaseStruct) return QModelIndex();
QVector<u32> RowNumbers;
IProperty *pChild = pProp;
CPropertyStruct *pParent = pProp->Parent();
while (pParent)
{
// Check for array with one sub-property
CPropertyStruct *pGrandparent = pParent->Parent();
if (pGrandparent && pGrandparent->Type() == eArrayProperty && pParent->Count() == 1)
{
pChild = pParent;
pParent = pGrandparent;
continue;
}
// Find row index for this child property
for (u32 iChild = 0; iChild < pParent->Count(); iChild++)
{
if (pParent->PropertyByIndex(iChild) == pChild)
{
RowNumbers << iChild;
break;
}
}
pChild = pParent;
pParent = pGrandparent;
}
// Find the corresponding QModelIndex in the same spot
QModelIndex Index = QModelIndex();
for (int iChild = RowNumbers.size() - 1; iChild >= 0; iChild--)
Index = index(RowNumbers[iChild], 0, Index);
return Index;
}
int CPropertyModel::columnCount(const QModelIndex& /*rkParent*/) const
{
return 2;
@ -393,6 +435,11 @@ Qt::ItemFlags CPropertyModel::flags(const QModelIndex& rkIndex) const
else return (Qt::ItemIsEnabled | Qt::ItemIsEditable);
}
void CPropertyModel::NotifyPropertyModified(IProperty *pProp)
{
NotifyPropertyModified(IndexForProperty(pProp));
}
void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
{
if (rowCount(rkIndex) != 0)
@ -405,7 +452,9 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
emit dataChanged(Parent, Parent);
}
emit dataChanged(rkIndex, rkIndex);
QModelIndex IndexC1 = rkIndex.sibling(rkIndex.row(), 1);
emit dataChanged(IndexC1, IndexC1);
emit PropertyModified(rkIndex);
}

View File

@ -14,6 +14,7 @@ public:
CPropertyModel(QObject *pParent = 0);
void SetBaseStruct(CPropertyStruct *pBaseStruct);
IProperty* PropertyForIndex(const QModelIndex& rkIndex, bool HandleFlaggedPointers) const;
QModelIndex IndexForProperty(IProperty *pProp) const;
int columnCount(const QModelIndex& rkParent) const;
int rowCount(const QModelIndex& rkParent) const;
@ -23,10 +24,14 @@ public:
QModelIndex parent(const QModelIndex& rkChild) const;
Qt::ItemFlags flags(const QModelIndex& rkIndex) const;
void NotifyPropertyModified(const QModelIndex& rkIndex);
void ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize);
void ArrayResized(const QModelIndex& rkIndex, u32 OldSize);
void ResizeArray(const QModelIndex& rkIndex, u32 NewSize);
public slots:
void NotifyPropertyModified(IProperty *pProp);
void NotifyPropertyModified(const QModelIndex& rkIndex);
signals:
void PropertyModified(const QModelIndex& rkIndex);
};

View File

@ -17,7 +17,7 @@ CPropertyView::CPropertyView(QWidget *pParent)
connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(edit(QModelIndex)));
connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(mpModel, SIGNAL(PropertyModified(QModelIndex)), this, SLOT(OnPropertyModified(QModelIndex)));
connect(mpModel, SIGNAL(PropertyModified(const QModelIndex&)), this, SLOT(OnPropertyModified(const QModelIndex&)));
}
void CPropertyView::setModel(QAbstractItemModel *pModel)
@ -66,6 +66,7 @@ void CPropertyView::SetEditor(CWorldEditor *pEditor)
{
mpEditor = pEditor;
mpDelegate->SetEditor(pEditor);
connect(mpEditor, SIGNAL(PropertyModified(IProperty*,bool)), mpModel, SLOT(NotifyPropertyModified(IProperty*)));
}
void CPropertyView::SetInstance(CScriptObject *pObj)
@ -83,7 +84,10 @@ void CPropertyView::SetInstance(CScriptObject *pObj)
void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent)
{
// Iterate over all properties and update if they're an editor property. Ignore structs unless they're EditorProperties or a single struct.
// Check what game this is
EGame Game = mpEditor->ActiveArea()->Version();
// Iterate over all properties and update if they're an editor property.
for (int iRow = 0; iRow < mpModel->rowCount(rkParent); iRow++)
{
QModelIndex Index0 = mpModel->index(iRow, 0, rkParent);
@ -92,11 +96,15 @@ void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent)
if (pProp)
{
// For structs, update sub-properties.
if (pProp->Type() == eStructProperty)
{
CStructTemplate *pStruct = static_cast<CStructTemplate*>(pProp->Template());
if (pStruct->IsSingleProperty() || pStruct->PropertyID() == 0x255A4580)
// As an optimization, in MP2+, we don't need to update unless this is a single struct or if
// it's EditorProperties, because other structs never have editor properties in them.
// In MP1 this isn't the case so we need to update every struct regardless
if ((Game <= ePrime) || (pStruct->IsSingleProperty() || pStruct->PropertyID() == 0x255A4580))
UpdateEditorProperties(Index0);
else
continue;
@ -180,16 +188,9 @@ void CPropertyView::OnPropertyModified(const QModelIndex& rkIndex)
// Check for a character resource being changed. If that's the case we need to remake the persistent editors.
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, true);
if (pProp->Type() == eCharacterProperty && rkIndex.internalId() & 0x1)
if (pProp->Type() == eCharacterProperty /*&& rkIndex.internalId() & 0x1*/)
{
EGame Game = static_cast<TCharacterProperty*>(pProp)->Get().Version();
if (mpDelegate->DetermineCharacterPropType(Game, rkIndex) == eFileProperty)
{
ClosePersistentEditors(rkIndex.parent());
SetPersistentEditors(rkIndex.parent());
}
ClosePersistentEditors(rkIndex);
SetPersistentEditors(rkIndex);
}
emit PropertyModified(pProp);
}

View File

@ -29,9 +29,6 @@ public slots:
void SetPersistentEditors(const QModelIndex& rkIndex);
void ClosePersistentEditors(const QModelIndex& rkIndex);
void OnPropertyModified(const QModelIndex& rkIndex);
signals:
void PropertyModified(IProperty *pProperty);
};
#endif // CPROPERTYVIEW_H

View File

@ -1,16 +1,16 @@
#include "CBasicPropertyCommand.h"
#include <Core/Resource/Script/IPropertyTemplate.h>
CBasicPropertyCommand::CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex)
: IUndoCommand("Edit Property")
, mpModel(pModel)
, mpProperty(pModel->PropertyForIndex(rkIndex, true))
CBasicPropertyCommand::CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName /*="Edit Property"*/)
: IUndoCommand(rkCommandName)
, mpProperty(pProp)
, mpTemplate(mpProperty->Template())
, mIndex(rkIndex)
, mpBaseStruct(pProp->RootStruct())
, mpEditor(pEditor)
, mIsInArray(false)
{
// Check for array
IProperty *pProp = mpProperty;
IProperty *pChild = mpProperty;
IProperty *pParent = mpProperty->Parent();
while (pParent)
@ -24,31 +24,28 @@ CBasicPropertyCommand::CBasicPropertyCommand(CPropertyModel *pModel, const QMode
for (u32 iSub = 0; iSub < pArray->Count(); iSub++)
{
if (pArray->PropertyByIndex(iSub) == pProp)
if (pArray->PropertyByIndex(iSub) == pChild)
{
mArrayIndices << iSub;
break;
}
}
}
pProp = pParent;
pChild = pParent;
pParent = pParent->Parent();
}
}
void CBasicPropertyCommand::UpdateArraySubProperty()
{
// If an array has been sized down and then back up, then we might have an index to an invalid property.
// Since we can't assume our index is still valid, we'll use the template and the model to find the corresponding property.
// If an array has been sized down and then back up, then we might have a pointer to an invalid property.
// Since we can't assume our pointer is still valid, we'll use the template to find the corresponding property.
IPropertyTemplate *pTemp = mpTemplate;
CStructTemplate *pParent = mpTemplate->Parent();
QVector<u32> SubIndices;
int IndexIndex = 0;
if (mIndex.internalId() & 0x1)
SubIndices << mIndex.row();
while (pParent)
{
if (pParent->Type() != eArrayProperty || static_cast<CArrayTemplate*>(pParent)->Count() > 1)
@ -62,6 +59,8 @@ void CBasicPropertyCommand::UpdateArraySubProperty()
}
}
}
else
SubIndices << 0;
if (pParent->Type() == eArrayProperty)
{
@ -73,15 +72,9 @@ void CBasicPropertyCommand::UpdateArraySubProperty()
pParent = pParent->Parent();
}
// Find corresponding index
QModelIndex Index = QModelIndex();
// Find corresponding property
mpProperty = mpBaseStruct;
for (int iSub = SubIndices.size() - 1; iSub >= 0; iSub--)
Index = mpModel->index(SubIndices[iSub], 0, Index);
Index = Index.sibling(Index.row(), 1);
// Get property
mpProperty = mpModel->PropertyForIndex(Index, true);
mIndex = Index;
for (int iChild = SubIndices.size() - 1; iChild >= 0; iChild--)
mpProperty = static_cast<CPropertyStruct*>(mpProperty)->PropertyByIndex(SubIndices[iChild]);
}

View File

@ -3,20 +3,21 @@
#include "IUndoCommand.h"
#include "Editor/PropertyEdit/CPropertyModel.h"
#include "Editor/WorldEditor/CWorldEditor.h"
class CBasicPropertyCommand : public IUndoCommand
{
protected:
CPropertyModel *mpModel;
IProperty *mpProperty;
IPropertyTemplate *mpTemplate;
QModelIndex mIndex;
CPropertyStruct *mpBaseStruct;
CWorldEditor *mpEditor;
bool mIsInArray;
QVector<u32> mArrayIndices;
public:
CBasicPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex);
CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName = "Edit Property");
virtual void UpdateArraySubProperty();
virtual bool AffectsCleanState() const { return true; }
};

View File

@ -0,0 +1,42 @@
#include "CChangeLayerCommand.h"
CChangeLayerCommand::CChangeLayerCommand(CWorldEditor *pEditor, const QList<CScriptNode*>& rkNodeList, CScriptLayer *pNewLayer)
: IUndoCommand("Change Layer")
, mNodeList(rkNodeList)
, mpNewLayer(pNewLayer)
, mpEditor(pEditor)
{
foreach (CScriptNode *pNode, mNodeList)
{
CScriptLayer *pLayer = pNode->Object()->Layer();
if (pLayer == pNewLayer)
{
mNodeList.removeOne(pNode);
continue;
}
mOldLayers[pNode] = pLayer;
}
}
void CChangeLayerCommand::undo()
{
mpEditor->InstancesLayerAboutToChange();
foreach (CScriptNode *pNode, mNodeList)
pNode->Object()->SetLayer(mOldLayers[pNode]);
mpEditor->InstancesLayerChanged(mNodeList);
}
void CChangeLayerCommand::redo()
{
mpEditor->InstancesLayerAboutToChange();
foreach (CScriptNode *pNode, mNodeList)
pNode->Object()->SetLayer(mpNewLayer);
mpEditor->InstancesLayerChanged(mNodeList);
}

View File

@ -0,0 +1,22 @@
#ifndef CCHANGELAYERCOMMAND_H
#define CCHANGELAYERCOMMAND_H
#include "IUndoCommand.h"
#include "Editor/WorldEditor/CWorldEditor.h"
#include <Core/Scene/CScriptNode.h>
class CChangeLayerCommand : public IUndoCommand
{
QList<CScriptNode*> mNodeList;
QMap<CScriptNode*, CScriptLayer*> mOldLayers;
CScriptLayer *mpNewLayer;
CWorldEditor *mpEditor;
public:
CChangeLayerCommand(CWorldEditor *pEditor, const QList<CScriptNode*>& rkNodeList, CScriptLayer *pNewLayer);
void undo();
void redo();
bool AffectsCleanState() const { return true; }
};
#endif // CCHANGELAYERCOMMAND_H

View File

@ -1,8 +1,8 @@
#include "CEditScriptPropertyCommand.h"
#include "EUndoCommand.h"
CEditScriptPropertyCommand::CEditScriptPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, IPropertyValue *pOldValue, bool IsDone)
: CBasicPropertyCommand(pModel, rkIndex)
CEditScriptPropertyCommand::CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName /*= "Edit Property"*/)
: CBasicPropertyCommand(pProp, pEditor, rkCommandName)
, mCommandEnded(IsDone)
{
mpOldValue = pOldValue;
@ -41,12 +41,13 @@ void CEditScriptPropertyCommand::undo()
{
if (mIsInArray) UpdateArraySubProperty();
mpProperty->RawValue()->Copy(mpOldValue);
mpModel->NotifyPropertyModified(mIndex);
mpEditor->OnPropertyModified(mpProperty);
mCommandEnded = true;
}
void CEditScriptPropertyCommand::redo()
{
if (mIsInArray) UpdateArraySubProperty();
mpProperty->RawValue()->Copy(mpNewValue);
mpModel->NotifyPropertyModified(mIndex);
mpEditor->OnPropertyModified(mpProperty);
}

View File

@ -3,7 +3,6 @@
#include "CBasicPropertyCommand.h"
#include "Editor/PropertyEdit/CPropertyModel.h"
#include <QUndoCommand>
class CEditScriptPropertyCommand : public CBasicPropertyCommand
{
@ -12,7 +11,7 @@ class CEditScriptPropertyCommand : public CBasicPropertyCommand
bool mCommandEnded;
public:
CEditScriptPropertyCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, IPropertyValue *pOldValue, bool IsDone);
CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName = "Edit Property");
~CEditScriptPropertyCommand();
int id() const;
bool mergeWith(const QUndoCommand *pkOther);

View File

@ -1,8 +1,9 @@
#include "CResizeScriptArrayCommand.h"
CResizeScriptArrayCommand::CResizeScriptArrayCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, u32 NewSize)
: CBasicPropertyCommand(pModel, rkIndex)
CResizeScriptArrayCommand::CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize)
: CBasicPropertyCommand(pProp, pEditor)
, mpArray(static_cast<CArrayProperty*>(mpProperty))
, mpModel(pModel)
, mOldSize(mpArray->Count())
, mNewSize(NewSize)
{
@ -10,7 +11,7 @@ CResizeScriptArrayCommand::CResizeScriptArrayCommand(CPropertyModel *pModel, con
if (!mNewSizeLarger)
{
for (u32 iSub = mNewSize; iSub < mOldSize; iSub++)
for (int iSub = mNewSize; iSub < mOldSize; iSub++)
{
mDeletedProperties << mpArray->PropertyByIndex(iSub)->Clone();
}
@ -29,21 +30,22 @@ void CResizeScriptArrayCommand::undo()
{
if (mIsInArray) UpdateArraySubProperty();
mpModel->ArrayAboutToBeResized(mIndex, mOldSize);
QModelIndex Index = mpModel->IndexForProperty(mpProperty);
mpModel->ArrayAboutToBeResized(Index, (u32) mOldSize);
mpArray->Resize(mOldSize);
if (!mNewSizeLarger)
{
u32 NumNewElements = mOldSize - mNewSize;
int NumNewElements = mOldSize - mNewSize;
for (u32 iSub = 0; iSub < NumNewElements; iSub++)
for (int iSub = 0; iSub < NumNewElements; iSub++)
{
u32 Idx = iSub + mNewSize;
mpArray->PropertyByIndex(Idx)->Copy(mDeletedProperties[iSub]);
}
}
mpModel->ArrayResized(mIndex, mNewSize);
mpModel->ArrayResized(Index, (u32) mNewSize);
}
}
@ -54,9 +56,10 @@ void CResizeScriptArrayCommand::redo()
{
if (mIsInArray) UpdateArraySubProperty();
mpModel->ArrayAboutToBeResized(mIndex, mNewSize);
QModelIndex Index = mpModel->IndexForProperty(mpProperty);
mpModel->ArrayAboutToBeResized(Index, (u32) mNewSize);
mpArray->Resize(mNewSize);
mpModel->ArrayResized(mIndex, mOldSize);
mpModel->ArrayResized(Index, (u32) mOldSize);
}
}

View File

@ -9,13 +9,14 @@ class CResizeScriptArrayCommand : public CBasicPropertyCommand
{
CArrayProperty *mpArray;
QVector<IProperty*> mDeletedProperties;
CPropertyModel *mpModel;
u32 mOldSize;
u32 mNewSize;
int mOldSize;
int mNewSize;
bool mNewSizeLarger;
public:
CResizeScriptArrayCommand(CPropertyModel *pModel, const QModelIndex& rkIndex, u32 NewSize);
CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize);
~CResizeScriptArrayCommand();
void undo();
void redo();

View File

@ -1,6 +1,8 @@
#ifndef EUNDOCOMMAND
#define EUNDOCOMMAND
// This enum is used as an ID for merging undo commands.
// If a command can't merge, then it doesn't have to be listed here.
enum EUndoCommand
{
eTranslateNodeCmd,

View File

@ -4,13 +4,17 @@
#include "CTranslateNodeCommand.h"
#include "CRotateNodeCommand.h"
#include "CScaleNodeCommand.h"
#include "CSelectNodeCommand.h"
#include "CDeselectNodeCommand.h"
#include "CClearSelectionCommand.h"
#include "CSelectAllCommand.h"
#include "CInvertSelectionCommand.h"
#include "CEditScriptPropertyCommand.h"
#include "CResizeScriptArrayCommand.h"
#include "CChangeLayerCommand.h"
#include "EUndoCommand.h"
#endif // UNDOCOMMANDS

View File

@ -5,7 +5,8 @@
#include <QApplication>
#include <QIcon>
/* The tree has 3 levels:
/*
* The tree has 3 levels:
* 1. Node Type (Script Object, Light, World Mesh, etc) - represented with ID of 0
* 2. Object Type (Actor, Platform, SpawnPoint, etc) - represented with flags
* 3. Instance - represented with pointer to instance (0x1 bit is guaranteed to be clear)
@ -15,6 +16,8 @@
* A: Row index
* B: Node type row index
* C: Item type (ObjType, Instance)
*
* Also this class is kind of a mess, it would be nice to rewrite it at some point
*/
#define TYPES_ROW_INDEX_MASK 0xFFFFFFE0
#define TYPES_NODE_TYPE_MASK 0x0000001E
@ -87,7 +90,7 @@ QModelIndex CInstancesModel::index(int row, int column, const QModelIndex &paren
if (mModelType == eLayers)
{
CScriptLayer *pLayer = mpArea->GetScriptLayer(parent.row());
if ((u32) row >= pLayer->GetNumObjects())
if ((u32) row >= pLayer->NumInstances())
return QModelIndex();
else
return createIndex(row, column, (*pLayer)[row]);
@ -185,7 +188,7 @@ int CInstancesModel::rowCount(const QModelIndex &parent) const
{
u32 RowIndex = ((parent.internalId() & TYPES_ROW_INDEX_MASK) >> TYPES_ROW_INDEX_SHIFT);
if (mModelType == eLayers)
return (mpArea ? mpArea->GetScriptLayer(RowIndex)->GetNumObjects() : 0);
return (mpArea ? mpArea->GetScriptLayer(RowIndex)->NumInstances() : 0);
else
return mTemplateList[RowIndex]->NumObjects();
}
@ -310,8 +313,13 @@ QVariant CInstancesModel::data(const QModelIndex &index, int role) const
void CInstancesModel::SetEditor(CWorldEditor *pEditor)
{
if (mpEditor)
disconnect(mpEditor, 0, this, 0);
mpEditor = pEditor;
mpScene = (pEditor ? pEditor->Scene() : nullptr);
connect(mpEditor, SIGNAL(InstancesLayerAboutToChange()), this, SLOT(InstancesLayerPreChange()));
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(InstancesLayerPostChange(QList<CScriptNode*>)));
}
void CInstancesModel::SetMaster(CMasterTemplate *pMaster)
@ -404,6 +412,46 @@ CScriptObject* CInstancesModel::IndexObject(const QModelIndex& index) const
return static_cast<CScriptObject*>(index.internalPointer());
}
// ************ PUBLIC SLOTS ************
void CInstancesModel::InstancesLayerPreChange()
{
// This is only really needed on layers, which have rows moved.
// Types just need to update column 1 so we can handle that when the change is finished.
if (mModelType == eLayers)
emit layoutAboutToBeChanged();
}
void CInstancesModel::InstancesLayerPostChange(const QList<CScriptNode*>& rkInstanceList)
{
QList<CScriptObject*> InstanceList;
foreach (CScriptNode *pNode, rkInstanceList)
InstanceList << pNode->Object();
QModelIndex ScriptIdx = index(0, 0, QModelIndex());
// For types, just find the instances that have changed layers and emit dataChanged for column 1.
if (mModelType == eTypes)
{
for (int iType = 0; iType < rowCount(ScriptIdx); iType++)
{
QModelIndex TypeIdx = index(iType, 0, ScriptIdx);
for (int iInst = 0; iInst < rowCount(TypeIdx); iInst++)
{
QModelIndex InstIdx = index(iInst, 1, TypeIdx);
CScriptObject *pInst = IndexObject(InstIdx);
if (InstanceList.contains(pInst))
emit dataChanged(InstIdx, InstIdx);
}
}
}
// For layers we just need to emit layoutChanged() and done
else
emit layoutChanged();
}
// ************ STATIC ************
CInstancesModel::EIndexType CInstancesModel::IndexType(const QModelIndex& index)
{

View File

@ -56,6 +56,10 @@ public:
CScriptTemplate* IndexTemplate(const QModelIndex& index) const;
CScriptObject* IndexObject(const QModelIndex& index) const;
public slots:
void InstancesLayerPreChange();
void InstancesLayerPostChange(const QList<CScriptNode*>& rkInstanceList);
// Static
static EIndexType IndexType(const QModelIndex& index);
static ENodeType IndexNodeType(const QModelIndex& index);

View File

@ -5,6 +5,7 @@
#include "WInstancesTab.h"
#include "Editor/CBasicViewport.h"
#include "Editor/PropertyEdit/CPropertyView.h"
#include "Editor/Widgets/WDraggableSpinBox.h"
#include "Editor/Widgets/WVectorEditor.h"
#include "Editor/Undo/UndoCommands.h"
@ -80,6 +81,12 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
connect(&mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(OnUndoStackIndexChanged()));
connect(ui->ActionSave, SIGNAL(triggered()), this, SLOT(Save()));
ui->CreateTabEditorProperties->SyncToEditor(this);
ui->ModifyTabEditorProperties->SyncToEditor(this);
ui->InstancesTabEditorProperties->SyncToEditor(this);
ui->DisplayTabEditorProperties->SyncToEditor(this);
ui->WorldTabEditorProperties->SyncToEditor(this);
}
CWorldEditor::~CWorldEditor()
@ -172,18 +179,24 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex)
CStringTable *pWorldNameTable = mpWorld->GetWorldName();
TWideString WorldName = pWorldNameTable ? pWorldNameTable->GetString("ENGL", 0) : "[Untitled World]";
CStringTable *pAreaNameTable = mpWorld->GetAreaName(AreaIndex);
TWideString AreaName = pAreaNameTable ? pAreaNameTable->GetString("ENGL", 0) : (TWideString("!") + mpWorld->GetAreaInternalName(AreaIndex).ToUTF16());
if (CurrentGame() < eReturns)
{
CStringTable *pAreaNameTable = mpWorld->GetAreaName(AreaIndex);
TWideString AreaName = pAreaNameTable ? pAreaNameTable->GetString("ENGL", 0) : (TWideString("!") + mpWorld->GetAreaInternalName(AreaIndex).ToUTF16());
if (AreaName.IsEmpty())
AreaName = "[Untitled Area]";
if (AreaName.IsEmpty())
AreaName = "[Untitled Area]";
setWindowTitle(QString("Prime World Editor - %1 - %2[*]").arg(TO_QSTRING(WorldName)).arg(TO_QSTRING(AreaName)));
}
setWindowTitle(QString("Prime World Editor - %1 - %2[*]").arg(TO_QSTRING(WorldName)).arg(TO_QSTRING(AreaName)));
}
CGameArea* CWorldEditor::ActiveArea()
{
return mpArea;
else
{
setWindowTitle(QString("Prime World Editor - %1[*]").arg(TO_QSTRING(WorldName)));
}
// Emit signals
emit LayersModified();
}
bool CWorldEditor::CheckUnsavedChanges()
@ -228,6 +241,110 @@ bool CWorldEditor::Save()
}
}
void CWorldEditor::OnPropertyModified(IProperty *pProp)
{
bool EditorProperty = false;
if (!mSelection.isEmpty() && mSelection.front()->NodeType() == eScriptNode)
{
CScriptNode *pScript = static_cast<CScriptNode*>(mSelection.front());
pScript->PropertyModified(pProp);
// Check editor property
if (pScript->Object()->IsEditorProperty(pProp))
EditorProperty = true;
// If this is an editor property, update other parts of the UI to reflect the new value.
if (EditorProperty)
{
UpdateStatusBar();
UpdateSelectionUI();
}
// If this is a model/character, then we'll treat this as a modified selection. This is to make sure the selection bounds updates.
if (pProp->Type() == eFileProperty)
{
CFileTemplate *pFile = static_cast<CFileTemplate*>(pProp->Template());
if (pFile->AcceptsExtension("CMDL") || pFile->AcceptsExtension("ANCS") || pFile->AcceptsExtension("CHAR"))
NotifySelectionModified();
}
else if (pProp->Type() == eCharacterProperty)
NotifySelectionModified();
// Emit signal so other widgets can react to the property change
emit PropertyModified(pProp, EditorProperty);
}
}
void CWorldEditor::SetSelectionActive(bool Active)
{
// Gather list of selected objects that actually have Active properties
QVector<CScriptObject*> Objects;
foreach (CSceneNode *pNode, mSelection)
{
if (pNode->NodeType() == eScriptNode)
{
CScriptNode *pScript = static_cast<CScriptNode*>(pNode);
CScriptObject *pInst = pScript->Object();
IProperty *pActive = pInst->ActiveProperty();
if (pActive)
Objects << pInst;
}
}
if (!Objects.isEmpty())
{
mUndoStack.beginMacro("Toggle Active");
foreach (CScriptObject *pInst, Objects)
{
IProperty *pActive = pInst->ActiveProperty();
IPropertyValue *pOld = pActive->RawValue()->Clone();
pInst->SetActive(Active);
mUndoStack.push(new CEditScriptPropertyCommand(pActive, this, pOld, true));
}
mUndoStack.endMacro();
}
}
void CWorldEditor::SetSelectionInstanceNames(const QString& rkNewName, bool IsDone)
{
// todo: this only supports one node at a time because a macro prevents us from merging undo commands
// this is fine right now because this function is only ever called with a selection of one node, but probably want to fix in the future
if (mSelection.size() == 1 && mSelection.front()->NodeType() == eScriptNode)
{
CScriptNode *pNode = static_cast<CScriptNode*>(mSelection.front());
CScriptObject *pInst = pNode->Object();
IProperty *pName = pInst->InstanceNameProperty();
if (pName)
{
TString NewName = TO_TSTRING(rkNewName);
IPropertyValue *pOld = pName->RawValue()->Clone();
pInst->SetName(NewName);
mUndoStack.push(new CEditScriptPropertyCommand(pName, this, pOld, IsDone, "Edit Instance Name"));
}
}
}
void CWorldEditor::SetSelectionLayer(CScriptLayer *pLayer)
{
QList<CScriptNode*> ScriptNodes;
foreach (CSceneNode *pNode, mSelection)
{
if (pNode->NodeType() == eScriptNode)
ScriptNodes << static_cast<CScriptNode*>(pNode);
}
if (!ScriptNodes.isEmpty())
mUndoStack.push(new CChangeLayerCommand(this, ScriptNodes, pLayer));
}
void CWorldEditor::UpdateStatusBar()
{
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
@ -368,7 +485,13 @@ void CWorldEditor::OnUndoStackIndexChanged()
{
const QUndoCommand *pkQCmd = mUndoStack.command(iIdx);
if (pkQCmd->childCount() > 0)
if (const IUndoCommand *pkCmd = dynamic_cast<const IUndoCommand*>(pkQCmd))
{
if (pkCmd->AffectsCleanState())
IsClean = false;
}
else if (pkQCmd->childCount() > 0)
{
for (int iChild = 0; iChild < pkQCmd->childCount(); iChild++)
{
@ -382,14 +505,6 @@ void CWorldEditor::OnUndoStackIndexChanged()
}
}
else
{
const IUndoCommand *pkCmd = static_cast<const IUndoCommand*>(pkQCmd);
if (pkCmd->AffectsCleanState())
IsClean = false;
}
if (!IsClean) break;
}

View File

@ -43,11 +43,17 @@ public:
void closeEvent(QCloseEvent *pEvent);
bool eventFilter(QObject *pObj, QEvent *pEvent);
void SetArea(CWorld *pWorld, CGameArea *pArea, u32 AreaIndex);
CGameArea* ActiveArea();
bool CheckUnsavedChanges();
inline CGameArea* ActiveArea() const { return mpArea; }
inline EGame CurrentGame() const { return mpArea->Version(); }
public slots:
bool Save();
void OnPropertyModified(IProperty *pProp);
void SetSelectionActive(bool Active);
void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone);
void SetSelectionLayer(CScriptLayer *pLayer);
void UpdateStatusBar();
void UpdateGizmoUI();
@ -89,6 +95,12 @@ private slots:
void on_ActionSelectAll_triggered();
void on_ActionInvertSelection_triggered();
void on_ActionEditPoiToWorldMap_triggered();
signals:
void LayersModified();
void InstancesLayerAboutToChange();
void InstancesLayerChanged(const QList<CScriptNode*>& rkInstanceList);
void PropertyModified(IProperty *pProp, bool IsEditorProperty);
};
#endif // CWORLDEDITOR_H

View File

@ -20,7 +20,7 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="CSceneViewport" name="MainViewport" native="true">
@ -251,19 +251,7 @@
<attribute name="toolTip">
<string>Create</string>
</attribute>
</widget>
<widget class="QWidget" name="ModifyTab">
<attribute name="icon">
<iconset resource="../Icons.qrc">
<normaloff>:/icons/Modify.png</normaloff>:/icons/Modify.png</iconset>
</attribute>
<attribute name="title">
<string/>
</attribute>
<attribute name="toolTip">
<string>Modify</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
@ -277,7 +265,62 @@
<number>0</number>
</property>
<item>
<widget class="WModifyTab" name="ModifyTabContents" native="true"/>
<widget class="WEditorProperties" name="CreateTabEditorProperties" native="true"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="ModifyTab">
<attribute name="icon">
<iconset resource="../Icons.qrc">
<normaloff>:/icons/Modify.png</normaloff>:/icons/Modify.png</iconset>
</attribute>
<attribute name="title">
<string/>
</attribute>
<attribute name="toolTip">
<string>Modify</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="WEditorProperties" name="ModifyTabEditorProperties" native="true"/>
</item>
<item>
<widget class="WModifyTab" name="ModifyTabContents" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
@ -292,7 +335,7 @@
<attribute name="toolTip">
<string>Instances</string>
</attribute>
<layout class="QHBoxLayout" name="InstancesTabLayout">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
@ -306,7 +349,24 @@
<number>0</number>
</property>
<item>
<widget class="WInstancesTab" name="InstancesTabContents" native="true"/>
<widget class="WEditorProperties" name="InstancesTabEditorProperties" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="WInstancesTab" name="InstancesTabContents" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
@ -321,6 +381,36 @@
<attribute name="toolTip">
<string>Display</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="WEditorProperties" name="DisplayTabEditorProperties" native="true"/>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="WorldTab">
<attribute name="icon">
@ -333,6 +423,36 @@
<attribute name="toolTip">
<string>World</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="WEditorProperties" name="WorldTabEditorProperties" native="true"/>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</widget>
@ -771,6 +891,12 @@
<header>Editor/CSceneViewport.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>WEditorProperties</class>
<extends>QWidget</extends>
<header>Editor/WorldEditor/WEditorProperties.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../Icons.qrc"/>

View File

@ -0,0 +1,196 @@
#include "WEditorProperties.h"
#include "Editor/Undo/CEditScriptPropertyCommand.h"
#include <Core/Resource/Script/CScriptLayer.h>
WEditorProperties::WEditorProperties(QWidget *pParent /*= 0*/)
: QWidget(pParent)
, mpEditor(nullptr)
, mpDisplayNode(nullptr)
, mHasEditedName(false)
{
mpActiveCheckBox = new QCheckBox;
mpActiveCheckBox->setToolTip("Active");
mpInstanceNameLineEdit = new QLineEdit;
mpInstanceNameLineEdit->setToolTip("Instance Name");
mpNameLayout = new QHBoxLayout;
mpNameLayout->addWidget(mpActiveCheckBox);
mpNameLayout->addWidget(mpInstanceNameLineEdit);
mpLayersLabel = new QLabel;
mpLayersLabel->setText("Layer:");
mpLayersLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
mpLayersComboBox = new QComboBox;
mpLayersComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
mpLayersLayout = new QHBoxLayout;
mpLayersLayout->addWidget(mpLayersLabel);
mpLayersLayout->addWidget(mpLayersComboBox);
mpMainLayout = new QVBoxLayout;
mpMainLayout->addLayout(mpNameLayout);
mpMainLayout->addLayout(mpLayersLayout);
mpMainLayout->setContentsMargins(6, 6, 6, 0);
mpMainLayout->setSpacing(3);
setLayout(mpMainLayout);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QFont Font = font();
Font.setPointSize(10);
setFont(Font);
mpInstanceNameLineEdit->setFont(Font);
mpLayersLabel->setFont(Font);
QFont ComboFont = mpLayersComboBox->font();
ComboFont.setPointSize(10);
mpLayersComboBox->setFont(ComboFont);
connect(mpActiveCheckBox, SIGNAL(clicked()), this, SLOT(OnActiveChanged()));
connect(mpInstanceNameLineEdit, SIGNAL(textEdited(QString)), this, SLOT(OnInstanceNameEdited()));
connect(mpInstanceNameLineEdit, SIGNAL(editingFinished()), this, SLOT(OnInstanceNameEditFinished()));
connect(mpLayersComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnLayerChanged()));
}
void WEditorProperties::SyncToEditor(CWorldEditor *pEditor)
{
if (mpEditor)
disconnect(mpEditor, 0, this, 0);
mpEditor = pEditor;
connect(mpEditor, SIGNAL(SelectionModified()), this, SLOT(OnSelectionModified()));
connect(mpEditor, SIGNAL(LayersModified()), this, SLOT(OnLayersModified()));
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(OnInstancesLayerChanged(QList<CScriptNode*>)));
connect(mpEditor, SIGNAL(PropertyModified(IProperty*,bool)), this, SLOT(OnPropertyModified(IProperty*,bool)));
OnLayersModified();
}
void WEditorProperties::SetLayerComboBox()
{
mpLayersComboBox->blockSignals(true);
if (mpDisplayNode && mpDisplayNode->NodeType() == eScriptNode)
{
CScriptNode *pScript = static_cast<CScriptNode*>(mpDisplayNode);
CScriptLayer *pLayer = pScript->Object()->Layer();
for (u32 iLyr = 0; iLyr < mpEditor->ActiveArea()->GetScriptLayerCount(); iLyr++)
{
if (mpEditor->ActiveArea()->GetScriptLayer(iLyr) == pLayer)
{
mpLayersComboBox->setCurrentIndex(iLyr);
break;
}
}
mpLayersComboBox->setEnabled(true);
}
else
{
mpLayersComboBox->setCurrentIndex(-1);
mpLayersComboBox->setEnabled(false);
}
mpLayersComboBox->blockSignals(false);
}
// ************ PUBLIC SLOTS ************
void WEditorProperties::OnSelectionModified()
{
const QList<CSceneNode*>& rkSelection = mpEditor->GetSelection();
mpDisplayNode = (rkSelection.size() == 1 ? rkSelection.front() : nullptr);
if (rkSelection.empty() || rkSelection.size() != 1 || mpDisplayNode->NodeType() != eScriptNode)
{
mpActiveCheckBox->setChecked(false);
mpActiveCheckBox->setEnabled(false);
mpInstanceNameLineEdit->setEnabled(false);
if (rkSelection.empty())
mpInstanceNameLineEdit->clear();
else if (mpDisplayNode)
mpInstanceNameLineEdit->setText(TO_QSTRING(mpDisplayNode->Name()));
else
mpInstanceNameLineEdit->setText(QString("[%1 objects selected]").arg(rkSelection.size()));
}
else
{
UpdatePropertyValues();
}
SetLayerComboBox();
}
void WEditorProperties::OnPropertyModified(IProperty* /*pProp*/, bool IsEditorProperty)
{
if (!mpInstanceNameLineEdit->hasFocus())
{
if (mpDisplayNode->NodeType() == eScriptNode && IsEditorProperty)
UpdatePropertyValues();
}
}
void WEditorProperties::OnInstancesLayerChanged(const QList<CScriptNode*>& rkNodeList)
{
if (rkNodeList.contains((CScriptNode*) mpDisplayNode))
SetLayerComboBox();
}
void WEditorProperties::OnLayersModified()
{
CGameArea *pArea = mpEditor->ActiveArea();
mpLayersComboBox->clear();
if (pArea)
{
for (u32 iLyr = 0; iLyr < pArea->GetScriptLayerCount(); iLyr++)
mpLayersComboBox->addItem(TO_QSTRING(pArea->GetScriptLayer(iLyr)->Name()));
}
SetLayerComboBox();
}
void WEditorProperties::UpdatePropertyValues()
{
CScriptNode *pScript = static_cast<CScriptNode*>(mpDisplayNode);
CScriptObject *pInst = pScript->Object();
mpActiveCheckBox->setChecked(pInst->IsActive());
mpActiveCheckBox->setEnabled(pInst->ActiveProperty() != nullptr);
mpInstanceNameLineEdit->blockSignals(true);
mpInstanceNameLineEdit->setText(TO_QSTRING(pInst->InstanceName()));
mpInstanceNameLineEdit->setEnabled(pInst->InstanceNameProperty() != nullptr);
mpInstanceNameLineEdit->blockSignals(false);
}
// ************ PROTECTED SLOTS ************
void WEditorProperties::OnActiveChanged()
{
mpEditor->SetSelectionActive(mpActiveCheckBox->isChecked());
}
void WEditorProperties::OnInstanceNameEdited()
{
// This function triggers when the user is actively editing the Instance Name line edit.
mHasEditedName = true;
mpEditor->SetSelectionInstanceNames(mpInstanceNameLineEdit->text(), false);
}
void WEditorProperties::OnInstanceNameEditFinished()
{
// This function triggers when the user is finished editing the Instance Name line edit.
if (mHasEditedName)
mpEditor->SetSelectionInstanceNames(mpInstanceNameLineEdit->text(), true);
mHasEditedName = false;
}
void WEditorProperties::OnLayerChanged()
{
int Index = mpLayersComboBox->currentIndex();
if (Index >= 0)
{
CScriptLayer *pLayer = mpEditor->ActiveArea()->GetScriptLayer(Index);
mpEditor->SetSelectionLayer(pLayer);
}
}

View File

@ -0,0 +1,51 @@
#ifndef WEDITORPROPERTIES_H
#define WEDITORPROPERTIES_H
#include <QWidget>
#include "CWorldEditor.h"
#include <QCheckBox>
#include <QComboBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QVBoxLayout>
class WEditorProperties : public QWidget
{
Q_OBJECT
CWorldEditor *mpEditor;
CSceneNode *mpDisplayNode;
QVBoxLayout *mpMainLayout;
QCheckBox *mpActiveCheckBox;
QLineEdit *mpInstanceNameLineEdit;
QHBoxLayout *mpNameLayout;
QLabel *mpLayersLabel;
QComboBox *mpLayersComboBox;
QHBoxLayout *mpLayersLayout;
bool mHasEditedName;
public:
WEditorProperties(QWidget *pParent = 0);
void SyncToEditor(CWorldEditor *pEditor);
void SetLayerComboBox();
public slots:
void OnSelectionModified();
void OnPropertyModified(IProperty *pProp, bool IsEditorProperty);
void OnInstancesLayerChanged(const QList<CScriptNode*>& rkNodeList);
void OnLayersModified();
void UpdatePropertyValues();
protected slots:
void OnActiveChanged();
void OnInstanceNameEdited();
void OnInstanceNameEditFinished();
void OnLayerChanged();
};
#endif // WEDITORPROPERTIES_H

View File

@ -16,7 +16,6 @@ WModifyTab::WModifyTab(QWidget *pParent) :
ui->PropertyView->header()->resizeSection(0, PropViewWidth * 0.3);
ui->PropertyView->header()->resizeSection(1, PropViewWidth * 0.3);
ui->PropertyView->header()->setSectionResizeMode(1, QHeaderView::Fixed);
connect(ui->PropertyView, SIGNAL(PropertyModified(IProperty*)), this, SLOT(OnPropertyModified(IProperty*)));
mpInLinkModel = new CLinkModel(this);
mpInLinkModel->SetConnectionType(CLinkModel::eIncoming);
@ -86,30 +85,7 @@ void WModifyTab::OnWorldSelectionTransformed()
ui->PropertyView->UpdateEditorProperties(QModelIndex());
}
void WModifyTab::OnPropertyModified(IProperty *pProp)
{
if (mpSelectedNode->NodeType() == eScriptNode)
{
CScriptNode *pNode = static_cast<CScriptNode*>(mpSelectedNode);
pNode->PropertyModified(pProp);
// If this is the instance name property, then other parts of the UI need to be updated to reflect the new name.
if (pNode->Object()->IsEditorProperty(pProp) && pProp->Type() == eStringProperty)
mpWorldEditor->UpdateSelectionUI();
// If this is a model/character, then we'll treat it as a modified selection. This is to make sure the selection bounds updates.
if (pProp->Type() == eFileProperty)
{
CFileTemplate *pFile = static_cast<CFileTemplate*>(pProp->Template());
if (pFile->AcceptsExtension("CMDL") || pFile->AcceptsExtension("ANCS") || pFile->AcceptsExtension("CHAR"))
mpWorldEditor->NotifySelectionModified();
}
else if (pProp->Type() == eCharacterProperty)
mpWorldEditor->NotifySelectionModified();
}
}
// ************ PRIVATE SLOTS ************
void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index)
{
if (Index.column() == 0)

View File

@ -36,7 +36,6 @@ public:
public slots:
void OnWorldSelectionTransformed();
void OnPropertyModified(IProperty *pProp);
private:
Ui::WModifyTab *ui;

View File

@ -13,7 +13,10 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="MainLayout">
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -105,7 +108,7 @@
<x>0</x>
<y>0</y>
<width>276</width>
<height>457</height>
<height>460</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">

View File

@ -30,7 +30,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/>
</properties>
<assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -18,6 +18,7 @@
<assets>
<model source="file">script/common/CameraWaypoint.cmdl</model>
</assets>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -16,6 +16,7 @@
<assets>
<model source="file">script/common/CameraWaypoint.cmdl</model>
</assets>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -17,6 +17,7 @@
<assets>
<model source="file">script/common/SpiderBallWaypoint.cmdl</model>
</assets>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -25,6 +25,7 @@
<assets>
<model source="file">script/common/Waypoint.CMDL</model>
</assets>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<ScriptTemplate version="4">
<name>AIHint</name>
<properties>
@ -30,7 +30,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/>
</properties>
<assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -21,7 +21,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/>
</properties>
<assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -21,7 +21,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/>
</properties>
<assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -30,7 +30,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/>
</properties>
<assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -30,7 +30,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/>
</properties>
<assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>

View File

@ -21,7 +21,6 @@
<property name="Active" ID="0x255A4580:0x41435456"/>
</properties>
<assets/>
<preview_scale>0.5</preview_scale>
<rotation_type>enabled</rotation_type>
<scale_type>enabled</scale_type>
</editor>