From 7b005d7ebd9477cc79b5dd6cc2ee05f84cdf9b21 Mon Sep 17 00:00:00 2001 From: Aruki Date: Sun, 30 Dec 2018 03:55:50 -0700 Subject: [PATCH] Changes made in the tweak editor are now correctly applied to the tweak data & are undo/redo supported --- .../Script/Property/CAnimationSetProperty.h | 2 +- .../Resource/Script/Property/CColorProperty.h | 2 +- src/Editor/CTweakEditor.cpp | 39 +++++- src/Editor/CTweakEditor.h | 1 + src/Editor/Editor.pro | 3 +- src/Editor/IEditor.cpp | 67 +++++++++- src/Editor/IEditor.h | 6 +- src/Editor/PropertyEdit/CPropertyDelegate.cpp | 43 +++--- src/Editor/PropertyEdit/CPropertyDelegate.h | 25 ++-- src/Editor/PropertyEdit/CPropertyView.cpp | 22 ++-- src/Editor/PropertyEdit/CPropertyView.h | 31 +++-- src/Editor/UICommon.h | 19 ++- .../Undo/CEditIntrinsicPropertyCommand.h | 28 ++++ src/Editor/Undo/CEditScriptPropertyCommand.h | 53 ++------ src/Editor/Undo/CResizeScriptArrayCommand.h | 15 +-- src/Editor/Undo/IEditPropertyCommand.cpp | 46 ++++++- src/Editor/Undo/IEditPropertyCommand.h | 8 +- src/Editor/WorldEditor/CInstancesModel.cpp | 4 +- src/Editor/WorldEditor/CInstancesModel.h | 2 +- src/Editor/WorldEditor/CWorldEditor.cpp | 122 ++++++------------ src/Editor/WorldEditor/CWorldEditor.h | 6 +- src/Editor/WorldEditor/WEditorProperties.cpp | 4 +- src/Editor/WorldEditor/WEditorProperties.h | 28 ++-- src/Editor/WorldEditor/WModifyTab.cpp | 6 + src/Editor/WorldEditor/WModifyTab.h | 2 + 25 files changed, 359 insertions(+), 225 deletions(-) create mode 100644 src/Editor/Undo/CEditIntrinsicPropertyCommand.h diff --git a/src/Core/Resource/Script/Property/CAnimationSetProperty.h b/src/Core/Resource/Script/Property/CAnimationSetProperty.h index 302c3b88..90f3fde2 100644 --- a/src/Core/Resource/Script/Property/CAnimationSetProperty.h +++ b/src/Core/Resource/Script/Property/CAnimationSetProperty.h @@ -17,7 +17,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Value(pData).Serialize(Arc); + ValueRef(pData).Serialize(Arc); } virtual const char* HashableTypeName() const diff --git a/src/Core/Resource/Script/Property/CColorProperty.h b/src/Core/Resource/Script/Property/CColorProperty.h index 98ffdc34..12c0c3bb 100644 --- a/src/Core/Resource/Script/Property/CColorProperty.h +++ b/src/Core/Resource/Script/Property/CColorProperty.h @@ -25,7 +25,7 @@ public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Value(pData).Serialize(Arc); + ValueRef(pData).Serialize(Arc); } }; diff --git a/src/Editor/CTweakEditor.cpp b/src/Editor/CTweakEditor.cpp index e2c0d988..eb189a12 100644 --- a/src/Editor/CTweakEditor.cpp +++ b/src/Editor/CTweakEditor.cpp @@ -1,5 +1,6 @@ #include "CTweakEditor.h" #include "ui_CTweakEditor.h" +#include "Editor/Undo/IUndoCommand.h" CTweakEditor::CTweakEditor(QWidget* pParent) : IEditor(pParent) @@ -9,9 +10,11 @@ CTweakEditor::CTweakEditor(QWidget* pParent) { mpUI->setupUi(this); mpUI->TweakTabs->setExpanding(false); - SET_WINDOWTITLE_APPVARS("%APP_FULL_NAME% - Tweak Editor"); + mpUI->ToolBar->addSeparator(); + AddUndoActions(mpUI->ToolBar); + SET_WINDOWTITLE_APPVARS("%APP_FULL_NAME% - Tweak Editor[*]"); - connect(mpUI->TweakTabs, SIGNAL(currentChanged(int)), this, SLOT(SetActiveTweakIndex(int))); + connect(mpUI->TweakTabs, SIGNAL(currentChanged(int)), this, SLOT(OnTweakTabClicked(int))); } CTweakEditor::~CTweakEditor() @@ -64,6 +67,34 @@ void CTweakEditor::SetActiveTweakIndex(int Index) } } +void CTweakEditor::OnTweakTabClicked(int Index) +{ + /** Internal undo command for changing tabs */ + class CSetTweakIndexCommand : public IUndoCommand + { + CTweakEditor* mpEditor; + int mOldIndex, mNewIndex; + + public: + CSetTweakIndexCommand(CTweakEditor* pEditor, int OldIndex, int NewIndex) + : IUndoCommand("Change Tab") + , mpEditor(pEditor) + , mOldIndex(OldIndex) + , mNewIndex(NewIndex) + {} + + virtual void undo() override { mpEditor->SetActiveTweakIndex(mOldIndex); } + virtual void redo() override { mpEditor->SetActiveTweakIndex(mNewIndex); } + virtual bool AffectsCleanState() const { return false; } + }; + + if (Index != mCurrentTweakIndex) + { + CSetTweakIndexCommand* pCommand = new CSetTweakIndexCommand(this, mCurrentTweakIndex, Index); + UndoStack().push(pCommand); + } +} + void CTweakEditor::OnProjectChanged(CGameProject* pNewProject) { // Close and clear tabs @@ -78,8 +109,8 @@ void CTweakEditor::OnProjectChanged(CGameProject* pNewProject) mpUI->TweakTabs->removeTab(0); } - mpUI->TweakTabs->blockSignals(false); mTweakAssets.clear(); + UndoStack().clear(); // Create tweak list if (pNewProject != nullptr) @@ -105,4 +136,6 @@ void CTweakEditor::OnProjectChanged(CGameProject* pNewProject) SetActiveTweakIndex(0); } + + mpUI->TweakTabs->blockSignals(false); } diff --git a/src/Editor/CTweakEditor.h b/src/Editor/CTweakEditor.h index 4b312ec9..c1fe2556 100644 --- a/src/Editor/CTweakEditor.h +++ b/src/Editor/CTweakEditor.h @@ -33,6 +33,7 @@ public: public slots: void SetActiveTweakData(CTweakData* pTweakData); void SetActiveTweakIndex(int Index); + void OnTweakTabClicked(int Index); void OnProjectChanged(CGameProject* pNewProject); }; diff --git a/src/Editor/Editor.pro b/src/Editor/Editor.pro index 1424675b..bdd361d3 100644 --- a/src/Editor/Editor.pro +++ b/src/Editor/Editor.pro @@ -204,7 +204,8 @@ HEADERS += \ StringEditor/CStringListModel.h \ StringEditor/CStringDelegate.h \ CCustomDelegate.h \ - CTweakEditor.h + CTweakEditor.h \ + Undo/CEditIntrinsicPropertyCommand.h # Source Files SOURCES += \ diff --git a/src/Editor/IEditor.cpp b/src/Editor/IEditor.cpp index aa932391..57beff3a 100644 --- a/src/Editor/IEditor.cpp +++ b/src/Editor/IEditor.cpp @@ -1,5 +1,7 @@ #include "IEditor.h" +#include "Editor/Undo/IUndoCommand.h" + #include #include #include @@ -19,6 +21,8 @@ IEditor::IEditor(QWidget* pParent) pRedoAction->setIcon(QIcon(":/icons/Redo.png")); mUndoActions.push_back(pUndoAction); mUndoActions.push_back(pRedoAction); + + connect(&mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(OnUndoStackIndexChanged())); } QUndoStack& IEditor::UndoStack() @@ -26,12 +30,12 @@ QUndoStack& IEditor::UndoStack() return mUndoStack; } -void IEditor::AddUndoActions(QToolBar* pToolBar, QAction* pBefore) +void IEditor::AddUndoActions(QToolBar* pToolBar, QAction* pBefore /*= 0*/) { pToolBar->insertActions(pBefore, mUndoActions); } -void IEditor::AddUndoActions(QMenu* pMenu, QAction* pBefore) +void IEditor::AddUndoActions(QMenu* pMenu, QAction* pBefore /*= 0*/) { pMenu->insertActions(pBefore, mUndoActions); } @@ -49,7 +53,10 @@ bool IEditor::CheckUnsavedChanges() OkToClear = Save(); else if (Result == QMessageBox::No) + { + mUndoStack.setIndex(0); // Revert all changes OkToClear = true; + } else if (Result == QMessageBox::Cancel) OkToClear = false; @@ -83,3 +90,59 @@ bool IEditor::SaveAndRepack() } else return false; } + + +void IEditor::OnUndoStackIndexChanged() +{ + // Check the commands that have been executed on the undo stack and find out whether any of them affect the clean state. + // This is to prevent commands like select/deselect from altering the clean state. + int CurrentIndex = mUndoStack.index(); + int CleanIndex = mUndoStack.cleanIndex(); + + if (CleanIndex == -1) + { + if (!isWindowModified()) + mUndoStack.setClean(); + + return; + } + + if (CurrentIndex == CleanIndex) + setWindowModified(false); + + else + { + bool IsClean = true; + int LowIndex = (CurrentIndex > CleanIndex ? CleanIndex : CurrentIndex); + int HighIndex = (CurrentIndex > CleanIndex ? CurrentIndex - 1 : CleanIndex - 1); + + for (int i = LowIndex; i <= HighIndex; i++) + { + const QUndoCommand *pkQCmd = mUndoStack.command(i); + + if (const IUndoCommand* pkCmd = dynamic_cast(pkQCmd)) + { + if (pkCmd->AffectsCleanState()) + IsClean = false; + } + + else if (pkQCmd->childCount() > 0) + { + for (int ChildIdx = 0; ChildIdx < pkQCmd->childCount(); ChildIdx++) + { + const IUndoCommand *pkCmd = static_cast(pkQCmd->child(ChildIdx)); + + if (pkCmd->AffectsCleanState()) + { + IsClean = false; + break; + } + } + } + + if (!IsClean) break; + } + + setWindowModified(!IsClean); + } +} diff --git a/src/Editor/IEditor.h b/src/Editor/IEditor.h index cc300064..2195a764 100644 --- a/src/Editor/IEditor.h +++ b/src/Editor/IEditor.h @@ -21,8 +21,8 @@ protected: public: IEditor(QWidget* pParent); QUndoStack& UndoStack(); - void AddUndoActions(QToolBar* pToolBar, QAction* pBefore); - void AddUndoActions(QMenu* pMenu, QAction* pBefore); + void AddUndoActions(QToolBar* pToolBar, QAction* pBefore = 0); + void AddUndoActions(QMenu* pMenu, QAction* pBefore = 0); bool CheckUnsavedChanges(); /** QMainWindow overrides */ @@ -39,12 +39,12 @@ public slots: // Default implementation for editor windows that do not support resaving assets. // This should not be called. warnf("Base IEditor::Save() implementation called. Changes will not be saved."); - ASSERT(false); return true; } /** Non-virtual slots */ bool SaveAndRepack(); + void OnUndoStackIndexChanged(); signals: void Closed(); diff --git a/src/Editor/PropertyEdit/CPropertyDelegate.cpp b/src/Editor/PropertyEdit/CPropertyDelegate.cpp index 5c35d342..40141320 100644 --- a/src/Editor/PropertyEdit/CPropertyDelegate.cpp +++ b/src/Editor/PropertyEdit/CPropertyDelegate.cpp @@ -3,6 +3,7 @@ #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" @@ -25,22 +26,23 @@ connect(pRelay, SIGNAL(WidgetEdited(QWidget*, const QModelIndex&)), this, SLOT(WidgetEdited(QWidget*, const QModelIndex&))); \ } -CPropertyDelegate::CPropertyDelegate(QObject *pParent /*= 0*/) +CPropertyDelegate::CPropertyDelegate(QObject* pParent /*= 0*/) : QStyledItemDelegate(pParent) + , mpEditor(nullptr) , mpModel(nullptr) , mInRelayWidgetEdit(false) , mEditInProgress(false) , mRelaysBlocked(false) { - mpEditor = gpEdApp->WorldEditor(); + mpEditor = UICommon::FindAncestor(this); } -void CPropertyDelegate::SetPropertyModel(CPropertyModel *pModel) +void CPropertyDelegate::SetPropertyModel(CPropertyModel* pModel) { mpModel = pModel; } -QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionViewItem& /*rkOption*/, const QModelIndex& rkIndex) const +QWidget* CPropertyDelegate::createEditor(QWidget* pParent, const QStyleOptionViewItem& /*rkOption*/, const QModelIndex& rkIndex) const { if (!mpModel) return nullptr; IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false); @@ -361,16 +363,28 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo if (pProp) { EPropertyType Type = mpModel->GetEffectiveFieldType(pProp); + CScriptObject* pObject = mpModel->GetScriptObject(); - QVector Objects; - Objects << mpModel->GetScriptObject(); + if (!pObject) + { + QVector DataPointers; + DataPointers << pData; + pCommand = new CEditIntrinsicPropertyCommand(pProp, DataPointers, mpModel, rkIndex); + } + else + { + QVector 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) { - // TODO: support this for non script object properties - pCommand = new CEditScriptPropertyCommand(pProp, mpEditor, Objects, rkIndex); - pCommand->SaveOldData(); - // Handle sub-properties of flags and animation sets if (rkIndex.internalId() & 0x80000000) { @@ -482,9 +496,6 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo // Array else { - pCommand = new CResizeScriptArrayCommand(pProp, mpEditor, Objects, mpModel, rkIndex); - pCommand->SaveOldData(); - WIntegralSpinBox* pSpinBox = static_cast(pEditor); CArrayProperty* pArray = static_cast(pProp); int OldCount = pArray->ArrayCount(pData); @@ -560,9 +571,9 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel pSelector->SetFrameVisible(false); if (Params.Version() <= EGame::Echoes) - pSelector->SetTypeFilter(mpEditor->CurrentGame(), "ANCS"); + pSelector->SetTypeFilter(gpEdApp->CurrentGame(), "ANCS"); else - pSelector->SetTypeFilter(mpEditor->CurrentGame(), "CHAR"); + pSelector->SetTypeFilter(gpEdApp->CurrentGame(), "CHAR"); CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*)); return pSelector; @@ -626,7 +637,7 @@ void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelInde if (Type == EPropertyType::Asset) { CResourceEntry *pEntry = static_cast(pEditor)->Entry(); - Params.SetResource( pEntry ? pEntry->ID() : CAssetID::InvalidID(mpEditor->CurrentGame()) ); + Params.SetResource( pEntry ? pEntry->ID() : CAssetID::InvalidID(gpEdApp->CurrentGame()) ); } else if (Type == EPropertyType::Enum || Type == EPropertyType::Choice) diff --git a/src/Editor/PropertyEdit/CPropertyDelegate.h b/src/Editor/PropertyEdit/CPropertyDelegate.h index a79008ae..f9a998d8 100644 --- a/src/Editor/PropertyEdit/CPropertyDelegate.h +++ b/src/Editor/PropertyEdit/CPropertyDelegate.h @@ -9,28 +9,29 @@ class CPropertyDelegate : public QStyledItemDelegate { Q_OBJECT - CWorldEditor *mpEditor; - CPropertyModel *mpModel; + IEditor* mpEditor; + CPropertyModel* mpModel; bool mInRelayWidgetEdit; mutable bool mEditInProgress; mutable bool mRelaysBlocked; public: - CPropertyDelegate(QObject *pParent = 0); - void SetPropertyModel(CPropertyModel *pModel); + CPropertyDelegate(QObject* pParent = 0); + void SetEditor(IEditor* pEditor); + void SetPropertyModel(CPropertyModel* pModel); - virtual QWidget* createEditor(QWidget *pParent, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const; - virtual void setEditorData(QWidget *pEditor, const QModelIndex &rkIndex) const; - virtual void setModelData(QWidget *pEditor, QAbstractItemModel *pModel, const QModelIndex &rkIndex) const; - bool eventFilter(QObject *pObject, QEvent *pEvent); + virtual QWidget* createEditor(QWidget* pParent, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const; + virtual void setEditorData(QWidget* pEditor, const QModelIndex& rkIndex) const; + virtual void setModelData(QWidget* pEditor, QAbstractItemModel* pModel, const QModelIndex& rkIndex) const; + bool eventFilter(QObject* pObject, QEvent* pEvent); - QWidget* CreateCharacterEditor(QWidget *pParent, const QModelIndex& rkIndex) const; - void SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const; - void SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const; + QWidget* CreateCharacterEditor(QWidget* pParent, const QModelIndex& rkIndex) const; + void SetCharacterEditorData(QWidget* pEditor, const QModelIndex& rkIndex) const; + void SetCharacterModelData(QWidget* pEditor, const QModelIndex& rkIndex) const; EPropertyType DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const; public slots: - void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex); + void WidgetEdited(QWidget* pWidget, const QModelIndex& rkIndex); protected: void BlockRelays(bool Block) const { mRelaysBlocked = Block; } diff --git a/src/Editor/PropertyEdit/CPropertyView.cpp b/src/Editor/PropertyEdit/CPropertyView.cpp index 36e296b0..0bcb547e 100644 --- a/src/Editor/PropertyEdit/CPropertyView.cpp +++ b/src/Editor/PropertyEdit/CPropertyView.cpp @@ -39,9 +39,6 @@ CPropertyView::CPropertyView(QWidget *pParent) connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CreateContextMenu(QPoint))); connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex))); connect(mpModel, SIGNAL(PropertyModified(const QModelIndex&)), this, SLOT(OnPropertyModified(const QModelIndex&))); - - mpEditor = gpEdApp->WorldEditor(); - connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IProperty*)), mpModel, SLOT(NotifyPropertyModified(CScriptObject*,IProperty*))); } void CPropertyView::setModel(QAbstractItemModel *pModel) @@ -110,7 +107,7 @@ void CPropertyView::SetIntrinsicProperties(CStructRef InProperties) void CPropertyView::SetInstance(CScriptObject *pObj) { mpObject = pObj; - mpModel->SetBoldModifiedProperties(mpEditor ? (mpEditor->CurrentGame() > EGame::Prime) : true); + mpModel->SetBoldModifiedProperties(gpEdApp->CurrentGame() > EGame::Prime); if (pObj) mpModel->ConfigureScript(pObj->Area()->Entry()->Project(), pObj->Template()->Properties(), pObj); @@ -129,7 +126,7 @@ void CPropertyView::SetInstance(CScriptObject *pObj) void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent) { // Check what game this is - EGame Game = mpEditor->CurrentGame(); + EGame Game = gpEdApp->CurrentGame(); // Iterate over all properties and update if they're an editor property. for (int iRow = 0; iRow < mpModel->rowCount(rkParent); iRow++) @@ -245,6 +242,10 @@ void CPropertyView::OnPropertyModified(const QModelIndex& rkIndex) ClosePersistentEditors(rkIndex); SetPersistentEditors(rkIndex); } + + scrollTo(rkIndex); + emit PropertyModified(rkIndex); + emit PropertyModified(pProperty); } void CPropertyView::RefreshView() @@ -268,7 +269,7 @@ void CPropertyView::CreateContextMenu(const QPoint& rkPos) Menu.addAction(mpEditTemplateAction); } - if (mpEditor->CurrentGame() >= EGame::EchoesDemo) + if (gpEdApp->CurrentGame() >= EGame::EchoesDemo) { Menu.addAction(mpShowNameValidityAction); } @@ -305,7 +306,8 @@ void CPropertyView::ToggleShowNameValidity(bool ShouldShow) void CPropertyView::EditPropertyTemplate() { - CTemplateEditDialog Dialog(mpMenuProperty, mpEditor); + QMainWindow* pParentWindow = UICommon::FindAncestor(this); + CTemplateEditDialog Dialog(mpMenuProperty, pParentWindow); connect(&Dialog, SIGNAL(PerformedTypeConversion()), this, SLOT(RefreshView())); Dialog.exec(); } @@ -313,21 +315,21 @@ void CPropertyView::EditPropertyTemplate() void CPropertyView::GenerateNamesForProperty() { - CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog(); + CGeneratePropertyNamesDialog* pDialog = gpEdApp->WorldEditor()->NameGeneratorDialog(); pDialog->AddToIDPool(mpMenuProperty); pDialog->show(); } void CPropertyView::GenerateNamesForSiblings() { - CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog(); + CGeneratePropertyNamesDialog* pDialog = gpEdApp->WorldEditor()->NameGeneratorDialog(); pDialog->AddChildrenToIDPool(mpMenuProperty->Parent(), false); pDialog->show(); } void CPropertyView::GenerateNamesForChildren() { - CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog(); + CGeneratePropertyNamesDialog* pDialog = gpEdApp->WorldEditor()->NameGeneratorDialog(); pDialog->AddChildrenToIDPool(mpMenuProperty, false); pDialog->show(); } diff --git a/src/Editor/PropertyEdit/CPropertyView.h b/src/Editor/PropertyEdit/CPropertyView.h index cc7c38eb..835ea75c 100644 --- a/src/Editor/PropertyEdit/CPropertyView.h +++ b/src/Editor/PropertyEdit/CPropertyView.h @@ -10,26 +10,25 @@ class CPropertyView : public QTreeView { Q_OBJECT - CWorldEditor *mpEditor; - CPropertyModel *mpModel; - CPropertyDelegate *mpDelegate; - CScriptObject *mpObject; + CPropertyModel* mpModel; + CPropertyDelegate* mpDelegate; + CScriptObject* mpObject; - IProperty *mpMenuProperty; - QAction *mpShowNameValidityAction; - QAction *mpEditTemplateAction; - QAction *mpGenNamesForPropertyAction; - QAction *mpGenNamesForSiblingsAction; - QAction *mpGenNamesForChildrenAction; + IProperty* mpMenuProperty; + QAction* mpShowNameValidityAction; + QAction* mpEditTemplateAction; + QAction* mpGenNamesForPropertyAction; + QAction* mpGenNamesForSiblingsAction; + QAction* mpGenNamesForChildrenAction; public: - CPropertyView(QWidget *pParent = 0); - void setModel(QAbstractItemModel *pModel); - bool event(QEvent *pEvent); + CPropertyView(QWidget* pParent = 0); + void setModel(QAbstractItemModel* pModel); + bool event(QEvent* pEvent); void InitColumnWidths(float NameColumnPercentage, float ValueColumnPercentage); void ClearProperties(); void SetIntrinsicProperties(CStructRef InProperties); - void SetInstance(CScriptObject *pObj); + void SetInstance(CScriptObject* pObj); void UpdateEditorProperties(const QModelIndex& rkParent); inline CPropertyModel* PropertyModel() const { return mpModel; } @@ -47,6 +46,10 @@ public slots: void GenerateNamesForProperty(); void GenerateNamesForSiblings(); void GenerateNamesForChildren(); + +signals: + void PropertyModified(const QModelIndex& kIndex); + void PropertyModified(IProperty* pProperty); }; #endif // CPROPERTYVIEW_H diff --git a/src/Editor/UICommon.h b/src/Editor/UICommon.h index b0347e19..dbea8f0e 100644 --- a/src/Editor/UICommon.h +++ b/src/Editor/UICommon.h @@ -42,10 +42,27 @@ namespace UICommon { // Utility -QWindow* FindWidgetWindowHandle(QWidget *pWidget); +QWindow* FindWidgetWindowHandle(QWidget* pWidget); void OpenContainingFolder(const QString& rkPath); bool OpenInExternalApplication(const QString& rkPath); +// Searches the widget's ancestry tree to find an ancestor of type ObjectT. +// ObjectT must be a QObject subclass. +template +ObjectT* FindAncestor(QObject* pObject) +{ + for (QObject* pParent = pObject->parent(); pParent; pParent = pParent->parent()) + { + ObjectT* pCasted = qobject_cast(pParent); + + if (pCasted) + { + return pCasted; + } + } + return nullptr; +} + // TString/TWideString <-> QString inline QString ToQString(const TString& rkStr) { diff --git a/src/Editor/Undo/CEditIntrinsicPropertyCommand.h b/src/Editor/Undo/CEditIntrinsicPropertyCommand.h new file mode 100644 index 00000000..ba2fdaea --- /dev/null +++ b/src/Editor/Undo/CEditIntrinsicPropertyCommand.h @@ -0,0 +1,28 @@ +#ifndef CEDITINTRINSICPROPERTYCOMMAND_H +#define CEDITINTRINSICPROPERTYCOMMAND_H + +#include "IEditPropertyCommand.h" + +class CEditIntrinsicPropertyCommand : public IEditPropertyCommand +{ +protected: + QVector mDataPointers; + +public: + CEditIntrinsicPropertyCommand(IProperty* pProperty, + const QVector& kDataPointers, + CPropertyModel* pModel, + QModelIndex Index = QModelIndex(), + const QString& kCommandName = "Edit Property") + : IEditPropertyCommand(pProperty, pModel, Index, kCommandName) + , mDataPointers(kDataPointers) + { + } + + virtual void GetObjectDataPointers(QVector& rOutPointers) const override + { + rOutPointers = mDataPointers; + } +}; + +#endif // CEDITINTRINSICPROPERTYCOMMAND_H diff --git a/src/Editor/Undo/CEditScriptPropertyCommand.h b/src/Editor/Undo/CEditScriptPropertyCommand.h index e4c9f8ad..6e7cc90f 100644 --- a/src/Editor/Undo/CEditScriptPropertyCommand.h +++ b/src/Editor/Undo/CEditScriptPropertyCommand.h @@ -9,72 +9,41 @@ class CEditScriptPropertyCommand : public IEditPropertyCommand { protected: QVector mInstances; - CWorldEditor* mpEditor; QModelIndex mIndex; public: CEditScriptPropertyCommand(IProperty* pProperty, - CWorldEditor* pEditor, - const QVector& rkInstances, + const QVector& kInstances, + CPropertyModel* pModel, QModelIndex Index = QModelIndex(), - const QString& rkCommandName = "Edit Property") - : IEditPropertyCommand(pProperty, rkCommandName) - , mpEditor(pEditor) + const QString& kCommandName = "Edit Property") + : IEditPropertyCommand(pProperty, pModel, Index, kCommandName) , mIndex(Index) { - // If the property being passed in is part of an array archetype, then we MUST have a QModelIndex. - // Without the index, there's no way to identify the correct child being edited. - if (!Index.isValid() && pProperty && pProperty->IsArrayArchetype()) - { - while (pProperty && pProperty->IsArrayArchetype()) - { - pProperty = pProperty->Parent(); - } - ASSERT(pProperty && !pProperty->IsArrayArchetype()); - } - // Convert CScriptObject pointers to CInstancePtrs - mInstances.reserve( rkInstances.size() ); + mInstances.reserve( kInstances.size() ); - for (int i = 0; i < rkInstances.size(); i++) - mInstances.push_back( CInstancePtr(rkInstances[i]) ); + for (int i = 0; i < kInstances.size(); i++) + mInstances.push_back( CInstancePtr(kInstances[i]) ); } - virtual void GetObjectDataPointers(QVector& rOutPointers) const override + virtual void GetObjectDataPointers(QVector& OutPointers) const override { // todo: support multiple objects being edited at once on the property view if (mIndex.isValid()) { ASSERT(mInstances.size() == 1); - rOutPointers << mInstances[0]->PropertyData(); + OutPointers << mInstances[0]->PropertyData(); return; } // grab instance pointers ASSERT(!mpProperty->IsArrayArchetype()); - rOutPointers.resize(mInstances.size()); + OutPointers.resize(mInstances.size()); for (int i = 0; i < mInstances.size(); i++) - rOutPointers[i] = mInstances[i]->PropertyData(); - } - - virtual void undo() override - { - IEditPropertyCommand::undo(); - NotifyWorldEditor(); - } - - virtual void redo() override - { - IEditPropertyCommand::redo(); - NotifyWorldEditor(); - } - - void NotifyWorldEditor() - { - for (int InstanceIdx = 0; InstanceIdx < mInstances.size(); InstanceIdx++) - mpEditor->OnPropertyModified(*mInstances[InstanceIdx], mpProperty); + OutPointers[i] = mInstances[i]->PropertyData(); } }; diff --git a/src/Editor/Undo/CResizeScriptArrayCommand.h b/src/Editor/Undo/CResizeScriptArrayCommand.h index b219d15a..963a092c 100644 --- a/src/Editor/Undo/CResizeScriptArrayCommand.h +++ b/src/Editor/Undo/CResizeScriptArrayCommand.h @@ -5,31 +5,21 @@ class CResizeScriptArrayCommand : public CEditScriptPropertyCommand { - /** Property model the edit was performed on */ - CPropertyModel* mpModel; - /** Old/new model row counts; we store this here to support editing arrays on multiple instances at once */ int mOldRowCount; int mNewRowCount; public: CResizeScriptArrayCommand(IProperty* pProperty, - CWorldEditor* pEditor, const QVector& rkInstances, - CPropertyModel* pModel = nullptr, + CPropertyModel* pModel, QModelIndex Index = QModelIndex(), const QString& rkCommandName = "Resize Array" ) - : CEditScriptPropertyCommand(pProperty, pEditor, rkInstances, Index, rkCommandName) - , mpModel(nullptr) + : CEditScriptPropertyCommand(pProperty, rkInstances, pModel, Index, rkCommandName) , mOldRowCount(-1) , mNewRowCount(-1) { - if (Index.isValid()) - { - ASSERT(pModel != nullptr); - mpModel = pModel; - } } bool mergeWith(const QUndoCommand *pkOther) @@ -61,6 +51,7 @@ public: // This is why we need to check the array's actual current size instead of assuming it will match one of the arrays void undo() { + //@todo verify, do we need to fully override undo()? if (mpModel) { mpModel->ArrayAboutToBeResized(mIndex, mOldRowCount); diff --git a/src/Editor/Undo/IEditPropertyCommand.cpp b/src/Editor/Undo/IEditPropertyCommand.cpp index 2bf5a81a..c4da47bf 100644 --- a/src/Editor/Undo/IEditPropertyCommand.cpp +++ b/src/Editor/Undo/IEditPropertyCommand.cpp @@ -1,4 +1,6 @@ #include "IEditPropertyCommand.h" +#include "Editor/CEditorApplication.h" +#include "Editor/WorldEditor/CWorldEditor.h" /** Save the current state of the object properties to the given data buffer */ void IEditPropertyCommand::SaveObjectStateToArray(std::vector& rVector) @@ -31,14 +33,36 @@ void IEditPropertyCommand::RestoreObjectStateFromArray(std::vector& rArray IEditPropertyCommand::IEditPropertyCommand( IProperty* pProperty, - const QString& rkCommandName /*= "Edit Property"*/ + CPropertyModel* pModel, + const QModelIndex& kIndex, + const QString& kCommandName /*= "Edit Property"*/ ) - : IUndoCommand(rkCommandName) + : IUndoCommand(kCommandName) , mpProperty(pProperty) + , mpModel(pModel) + , mIndex(kIndex) , mSavedOldData(false) , mSavedNewData(false) { ASSERT(mpProperty); + + if (!mIndex.isValid()) + { + // If the property being passed in is part of an array archetype, then we MUST have a QModelIndex. + // Without the index, there's no way to identify the correct child being edited. + // So if we don't have an index, we need to serialize the entire array property. + if (mpProperty->IsArrayArchetype()) + { + while (mpProperty && mpProperty->IsArrayArchetype()) + { + mpProperty = mpProperty->Parent(); + } + ASSERT(mpProperty && !mpProperty->IsArrayArchetype()); + } + + // Now we can fetch the index from the model + mIndex = mpModel->IndexForProperty(mpProperty); + } } void IEditPropertyCommand::SaveOldData() @@ -108,12 +132,30 @@ void IEditPropertyCommand::undo() ASSERT(mSavedOldData && mSavedNewData); RestoreObjectStateFromArray(mOldData); mCommandEnded = true; + + if (mpModel && mIndex.isValid()) + { + mpModel->NotifyPropertyModified(mIndex); + } + else + { + gpEdApp->WorldEditor()->OnPropertyModified(mpProperty); + } } void IEditPropertyCommand::redo() { ASSERT(mSavedOldData && mSavedNewData); RestoreObjectStateFromArray(mNewData); + + if (mpModel && mIndex.isValid()) + { + mpModel->NotifyPropertyModified(mIndex); + } + else + { + gpEdApp->WorldEditor()->OnPropertyModified(mpProperty); + } } bool IEditPropertyCommand::AffectsCleanState() const diff --git a/src/Editor/Undo/IEditPropertyCommand.h b/src/Editor/Undo/IEditPropertyCommand.h index 59222ed5..bf91540a 100644 --- a/src/Editor/Undo/IEditPropertyCommand.h +++ b/src/Editor/Undo/IEditPropertyCommand.h @@ -13,6 +13,8 @@ protected: std::vector mNewData; IProperty* mpProperty; + CPropertyModel* mpModel; + QModelIndex mIndex; bool mCommandEnded; bool mSavedOldData; bool mSavedNewData; @@ -26,9 +28,13 @@ protected: public: IEditPropertyCommand( IProperty* pProperty, - const QString& rkCommandName = "Edit Property" + CPropertyModel* pModel, + const QModelIndex& kIndex, + const QString& kCommandName = "Edit Property" ); + virtual ~IEditPropertyCommand() {} + virtual void SaveOldData(); virtual void SaveNewData(); diff --git a/src/Editor/WorldEditor/CInstancesModel.cpp b/src/Editor/WorldEditor/CInstancesModel.cpp index a6ab19ef..0a4bc9a2 100644 --- a/src/Editor/WorldEditor/CInstancesModel.cpp +++ b/src/Editor/WorldEditor/CInstancesModel.cpp @@ -45,7 +45,7 @@ CInstancesModel::CInstancesModel(CWorldEditor *pEditor, QObject *pParent) connect(mpEditor, SIGNAL(NodeSpawned(CSceneNode*)), this, SLOT(NodeCreated(CSceneNode*))); connect(mpEditor, SIGNAL(NodeAboutToBeDeleted(CSceneNode*)), this, SLOT(NodeAboutToBeDeleted(CSceneNode*))); connect(mpEditor, SIGNAL(NodeDeleted()), this, SLOT(NodeDeleted())); - connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IProperty*)), this, SLOT(PropertyModified(CScriptObject*,IProperty*))); + connect(mpEditor, SIGNAL(PropertyModified(IProperty*,CScriptObject*)), this, SLOT(PropertyModified(IProperty*,CScriptObject*))); connect(mpEditor, SIGNAL(InstancesLayerAboutToChange()), this, SLOT(InstancesLayerPreChange())); connect(mpEditor, SIGNAL(InstancesLayerChanged(QList)), this, SLOT(InstancesLayerPostChange(QList))); } @@ -472,7 +472,7 @@ void CInstancesModel::NodeDeleted() } } -void CInstancesModel::PropertyModified(CScriptObject *pInst, IProperty *pProp) +void CInstancesModel::PropertyModified(IProperty *pProp, CScriptObject *pInst) { if (pProp->Name() == "Name") { diff --git a/src/Editor/WorldEditor/CInstancesModel.h b/src/Editor/WorldEditor/CInstancesModel.h index be2ea7c5..ad4da1b4 100644 --- a/src/Editor/WorldEditor/CInstancesModel.h +++ b/src/Editor/WorldEditor/CInstancesModel.h @@ -60,7 +60,7 @@ public slots: void NodeAboutToBeDeleted(CSceneNode *pNode); void NodeDeleted(); - void PropertyModified(CScriptObject *pInst, IProperty *pProp); + void PropertyModified(IProperty *pProp, CScriptObject *pInst); void InstancesLayerPreChange(); void InstancesLayerPostChange(const QList& rkInstanceList); diff --git a/src/Editor/WorldEditor/CWorldEditor.cpp b/src/Editor/WorldEditor/CWorldEditor.cpp index 8c457760..03832f4b 100644 --- a/src/Editor/WorldEditor/CWorldEditor.cpp +++ b/src/Editor/WorldEditor/CWorldEditor.cpp @@ -541,42 +541,53 @@ void CWorldEditor::OnLinksModified(const QList& rkInstances) emit InstanceLinksModified(rkInstances); } -void CWorldEditor::OnPropertyModified(CScriptObject* pObject, IProperty *pProp) +void CWorldEditor::OnPropertyModified(IProperty *pProp) { - CScriptNode *pScript = mScene.NodeForInstance(pObject); + bool ShouldUpdateSelection = false; - if (pScript) + for (CSelectionIterator It(mpSelection); It; ++It) { - pScript->PropertyModified(pProp); + CSceneNode* pNode = *It; - // If this is the name, update other parts of the UI to reflect the new value. - if ( pProp->Name() == "Name" ) + if (pNode && pNode->NodeType() == ENodeType::Script) { - UpdateStatusBar(); - UpdateSelectionUI(); + CScriptNode* pScript = static_cast(pNode); + pScript->PropertyModified(pProp); + + // If this is the name, update other parts of the UI to reflect the new value. + if ( pProp->Name() == "Name" ) + { + UpdateStatusBar(); + UpdateSelectionUI(); + } + else if (pProp->Name() == "Position" || + pProp->Name() == "Rotation" || + pProp->Name() == "Scale") + { + mpSelection->UpdateBounds(); + } + + // Emit signal so other widgets can react to the property change + emit PropertyModified(pProp, pScript->Instance()); } - else if (pProp->Name() == "Position" || - pProp->Name() == "Rotation" || - pProp->Name() == "Scale") + + // 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() == EPropertyType::Asset) { - mpSelection->UpdateBounds(); + CAssetProperty *pAsset = TPropCast(pProp); + const CResTypeFilter& rkFilter = pAsset->GetTypeFilter(); + + if (rkFilter.Accepts(EResourceType::Model) || rkFilter.Accepts(EResourceType::AnimSet) || rkFilter.Accepts(EResourceType::Character)) + ShouldUpdateSelection = true; } + else if (pProp->Type() == EPropertyType::AnimationSet) + ShouldUpdateSelection = true; } - // 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() == EPropertyType::Asset) + if (ShouldUpdateSelection) { - CAssetProperty *pAsset = TPropCast(pProp); - const CResTypeFilter& rkFilter = pAsset->GetTypeFilter(); - - if (rkFilter.Accepts(EResourceType::Model) || rkFilter.Accepts(EResourceType::AnimSet) || rkFilter.Accepts(EResourceType::Character)) - SelectionModified(); - } - else if (pProp->Type() == EPropertyType::AnimationSet) SelectionModified(); - - // Emit signal so other widgets can react to the property change - emit PropertyModified(pObject, pProp); + } } void CWorldEditor::SetSelectionActive(bool Active) @@ -616,10 +627,14 @@ void CWorldEditor::SetSelectionActive(bool Active) if (pActiveProperty) { + CPropertyModel* pModel = qobject_cast( + mpScriptSidebar->ModifyTab()->PropertyView()->model() + ); + CEditScriptPropertyCommand* pCommand = new CEditScriptPropertyCommand( pActiveProperty, - this, - CommandObjects + CommandObjects, + pModel ); pCommand->SaveOldData(); @@ -1073,61 +1088,6 @@ void CWorldEditor::OnUnlinkClicked() } } -void CWorldEditor::OnUndoStackIndexChanged() -{ - // Check the commands that have been executed on the undo stack and find out whether any of them affect the clean state. - // This is to prevent commands like select/deselect from altering the clean state. - int CurrentIndex = UndoStack().index(); - int CleanIndex = UndoStack().cleanIndex(); - - if (CleanIndex == -1) - { - if (!isWindowModified()) - UndoStack().setClean(); - - return; - } - - if (CurrentIndex == CleanIndex) - setWindowModified(false); - - else - { - bool IsClean = true; - int LowIndex = (CurrentIndex > CleanIndex ? CleanIndex : CurrentIndex); - int HighIndex = (CurrentIndex > CleanIndex ? CurrentIndex - 1 : CleanIndex - 1); - - for (int iIdx = LowIndex; iIdx <= HighIndex; iIdx++) - { - const QUndoCommand *pkQCmd = UndoStack().command(iIdx); - - if (const IUndoCommand *pkCmd = dynamic_cast(pkQCmd)) - { - if (pkCmd->AffectsCleanState()) - IsClean = false; - } - - else if (pkQCmd->childCount() > 0) - { - for (int iChild = 0; iChild < pkQCmd->childCount(); iChild++) - { - const IUndoCommand *pkCmd = static_cast(pkQCmd->child(iChild)); - - if (pkCmd->AffectsCleanState()) - { - IsClean = false; - break; - } - } - } - - if (!IsClean) break; - } - - setWindowModified(!IsClean); - } -} - void CWorldEditor::OnPickModeEnter(QCursor Cursor) { ui->MainViewport->SetCursorState(Cursor); diff --git a/src/Editor/WorldEditor/CWorldEditor.h b/src/Editor/WorldEditor/CWorldEditor.h index 5dd8b916..739877a4 100644 --- a/src/Editor/WorldEditor/CWorldEditor.h +++ b/src/Editor/WorldEditor/CWorldEditor.h @@ -30,7 +30,6 @@ #include #include #include -#include namespace Ui { class CWorldEditor; @@ -115,7 +114,7 @@ public slots: void OnActiveProjectChanged(CGameProject *pProj); void OnLinksModified(const QList& rkInstances); - void OnPropertyModified(CScriptObject* pObject, IProperty *pProp); + void OnPropertyModified(IProperty *pProp); void SetSelectionActive(bool Active); void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone); void SetSelectionLayer(CScriptLayer *pLayer); @@ -143,7 +142,6 @@ private slots: void OnLinkEnd(); void OnUnlinkClicked(); - void OnUndoStackIndexChanged(); void OnPickModeEnter(QCursor Cursor); void OnPickModeExit(); void UpdateCameraOrbit(); @@ -178,7 +176,7 @@ signals: void InstancesLayerAboutToChange(); void InstancesLayerChanged(const QList& rkInstanceList); void InstanceLinksModified(const QList& rkInstances); - void PropertyModified(CScriptObject *pInst, IProperty *pProp); + void PropertyModified(IProperty *pProp, CScriptObject* pObject); }; #endif // CWORLDEDITOR_H diff --git a/src/Editor/WorldEditor/WEditorProperties.cpp b/src/Editor/WorldEditor/WEditorProperties.cpp index 81822b0c..96b9e64b 100644 --- a/src/Editor/WorldEditor/WEditorProperties.cpp +++ b/src/Editor/WorldEditor/WEditorProperties.cpp @@ -65,7 +65,7 @@ void WEditorProperties::SyncToEditor(CWorldEditor *pEditor) connect(mpEditor, SIGNAL(SelectionModified()), this, SLOT(OnSelectionModified())); connect(mpEditor, SIGNAL(LayersModified()), this, SLOT(OnLayersModified())); connect(mpEditor, SIGNAL(InstancesLayerChanged(QList)), this, SLOT(OnInstancesLayerChanged(QList))); - connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IProperty*)), this, SLOT(OnPropertyModified(CScriptObject*,IProperty*))); + connect(mpEditor, SIGNAL(PropertyModified(IProperty*,CScriptObject*)), this, SLOT(OnPropertyModified(IProperty*,CScriptObject*))); OnLayersModified(); } @@ -139,7 +139,7 @@ void WEditorProperties::OnSelectionModified() SetLayerComboBox(); } -void WEditorProperties::OnPropertyModified(CScriptObject *pInstance, IProperty *pProp) +void WEditorProperties::OnPropertyModified(IProperty* pProp, CScriptObject* pInstance) { if (!mpInstanceNameLineEdit->hasFocus()) { diff --git a/src/Editor/WorldEditor/WEditorProperties.h b/src/Editor/WorldEditor/WEditorProperties.h index e21ba9b2..eda69059 100644 --- a/src/Editor/WorldEditor/WEditorProperties.h +++ b/src/Editor/WorldEditor/WEditorProperties.h @@ -14,32 +14,32 @@ class WEditorProperties : public QWidget { Q_OBJECT - CWorldEditor *mpEditor; - CSceneNode *mpDisplayNode; + CWorldEditor* mpEditor; + CSceneNode* mpDisplayNode; - QVBoxLayout *mpMainLayout; + QVBoxLayout* mpMainLayout; - QLabel *mpInstanceInfoLabel; - QHBoxLayout *mpInstanceInfoLayout; + QLabel* mpInstanceInfoLabel; + QHBoxLayout* mpInstanceInfoLayout; - QCheckBox *mpActiveCheckBox; - QLineEdit *mpInstanceNameLineEdit; - QHBoxLayout *mpNameLayout; + QCheckBox* mpActiveCheckBox; + QLineEdit* mpInstanceNameLineEdit; + QHBoxLayout* mpNameLayout; - QLabel *mpLayersLabel; - QComboBox *mpLayersComboBox; - QHBoxLayout *mpLayersLayout; + QLabel* mpLayersLabel; + QComboBox* mpLayersComboBox; + QHBoxLayout* mpLayersLayout; bool mHasEditedName; public: - WEditorProperties(QWidget *pParent = 0); - void SyncToEditor(CWorldEditor *pEditor); + WEditorProperties(QWidget* pParent = 0); + void SyncToEditor(CWorldEditor* pEditor); void SetLayerComboBox(); public slots: void OnSelectionModified(); - void OnPropertyModified(CScriptObject *pInst, IProperty *pProp); + void OnPropertyModified(IProperty* pProp, CScriptObject* pInstance); void OnInstancesLayerChanged(const QList& rkNodeList); void OnLayersModified(); void UpdatePropertyValues(); diff --git a/src/Editor/WorldEditor/WModifyTab.cpp b/src/Editor/WorldEditor/WModifyTab.cpp index fcc3fc5b..999624d8 100644 --- a/src/Editor/WorldEditor/WModifyTab.cpp +++ b/src/Editor/WorldEditor/WModifyTab.cpp @@ -45,6 +45,7 @@ WModifyTab::WModifyTab(CWorldEditor *pEditor, QWidget *pParent) connect(ui->DeleteIncomingConnectionButton, SIGNAL(clicked()), this, SLOT(OnDeleteLinksClicked())); connect(ui->EditOutgoingConnectionButton, SIGNAL(clicked()), this, SLOT(OnEditLinkClicked())); connect(ui->EditIncomingConnectionButton, SIGNAL(clicked()), this, SLOT(OnEditLinkClicked())); + connect(ui->PropertyView, SIGNAL(PropertyModified(IProperty*)), mpWorldEditor, SLOT(OnPropertyModified(IProperty*))); connect(mpWorldEditor, SIGNAL(MapChanged(CWorld*,CGameArea*)), this, SLOT(OnMapChanged())); connect(mpWorldEditor, SIGNAL(SelectionTransformed()), this, SLOT(OnWorldSelectionTransformed())); connect(mpWorldEditor, SIGNAL(InstanceLinksModified(const QList&)), this, SLOT(OnInstanceLinksModified(const QList&))); @@ -65,6 +66,11 @@ void WModifyTab::ClearUI() mpSelectedNode = nullptr; } +CPropertyView* WModifyTab::PropertyView() const +{ + return ui->PropertyView; +} + // ************ PUBLIC SLOTS ************ void WModifyTab::GenerateUI() { diff --git a/src/Editor/WorldEditor/WModifyTab.h b/src/Editor/WorldEditor/WModifyTab.h index fa74b0d1..3f7e8328 100644 --- a/src/Editor/WorldEditor/WModifyTab.h +++ b/src/Editor/WorldEditor/WModifyTab.h @@ -4,6 +4,7 @@ #include "CLinkDialog.h" #include "CLinkModel.h" #include "Editor/CNodeSelection.h" +#include "Editor/PropertyEdit/CPropertyView.h" #include #include @@ -37,6 +38,7 @@ public: explicit WModifyTab(CWorldEditor *pEditor, QWidget *pParent = 0); ~WModifyTab(); void ClearUI(); + CPropertyView* PropertyView() const; public slots: void GenerateUI();