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);
mpLightParameters = mpTemplate->FindLightParameters(mpProperties);
mHasInGameModel = mpTemplate->HasInGameModel(mpProperties);
mVolumeShape = mpTemplate->VolumeShape(this);
mVolumeScale = mpTemplate->VolumeScale(this);
EvaluateDisplayModel();
EvaluateBillboard();
EvaluateCollisionModel();
EvaluateVolume();
}
void CScriptObject::EvaluateDisplayModel()
@ -53,6 +52,23 @@ void CScriptObject::EvaluateCollisionModel()
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 ************
IProperty* CScriptObject::PropertyByIndex(u32 index) const
{

View File

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

View File

@ -283,6 +283,13 @@ public:
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
{
return mAcceptedExtensions;
@ -404,10 +411,16 @@ class CBitfieldTemplate : public TLongTemplate
public:
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)
: TLongTemplate(ID, rkName, CookPreference, pParent) {}
: TLongTemplate(ID, rkName, CookPreference, pParent)
{
mDefaultValue.SetHexStringOutput(true);
}
virtual EPropertyType Type() const { return eBitfieldProperty; }
virtual bool CanHaveDefault() const { return true; }

View File

@ -28,6 +28,7 @@ CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pOb
CScriptTemplate *pTemp = Template();
// Determine transform
mHasValidPosition = pTemp->HasPosition();
mPosition = mpInstance->Position();
mRotation = CQuaternion::FromEuler(mpInstance->Rotation());
mScale = mpInstance->Scale();
@ -41,36 +42,15 @@ CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pOb
mpCollisionNode->SetCollision(mpInstance->GetCollision());
// Create preview volume node
mHasValidPosition = pTemp->HasPosition();
mpVolumePreviewNode = new CModelNode(pScene, this, nullptr);
if (pTemp->ScaleType() == CScriptTemplate::eScaleVolume)
{
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);
UpdatePreviewVolume();
if (mHasVolumePreview)
{
mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel);
mpVolumePreviewNode->SetInheritance(true, (shape != eAxisAlignedBoxShape), true);
mpVolumePreviewNode->SetScale(mpInstance->VolumeScale());
mpVolumePreviewNode->SetInheritance(true, (mpInstance->VolumeShape() != eAxisAlignedBoxShape), true);
mpVolumePreviewNode->ForceAlphaEnabled(true);
}
}
@ -395,6 +375,89 @@ CColor CScriptNode::TintColor(const SViewInfo &ViewInfo) const
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()
{
if (!mHasValidPosition)

View File

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

View File

@ -42,15 +42,21 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
{
switch (pProp->Type())
{
case eBoolProperty:
pOut = new QCheckBox(pParent);
{
QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
pOut = pCheckBox;
break;
}
case eShortProperty:
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT16_MIN);
pSpinBox->setMaximum(INT16_MAX);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
pOut = pSpinBox;
break;
}
@ -60,6 +66,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))
pOut = pSpinBox;
break;
}
@ -67,9 +74,9 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
case eFloatProperty:
{
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pSpinBox->setSingleStep(0.1);
pOut = pSpinBox;
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
break;
}
@ -82,17 +89,23 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
}
case eStringProperty:
pOut = new QLineEdit(pParent);
{
QLineEdit *pLineEdit = new QLineEdit(pParent);
CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString))
pOut = pLineEdit;
break;
}
case eEnumProperty:
{
QComboBox *pComboBox = new QComboBox(pParent);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pProp->Template());
for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++)
pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum)));
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
pOut = pComboBox;
break;
}
@ -102,12 +115,15 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
WResourceSelector *pSelector = new WResourceSelector(pParent);
CFileTemplate *pTemp = static_cast<CFileTemplate*>(pProp->Template());
pSelector->SetAllowedExtensions(pTemp->Extensions());
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString))
pOut = pSelector;
break;
}
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);
pSpinBox->setMinimum(0);
pSpinBox->setMaximum(999);
@ -129,13 +145,16 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
// Handle bitfield
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
else
{
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pSpinBox->setSingleStep(0.1);
// Limit to range of 0-1 on colors
@ -147,6 +166,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
pSpinBox->setMaximum(1.0);
}
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pOut = pSpinBox;
}
}
@ -442,9 +462,12 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
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)
@ -483,12 +506,14 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
else
pSelector->SetAllowedExtensions("CHAR");
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(QString))
return pSelector;
}
if (Type == eEnumProperty)
{
QComboBox *pComboBox = new QComboBox(pParent);
CAnimSet *pAnimSet = Params.AnimSet();
if (pAnimSet)
@ -497,11 +522,16 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
pComboBox->addItem(TO_QSTRING(pAnimSet->getNodeName(iChr)));
}
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
return pComboBox;
}
if (Type == eLongProperty)
return new WIntegralSpinBox(pParent);
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
return pSpinBox;
}
return nullptr;
}

View File

@ -25,6 +25,9 @@ public:
public slots:
void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex);
signals:
void PropertyEdited(const QModelIndex& rkIndex, bool IsDone) const;
};
#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(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(mpDelegate, SIGNAL(PropertyEdited(QModelIndex,bool)), this, SIGNAL(PropertyModified(QModelIndex,bool)));
}
void CPropertyView::setModel(QAbstractItemModel *pModel)

View File

@ -18,8 +18,13 @@ public:
bool event(QEvent *pEvent);
void SetBaseStruct(CPropertyStruct *pStruct);
inline CPropertyModel* PropertyModel() const { return mpModel; }
public slots:
void SetPersistentEditors(const QModelIndex& rkIndex);
signals:
void PropertyModified(const QModelIndex& rkIndex, bool IsDone);
};
#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(1, PropViewWidth * 0.3);
ui->PropertyView->header()->setSectionResizeMode(1, QHeaderView::Fixed);
connect(ui->PropertyView, SIGNAL(PropertyModified(QModelIndex,bool)), this, SLOT(OnPropertyModified(QModelIndex,bool)));
mpInLinkModel = new CLinkModel(this);
mpInLinkModel->SetConnectionType(CLinkModel::eIncoming);
@ -75,6 +76,16 @@ void WModifyTab::ClearUI()
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)
{
if (Index.column() == 0)

View File

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

View File

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

View File

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