Changes made in the tweak editor are now correctly applied to the tweak data & are undo/redo supported
This commit is contained in:
parent
e8d3224088
commit
7b005d7ebd
|
@ -17,7 +17,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||||
{
|
{
|
||||||
Value(pData).Serialize(Arc);
|
ValueRef(pData).Serialize(Arc);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const char* HashableTypeName() const
|
virtual const char* HashableTypeName() const
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
|
|
||||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||||
{
|
{
|
||||||
Value(pData).Serialize(Arc);
|
ValueRef(pData).Serialize(Arc);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "CTweakEditor.h"
|
#include "CTweakEditor.h"
|
||||||
#include "ui_CTweakEditor.h"
|
#include "ui_CTweakEditor.h"
|
||||||
|
#include "Editor/Undo/IUndoCommand.h"
|
||||||
|
|
||||||
CTweakEditor::CTweakEditor(QWidget* pParent)
|
CTweakEditor::CTweakEditor(QWidget* pParent)
|
||||||
: IEditor(pParent)
|
: IEditor(pParent)
|
||||||
|
@ -9,9 +10,11 @@ CTweakEditor::CTweakEditor(QWidget* pParent)
|
||||||
{
|
{
|
||||||
mpUI->setupUi(this);
|
mpUI->setupUi(this);
|
||||||
mpUI->TweakTabs->setExpanding(false);
|
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()
|
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)
|
void CTweakEditor::OnProjectChanged(CGameProject* pNewProject)
|
||||||
{
|
{
|
||||||
// Close and clear tabs
|
// Close and clear tabs
|
||||||
|
@ -78,8 +109,8 @@ void CTweakEditor::OnProjectChanged(CGameProject* pNewProject)
|
||||||
mpUI->TweakTabs->removeTab(0);
|
mpUI->TweakTabs->removeTab(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpUI->TweakTabs->blockSignals(false);
|
|
||||||
mTweakAssets.clear();
|
mTweakAssets.clear();
|
||||||
|
UndoStack().clear();
|
||||||
|
|
||||||
// Create tweak list
|
// Create tweak list
|
||||||
if (pNewProject != nullptr)
|
if (pNewProject != nullptr)
|
||||||
|
@ -105,4 +136,6 @@ void CTweakEditor::OnProjectChanged(CGameProject* pNewProject)
|
||||||
|
|
||||||
SetActiveTweakIndex(0);
|
SetActiveTweakIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mpUI->TweakTabs->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void SetActiveTweakData(CTweakData* pTweakData);
|
void SetActiveTweakData(CTweakData* pTweakData);
|
||||||
void SetActiveTweakIndex(int Index);
|
void SetActiveTweakIndex(int Index);
|
||||||
|
void OnTweakTabClicked(int Index);
|
||||||
void OnProjectChanged(CGameProject* pNewProject);
|
void OnProjectChanged(CGameProject* pNewProject);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,8 @@ HEADERS += \
|
||||||
StringEditor/CStringListModel.h \
|
StringEditor/CStringListModel.h \
|
||||||
StringEditor/CStringDelegate.h \
|
StringEditor/CStringDelegate.h \
|
||||||
CCustomDelegate.h \
|
CCustomDelegate.h \
|
||||||
CTweakEditor.h
|
CTweakEditor.h \
|
||||||
|
Undo/CEditIntrinsicPropertyCommand.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "IEditor.h"
|
#include "IEditor.h"
|
||||||
|
|
||||||
|
#include "Editor/Undo/IUndoCommand.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
|
@ -19,6 +21,8 @@ IEditor::IEditor(QWidget* pParent)
|
||||||
pRedoAction->setIcon(QIcon(":/icons/Redo.png"));
|
pRedoAction->setIcon(QIcon(":/icons/Redo.png"));
|
||||||
mUndoActions.push_back(pUndoAction);
|
mUndoActions.push_back(pUndoAction);
|
||||||
mUndoActions.push_back(pRedoAction);
|
mUndoActions.push_back(pRedoAction);
|
||||||
|
|
||||||
|
connect(&mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(OnUndoStackIndexChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QUndoStack& IEditor::UndoStack()
|
QUndoStack& IEditor::UndoStack()
|
||||||
|
@ -26,12 +30,12 @@ QUndoStack& IEditor::UndoStack()
|
||||||
return mUndoStack;
|
return mUndoStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEditor::AddUndoActions(QToolBar* pToolBar, QAction* pBefore)
|
void IEditor::AddUndoActions(QToolBar* pToolBar, QAction* pBefore /*= 0*/)
|
||||||
{
|
{
|
||||||
pToolBar->insertActions(pBefore, mUndoActions);
|
pToolBar->insertActions(pBefore, mUndoActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEditor::AddUndoActions(QMenu* pMenu, QAction* pBefore)
|
void IEditor::AddUndoActions(QMenu* pMenu, QAction* pBefore /*= 0*/)
|
||||||
{
|
{
|
||||||
pMenu->insertActions(pBefore, mUndoActions);
|
pMenu->insertActions(pBefore, mUndoActions);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +53,10 @@ bool IEditor::CheckUnsavedChanges()
|
||||||
OkToClear = Save();
|
OkToClear = Save();
|
||||||
|
|
||||||
else if (Result == QMessageBox::No)
|
else if (Result == QMessageBox::No)
|
||||||
|
{
|
||||||
|
mUndoStack.setIndex(0); // Revert all changes
|
||||||
OkToClear = true;
|
OkToClear = true;
|
||||||
|
}
|
||||||
|
|
||||||
else if (Result == QMessageBox::Cancel)
|
else if (Result == QMessageBox::Cancel)
|
||||||
OkToClear = false;
|
OkToClear = false;
|
||||||
|
@ -83,3 +90,59 @@ bool IEditor::SaveAndRepack()
|
||||||
}
|
}
|
||||||
else return false;
|
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<const IUndoCommand*>(pkQCmd))
|
||||||
|
{
|
||||||
|
if (pkCmd->AffectsCleanState())
|
||||||
|
IsClean = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (pkQCmd->childCount() > 0)
|
||||||
|
{
|
||||||
|
for (int ChildIdx = 0; ChildIdx < pkQCmd->childCount(); ChildIdx++)
|
||||||
|
{
|
||||||
|
const IUndoCommand *pkCmd = static_cast<const IUndoCommand*>(pkQCmd->child(ChildIdx));
|
||||||
|
|
||||||
|
if (pkCmd->AffectsCleanState())
|
||||||
|
{
|
||||||
|
IsClean = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsClean) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWindowModified(!IsClean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ protected:
|
||||||
public:
|
public:
|
||||||
IEditor(QWidget* pParent);
|
IEditor(QWidget* pParent);
|
||||||
QUndoStack& UndoStack();
|
QUndoStack& UndoStack();
|
||||||
void AddUndoActions(QToolBar* pToolBar, QAction* pBefore);
|
void AddUndoActions(QToolBar* pToolBar, QAction* pBefore = 0);
|
||||||
void AddUndoActions(QMenu* pMenu, QAction* pBefore);
|
void AddUndoActions(QMenu* pMenu, QAction* pBefore = 0);
|
||||||
bool CheckUnsavedChanges();
|
bool CheckUnsavedChanges();
|
||||||
|
|
||||||
/** QMainWindow overrides */
|
/** QMainWindow overrides */
|
||||||
|
@ -39,12 +39,12 @@ public slots:
|
||||||
// Default implementation for editor windows that do not support resaving assets.
|
// Default implementation for editor windows that do not support resaving assets.
|
||||||
// This should not be called.
|
// This should not be called.
|
||||||
warnf("Base IEditor::Save() implementation called. Changes will not be saved.");
|
warnf("Base IEditor::Save() implementation called. Changes will not be saved.");
|
||||||
ASSERT(false);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Non-virtual slots */
|
/** Non-virtual slots */
|
||||||
bool SaveAndRepack();
|
bool SaveAndRepack();
|
||||||
|
void OnUndoStackIndexChanged();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void Closed();
|
void Closed();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "Editor/UICommon.h"
|
#include "Editor/UICommon.h"
|
||||||
#include "Editor/Undo/CEditScriptPropertyCommand.h"
|
#include "Editor/Undo/CEditScriptPropertyCommand.h"
|
||||||
|
#include "Editor/Undo/CEditIntrinsicPropertyCommand.h"
|
||||||
#include "Editor/Undo/CResizeScriptArrayCommand.h"
|
#include "Editor/Undo/CResizeScriptArrayCommand.h"
|
||||||
#include "Editor/Widgets/CResourceSelector.h"
|
#include "Editor/Widgets/CResourceSelector.h"
|
||||||
#include "Editor/Widgets/WColorPicker.h"
|
#include "Editor/Widgets/WColorPicker.h"
|
||||||
|
@ -27,12 +28,13 @@
|
||||||
|
|
||||||
CPropertyDelegate::CPropertyDelegate(QObject* pParent /*= 0*/)
|
CPropertyDelegate::CPropertyDelegate(QObject* pParent /*= 0*/)
|
||||||
: QStyledItemDelegate(pParent)
|
: QStyledItemDelegate(pParent)
|
||||||
|
, mpEditor(nullptr)
|
||||||
, mpModel(nullptr)
|
, mpModel(nullptr)
|
||||||
, mInRelayWidgetEdit(false)
|
, mInRelayWidgetEdit(false)
|
||||||
, mEditInProgress(false)
|
, mEditInProgress(false)
|
||||||
, mRelaysBlocked(false)
|
, mRelaysBlocked(false)
|
||||||
{
|
{
|
||||||
mpEditor = gpEdApp->WorldEditor();
|
mpEditor = UICommon::FindAncestor<IEditor>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPropertyDelegate::SetPropertyModel(CPropertyModel* pModel)
|
void CPropertyDelegate::SetPropertyModel(CPropertyModel* pModel)
|
||||||
|
@ -361,16 +363,28 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
||||||
if (pProp)
|
if (pProp)
|
||||||
{
|
{
|
||||||
EPropertyType Type = mpModel->GetEffectiveFieldType(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;
|
QVector<CScriptObject*> Objects;
|
||||||
Objects << mpModel->GetScriptObject();
|
Objects << pObject;
|
||||||
|
|
||||||
|
pCommand = (Type != EPropertyType::Array) ?
|
||||||
|
new CEditScriptPropertyCommand(pProp, Objects, mpModel, rkIndex) :
|
||||||
|
new CResizeScriptArrayCommand (pProp, Objects, mpModel, rkIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
pCommand->SaveOldData();
|
||||||
|
|
||||||
if (Type != EPropertyType::Array)
|
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
|
// Handle sub-properties of flags and animation sets
|
||||||
if (rkIndex.internalId() & 0x80000000)
|
if (rkIndex.internalId() & 0x80000000)
|
||||||
{
|
{
|
||||||
|
@ -482,9 +496,6 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
|
||||||
// Array
|
// Array
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pCommand = new CResizeScriptArrayCommand(pProp, mpEditor, Objects, mpModel, rkIndex);
|
|
||||||
pCommand->SaveOldData();
|
|
||||||
|
|
||||||
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
WIntegralSpinBox* pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
|
||||||
CArrayProperty* pArray = static_cast<CArrayProperty*>(pProp);
|
CArrayProperty* pArray = static_cast<CArrayProperty*>(pProp);
|
||||||
int OldCount = pArray->ArrayCount(pData);
|
int OldCount = pArray->ArrayCount(pData);
|
||||||
|
@ -560,9 +571,9 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
|
||||||
pSelector->SetFrameVisible(false);
|
pSelector->SetFrameVisible(false);
|
||||||
|
|
||||||
if (Params.Version() <= EGame::Echoes)
|
if (Params.Version() <= EGame::Echoes)
|
||||||
pSelector->SetTypeFilter(mpEditor->CurrentGame(), "ANCS");
|
pSelector->SetTypeFilter(gpEdApp->CurrentGame(), "ANCS");
|
||||||
else
|
else
|
||||||
pSelector->SetTypeFilter(mpEditor->CurrentGame(), "CHAR");
|
pSelector->SetTypeFilter(gpEdApp->CurrentGame(), "CHAR");
|
||||||
|
|
||||||
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*));
|
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*));
|
||||||
return pSelector;
|
return pSelector;
|
||||||
|
@ -626,7 +637,7 @@ void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelInde
|
||||||
if (Type == EPropertyType::Asset)
|
if (Type == EPropertyType::Asset)
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = static_cast<CResourceSelector*>(pEditor)->Entry();
|
CResourceEntry *pEntry = static_cast<CResourceSelector*>(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)
|
else if (Type == EPropertyType::Enum || Type == EPropertyType::Choice)
|
||||||
|
|
|
@ -9,7 +9,7 @@ class CPropertyDelegate : public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
CWorldEditor *mpEditor;
|
IEditor* mpEditor;
|
||||||
CPropertyModel* mpModel;
|
CPropertyModel* mpModel;
|
||||||
bool mInRelayWidgetEdit;
|
bool mInRelayWidgetEdit;
|
||||||
mutable bool mEditInProgress;
|
mutable bool mEditInProgress;
|
||||||
|
@ -17,6 +17,7 @@ class CPropertyDelegate : public QStyledItemDelegate
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CPropertyDelegate(QObject* pParent = 0);
|
CPropertyDelegate(QObject* pParent = 0);
|
||||||
|
void SetEditor(IEditor* pEditor);
|
||||||
void SetPropertyModel(CPropertyModel* pModel);
|
void SetPropertyModel(CPropertyModel* pModel);
|
||||||
|
|
||||||
virtual QWidget* createEditor(QWidget* pParent, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const;
|
virtual QWidget* createEditor(QWidget* pParent, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const;
|
||||||
|
|
|
@ -39,9 +39,6 @@ CPropertyView::CPropertyView(QWidget *pParent)
|
||||||
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CreateContextMenu(QPoint)));
|
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CreateContextMenu(QPoint)));
|
||||||
connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex)));
|
connect(mpModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(SetPersistentEditors(QModelIndex)));
|
||||||
connect(mpModel, SIGNAL(PropertyModified(const QModelIndex&)), this, SLOT(OnPropertyModified(const 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)
|
void CPropertyView::setModel(QAbstractItemModel *pModel)
|
||||||
|
@ -110,7 +107,7 @@ void CPropertyView::SetIntrinsicProperties(CStructRef InProperties)
|
||||||
void CPropertyView::SetInstance(CScriptObject *pObj)
|
void CPropertyView::SetInstance(CScriptObject *pObj)
|
||||||
{
|
{
|
||||||
mpObject = pObj;
|
mpObject = pObj;
|
||||||
mpModel->SetBoldModifiedProperties(mpEditor ? (mpEditor->CurrentGame() > EGame::Prime) : true);
|
mpModel->SetBoldModifiedProperties(gpEdApp->CurrentGame() > EGame::Prime);
|
||||||
|
|
||||||
if (pObj)
|
if (pObj)
|
||||||
mpModel->ConfigureScript(pObj->Area()->Entry()->Project(), pObj->Template()->Properties(), 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)
|
void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent)
|
||||||
{
|
{
|
||||||
// Check what game this is
|
// 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.
|
// Iterate over all properties and update if they're an editor property.
|
||||||
for (int iRow = 0; iRow < mpModel->rowCount(rkParent); iRow++)
|
for (int iRow = 0; iRow < mpModel->rowCount(rkParent); iRow++)
|
||||||
|
@ -245,6 +242,10 @@ void CPropertyView::OnPropertyModified(const QModelIndex& rkIndex)
|
||||||
ClosePersistentEditors(rkIndex);
|
ClosePersistentEditors(rkIndex);
|
||||||
SetPersistentEditors(rkIndex);
|
SetPersistentEditors(rkIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scrollTo(rkIndex);
|
||||||
|
emit PropertyModified(rkIndex);
|
||||||
|
emit PropertyModified(pProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPropertyView::RefreshView()
|
void CPropertyView::RefreshView()
|
||||||
|
@ -268,7 +269,7 @@ void CPropertyView::CreateContextMenu(const QPoint& rkPos)
|
||||||
Menu.addAction(mpEditTemplateAction);
|
Menu.addAction(mpEditTemplateAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mpEditor->CurrentGame() >= EGame::EchoesDemo)
|
if (gpEdApp->CurrentGame() >= EGame::EchoesDemo)
|
||||||
{
|
{
|
||||||
Menu.addAction(mpShowNameValidityAction);
|
Menu.addAction(mpShowNameValidityAction);
|
||||||
}
|
}
|
||||||
|
@ -305,7 +306,8 @@ void CPropertyView::ToggleShowNameValidity(bool ShouldShow)
|
||||||
|
|
||||||
void CPropertyView::EditPropertyTemplate()
|
void CPropertyView::EditPropertyTemplate()
|
||||||
{
|
{
|
||||||
CTemplateEditDialog Dialog(mpMenuProperty, mpEditor);
|
QMainWindow* pParentWindow = UICommon::FindAncestor<QMainWindow>(this);
|
||||||
|
CTemplateEditDialog Dialog(mpMenuProperty, pParentWindow);
|
||||||
connect(&Dialog, SIGNAL(PerformedTypeConversion()), this, SLOT(RefreshView()));
|
connect(&Dialog, SIGNAL(PerformedTypeConversion()), this, SLOT(RefreshView()));
|
||||||
Dialog.exec();
|
Dialog.exec();
|
||||||
}
|
}
|
||||||
|
@ -313,21 +315,21 @@ void CPropertyView::EditPropertyTemplate()
|
||||||
|
|
||||||
void CPropertyView::GenerateNamesForProperty()
|
void CPropertyView::GenerateNamesForProperty()
|
||||||
{
|
{
|
||||||
CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog();
|
CGeneratePropertyNamesDialog* pDialog = gpEdApp->WorldEditor()->NameGeneratorDialog();
|
||||||
pDialog->AddToIDPool(mpMenuProperty);
|
pDialog->AddToIDPool(mpMenuProperty);
|
||||||
pDialog->show();
|
pDialog->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPropertyView::GenerateNamesForSiblings()
|
void CPropertyView::GenerateNamesForSiblings()
|
||||||
{
|
{
|
||||||
CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog();
|
CGeneratePropertyNamesDialog* pDialog = gpEdApp->WorldEditor()->NameGeneratorDialog();
|
||||||
pDialog->AddChildrenToIDPool(mpMenuProperty->Parent(), false);
|
pDialog->AddChildrenToIDPool(mpMenuProperty->Parent(), false);
|
||||||
pDialog->show();
|
pDialog->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPropertyView::GenerateNamesForChildren()
|
void CPropertyView::GenerateNamesForChildren()
|
||||||
{
|
{
|
||||||
CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog();
|
CGeneratePropertyNamesDialog* pDialog = gpEdApp->WorldEditor()->NameGeneratorDialog();
|
||||||
pDialog->AddChildrenToIDPool(mpMenuProperty, false);
|
pDialog->AddChildrenToIDPool(mpMenuProperty, false);
|
||||||
pDialog->show();
|
pDialog->show();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ class CPropertyView : public QTreeView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
CWorldEditor *mpEditor;
|
|
||||||
CPropertyModel* mpModel;
|
CPropertyModel* mpModel;
|
||||||
CPropertyDelegate* mpDelegate;
|
CPropertyDelegate* mpDelegate;
|
||||||
CScriptObject* mpObject;
|
CScriptObject* mpObject;
|
||||||
|
@ -47,6 +46,10 @@ public slots:
|
||||||
void GenerateNamesForProperty();
|
void GenerateNamesForProperty();
|
||||||
void GenerateNamesForSiblings();
|
void GenerateNamesForSiblings();
|
||||||
void GenerateNamesForChildren();
|
void GenerateNamesForChildren();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void PropertyModified(const QModelIndex& kIndex);
|
||||||
|
void PropertyModified(IProperty* pProperty);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CPROPERTYVIEW_H
|
#endif // CPROPERTYVIEW_H
|
||||||
|
|
|
@ -46,6 +46,23 @@ QWindow* FindWidgetWindowHandle(QWidget *pWidget);
|
||||||
void OpenContainingFolder(const QString& rkPath);
|
void OpenContainingFolder(const QString& rkPath);
|
||||||
bool OpenInExternalApplication(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<typename ObjectT>
|
||||||
|
ObjectT* FindAncestor(QObject* pObject)
|
||||||
|
{
|
||||||
|
for (QObject* pParent = pObject->parent(); pParent; pParent = pParent->parent())
|
||||||
|
{
|
||||||
|
ObjectT* pCasted = qobject_cast<ObjectT*>(pParent);
|
||||||
|
|
||||||
|
if (pCasted)
|
||||||
|
{
|
||||||
|
return pCasted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// TString/TWideString <-> QString
|
// TString/TWideString <-> QString
|
||||||
inline QString ToQString(const TString& rkStr)
|
inline QString ToQString(const TString& rkStr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef CEDITINTRINSICPROPERTYCOMMAND_H
|
||||||
|
#define CEDITINTRINSICPROPERTYCOMMAND_H
|
||||||
|
|
||||||
|
#include "IEditPropertyCommand.h"
|
||||||
|
|
||||||
|
class CEditIntrinsicPropertyCommand : public IEditPropertyCommand
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
QVector<void*> mDataPointers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CEditIntrinsicPropertyCommand(IProperty* pProperty,
|
||||||
|
const QVector<void*>& kDataPointers,
|
||||||
|
CPropertyModel* pModel,
|
||||||
|
QModelIndex Index = QModelIndex(),
|
||||||
|
const QString& kCommandName = "Edit Property")
|
||||||
|
: IEditPropertyCommand(pProperty, pModel, Index, kCommandName)
|
||||||
|
, mDataPointers(kDataPointers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void GetObjectDataPointers(QVector<void*>& rOutPointers) const override
|
||||||
|
{
|
||||||
|
rOutPointers = mDataPointers;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CEDITINTRINSICPROPERTYCOMMAND_H
|
|
@ -9,72 +9,41 @@ class CEditScriptPropertyCommand : public IEditPropertyCommand
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
QVector<CInstancePtr> mInstances;
|
QVector<CInstancePtr> mInstances;
|
||||||
CWorldEditor* mpEditor;
|
|
||||||
QModelIndex mIndex;
|
QModelIndex mIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CEditScriptPropertyCommand(IProperty* pProperty,
|
CEditScriptPropertyCommand(IProperty* pProperty,
|
||||||
CWorldEditor* pEditor,
|
const QVector<CScriptObject*>& kInstances,
|
||||||
const QVector<CScriptObject*>& rkInstances,
|
CPropertyModel* pModel,
|
||||||
QModelIndex Index = QModelIndex(),
|
QModelIndex Index = QModelIndex(),
|
||||||
const QString& rkCommandName = "Edit Property")
|
const QString& kCommandName = "Edit Property")
|
||||||
: IEditPropertyCommand(pProperty, rkCommandName)
|
: IEditPropertyCommand(pProperty, pModel, Index, kCommandName)
|
||||||
, mpEditor(pEditor)
|
|
||||||
, mIndex(Index)
|
, 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
|
// Convert CScriptObject pointers to CInstancePtrs
|
||||||
mInstances.reserve( rkInstances.size() );
|
mInstances.reserve( kInstances.size() );
|
||||||
|
|
||||||
for (int i = 0; i < rkInstances.size(); i++)
|
for (int i = 0; i < kInstances.size(); i++)
|
||||||
mInstances.push_back( CInstancePtr(rkInstances[i]) );
|
mInstances.push_back( CInstancePtr(kInstances[i]) );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void GetObjectDataPointers(QVector<void*>& rOutPointers) const override
|
virtual void GetObjectDataPointers(QVector<void*>& OutPointers) const override
|
||||||
{
|
{
|
||||||
// todo: support multiple objects being edited at once on the property view
|
// todo: support multiple objects being edited at once on the property view
|
||||||
if (mIndex.isValid())
|
if (mIndex.isValid())
|
||||||
{
|
{
|
||||||
ASSERT(mInstances.size() == 1);
|
ASSERT(mInstances.size() == 1);
|
||||||
rOutPointers << mInstances[0]->PropertyData();
|
OutPointers << mInstances[0]->PropertyData();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// grab instance pointers
|
// grab instance pointers
|
||||||
ASSERT(!mpProperty->IsArrayArchetype());
|
ASSERT(!mpProperty->IsArrayArchetype());
|
||||||
|
|
||||||
rOutPointers.resize(mInstances.size());
|
OutPointers.resize(mInstances.size());
|
||||||
|
|
||||||
for (int i = 0; i < mInstances.size(); i++)
|
for (int i = 0; i < mInstances.size(); i++)
|
||||||
rOutPointers[i] = mInstances[i]->PropertyData();
|
OutPointers[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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,31 +5,21 @@
|
||||||
|
|
||||||
class CResizeScriptArrayCommand : public CEditScriptPropertyCommand
|
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 */
|
/** Old/new model row counts; we store this here to support editing arrays on multiple instances at once */
|
||||||
int mOldRowCount;
|
int mOldRowCount;
|
||||||
int mNewRowCount;
|
int mNewRowCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResizeScriptArrayCommand(IProperty* pProperty,
|
CResizeScriptArrayCommand(IProperty* pProperty,
|
||||||
CWorldEditor* pEditor,
|
|
||||||
const QVector<CScriptObject*>& rkInstances,
|
const QVector<CScriptObject*>& rkInstances,
|
||||||
CPropertyModel* pModel = nullptr,
|
CPropertyModel* pModel,
|
||||||
QModelIndex Index = QModelIndex(),
|
QModelIndex Index = QModelIndex(),
|
||||||
const QString& rkCommandName = "Resize Array"
|
const QString& rkCommandName = "Resize Array"
|
||||||
)
|
)
|
||||||
: CEditScriptPropertyCommand(pProperty, pEditor, rkInstances, Index, rkCommandName)
|
: CEditScriptPropertyCommand(pProperty, rkInstances, pModel, Index, rkCommandName)
|
||||||
, mpModel(nullptr)
|
|
||||||
, mOldRowCount(-1)
|
, mOldRowCount(-1)
|
||||||
, mNewRowCount(-1)
|
, mNewRowCount(-1)
|
||||||
{
|
{
|
||||||
if (Index.isValid())
|
|
||||||
{
|
|
||||||
ASSERT(pModel != nullptr);
|
|
||||||
mpModel = pModel;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mergeWith(const QUndoCommand *pkOther)
|
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
|
// 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()
|
void undo()
|
||||||
{
|
{
|
||||||
|
//@todo verify, do we need to fully override undo()?
|
||||||
if (mpModel)
|
if (mpModel)
|
||||||
{
|
{
|
||||||
mpModel->ArrayAboutToBeResized(mIndex, mOldRowCount);
|
mpModel->ArrayAboutToBeResized(mIndex, mOldRowCount);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include "IEditPropertyCommand.h"
|
#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 */
|
/** Save the current state of the object properties to the given data buffer */
|
||||||
void IEditPropertyCommand::SaveObjectStateToArray(std::vector<char>& rVector)
|
void IEditPropertyCommand::SaveObjectStateToArray(std::vector<char>& rVector)
|
||||||
|
@ -31,14 +33,36 @@ void IEditPropertyCommand::RestoreObjectStateFromArray(std::vector<char>& rArray
|
||||||
|
|
||||||
IEditPropertyCommand::IEditPropertyCommand(
|
IEditPropertyCommand::IEditPropertyCommand(
|
||||||
IProperty* pProperty,
|
IProperty* pProperty,
|
||||||
const QString& rkCommandName /*= "Edit Property"*/
|
CPropertyModel* pModel,
|
||||||
|
const QModelIndex& kIndex,
|
||||||
|
const QString& kCommandName /*= "Edit Property"*/
|
||||||
)
|
)
|
||||||
: IUndoCommand(rkCommandName)
|
: IUndoCommand(kCommandName)
|
||||||
, mpProperty(pProperty)
|
, mpProperty(pProperty)
|
||||||
|
, mpModel(pModel)
|
||||||
|
, mIndex(kIndex)
|
||||||
, mSavedOldData(false)
|
, mSavedOldData(false)
|
||||||
, mSavedNewData(false)
|
, mSavedNewData(false)
|
||||||
{
|
{
|
||||||
ASSERT(mpProperty);
|
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()
|
void IEditPropertyCommand::SaveOldData()
|
||||||
|
@ -108,12 +132,30 @@ void IEditPropertyCommand::undo()
|
||||||
ASSERT(mSavedOldData && mSavedNewData);
|
ASSERT(mSavedOldData && mSavedNewData);
|
||||||
RestoreObjectStateFromArray(mOldData);
|
RestoreObjectStateFromArray(mOldData);
|
||||||
mCommandEnded = true;
|
mCommandEnded = true;
|
||||||
|
|
||||||
|
if (mpModel && mIndex.isValid())
|
||||||
|
{
|
||||||
|
mpModel->NotifyPropertyModified(mIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gpEdApp->WorldEditor()->OnPropertyModified(mpProperty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEditPropertyCommand::redo()
|
void IEditPropertyCommand::redo()
|
||||||
{
|
{
|
||||||
ASSERT(mSavedOldData && mSavedNewData);
|
ASSERT(mSavedOldData && mSavedNewData);
|
||||||
RestoreObjectStateFromArray(mNewData);
|
RestoreObjectStateFromArray(mNewData);
|
||||||
|
|
||||||
|
if (mpModel && mIndex.isValid())
|
||||||
|
{
|
||||||
|
mpModel->NotifyPropertyModified(mIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gpEdApp->WorldEditor()->OnPropertyModified(mpProperty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IEditPropertyCommand::AffectsCleanState() const
|
bool IEditPropertyCommand::AffectsCleanState() const
|
||||||
|
|
|
@ -13,6 +13,8 @@ protected:
|
||||||
std::vector<char> mNewData;
|
std::vector<char> mNewData;
|
||||||
|
|
||||||
IProperty* mpProperty;
|
IProperty* mpProperty;
|
||||||
|
CPropertyModel* mpModel;
|
||||||
|
QModelIndex mIndex;
|
||||||
bool mCommandEnded;
|
bool mCommandEnded;
|
||||||
bool mSavedOldData;
|
bool mSavedOldData;
|
||||||
bool mSavedNewData;
|
bool mSavedNewData;
|
||||||
|
@ -26,9 +28,13 @@ protected:
|
||||||
public:
|
public:
|
||||||
IEditPropertyCommand(
|
IEditPropertyCommand(
|
||||||
IProperty* pProperty,
|
IProperty* pProperty,
|
||||||
const QString& rkCommandName = "Edit Property"
|
CPropertyModel* pModel,
|
||||||
|
const QModelIndex& kIndex,
|
||||||
|
const QString& kCommandName = "Edit Property"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
virtual ~IEditPropertyCommand() {}
|
||||||
|
|
||||||
virtual void SaveOldData();
|
virtual void SaveOldData();
|
||||||
virtual void SaveNewData();
|
virtual void SaveNewData();
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ CInstancesModel::CInstancesModel(CWorldEditor *pEditor, QObject *pParent)
|
||||||
connect(mpEditor, SIGNAL(NodeSpawned(CSceneNode*)), this, SLOT(NodeCreated(CSceneNode*)));
|
connect(mpEditor, SIGNAL(NodeSpawned(CSceneNode*)), this, SLOT(NodeCreated(CSceneNode*)));
|
||||||
connect(mpEditor, SIGNAL(NodeAboutToBeDeleted(CSceneNode*)), this, SLOT(NodeAboutToBeDeleted(CSceneNode*)));
|
connect(mpEditor, SIGNAL(NodeAboutToBeDeleted(CSceneNode*)), this, SLOT(NodeAboutToBeDeleted(CSceneNode*)));
|
||||||
connect(mpEditor, SIGNAL(NodeDeleted()), this, SLOT(NodeDeleted()));
|
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(InstancesLayerAboutToChange()), this, SLOT(InstancesLayerPreChange()));
|
||||||
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(InstancesLayerPostChange(QList<CScriptNode*>)));
|
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(InstancesLayerPostChange(QList<CScriptNode*>)));
|
||||||
}
|
}
|
||||||
|
@ -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")
|
if (pProp->Name() == "Name")
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,7 +60,7 @@ public slots:
|
||||||
void NodeAboutToBeDeleted(CSceneNode *pNode);
|
void NodeAboutToBeDeleted(CSceneNode *pNode);
|
||||||
void NodeDeleted();
|
void NodeDeleted();
|
||||||
|
|
||||||
void PropertyModified(CScriptObject *pInst, IProperty *pProp);
|
void PropertyModified(IProperty *pProp, CScriptObject *pInst);
|
||||||
void InstancesLayerPreChange();
|
void InstancesLayerPreChange();
|
||||||
void InstancesLayerPostChange(const QList<CScriptNode*>& rkInstanceList);
|
void InstancesLayerPostChange(const QList<CScriptNode*>& rkInstanceList);
|
||||||
|
|
||||||
|
|
|
@ -541,12 +541,17 @@ void CWorldEditor::OnLinksModified(const QList<CScriptObject*>& rkInstances)
|
||||||
emit InstanceLinksModified(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)
|
||||||
{
|
{
|
||||||
|
CSceneNode* pNode = *It;
|
||||||
|
|
||||||
|
if (pNode && pNode->NodeType() == ENodeType::Script)
|
||||||
|
{
|
||||||
|
CScriptNode* pScript = static_cast<CScriptNode*>(pNode);
|
||||||
pScript->PropertyModified(pProp);
|
pScript->PropertyModified(pProp);
|
||||||
|
|
||||||
// If this is the name, update other parts of the UI to reflect the new value.
|
// If this is the name, update other parts of the UI to reflect the new value.
|
||||||
|
@ -561,6 +566,9 @@ void CWorldEditor::OnPropertyModified(CScriptObject* pObject, IProperty *pProp)
|
||||||
{
|
{
|
||||||
mpSelection->UpdateBounds();
|
mpSelection->UpdateBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit signal so other widgets can react to the property change
|
||||||
|
emit PropertyModified(pProp, pScript->Instance());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 this is a model/character, then we'll treat this as a modified selection. This is to make sure the selection bounds updates.
|
||||||
|
@ -570,13 +578,16 @@ void CWorldEditor::OnPropertyModified(CScriptObject* pObject, IProperty *pProp)
|
||||||
const CResTypeFilter& rkFilter = pAsset->GetTypeFilter();
|
const CResTypeFilter& rkFilter = pAsset->GetTypeFilter();
|
||||||
|
|
||||||
if (rkFilter.Accepts(EResourceType::Model) || rkFilter.Accepts(EResourceType::AnimSet) || rkFilter.Accepts(EResourceType::Character))
|
if (rkFilter.Accepts(EResourceType::Model) || rkFilter.Accepts(EResourceType::AnimSet) || rkFilter.Accepts(EResourceType::Character))
|
||||||
SelectionModified();
|
ShouldUpdateSelection = true;
|
||||||
}
|
}
|
||||||
else if (pProp->Type() == EPropertyType::AnimationSet)
|
else if (pProp->Type() == EPropertyType::AnimationSet)
|
||||||
SelectionModified();
|
ShouldUpdateSelection = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Emit signal so other widgets can react to the property change
|
if (ShouldUpdateSelection)
|
||||||
emit PropertyModified(pObject, pProp);
|
{
|
||||||
|
SelectionModified();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWorldEditor::SetSelectionActive(bool Active)
|
void CWorldEditor::SetSelectionActive(bool Active)
|
||||||
|
@ -616,10 +627,14 @@ void CWorldEditor::SetSelectionActive(bool Active)
|
||||||
|
|
||||||
if (pActiveProperty)
|
if (pActiveProperty)
|
||||||
{
|
{
|
||||||
|
CPropertyModel* pModel = qobject_cast<CPropertyModel*>(
|
||||||
|
mpScriptSidebar->ModifyTab()->PropertyView()->model()
|
||||||
|
);
|
||||||
|
|
||||||
CEditScriptPropertyCommand* pCommand = new CEditScriptPropertyCommand(
|
CEditScriptPropertyCommand* pCommand = new CEditScriptPropertyCommand(
|
||||||
pActiveProperty,
|
pActiveProperty,
|
||||||
this,
|
CommandObjects,
|
||||||
CommandObjects
|
pModel
|
||||||
);
|
);
|
||||||
|
|
||||||
pCommand->SaveOldData();
|
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<const IUndoCommand*>(pkQCmd))
|
|
||||||
{
|
|
||||||
if (pkCmd->AffectsCleanState())
|
|
||||||
IsClean = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (pkQCmd->childCount() > 0)
|
|
||||||
{
|
|
||||||
for (int iChild = 0; iChild < pkQCmd->childCount(); iChild++)
|
|
||||||
{
|
|
||||||
const IUndoCommand *pkCmd = static_cast<const IUndoCommand*>(pkQCmd->child(iChild));
|
|
||||||
|
|
||||||
if (pkCmd->AffectsCleanState())
|
|
||||||
{
|
|
||||||
IsClean = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsClean) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
setWindowModified(!IsClean);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CWorldEditor::OnPickModeEnter(QCursor Cursor)
|
void CWorldEditor::OnPickModeEnter(QCursor Cursor)
|
||||||
{
|
{
|
||||||
ui->MainViewport->SetCursorState(Cursor);
|
ui->MainViewport->SetCursorState(Cursor);
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QUndoStack>
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class CWorldEditor;
|
class CWorldEditor;
|
||||||
|
@ -115,7 +114,7 @@ public slots:
|
||||||
|
|
||||||
void OnActiveProjectChanged(CGameProject *pProj);
|
void OnActiveProjectChanged(CGameProject *pProj);
|
||||||
void OnLinksModified(const QList<CScriptObject*>& rkInstances);
|
void OnLinksModified(const QList<CScriptObject*>& rkInstances);
|
||||||
void OnPropertyModified(CScriptObject* pObject, IProperty *pProp);
|
void OnPropertyModified(IProperty *pProp);
|
||||||
void SetSelectionActive(bool Active);
|
void SetSelectionActive(bool Active);
|
||||||
void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone);
|
void SetSelectionInstanceNames(const QString& rkNewName, bool IsDone);
|
||||||
void SetSelectionLayer(CScriptLayer *pLayer);
|
void SetSelectionLayer(CScriptLayer *pLayer);
|
||||||
|
@ -143,7 +142,6 @@ private slots:
|
||||||
void OnLinkEnd();
|
void OnLinkEnd();
|
||||||
void OnUnlinkClicked();
|
void OnUnlinkClicked();
|
||||||
|
|
||||||
void OnUndoStackIndexChanged();
|
|
||||||
void OnPickModeEnter(QCursor Cursor);
|
void OnPickModeEnter(QCursor Cursor);
|
||||||
void OnPickModeExit();
|
void OnPickModeExit();
|
||||||
void UpdateCameraOrbit();
|
void UpdateCameraOrbit();
|
||||||
|
@ -178,7 +176,7 @@ signals:
|
||||||
void InstancesLayerAboutToChange();
|
void InstancesLayerAboutToChange();
|
||||||
void InstancesLayerChanged(const QList<CScriptNode*>& rkInstanceList);
|
void InstancesLayerChanged(const QList<CScriptNode*>& rkInstanceList);
|
||||||
void InstanceLinksModified(const QList<CScriptObject*>& rkInstances);
|
void InstanceLinksModified(const QList<CScriptObject*>& rkInstances);
|
||||||
void PropertyModified(CScriptObject *pInst, IProperty *pProp);
|
void PropertyModified(IProperty *pProp, CScriptObject* pObject);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CWORLDEDITOR_H
|
#endif // CWORLDEDITOR_H
|
||||||
|
|
|
@ -65,7 +65,7 @@ void WEditorProperties::SyncToEditor(CWorldEditor *pEditor)
|
||||||
connect(mpEditor, SIGNAL(SelectionModified()), this, SLOT(OnSelectionModified()));
|
connect(mpEditor, SIGNAL(SelectionModified()), this, SLOT(OnSelectionModified()));
|
||||||
connect(mpEditor, SIGNAL(LayersModified()), this, SLOT(OnLayersModified()));
|
connect(mpEditor, SIGNAL(LayersModified()), this, SLOT(OnLayersModified()));
|
||||||
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(OnInstancesLayerChanged(QList<CScriptNode*>)));
|
connect(mpEditor, SIGNAL(InstancesLayerChanged(QList<CScriptNode*>)), this, SLOT(OnInstancesLayerChanged(QList<CScriptNode*>)));
|
||||||
connect(mpEditor, SIGNAL(PropertyModified(CScriptObject*,IProperty*)), this, SLOT(OnPropertyModified(CScriptObject*,IProperty*)));
|
connect(mpEditor, SIGNAL(PropertyModified(IProperty*,CScriptObject*)), this, SLOT(OnPropertyModified(IProperty*,CScriptObject*)));
|
||||||
|
|
||||||
OnLayersModified();
|
OnLayersModified();
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ void WEditorProperties::OnSelectionModified()
|
||||||
SetLayerComboBox();
|
SetLayerComboBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WEditorProperties::OnPropertyModified(CScriptObject *pInstance, IProperty *pProp)
|
void WEditorProperties::OnPropertyModified(IProperty* pProp, CScriptObject* pInstance)
|
||||||
{
|
{
|
||||||
if (!mpInstanceNameLineEdit->hasFocus())
|
if (!mpInstanceNameLineEdit->hasFocus())
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnSelectionModified();
|
void OnSelectionModified();
|
||||||
void OnPropertyModified(CScriptObject *pInst, IProperty *pProp);
|
void OnPropertyModified(IProperty* pProp, CScriptObject* pInstance);
|
||||||
void OnInstancesLayerChanged(const QList<CScriptNode*>& rkNodeList);
|
void OnInstancesLayerChanged(const QList<CScriptNode*>& rkNodeList);
|
||||||
void OnLayersModified();
|
void OnLayersModified();
|
||||||
void UpdatePropertyValues();
|
void UpdatePropertyValues();
|
||||||
|
|
|
@ -45,6 +45,7 @@ WModifyTab::WModifyTab(CWorldEditor *pEditor, QWidget *pParent)
|
||||||
connect(ui->DeleteIncomingConnectionButton, SIGNAL(clicked()), this, SLOT(OnDeleteLinksClicked()));
|
connect(ui->DeleteIncomingConnectionButton, SIGNAL(clicked()), this, SLOT(OnDeleteLinksClicked()));
|
||||||
connect(ui->EditOutgoingConnectionButton, SIGNAL(clicked()), this, SLOT(OnEditLinkClicked()));
|
connect(ui->EditOutgoingConnectionButton, SIGNAL(clicked()), this, SLOT(OnEditLinkClicked()));
|
||||||
connect(ui->EditIncomingConnectionButton, 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(MapChanged(CWorld*,CGameArea*)), this, SLOT(OnMapChanged()));
|
||||||
connect(mpWorldEditor, SIGNAL(SelectionTransformed()), this, SLOT(OnWorldSelectionTransformed()));
|
connect(mpWorldEditor, SIGNAL(SelectionTransformed()), this, SLOT(OnWorldSelectionTransformed()));
|
||||||
connect(mpWorldEditor, SIGNAL(InstanceLinksModified(const QList<CScriptObject*>&)), this, SLOT(OnInstanceLinksModified(const QList<CScriptObject*>&)));
|
connect(mpWorldEditor, SIGNAL(InstanceLinksModified(const QList<CScriptObject*>&)), this, SLOT(OnInstanceLinksModified(const QList<CScriptObject*>&)));
|
||||||
|
@ -65,6 +66,11 @@ void WModifyTab::ClearUI()
|
||||||
mpSelectedNode = nullptr;
|
mpSelectedNode = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CPropertyView* WModifyTab::PropertyView() const
|
||||||
|
{
|
||||||
|
return ui->PropertyView;
|
||||||
|
}
|
||||||
|
|
||||||
// ************ PUBLIC SLOTS ************
|
// ************ PUBLIC SLOTS ************
|
||||||
void WModifyTab::GenerateUI()
|
void WModifyTab::GenerateUI()
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "CLinkDialog.h"
|
#include "CLinkDialog.h"
|
||||||
#include "CLinkModel.h"
|
#include "CLinkModel.h"
|
||||||
#include "Editor/CNodeSelection.h"
|
#include "Editor/CNodeSelection.h"
|
||||||
|
#include "Editor/PropertyEdit/CPropertyView.h"
|
||||||
#include <Core/Scene/CSceneNode.h>
|
#include <Core/Scene/CSceneNode.h>
|
||||||
#include <Core/Scene/CScriptNode.h>
|
#include <Core/Scene/CScriptNode.h>
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ public:
|
||||||
explicit WModifyTab(CWorldEditor *pEditor, QWidget *pParent = 0);
|
explicit WModifyTab(CWorldEditor *pEditor, QWidget *pParent = 0);
|
||||||
~WModifyTab();
|
~WModifyTab();
|
||||||
void ClearUI();
|
void ClearUI();
|
||||||
|
CPropertyView* PropertyView() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void GenerateUI();
|
void GenerateUI();
|
||||||
|
|
Loading…
Reference in New Issue