Notify script nodes when their properties are modified

This commit is contained in:
parax0 2016-01-30 11:21:29 -07:00
parent b4c8226e15
commit 2e6024b413
13 changed files with 191 additions and 41 deletions

View File

@ -31,11 +31,10 @@ CScriptObject::~CScriptObject()
mpActive = mpTemplate->FindActive(mpProperties); mpActive = mpTemplate->FindActive(mpProperties);
mpLightParameters = mpTemplate->FindLightParameters(mpProperties); mpLightParameters = mpTemplate->FindLightParameters(mpProperties);
mHasInGameModel = mpTemplate->HasInGameModel(mpProperties); mHasInGameModel = mpTemplate->HasInGameModel(mpProperties);
mVolumeShape = mpTemplate->VolumeShape(this);
mVolumeScale = mpTemplate->VolumeScale(this);
EvaluateDisplayModel(); EvaluateDisplayModel();
EvaluateBillboard(); EvaluateBillboard();
EvaluateCollisionModel(); EvaluateCollisionModel();
EvaluateVolume();
} }
void CScriptObject::EvaluateDisplayModel() void CScriptObject::EvaluateDisplayModel()
@ -53,6 +52,23 @@ void CScriptObject::EvaluateCollisionModel()
mpCollision = mpTemplate->FindCollision(mpProperties); mpCollision = mpTemplate->FindCollision(mpProperties);
} }
void CScriptObject::EvaluateVolume()
{
mVolumeShape = mpTemplate->VolumeShape(this);
mVolumeScale = mpTemplate->VolumeScale(this);
}
bool CScriptObject::IsEditorProperty(IProperty *pProp)
{
return ( (pProp == mpInstanceName) ||
(pProp == mpPosition) ||
(pProp == mpRotation) ||
(pProp == mpScale) ||
(pProp == mpActive) ||
(pProp->Parent() == mpLightParameters)
);
}
// ************ GETTERS ************ // ************ GETTERS ************
IProperty* CScriptObject::PropertyByIndex(u32 index) const IProperty* CScriptObject::PropertyByIndex(u32 index) const
{ {

View File

@ -48,6 +48,8 @@ public:
void EvaluateDisplayModel(); void EvaluateDisplayModel();
void EvaluateBillboard(); void EvaluateBillboard();
void EvaluateCollisionModel(); void EvaluateCollisionModel();
void EvaluateVolume();
bool IsEditorProperty(IProperty *pProp);
CScriptTemplate* Template() const; CScriptTemplate* Template() const;
CMasterTemplate* MasterTemplate() const; CMasterTemplate* MasterTemplate() const;

View File

@ -283,6 +283,13 @@ public:
mAcceptedExtensions = rkExtensions; mAcceptedExtensions = rkExtensions;
} }
bool AcceptsExtension(const TString& rkExtension)
{
for (auto it = mAcceptedExtensions.begin(); it != mAcceptedExtensions.end(); it++)
if (*it == rkExtension) return true;
return false;
}
const TStringList& Extensions() const const TStringList& Extensions() const
{ {
return mAcceptedExtensions; return mAcceptedExtensions;
@ -404,10 +411,16 @@ class CBitfieldTemplate : public TLongTemplate
public: public:
CBitfieldTemplate(u32 ID, CStructTemplate *pParent = 0) CBitfieldTemplate(u32 ID, CStructTemplate *pParent = 0)
: TLongTemplate(ID, pParent) {} : TLongTemplate(ID, pParent)
{
mDefaultValue.SetHexStringOutput(true);
}
CBitfieldTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CStructTemplate *pParent = 0) CBitfieldTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CStructTemplate *pParent = 0)
: TLongTemplate(ID, rkName, CookPreference, pParent) {} : TLongTemplate(ID, rkName, CookPreference, pParent)
{
mDefaultValue.SetHexStringOutput(true);
}
virtual EPropertyType Type() const { return eBitfieldProperty; } virtual EPropertyType Type() const { return eBitfieldProperty; }
virtual bool CanHaveDefault() const { return true; } virtual bool CanHaveDefault() const { return true; }

