mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-07-18 02:56:00 +00:00
704 lines
24 KiB
C++
704 lines
24 KiB
C++
#include "CPropertyDelegate.h"
|
|
#include "CPropertyRelay.h"
|
|
|
|
#include "Editor/UICommon.h"
|
|
#include "Editor/Undo/CEditScriptPropertyCommand.h"
|
|
#include "Editor/Undo/CEditIntrinsicPropertyCommand.h"
|
|
#include "Editor/Undo/CResizeScriptArrayCommand.h"
|
|
#include "Editor/Widgets/CResourceSelector.h"
|
|
#include "Editor/Widgets/WColorPicker.h"
|
|
#include "Editor/Widgets/WDraggableSpinBox.h"
|
|
#include "Editor/Widgets/WIntegralSpinBox.h"
|
|
|
|
#include <Core/Resource/Animation/CAnimSet.h>
|
|
#include <Core/Resource/Script/Property/Properties.h>
|
|
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QEvent>
|
|
#include <QLineEdit>
|
|
|
|
// This macro should be used on every widget where changes should be reflected in realtime and not just when the edit is finished.
|
|
#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&))); \
|
|
}
|
|
|
|
CPropertyDelegate::CPropertyDelegate(QObject* pParent /*= 0*/)
|
|
: QStyledItemDelegate(pParent)
|
|
, mpEditor(nullptr)
|
|
, mpModel(nullptr)
|
|
, mInRelayWidgetEdit(false)
|
|
, mEditInProgress(false)
|
|
, mRelaysBlocked(false)
|
|
{
|
|
mpEditor = UICommon::FindAncestor<IEditor>(pParent);
|
|
}
|
|
|
|
void CPropertyDelegate::SetEditor(IEditor* pEditor)
|
|
{
|
|
mpEditor = pEditor;
|
|
}
|
|
|
|
void CPropertyDelegate::SetPropertyModel(CPropertyModel* pModel)
|
|
{
|
|
mpModel = pModel;
|
|
}
|
|
|
|
QWidget* CPropertyDelegate::createEditor(QWidget* pParent, const QStyleOptionViewItem& /*rkOption*/, const QModelIndex& rkIndex) const
|
|
{
|
|
if (!mpModel) return nullptr;
|
|
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false);
|
|
QWidget *pOut = nullptr;
|
|
|
|
if (pProp)
|
|
{
|
|
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
|
|
|
switch (Type)
|
|
{
|
|
|
|
case EPropertyType::Bool:
|
|
{
|
|
QCheckBox *pCheckBox = new QCheckBox(pParent);
|
|
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
|
|
pOut = pCheckBox;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Short:
|
|
{
|
|
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
|
|
pSpinBox->setMinimum(INT16_MIN);
|
|
pSpinBox->setMaximum(INT16_MAX);
|
|
pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
|
|
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
|
|
pOut = pSpinBox;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Int:
|
|
{
|
|
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
|
|
pSpinBox->setMinimum(INT32_MIN);
|
|
pSpinBox->setMaximum(INT32_MAX);
|
|
pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
|
|
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
|
|
pOut = pSpinBox;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Float:
|
|
{
|
|
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
|
|
pSpinBox->setSingleStep(0.1);
|
|
pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
|
|
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
|
|
pOut = pSpinBox;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Color:
|
|
{
|
|
WColorPicker *pColorPicker = new WColorPicker(pParent);
|
|
CONNECT_RELAY(pColorPicker, rkIndex, ColorChanged(QColor))
|
|
pOut = pColorPicker;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Sound:
|
|
{
|
|
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
|
|
pSpinBox->setMinimum(-1);
|
|
pSpinBox->setMaximum(0xFFFF);
|
|
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
|
|
pOut = pSpinBox;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::String:
|
|
{
|
|
QLineEdit *pLineEdit = new QLineEdit(pParent);
|
|
CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString))
|
|
pOut = pLineEdit;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Enum:
|
|
case EPropertyType::Choice:
|
|
{
|
|
QComboBox *pComboBox = new QComboBox(pParent);
|
|
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
|
|
|
|
for (size_t ValueIdx = 0; ValueIdx < pEnum->NumPossibleValues(); ValueIdx++)
|
|
pComboBox->addItem(TO_QSTRING(pEnum->ValueName(ValueIdx)));
|
|
|
|
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
|
|
pOut = pComboBox;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Asset:
|
|
{
|
|
CResourceSelector *pSelector = new CResourceSelector(pParent);
|
|
pSelector->SetFrameVisible(false);
|
|
|
|
CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
|
|
pSelector->SetTypeFilter(pAsset->GetTypeFilter());
|
|
|
|
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*))
|
|
pOut = pSelector;
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Array:
|
|
{
|
|
// 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);
|
|
pOut = pSpinBox;
|
|
break;
|
|
}
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
// Check for sub-property of flags/animation set
|
|
else if (rkIndex.internalId() & 0x80000000)
|
|
{
|
|
pProp = mpModel->PropertyForIndex(rkIndex, true);
|
|
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
|
|
|
// Handle character
|
|
if (Type == EPropertyType::AnimationSet)
|
|
pOut = CreateCharacterEditor(pParent, rkIndex);
|
|
|
|
// Handle flags
|
|
else if (Type == EPropertyType::Flags)
|
|
{
|
|
QCheckBox *pCheckBox = new QCheckBox(pParent);
|
|
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
|
|
pOut = pCheckBox;
|
|
}
|
|
}
|
|
|
|
if (pOut)
|
|
{
|
|
pOut->setFocusPolicy(Qt::StrongFocus);
|
|
QSize Size = mpModel->data(rkIndex, Qt::SizeHintRole).toSize();
|
|
pOut->setFixedHeight(Size.height());
|
|
}
|
|
|
|
return pOut;
|
|
}
|
|
|
|
void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkIndex) const
|
|
{
|
|
BlockRelays(true);
|
|
mEditInProgress = false; // fixes case where user does undo mid-edit
|
|
|
|
if (pEditor)
|
|
{
|
|
// Set editor data for regular property
|
|
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false);
|
|
void* pData = mpModel->DataPointerForIndex(rkIndex);
|
|
|
|
if (pProp)
|
|
{
|
|
if (!mEditInProgress)
|
|
{
|
|
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
|
|
|
switch (Type)
|
|
{
|
|
|
|
case EPropertyType::Bool:
|
|
{
|
|
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
|
|
CBoolProperty *pBool = TPropCast<CBoolProperty>(pProp);
|
|
pCheckBox->setChecked( pBool->Value(pData) );
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Short:
|
|
{
|
|
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
|
|
|
if (!pSpinBox->hasFocus())
|
|
{
|
|
CShortProperty *pShort = TPropCast<CShortProperty>(pProp);
|
|
pSpinBox->setValue( pShort->Value(pData) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Int:
|
|
{
|
|
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
|
|
|
if (!pSpinBox->hasFocus())
|
|
{
|
|
// Ints use static_cast since sometimes we treat other property types as ints
|
|
CIntProperty *pInt = static_cast<CIntProperty*>(pProp);
|
|
pSpinBox->setValue( pInt->Value(pData) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Sound:
|
|
{
|
|
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
|
|
|
if (!pSpinBox->hasFocus())
|
|
{
|
|
CSoundProperty *pSound = TPropCast<CSoundProperty>(pProp);
|
|
pSpinBox->setValue( pSound->Value(pData) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Float:
|
|
{
|
|
WDraggableSpinBox *pSpinBox = static_cast<WDraggableSpinBox*>(pEditor);
|
|
|
|
if (!pSpinBox->hasFocus())
|
|
{
|
|
CFloatProperty *pFloat = TPropCast<CFloatProperty>(pProp);
|
|
pSpinBox->setValue( pFloat->Value(pData) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Color:
|
|
{
|
|
WColorPicker *pColorPicker = static_cast<WColorPicker*>(pEditor);
|
|
CColorProperty *pColor = TPropCast<CColorProperty>(pProp);
|
|
|
|
CColor Color = pColor->Value(pData);
|
|
pColorPicker->SetColor(TO_QCOLOR(Color));
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::String:
|
|
{
|
|
QLineEdit *pLineEdit = static_cast<QLineEdit*>(pEditor);
|
|
|
|
if (!pLineEdit->hasFocus())
|
|
{
|
|
CStringProperty *pString = TPropCast<CStringProperty>(pProp);
|
|
pLineEdit->setText( TO_QSTRING(pString->Value(pData)) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Enum:
|
|
case EPropertyType::Choice:
|
|
{
|
|
QComboBox *pComboBox = static_cast<QComboBox*>(pEditor);
|
|
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
|
|
pComboBox->setCurrentIndex( pEnum->ValueIndex( pEnum->Value(pData) ) );
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Asset:
|
|
{
|
|
CResourceSelector *pSelector = static_cast<CResourceSelector*>(pEditor);
|
|
CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
|
|
pSelector->SetResource(pAsset->Value(pData));
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Array:
|
|
{
|
|
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
|
|
|
if (!pSpinBox->hasFocus())
|
|
{
|
|
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
|
|
pSpinBox->setValue( pArray->ArrayCount(pData) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set editor data for animation set/flags sub-property
|
|
else if (rkIndex.internalId() & 0x80000000)
|
|
{
|
|
pProp = mpModel->PropertyForIndex(rkIndex, true);
|
|
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
|
|
|
if (Type == EPropertyType::AnimationSet)
|
|
SetCharacterEditorData(pEditor, rkIndex);
|
|
|
|
else if (Type == EPropertyType::Flags)
|
|
{
|
|
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
|
|
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
|
|
uint32 Mask = pFlags->FlagMask(rkIndex.row());
|
|
bool Set = (pFlags->Value(pData) & Mask) != 0;
|
|
pCheckBox->setChecked(Set);
|
|
}
|
|
}
|
|
}
|
|
|
|
BlockRelays(false);
|
|
}
|
|
|
|
void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pModel*/, const QModelIndex &rkIndex) const
|
|
{
|
|
if (!mpModel) return;
|
|
if (!pEditor) return;
|
|
|
|
IEditPropertyCommand* pCommand = nullptr;
|
|
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, true);
|
|
void* pData = mpModel->DataPointerForIndex(rkIndex);
|
|
|
|
if (pProp)
|
|
{
|
|
EPropertyType Type = mpModel->GetEffectiveFieldType(pProp);
|
|
CScriptObject* pObject = mpModel->GetScriptObject();
|
|
|
|
if (!pObject)
|
|
{
|
|
QVector<void*> DataPointers;
|
|
DataPointers << pData;
|
|
pCommand = new CEditIntrinsicPropertyCommand(pProp, DataPointers, mpModel, rkIndex);
|
|
}
|
|
else
|
|
{
|
|
QVector<CScriptObject*> Objects;
|
|
Objects << pObject;
|
|
|
|
pCommand = (Type != EPropertyType::Array) ?
|
|
new CEditScriptPropertyCommand(pProp, Objects, mpModel, rkIndex) :
|
|
new CResizeScriptArrayCommand (pProp, Objects, mpModel, rkIndex);
|
|
}
|
|
|
|
pCommand->SaveOldData();
|
|
|
|
if (Type != EPropertyType::Array)
|
|
{
|
|
// Handle sub-properties of flags and animation sets
|
|
if (rkIndex.internalId() & 0x80000000)
|
|
{
|
|
if (Type == EPropertyType::AnimationSet)
|
|
SetCharacterModelData(pEditor, rkIndex);
|
|
|
|
else if (Type == EPropertyType::Flags)
|
|
{
|
|
QCheckBox* pCheckBox = static_cast<QCheckBox*>(pEditor);
|
|
CFlagsProperty* pFlags = static_cast<CFlagsProperty*>(pProp);
|
|
uint32 Mask = pFlags->FlagMask(rkIndex.row());
|
|
|
|
int Flags = pFlags->Value(pData);
|
|
if (pCheckBox->isChecked()) Flags |= Mask;
|
|
else Flags &= ~Mask;
|
|
pFlags->ValueRef(pData) = Flags;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
switch (Type)
|
|
{
|
|
|
|
case EPropertyType::Bool:
|
|
{
|
|
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
|
|
CBoolProperty* pBool = static_cast<CBoolProperty*>(pProp);
|
|
pBool->ValueRef(pData) = pCheckBox->isChecked();
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Short:
|
|
{
|
|
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
|
CShortProperty* pShort = static_cast<CShortProperty*>(pProp);
|
|
pShort->ValueRef(pData) = pSpinBox->value();
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Int:
|
|
{
|
|
// Ints use static_cast since sometimes we treat other property types as ints
|
|
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
|
CIntProperty* pInt = static_cast<CIntProperty*>(pProp);
|
|
pInt->ValueRef(pData) = pSpinBox->value();
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Sound:
|
|
{
|
|
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
|
CSoundProperty* pSound = static_cast<CSoundProperty*>(pProp);
|
|
pSound->ValueRef(pData) = pSpinBox->value();
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Float:
|
|
{
|
|
WDraggableSpinBox* pSpinBox = static_cast<WDraggableSpinBox*>(pEditor);
|
|
CFloatProperty* pFloat = static_cast<CFloatProperty*>(pProp);
|
|
pFloat->ValueRef(pData) = (float) pSpinBox->value();
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Color:
|
|
{
|
|
WColorPicker* pColorPicker = static_cast<WColorPicker*>(pEditor);
|
|
CColorProperty* pColor = static_cast<CColorProperty*>(pProp);
|
|
|
|
QColor Color = pColorPicker->Color();
|
|
pColor->ValueRef(pData) = TO_CCOLOR(Color);
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::String:
|
|
{
|
|
QLineEdit* pLineEdit = static_cast<QLineEdit*>(pEditor);
|
|
CStringProperty* pString = static_cast<CStringProperty*>(pProp);
|
|
pString->ValueRef(pData) = TO_TSTRING(pLineEdit->text());
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Enum:
|
|
case EPropertyType::Choice:
|
|
{
|
|
QComboBox* pComboBox = static_cast<QComboBox*>(pEditor);
|
|
CEnumProperty* pEnum = static_cast<CEnumProperty*>(pProp);
|
|
pEnum->ValueRef(pData) = pEnum->ValueID(pComboBox->currentIndex());
|
|
break;
|
|
}
|
|
|
|
case EPropertyType::Asset:
|
|
{
|
|
CResourceSelector* pSelector = static_cast<CResourceSelector*>(pEditor);
|
|
CResourceEntry* pEntry = pSelector->Entry();
|
|
|
|
CAssetProperty* pAsset = static_cast<CAssetProperty*>(pProp);
|
|
pAsset->ValueRef(pData) = (pEntry ? pEntry->ID() : CAssetID::InvalidID(pAsset->Game()));
|
|
break;
|
|
}
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
pCommand->SaveNewData();
|
|
}
|
|
|
|
// Array
|
|
else
|
|
{
|
|
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
|
CArrayProperty* pArray = static_cast<CArrayProperty*>(pProp);
|
|
int OldCount = pArray->ArrayCount(pData);
|
|
int NewCount = pSpinBox->value();
|
|
|
|
if (OldCount != NewCount)
|
|
{
|
|
mpModel->ArrayAboutToBeResized(rkIndex, NewCount);
|
|
pArray->Resize(pData, NewCount);
|
|
mpModel->ArrayResized(rkIndex, OldCount);
|
|
}
|
|
|
|
pCommand->SaveNewData();
|
|
}
|
|
}
|
|
|
|
if (pCommand)
|
|
{
|
|
// Check for edit in progress
|
|
bool DataChanged = pCommand->IsNewDataDifferent();
|
|
|
|
if (DataChanged && mInRelayWidgetEdit && (pEditor->hasFocus() || pProp->Type() == EPropertyType::Color))
|
|
mEditInProgress = true;
|
|
|
|
bool EditWasInProgress = mEditInProgress;
|
|
|
|
// Check for edit finished
|
|
if (!mInRelayWidgetEdit || (!pEditor->hasFocus() && pProp->Type() != EPropertyType::Color))
|
|
mEditInProgress = false;
|
|
|
|
// Push undo command
|
|
if (DataChanged || EditWasInProgress)
|
|
{
|
|
// Always consider the edit done for bool properties
|
|
pCommand->SetEditComplete(!mEditInProgress || pProp->Type() == EPropertyType::Bool);
|
|
mpEditor->UndoStack().push(pCommand);
|
|
}
|
|
|
|
else
|
|
delete pCommand;
|
|
}
|
|
}
|
|
|
|
bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent)
|
|
{
|
|
if (pEvent->type() == QEvent::Wheel)
|
|
{
|
|
QWidget *pWidget = static_cast<QWidget*>(pObject);
|
|
|
|
if (!pWidget->hasFocus())
|
|
return true;
|
|
|
|
pEvent->ignore();
|
|
return false;
|
|
}
|
|
|
|
return QStyledItemDelegate::eventFilter(pObject, pEvent);
|
|
}
|
|
|
|
// Character properties have separate functions because they're somewhat complicated - they have different layouts in different games
|
|
QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModelIndex& rkIndex) const
|
|
{
|
|
CAnimationSetProperty* pAnimSetProp = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true));
|
|
CAnimationParameters Params = pAnimSetProp->Value(mpModel->DataPointerForIndex(rkIndex));
|
|
|
|
// Determine property type
|
|
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
|
|
|
|
// Create widget
|
|
if (Type == EPropertyType::Asset)
|
|
{
|
|
CResourceSelector* pSelector = new CResourceSelector(pParent);
|
|
pSelector->SetFrameVisible(false);
|
|
|
|
if (Params.Version() <= EGame::Echoes)
|
|
pSelector->SetTypeFilter(gpEdApp->CurrentGame(), "ANCS");
|
|
else
|
|
pSelector->SetTypeFilter(gpEdApp->CurrentGame(), "CHAR");
|
|
|
|
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*));
|
|
return pSelector;
|
|
}
|
|
|
|
else if (Type == EPropertyType::Enum || Type == EPropertyType::Choice)
|
|
{
|
|
QComboBox* pComboBox = new QComboBox(pParent);
|
|
CAnimSet* pAnimSet = Params.AnimSet();
|
|
|
|
if (pAnimSet)
|
|
{
|
|
for (size_t CharIdx = 0; CharIdx < pAnimSet->NumCharacters(); CharIdx++)
|
|
pComboBox->addItem(TO_QSTRING(pAnimSet->Character(CharIdx)->Name));
|
|
}
|
|
|
|
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int));
|
|
return pComboBox;
|
|
}
|
|
|
|
else if (Type == EPropertyType::Int)
|
|
{
|
|
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
|
|
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
|
|
return pSpinBox;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const
|
|
{
|
|
CAnimationSetProperty* pAnimSetProp = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true));
|
|
CAnimationParameters Params = pAnimSetProp->Value(mpModel->DataPointerForIndex(rkIndex));
|
|
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
|
|
|
|
if (Type == EPropertyType::Asset)
|
|
{
|
|
static_cast<CResourceSelector*>(pEditor)->SetResource(Params.AnimSet());
|
|
}
|
|
|
|
else if (Type == EPropertyType::Enum || Type == EPropertyType::Choice)
|
|
{
|
|
static_cast<QComboBox*>(pEditor)->setCurrentIndex(Params.CharacterIndex());
|
|
}
|
|
|
|
else if (Type == EPropertyType::Int && !pEditor->hasFocus())
|
|
{
|
|
int UnkIndex = (Params.Version() <= EGame::Echoes ? rkIndex.row() - 2 : rkIndex.row() - 1);
|
|
uint32 Value = Params.Unknown(UnkIndex);
|
|
static_cast<WIntegralSpinBox*>(pEditor)->setValue(Value);
|
|
}
|
|
}
|
|
|
|
void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const
|
|
{
|
|
CAnimationSetProperty* pAnimSetProp = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true));
|
|
CAnimationParameters Params = pAnimSetProp->Value(mpModel->DataPointerForIndex(rkIndex));
|
|
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
|
|
|
|
if (Type == EPropertyType::Asset)
|
|
{
|
|
CResourceEntry *pEntry = static_cast<CResourceSelector*>(pEditor)->Entry();
|
|
Params.SetResource( pEntry ? pEntry->ID() : CAssetID::InvalidID(gpEdApp->CurrentGame()) );
|
|
}
|
|
|
|
else if (Type == EPropertyType::Enum || Type == EPropertyType::Choice)
|
|
{
|
|
Params.SetCharIndex( static_cast<QComboBox*>(pEditor)->currentIndex() );
|
|
}
|
|
|
|
else if (Type == EPropertyType::Int)
|
|
{
|
|
int UnkIndex = (Params.Version() <= EGame::Echoes ? rkIndex.row() - 2 : rkIndex.row() - 1);
|
|
Params.SetUnknown(UnkIndex, static_cast<WIntegralSpinBox*>(pEditor)->value() );
|
|
}
|
|
|
|
pAnimSetProp->ValueRef(mpModel->DataPointerForIndex(rkIndex)) = Params;
|
|
|
|
// If we just updated the resource, make sure all the sub-properties of the character are flagged as changed.
|
|
// We want to do this -after- updating the anim params on the property, which is why we have a second type check.
|
|
if (Type == EPropertyType::Asset)
|
|
{
|
|
QModelIndex ParentIndex = rkIndex.parent();
|
|
mpModel->dataChanged(mpModel->index(1, 1, ParentIndex), mpModel->index(mpModel->rowCount(ParentIndex) - 1, 1, ParentIndex));
|
|
}
|
|
}
|
|
|
|
EPropertyType CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const
|
|
{
|
|
if (Game <= EGame::Echoes)
|
|
{
|
|
if (rkIndex.row() == 0) return EPropertyType::Asset;
|
|
else if (rkIndex.row() == 1) return EPropertyType::Choice;
|
|
else if (rkIndex.row() == 2) return EPropertyType::Int;
|
|
}
|
|
else if (Game <= EGame::Corruption)
|
|
{
|
|
if (rkIndex.row() == 0) return EPropertyType::Asset;
|
|
else if (rkIndex.row() == 1) return EPropertyType::Int;
|
|
}
|
|
else
|
|
{
|
|
if (rkIndex.row() == 0) return EPropertyType::Asset;
|
|
else if (rkIndex.row() <= 2) return EPropertyType::Int;
|
|
}
|
|
return EPropertyType::Invalid;
|
|
}
|
|
|
|
// ************ PUBLIC SLOTS ************
|
|
void CPropertyDelegate::WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex)
|
|
{
|
|
// This slot is used to update property values as they're being updated so changes can be
|
|
// reflected in realtime in other parts of the application.
|
|
mInRelayWidgetEdit = true;
|
|
|
|
if (!mRelaysBlocked)
|
|
setModelData(pWidget, mpModel, rkIndex);
|
|
|
|
mInRelayWidgetEdit = false;
|
|
}
|