View File

@ -28,6 +28,7 @@ CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pOb
CScriptTemplate *pTemp = Template(); CScriptTemplate *pTemp = Template();
// Determine transform // Determine transform
mHasValidPosition = pTemp->HasPosition();
mPosition = mpInstance->Position(); mPosition = mpInstance->Position();
mRotation = CQuaternion::FromEuler(mpInstance->Rotation()); mRotation = CQuaternion::FromEuler(mpInstance->Rotation());
mScale = mpInstance->Scale(); mScale = mpInstance->Scale();
@ -41,36 +42,15 @@ CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pOb
mpCollisionNode->SetCollision(mpInstance->GetCollision()); mpCollisionNode->SetCollision(mpInstance->GetCollision());
// Create preview volume node // Create preview volume node
mHasValidPosition = pTemp->HasPosition(); mpVolumePreviewNode = new CModelNode(pScene, this, nullptr);
if (pTemp->ScaleType() == CScriptTemplate::eScaleVolume) if (pTemp->ScaleType() == CScriptTemplate::eScaleVolume)
{ {
EVolumeShape shape = mpInstance->VolumeShape(); UpdatePreviewVolume();
TResPtr<CModel> pVolumeModel = nullptr;
switch (shape)
{
case eAxisAlignedBoxShape:
case eBoxShape:
pVolumeModel = gResCache.GetResource("../resources/VolumeBox.cmdl");
break;
case eEllipsoidShape:
pVolumeModel = gResCache.GetResource("../resources/VolumeSphere.cmdl");
break;
case eCylinderShape:
pVolumeModel = gResCache.GetResource("../resources/VolumeCylinder.cmdl");
break;
}
mHasVolumePreview = (pVolumeModel != nullptr);
if (mHasVolumePreview) if (mHasVolumePreview)
{ {
mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel); mpVolumePreviewNode->SetInheritance(true, (mpInstance->VolumeShape() != eAxisAlignedBoxShape), true);
mpVolumePreviewNode->SetInheritance(true, (shape != eAxisAlignedBoxShape), true);
mpVolumePreviewNode->SetScale(mpInstance->VolumeScale());
mpVolumePreviewNode->ForceAlphaEnabled(true); mpVolumePreviewNode->ForceAlphaEnabled(true);
} }
} }
@ -395,6 +375,89 @@ CColor CScriptNode::TintColor(const SViewInfo &ViewInfo) const
return BaseColor; return BaseColor;
} }
void CScriptNode::PropertyModified(IProperty *pProp)
{
// Update volume
if ( (pProp->Type() == eBoolProperty) || (pProp->Type() == eByteProperty) || (pProp->Type() == eShortProperty) ||
(pProp->Type() == eLongProperty) || (pProp->Type() == eEnumProperty) )
{
mpInstance->EvaluateVolume();
UpdatePreviewVolume();
}
// Update resources
if (pProp->Type() == eCharacterProperty)
{
mpInstance->EvaluateDisplayModel();
mpActiveModel = mpInstance->GetDisplayModel();
}
else if (pProp->Type() == eFileProperty)
{
CFileTemplate *pFile = static_cast<CFileTemplate*>(pProp->Template());
if (pFile->AcceptsExtension("CMDL") || pFile->AcceptsExtension("ANCS") || pFile->AcceptsExtension("CHAR"))
{
mpInstance->EvaluateDisplayModel();
mpActiveModel = mpInstance->GetDisplayModel();
}
else if (pFile->AcceptsExtension("TXTR"))
{
mpInstance->EvaluateBillboard();
mpBillboard = mpInstance->GetBillboard();
}
else if (pFile->AcceptsExtension("DCLN"))
{
mpInstance->EvaluateCollisionModel();
mpCollisionNode->SetCollision(mpInstance->GetCollision());
}
}
// Update other editor properties
if (mpInstance->IsEditorProperty(pProp))
{
SetName("[" + mpInstance->Template()->Name() + "] " + mpInstance->InstanceName());
mPosition = mpInstance->Position();
mRotation = CQuaternion::FromEuler(mpInstance->Rotation());
mScale = mpInstance->Scale();
MarkTransformChanged();
SetLightLayerIndex(mpLightParameters->LightLayerIndex());
}
// Update script extra
if (mpExtra) mpExtra->PropertyModified(pProp);
}
void CScriptNode::UpdatePreviewVolume()
{
EVolumeShape Shape = mpInstance->VolumeShape();
TResPtr<CModel> pVolumeModel = nullptr;
switch (Shape)
{
case eAxisAlignedBoxShape:
case eBoxShape:
pVolumeModel = gResCache.GetResource("../resources/VolumeBox.cmdl");
break;
case eEllipsoidShape:
pVolumeModel = gResCache.GetResource("../resources/VolumeSphere.cmdl");
break;
case eCylinderShape:
pVolumeModel = gResCache.GetResource("../resources/VolumeCylinder.cmdl");
break;
}
mHasVolumePreview = (pVolumeModel != nullptr);
if (mHasVolumePreview)
{
mpVolumePreviewNode->SetModel(pVolumeModel);
mpVolumePreviewNode->SetScale(mpInstance->VolumeScale());
}
}
void CScriptNode::GeneratePosition() void CScriptNode::GeneratePosition()
{ {
if (!mHasValidPosition) if (!mHasValidPosition)

View File

@ -38,6 +38,8 @@ public:
CColor TintColor(const SViewInfo &ViewInfo) const; CColor TintColor(const SViewInfo &ViewInfo) const;
CColor WireframeColor() const; CColor WireframeColor() const;
void PropertyModified(IProperty *pProp);
void UpdatePreviewVolume();
void GeneratePosition(); void GeneratePosition();
CScriptObject* Object() const; CScriptObject* Object() const;
CScriptTemplate* Template() const; CScriptTemplate* Template() const;

View File

@ -42,15 +42,21 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
{ {
switch (pProp->Type()) switch (pProp->Type())
{ {
case eBoolProperty: case eBoolProperty:
pOut = new QCheckBox(pParent); {
QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
pOut = pCheckBox;
break; break;
}
case eShortProperty: case eShortProperty:
{ {
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT16_MIN); pSpinBox->setMinimum(INT16_MIN);
pSpinBox->setMaximum(INT16_MAX); pSpinBox->setMaximum(INT16_MAX);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
pOut = pSpinBox; pOut = pSpinBox;
break; break;
} }
@ -60,6 +66,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT32_MIN); pSpinBox->setMinimum(INT32_MIN);
pSpinBox->setMaximum(INT32_MAX); pSpinBox->setMaximum(INT32_MAX);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
pOut = pSpinBox; pOut = pSpinBox;
break; break;
} }
@ -67,9 +74,9 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
case eFloatProperty: case eFloatProperty:
{ {
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent); WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pSpinBox->setSingleStep(0.1); pSpinBox->setSingleStep(0.1);
pOut = pSpinBox; pOut = pSpinBox;
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
break; break;
} }
@ -82,17 +89,23 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
} }
case eStringProperty: case eStringProperty:
pOut = new QLineEdit(pParent); {
QLineEdit *pLineEdit = new QLineEdit(pParent);
CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString))
pOut = pLineEdit;
break; break;
}
case eEnumProperty: case eEnumProperty:
{ {
QComboBox *pComboBox = new QComboBox(pParent); QComboBox *pComboBox = new QComboBox(pParent);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pProp->Template()); CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pProp->Template());
for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++) for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++)
pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum))); pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum)));
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
pOut = pComboBox; pOut = pComboBox;
break; break;
} }
@ -102,12 +115,15 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
WResourceSelector *pSelector = new WResourceSelector(pParent); WResourceSelector *pSelector = new WResourceSelector(pParent);
CFileTemplate *pTemp = static_cast<CFileTemplate*>(pProp->Template()); CFileTemplate *pTemp = static_cast<CFileTemplate*>(pProp->Template());
pSelector->SetAllowedExtensions(pTemp->Extensions()); pSelector->SetAllowedExtensions(pTemp->Extensions());
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString))
pOut = pSelector; pOut = pSelector;
break; break;
} }
case eArrayProperty: case eArrayProperty:
{ {
// No relay here, would prefer user to be sure of their change before it's reflected on the UI
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(0); pSpinBox->setMinimum(0);
pSpinBox->setMaximum(999); pSpinBox->setMaximum(999);
@ -129,13 +145,16 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
// Handle bitfield // Handle bitfield
else if (pProp->Type() == eBitfieldProperty) else if (pProp->Type() == eBitfieldProperty)
pOut = new QCheckBox(pParent); {
QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
pOut = pCheckBox;
}
// Handle vector/color // Handle vector/color
else else
{ {
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent); WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pSpinBox->setSingleStep(0.1); pSpinBox->setSingleStep(0.1);
// Limit to range of 0-1 on colors // Limit to range of 0-1 on colors
@ -147,6 +166,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
pSpinBox->setMaximum(1.0); pSpinBox->setMaximum(1.0);
} }
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pOut = pSpinBox; pOut = pSpinBox;
} }
} }
@ -442,9 +462,12 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
pColor->Set(Value); pColor->Set(Value);
} }
mpModel->dataChanged(rkIndex.parent(), rkIndex.parent()); QModelIndex ParentWidgetIndex = mpModel->index(rkIndex.parent().row(), 1, rkIndex.parent().parent());
mpModel->dataChanged(ParentWidgetIndex, ParentWidgetIndex);
} }
} }
emit PropertyEdited(rkIndex, true);
} }
bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent) bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent)
@ -483,12 +506,14 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
else else
pSelector->SetAllowedExtensions("CHAR"); pSelector->SetAllowedExtensions("CHAR");
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString))
return pSelector; return pSelector;
} }
if (Type == eEnumProperty) if (Type == eEnumProperty)
{ {
QComboBox *pComboBox = new QComboBox(pParent); QComboBox *pComboBox = new QComboBox(pParent);
CAnimSet *pAnimSet = Params.AnimSet(); CAnimSet *pAnimSet = Params.AnimSet();
if (pAnimSet) if (pAnimSet)
@ -497,11 +522,16 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
pComboBox->addItem(TO_QSTRING(pAnimSet->getNodeName(iChr))); pComboBox->addItem(TO_QSTRING(pAnimSet->getNodeName(iChr)));
} }
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
return pComboBox; return pComboBox;
} }
if (Type == eLongProperty) if (Type == eLongProperty)
return new WIntegralSpinBox(pParent); {
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
return pSpinBox;
}
return nullptr; return nullptr;
} }

View File

@ -25,6 +25,9 @@ public:
public slots: public slots:
void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex); void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex);
signals:
void PropertyEdited(const QModelIndex& rkIndex, bool IsDone) const;
}; };
#endif // CPROPERTYDELEGATE_H #endif // CPROPERTYDELEGATE_H

View File

@ -16,6 +16,7 @@ CPropertyView::CPropertyView(QWidget *pParent)
connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex))); connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex))); connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(mpDelegate, SIGNAL(PropertyEdited(QModelIndex,bool)), this, SIGNAL(PropertyModified(QModelIndex,bool)));
} }
void CPropertyView::setModel(QAbstractItemModel *pModel) void CPropertyView::setModel(QAbstractItemModel *pModel)

View File

@ -18,8 +18,13 @@ public:
bool event(QEvent *pEvent); bool event(QEvent *pEvent);
void SetBaseStruct(CPropertyStruct *pStruct); void SetBaseStruct(CPropertyStruct *pStruct);
inline CPropertyModel* PropertyModel() const { return mpModel; }
public slots: public slots:
void SetPersistentEditors(const QModelIndex& rkIndex); void SetPersistentEditors(const QModelIndex& rkIndex);
signals:
void PropertyModified(const QModelIndex& rkIndex, bool IsDone);
}; };
#endif // CPROPERTYVIEW_H #endif // CPROPERTYVIEW_H

View File

@ -16,6 +16,7 @@ WModifyTab::WModifyTab(QWidget *pParent) :
ui->PropertyView->header()->resizeSection(0, PropViewWidth * 0.3); ui->PropertyView->header()->resizeSection(0, PropViewWidth * 0.3);
ui->PropertyView->header()->resizeSection(1, PropViewWidth * 0.3); ui->PropertyView->header()->resizeSection(1, PropViewWidth * 0.3);
ui->PropertyView->header()->setSectionResizeMode(1, QHeaderView::Fixed); ui->PropertyView->header()->setSectionResizeMode(1, QHeaderView::Fixed);
connect(ui->PropertyView, SIGNAL(PropertyModified(QModelIndex,bool)), this, SLOT(OnPropertyModified(QModelIndex,bool)));
mpInLinkModel = new CLinkModel(this); mpInLinkModel = new CLinkModel(this);
mpInLinkModel->SetConnectionType(CLinkModel::eIncoming); mpInLinkModel->SetConnectionType(CLinkModel::eIncoming);
@ -75,6 +76,16 @@ void WModifyTab::ClearUI()
ui->LightGroupBox->hide(); ui->LightGroupBox->hide();
} }
void WModifyTab::OnPropertyModified(const QModelIndex& rkIndex, bool /*IsDone*/)
{
if (mpSelectedNode->NodeType() == eScriptNode)
{
CScriptNode *pNode = static_cast<CScriptNode*>(mpSelectedNode);
IProperty *pProperty = ui->PropertyView->PropertyModel()->PropertyForIndex(rkIndex, true);
pNode->PropertyModified(pProperty);
}
}
void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index) void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index)
{ {
if (Index.column() == 0) if (Index.column() == 0)

View File

@ -3,6 +3,7 @@
#include "CLinkModel.h" #include "CLinkModel.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
#include <Core/Scene/CScriptNode.h>
#include <QWidget> #include <QWidget>
#include <QScrollArea> #include <QScrollArea>
@ -33,6 +34,9 @@ public:
void GenerateUI(QList<CSceneNode*>& Selection); void GenerateUI(QList<CSceneNode*>& Selection);
void ClearUI(); void ClearUI();
public slots:
void OnPropertyModified(const QModelIndex& rkIndex, bool IsDone);
private: private:
Ui::WModifyTab *ui; Ui::WModifyTab *ui;

View File

@ -8,8 +8,8 @@
<enumerators> <enumerators>
<enumerator ID="0x482B22F1" name="Box"/> <enumerator ID="0x482B22F1" name="Box"/>
<enumerator ID="0x779DB545" name="Box"/> <enumerator ID="0x779DB545" name="Box"/>
<enumerator ID="0x8392F5E4" name="Cylinder"/> <enumerator ID="0x8392F5E4" name="Ellipsoid"/>
<enumerator ID="0x39ED7B8E" name="Ellipsoid"/> <enumerator ID="0x39ED7B8E" name="Cylinder"/>
</enumerators> </enumerators>
</enum> </enum>
<struct ID="0x77A27411" template="Structs/TriggerInfo.xml"/> <struct ID="0x77A27411" template="Structs/TriggerInfo.xml"/>

View File

@ -6,10 +6,10 @@
<enum ID="0x09ECEE0C"> <enum ID="0x09ECEE0C">
<default>0x482B22F1</default> <default>0x482B22F1</default>
<enumerators> <enumerators>
<enumerator ID="0x482B22F1" name="Unknown 1"/> <enumerator ID="0x482B22F1" name="Box"/>
<enumerator ID="0x779DB545" name="Unknown 2"/> <enumerator ID="0x779DB545" name="Box"/>
<enumerator ID="0x8392F5E4" name="Unknown 3"/> <enumerator ID="0x8392F5E4" name="Ellipsoid"/>
<enumerator ID="0x39ED7B8E" name="Unknown 4"/> <enumerator ID="0x39ED7B8E" name="Cylinder"/>
</enumerators> </enumerators>
</enum> </enum>
<struct ID="0x77A27411" template="Structs/TriggerInfo.xml"/> <struct ID="0x77A27411" template="Structs/TriggerInfo.xml"/>