From 581d5f72676c75b384fc0feed304a4aef696a9c6 Mon Sep 17 00:00:00 2001 From: Aruki Date: Mon, 10 Jul 2017 15:19:11 -0600 Subject: [PATCH] Changed resource selector widgets so they can pop up a panel with a list of acceptable resources --- src/Core/Core.pro | 3 +- src/Core/Resource/CResTypeFilter.h | 87 ++++++++++++ src/Core/Resource/CResTypeInfo.cpp | 8 +- src/Core/Resource/Cooker/CTemplateWriter.cpp | 18 +-- src/Core/Resource/Factory/CScriptLoader.cpp | 16 +-- src/Core/Resource/Factory/CTemplateLoader.cpp | 4 +- src/Core/Resource/Script/IPropertyTemplate.h | 18 +-- src/Core/Scene/CScriptNode.cpp | 5 +- src/Editor/Editor.pro | 10 +- src/Editor/Icons.qrc | 1 + src/Editor/ModelEditor/CModelEditorWindow.cpp | 4 +- src/Editor/PropertyEdit/CPropertyDelegate.cpp | 6 +- src/Editor/Widgets/CFilteredResourceModel.h | 131 ++++++++++++++++++ src/Editor/Widgets/CResourceSelector.cpp | 38 +++-- src/Editor/Widgets/CResourceSelector.h | 15 +- src/Editor/Widgets/CSelectResourcePanel.cpp | 96 +++++++++++++ src/Editor/Widgets/CSelectResourcePanel.h | 31 +++++ src/Editor/Widgets/CSelectResourcePanel.ui | 95 +++++++++++++ src/Editor/WorldEditor/CWorldEditor.cpp | 3 +- src/Editor/icons/ArrowD_16px.png | Bin 0 -> 160 bytes 20 files changed, 507 insertions(+), 82 deletions(-) create mode 100644 src/Core/Resource/CResTypeFilter.h create mode 100644 src/Editor/Widgets/CFilteredResourceModel.h create mode 100644 src/Editor/Widgets/CSelectResourcePanel.cpp create mode 100644 src/Editor/Widgets/CSelectResourcePanel.h create mode 100644 src/Editor/Widgets/CSelectResourcePanel.ui create mode 100644 src/Editor/icons/ArrowD_16px.png diff --git a/src/Core/Core.pro b/src/Core/Core.pro index 7397c5b8..cda46bbc 100644 --- a/src/Core/Core.pro +++ b/src/Core/Core.pro @@ -229,7 +229,8 @@ HEADERS += \ Resource/CMapArea.h \ Resource/CSavedStateID.h \ IProgressNotifier.h \ - IUIRelay.h + IUIRelay.h \ + Resource/CResTypeFilter.h # Source Files SOURCES += \ diff --git a/src/Core/Resource/CResTypeFilter.h b/src/Core/Resource/CResTypeFilter.h new file mode 100644 index 00000000..068313b4 --- /dev/null +++ b/src/Core/Resource/CResTypeFilter.h @@ -0,0 +1,87 @@ +#ifndef CRESTYPEFILTER_H +#define CRESTYPEFILTER_H + +#include "EResType.h" +#include "CResTypeInfo.h" +#include "Core/GameProject/CResourceEntry.h" + +class CResTypeFilter +{ + EGame mGame; + std::set mAcceptedTypes; + +public: + CResTypeFilter() { } + CResTypeFilter(EGame Game, const TString& rkTypeList) { FromString(Game, rkTypeList); } + + void SetAcceptedTypes(EGame Game, const TStringList& rkTypes) + { + mAcceptedTypes.clear(); + mGame = Game; + + for (auto Iter = rkTypes.begin(); Iter != rkTypes.end(); Iter++) + { + CResTypeInfo *pTypeInfo = CResTypeInfo::TypeForCookedExtension(mGame, CFourCC(*Iter)); + + if (pTypeInfo) + mAcceptedTypes.insert(pTypeInfo->Type()); + } + } + + TString ToString() const + { + TString Out; + + for (auto Iter = mAcceptedTypes.begin(); Iter != mAcceptedTypes.end(); Iter++) + { + if (!Out.IsEmpty()) Out += ','; + CResTypeInfo *pTypeInfo = CResTypeInfo::FindTypeInfo(*Iter); + Out += pTypeInfo->CookedExtension(mGame).ToString(); + } + + return Out; + } + + void FromString(EGame Game, const TString& rkString) + { + SetAcceptedTypes(Game, rkString.Split(",")); + } + + inline bool Accepts(EResType Type) const + { + return mAcceptedTypes.find(Type) != mAcceptedTypes.end(); + } + + inline bool Accepts(CResTypeInfo *pType) const + { + return pType && Accepts(pType->Type()); + } + + inline bool Accepts(CResourceEntry *pEntry) const + { + return pEntry && Accepts(pEntry->ResourceType()); + } + + inline bool Accepts(const CResTypeFilter& rkFilter) const + { + for (auto Iter = mAcceptedTypes.begin(); Iter != mAcceptedTypes.end(); Iter++) + { + if (rkFilter.Accepts(*Iter)) + return true; + } + + return false; + } + + inline bool operator==(const CResTypeFilter& rkOther) const + { + return mAcceptedTypes == rkOther.mAcceptedTypes; + } + + inline bool operator!=(const CResTypeFilter& rkOther) const + { + return !(*this == rkOther); + } +}; + +#endif // CRESTYPEFILTER_H diff --git a/src/Core/Resource/CResTypeInfo.cpp b/src/Core/Resource/CResTypeInfo.cpp index c4c9659e..567640ce 100644 --- a/src/Core/Resource/CResTypeInfo.cpp +++ b/src/Core/Resource/CResTypeInfo.cpp @@ -93,8 +93,12 @@ CResTypeInfo* CResTypeInfo::TypeForCookedExtension(EGame Game, CFourCC Ext) } // Haven't found it; caller gave us an invalid type - Log::Error("Failed to find resource type for cooked extension: " + Ext.ToString()); - DEBUG_BREAK; + // Note UNKN is used to indicate unknown asset type + if (Ext != FOURCC('UNKN')) + { + Log::Error("Failed to find resource type for cooked extension: " + Ext.ToString()); + DEBUG_BREAK; + } sCachedTypeMap[Ext] = nullptr; return nullptr; } diff --git a/src/Core/Resource/Cooker/CTemplateWriter.cpp b/src/Core/Resource/Cooker/CTemplateWriter.cpp index 19a8198f..90ba206e 100644 --- a/src/Core/Resource/Cooker/CTemplateWriter.cpp +++ b/src/Core/Resource/Cooker/CTemplateWriter.cpp @@ -624,13 +624,8 @@ void CTemplateWriter::SaveProperties(XMLDocument *pDoc, XMLElement *pParent, CSt if (pProp->Type() == eAssetProperty) { CAssetTemplate *pAsset = static_cast(pProp); - const TStringList& rkExtensions = pAsset->AllowedExtensions(); - TString ExtensionsString; - - for (auto it = rkExtensions.begin(); it != rkExtensions.end(); it++) - ExtensionsString += *it + ","; - - ExtensionsString = ExtensionsString.ChopBack(1); // Remove extra comma + const CResTypeFilter& rkFilter = pAsset->TypeFilter(); + TString ExtensionsString = rkFilter.ToString(); if (ExtensionsString.IsEmpty()) ExtensionsString = "UNKN"; pElem->SetAttribute("extensions", *ExtensionsString); } @@ -796,14 +791,9 @@ void CTemplateWriter::SavePropertyOverrides(XMLDocument *pDoc, XMLElement *pPare CAssetTemplate *pAsset = static_cast(pProp); CAssetTemplate *pSourceAsset = static_cast(pSource); - if (pAsset->AllowedExtensions() != pSourceAsset->AllowedExtensions()) + if (pAsset->TypeFilter() != pSourceAsset->TypeFilter()) { - TString ExtensionsString; - - for (auto it = pAsset->AllowedExtensions().begin(); it != pAsset->AllowedExtensions().end(); it++) - ExtensionsString += *it + ","; - - ExtensionsString = ExtensionsString.ChopBack(1); + TString ExtensionsString = pAsset->TypeFilter().ToString(); if (ExtensionsString.IsEmpty()) ExtensionsString = "UNKN"; pElem->SetAttribute("extensions", *ExtensionsString); } diff --git a/src/Core/Resource/Factory/CScriptLoader.cpp b/src/Core/Resource/Factory/CScriptLoader.cpp index bdb0114b..b71e87ef 100644 --- a/src/Core/Resource/Factory/CScriptLoader.cpp +++ b/src/Core/Resource/Factory/CScriptLoader.cpp @@ -133,21 +133,11 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY if (pEntry) { - TString CookedExt = pEntry->CookedExtension().ToString(); - const TStringList& rkExtensions = static_cast(pTemp)->AllowedExtensions(); - bool Valid = false; - - for (auto It = rkExtensions.begin(); It != rkExtensions.end(); It++) - { - if (*It == CookedExt) - { - Valid = true; - break; - } - } + const CResTypeFilter& rkFilter = static_cast(pTemp)->TypeFilter(); + bool Valid = rkFilter.Accepts(pEntry->ResourceType()); if (!Valid) - Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - ID.Length(), "Asset property \"" + pTemp->FullName() + "\" (" + pTemp->IDString(true) + ") has a reference to an illegal asset type: " + CookedExt); + Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - ID.Length(), "Asset property \"" + pTemp->FullName() + "\" (" + pTemp->IDString(true) + ") has a reference to an illegal asset type: " + pEntry->CookedExtension()); } } diff --git a/src/Core/Resource/Factory/CTemplateLoader.cpp b/src/Core/Resource/Factory/CTemplateLoader.cpp index 2ceb1907..4eebdae2 100644 --- a/src/Core/Resource/Factory/CTemplateLoader.cpp +++ b/src/Core/Resource/Factory/CTemplateLoader.cpp @@ -114,7 +114,7 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl { TStringList ExtensionsList = ExtensionsAttr.Split(", "); CAssetTemplate *pAsset = static_cast(pProp); - pAsset->SetAllowedExtensions(ExtensionsList); + pAsset->SetTypeFilter(ExtensionsList); } } @@ -606,7 +606,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS if (!pProp) Log::Error(rkTemplateName + ": Invalid property for attachment " + TString::FromInt32(AttachIdx) + ": " + Attachment.AttachProperty); - else if (pProp->Type() != eCharacterProperty && (pProp->Type() != eAssetProperty || !static_cast(pProp)->AcceptsExtension("CMDL"))) + else if (pProp->Type() != eCharacterProperty && (pProp->Type() != eAssetProperty || !static_cast(pProp)->TypeFilter().Accepts(eModel))) Log::Error(rkTemplateName + ": Property referred to by attachment " + TString::FromInt32(AttachIdx) + " is not an attachable asset! Must be a file property that accepts CMDLs, or a character property."); else diff --git a/src/Core/Resource/Script/IPropertyTemplate.h b/src/Core/Resource/Script/IPropertyTemplate.h index eb9b9340..aa9aeaaf 100644 --- a/src/Core/Resource/Script/IPropertyTemplate.h +++ b/src/Core/Resource/Script/IPropertyTemplate.h @@ -4,6 +4,7 @@ #include "EPropertyType.h" #include "IProperty.h" #include "IPropertyValue.h" +#include "Core/Resource/CResTypeFilter.h" #include "Core/Resource/Animation/CAnimationParameters.h" #include #include @@ -389,7 +390,7 @@ class CAssetTemplate : public IPropertyTemplate friend class CTemplateLoader; friend class CTemplateWriter; - TStringList mAcceptedExtensions; + CResTypeFilter mTypeFilter; public: CAssetTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0) : IPropertyTemplate(ID, pScript, pMaster, pParent) {} @@ -411,7 +412,7 @@ public: virtual void Copy(const IPropertyTemplate *pkTemp) { IPropertyTemplate::Copy(pkTemp); - mAcceptedExtensions = static_cast(pkTemp)->mAcceptedExtensions; + mTypeFilter = static_cast(pkTemp)->mTypeFilter; } virtual bool Matches(const IPropertyTemplate *pkTemp) const @@ -419,18 +420,11 @@ public: const CAssetTemplate *pkAsset = static_cast(pkTemp); return ( (IPropertyTemplate::Matches(pkTemp)) && - (mAcceptedExtensions == pkAsset->mAcceptedExtensions) ); + (mTypeFilter == pkAsset->mTypeFilter) ); } - bool AcceptsExtension(const TString& rkExtension) - { - for (auto it = mAcceptedExtensions.begin(); it != mAcceptedExtensions.end(); it++) - if (*it == rkExtension) return true; - return false; - } - - void SetAllowedExtensions(const TStringList& rkExtensions) { mAcceptedExtensions = rkExtensions; } - const TStringList& AllowedExtensions() const { return mAcceptedExtensions; } + void SetTypeFilter(const TStringList& rkExtensions) { mTypeFilter.SetAcceptedTypes(Game(), rkExtensions); } + const CResTypeFilter& TypeFilter() const { return mTypeFilter; } }; // CEnumTemplate - Property template for enums. Tracks a list of possible values (enumerators). diff --git a/src/Core/Scene/CScriptNode.cpp b/src/Core/Scene/CScriptNode.cpp index 9bc16928..ed5b7bcc 100644 --- a/src/Core/Scene/CScriptNode.cpp +++ b/src/Core/Scene/CScriptNode.cpp @@ -476,13 +476,14 @@ void CScriptNode::PropertyModified(IProperty *pProp) else if (pProp->Type() == eAssetProperty) { CAssetTemplate *pAssetTemp = static_cast(pProp->Template()); + const CResTypeFilter& rkFilter = pAssetTemp->TypeFilter(); - if (pAssetTemp->AcceptsExtension("CMDL") || pAssetTemp->AcceptsExtension("TXTR") || pAssetTemp->AcceptsExtension("ANCS") || pAssetTemp->AcceptsExtension("CHAR")) + if (rkFilter.Accepts(eModel) || rkFilter.Accepts(eTexture) || rkFilter.Accepts(eAnimSet) || rkFilter.Accepts(eCharacter)) { mpInstance->EvaluateDisplayAsset(); SetDisplayAsset(mpInstance->DisplayAsset()); } - else if (pAssetTemp->AcceptsExtension("DCLN")) + else if (rkFilter.Accepts(eDynamicCollision)) { mpInstance->EvaluateCollisionModel(); mpCollisionNode->SetCollision(mpInstance->Collision()); diff --git a/src/Editor/Editor.pro b/src/Editor/Editor.pro index 4c14a548..43009514 100644 --- a/src/Editor/Editor.pro +++ b/src/Editor/Editor.pro @@ -183,7 +183,9 @@ HEADERS += \ WorldEditor/CWorldEditorSidebar.h \ CProgressDialog.h \ IProgressNotifierUI.h \ - CUIRelay.h + CUIRelay.h \ + Widgets/CSelectResourcePanel.h \ + Widgets/CFilteredResourceModel.h # Source Files SOURCES += \ @@ -250,7 +252,8 @@ SOURCES += \ CProjectSettingsDialog.cpp \ WorldEditor/CPoiMapSidebar.cpp \ WorldEditor/CWorldEditorSidebar.cpp \ - CProgressDialog.cpp + CProgressDialog.cpp \ + Widgets/CSelectResourcePanel.cpp # UI Files FORMS += \ @@ -275,4 +278,5 @@ FORMS += \ WorldEditor/CWorldInfoSidebar.ui \ CProjectSettingsDialog.ui \ WorldEditor/CPoiMapSidebar.ui \ - CProgressDialog.ui + CProgressDialog.ui \ + Widgets/CSelectResourcePanel.ui diff --git a/src/Editor/Icons.qrc b/src/Editor/Icons.qrc index eae96bfe..d987b9a4 100644 --- a/src/Editor/Icons.qrc +++ b/src/Editor/Icons.qrc @@ -72,5 +72,6 @@ icons/Disc_16px.png icons/World_16px.png icons/PoiSymbol_24px.png + icons/ArrowD_16px.png diff --git a/src/Editor/ModelEditor/CModelEditorWindow.cpp b/src/Editor/ModelEditor/CModelEditorWindow.cpp index cd606da9..55592334 100644 --- a/src/Editor/ModelEditor/CModelEditorWindow.cpp +++ b/src/Editor/ModelEditor/CModelEditorWindow.cpp @@ -44,8 +44,8 @@ CModelEditorWindow::CModelEditorWindow(CModel *pModel, QWidget *pParent) // UI initialization UpdateAnimParamUI(-1); - ui->IndTextureResSelector->SetAllowedExtensions("TXTR"); - ui->PassTextureResSelector->SetAllowedExtensions("TXTR"); + ui->IndTextureResSelector->SetTypeFilter(pModel->Game(), "TXTR"); + ui->PassTextureResSelector->SetTypeFilter(pModel->Game(), "TXTR"); ui->PassTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); ui->PassTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents); ui->ClearColorPicker->SetColor(QColor(76, 76, 76, 255)); diff --git a/src/Editor/PropertyEdit/CPropertyDelegate.cpp b/src/Editor/PropertyEdit/CPropertyDelegate.cpp index ca754e0c..ff9a99c6 100644 --- a/src/Editor/PropertyEdit/CPropertyDelegate.cpp +++ b/src/Editor/PropertyEdit/CPropertyDelegate.cpp @@ -143,7 +143,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie pSelector->SetFrameVisible(false); CAssetTemplate *pTemp = static_cast(pProp->Template()); - pSelector->SetAllowedExtensions(pTemp->AllowedExtensions()); + pSelector->SetTypeFilter(pTemp->TypeFilter()); CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*)) pOut = pSelector; @@ -603,9 +603,9 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel pSelector->SetFrameVisible(false); if (Params.Version() <= eEchoes) - pSelector->SetAllowedExtensions("ANCS"); + pSelector->SetTypeFilter(mpEditor->CurrentGame(), "ANCS"); else - pSelector->SetAllowedExtensions("CHAR"); + pSelector->SetTypeFilter(mpEditor->CurrentGame(), "CHAR"); CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*)); return pSelector; diff --git a/src/Editor/Widgets/CFilteredResourceModel.h b/src/Editor/Widgets/CFilteredResourceModel.h new file mode 100644 index 00000000..30c9a31a --- /dev/null +++ b/src/Editor/Widgets/CFilteredResourceModel.h @@ -0,0 +1,131 @@ +#ifndef CFILTEREDRESOURCEMODEL_H +#define CFILTEREDRESOURCEMODEL_H + +#include "CResourceSelector.h" +#include "Editor/UICommon.h" + +#include +#include +#include + +#include +#include + +class CFilteredResourceModel : public QAbstractTableModel +{ + Q_OBJECT + QVector mEntries; + int mInitialRow; + +public: + CFilteredResourceModel(CResourceSelector *pSelector, QObject *pParent = 0) + : QAbstractTableModel(pParent) + , mInitialRow(0) + { + const CResTypeFilter& rkFilter = pSelector->TypeFilter(); + + for (CResourceIterator It; It; ++It) + { + if (rkFilter.Accepts(*It)) + { + mEntries << *It; + } + } + + qSort(mEntries.begin(), mEntries.end(), [](CResourceEntry *pA, CResourceEntry *pB) -> bool { + return pA->UppercaseName() < pB->UppercaseName(); + }); + + for (int ResIdx = 0; ResIdx < mEntries.size(); ResIdx++) + { + if (mEntries[ResIdx] == pSelector->Entry()) + { + mInitialRow = ResIdx; + break; + } + } + } + + // QAbstractTableModel interface + int rowCount(const QModelIndex&) const + { + return mEntries.size(); + } + + int columnCount(const QModelIndex&) const + { + return 1; + } + + QVariant data(const QModelIndex& rkIndex, int Role) const + { + CResourceEntry *pEntry = EntryForIndex(rkIndex); + + if (rkIndex.column() == 0) + { + if (Role == Qt::DisplayRole) + { + return TO_QSTRING( pEntry->Name() + "." + pEntry->CookedExtension() ); + } + else if (Role == Qt::ToolTipRole) + { + return TO_QSTRING( pEntry->CookedAssetPath(true) ); + } + else if (Role == Qt::DecorationRole) + { + return QIcon(":/icons/Sphere Preview.png"); + } + } + else + { + if (Role == Qt::DisplayRole || Role == Qt::ToolTipRole) + { + return TO_QSTRING( pEntry->TypeInfo()->TypeName() ); + } + } + + return QVariant::Invalid; + } + + // Accessors + inline QModelIndex InitialIndex() const + { + return index(mInitialRow, 0); + } + + inline CResourceEntry* EntryForIndex(const QModelIndex& rkIndex) const + { + return mEntries[rkIndex.row()]; + } +}; + +class CFilteredResourceProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + TString mSearchString; + +public: + CFilteredResourceProxyModel(QObject *pParent = 0) + : QSortFilterProxyModel(pParent) + {} + + bool filterAcceptsRow(int SourceRow, const QModelIndex&) const + { + if (mSearchString.IsEmpty()) + return true; + + CFilteredResourceModel *pModel = qobject_cast(sourceModel()); + ASSERT(pModel); + + QModelIndex SrcIndex = pModel->index(SourceRow, 0); + return pModel->EntryForIndex(SrcIndex)->UppercaseName().Contains(mSearchString); + } + + inline void SetSearchString(const QString& rkString) + { + mSearchString = TO_TSTRING(rkString).ToUpper(); + invalidate(); + } +}; + +#endif // CFILTEREDRESOURCEMODEL_H diff --git a/src/Editor/Widgets/CResourceSelector.cpp b/src/Editor/Widgets/CResourceSelector.cpp index e73e7fca..777c1043 100644 --- a/src/Editor/Widgets/CResourceSelector.cpp +++ b/src/Editor/Widgets/CResourceSelector.cpp @@ -1,4 +1,5 @@ #include "CResourceSelector.h" +#include "CSelectResourcePanel.h" #include "Editor/CEditorApplication.h" #include "Editor/UICommon.h" #include "Editor/ResourceBrowser/CResourceBrowser.h" @@ -20,11 +21,11 @@ CResourceSelector::CResourceSelector(QWidget *pParent /*= 0*/) mpResNameButton->setFlat(true); mpResNameButton->setStyleSheet("text-align:left; font-size:10pt; margin:0px; padding-left:2px"); - mpSetButton = new QPushButton(this); - mpSetButton->setToolTip("Use selected asset in Resource Browser"); - mpSetButton->setIcon(QIcon(":/icons/ArrowL_16px.png")); - mpSetButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - mpSetButton->setFixedSize(16, 16); + mpSelectButton = new QPushButton(this); + mpSelectButton->setToolTip("Select Resource"); + mpSelectButton->setIcon(QIcon(":/icons/ArrowD_16px.png")); + mpSelectButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + mpSelectButton->setFixedSize(16, 16); mpClearButton = new QPushButton(this); mpClearButton->setToolTip("Clear"); @@ -36,7 +37,7 @@ CResourceSelector::CResourceSelector(QWidget *pParent /*= 0*/) mpFrameLayout->setSpacing(2); mpFrameLayout->setContentsMargins(0, 0, 0, 0); mpFrameLayout->addWidget(mpResNameButton); - mpFrameLayout->addWidget(mpSetButton); + mpFrameLayout->addWidget(mpSelectButton); mpFrameLayout->addWidget(mpClearButton); mpFrame = new QFrame(this); mpFrame->setBackgroundRole(QPalette::AlternateBase); @@ -51,7 +52,7 @@ CResourceSelector::CResourceSelector(QWidget *pParent /*= 0*/) // UI Connections connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CreateContextMenu(QPoint))); connect(mpResNameButton, SIGNAL(clicked()), this, SLOT(Find())); - connect(mpSetButton, SIGNAL(clicked()), this, SLOT(Set())); + connect(mpSelectButton, SIGNAL(clicked()), this, SLOT(Select())); connect(mpClearButton, SIGNAL(clicked()), this, SLOT(Clear())); // Set up context menu @@ -75,7 +76,7 @@ void CResourceSelector::SetFrameVisible(bool Visible) void CResourceSelector::SetEditable(bool Editable) { - mpSetButton->setVisible(Editable); + mpSelectButton->setVisible(Editable); mpClearButton->setVisible(Editable); mIsEditable = Editable; } @@ -95,14 +96,16 @@ void CResourceSelector::UpdateUI() mpCopyPathAction->setEnabled(HasResource); } -void CResourceSelector::SetAllowedExtensions(const QString& /*rkExtension*/) +void CResourceSelector::SetTypeFilter(const CResTypeFilter& rkFilter) { - // todo + mTypeFilter = rkFilter; + ASSERT(!mpResEntry || mTypeFilter.Accepts(mpResEntry)); } -void CResourceSelector::SetAllowedExtensions(const TStringList& /*rkExtensions*/) +void CResourceSelector::SetTypeFilter(EGame Game, const TString& rkTypeList) { - // todo + mTypeFilter.FromString(Game, rkTypeList); + ASSERT(!mpResEntry || mTypeFilter.Accepts(mpResEntry)); } void CResourceSelector::SetResource(const CAssetID& rkID) @@ -149,16 +152,9 @@ void CResourceSelector::CopyPath() gpEdApp->clipboard()->setText(Text); } -void CResourceSelector::Set() +void CResourceSelector::Select() { - // todo - validate this resource is a valid type - CResourceBrowser *pBrowser = gpEdApp->ResourceBrowser(); - - if (pBrowser->isVisible() && pBrowser->SelectedEntry()) - { - mpResEntry = gpEdApp->ResourceBrowser()->SelectedEntry(); - OnResourceChanged(); - } + new CSelectResourcePanel(this); } void CResourceSelector::Find() diff --git a/src/Editor/Widgets/CResourceSelector.h b/src/Editor/Widgets/CResourceSelector.h index 12d259e8..78a60b7c 100644 --- a/src/Editor/Widgets/CResourceSelector.h +++ b/src/Editor/Widgets/CResourceSelector.h @@ -2,6 +2,7 @@ #define CRESOURCESELECTOR #include +#include #include #include #include @@ -12,6 +13,7 @@ class CResourceSelector : public QWidget Q_OBJECT CResourceEntry *mpResEntry; + CResTypeFilter mTypeFilter; bool mIsEditable; // UI @@ -19,7 +21,7 @@ class CResourceSelector : public QWidget QHBoxLayout *mpFrameLayout; QFrame *mpFrame; QPushButton *mpResNameButton; - QPushButton *mpSetButton; + QPushButton *mpSelectButton; QPushButton *mpClearButton; // Context Menu @@ -31,19 +33,20 @@ public: explicit CResourceSelector(QWidget *pParent = 0); void SetFrameVisible(bool Visible); void SetEditable(bool Editable); - void SetAllowedExtensions(const QString& rkExtension); - void SetAllowedExtensions(const TStringList& rkExtensions); + void SetTypeFilter(const CResTypeFilter& rkFilter); + void SetTypeFilter(EGame Game, const TString& rkTypeList); void SetResource(const CAssetID& rkID); void SetResource(CResourceEntry *pEntry); void SetResource(CResource *pRes); // Accessors - inline CResourceEntry* Entry() const { return mpResEntry; } - inline bool IsEditable() const { return mIsEditable; } + inline CResourceEntry* Entry() const { return mpResEntry; } + inline const CResTypeFilter& TypeFilter() const { return mTypeFilter; } + inline bool IsEditable() const { return mIsEditable; } public slots: void CreateContextMenu(const QPoint& rkPoint); - void Set(); + void Select(); void Find(); void Clear(); void EditAsset(); diff --git a/src/Editor/Widgets/CSelectResourcePanel.cpp b/src/Editor/Widgets/CSelectResourcePanel.cpp new file mode 100644 index 00000000..983db28b --- /dev/null +++ b/src/Editor/Widgets/CSelectResourcePanel.cpp @@ -0,0 +1,96 @@ +#include "CSelectResourcePanel.h" +#include "ui_CSelectResourcePanel.h" +#include "Editor/CEditorApplication.h" +#include +#include +#include + +CSelectResourcePanel::CSelectResourcePanel(CResourceSelector *pSelector) + : QWidget(pSelector) + , mpUI(new Ui::CSelectResourcePanel) + , mpSelector(pSelector) + , mModel(pSelector) +{ + setWindowFlags( windowFlags() | Qt::FramelessWindowHint | Qt::Window ); + + mpUI->setupUi(this); + mProxyModel.setSourceModel(&mModel); + mpUI->ResourceTableView->setModel(&mProxyModel); + + // Signals/slots + connect(gpEdApp, SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(FocusChanged(QWidget*,QWidget*))); + connect(mpUI->SearchBar, SIGNAL(StoppedTyping(QString)), this, SLOT(SearchStringChanged(QString))); + connect(mpUI->ResourceTableView, SIGNAL(clicked(QModelIndex)), this, SLOT(ResourceClicked(QModelIndex))); + + // Determine size + QPoint SelectorPos = pSelector->parentWidget()->mapToGlobal( pSelector->pos() ); + QRect ScreenRect = gpEdApp->desktop()->availableGeometry(); + + int MaxWidthLeft = SelectorPos.x(); + int MaxWidthRight = ScreenRect.width() - SelectorPos.x() - pSelector->width(); + int MaxWidth = Math::Max(MaxWidthLeft, MaxWidthRight); + + int MaxHeightTop = SelectorPos.y(); + int MaxHeightBottom = ScreenRect.height() - SelectorPos.y() - pSelector->height(); + int MaxHeight = Math::Max(MaxHeightTop, MaxHeightBottom); + + QSize PanelSize(Math::Min(width(), MaxWidth), Math::Min(height(), MaxHeight)); + + // Determine position; place wherever we have the most amount of space + QPoint PanelPos; + + if (MaxHeightTop > MaxHeightBottom) + PanelPos.ry() = SelectorPos.y() - PanelSize.height(); + else + PanelPos.ry() = SelectorPos.y() + pSelector->height(); + + if (MaxWidthLeft > MaxWidthRight) + PanelPos.rx() = SelectorPos.x() + (pSelector->width() - PanelSize.width()); + else + PanelPos.rx() = SelectorPos.x(); + + // Clamp position to screen boundaries + PanelPos.rx() = Math::Clamp(0, ScreenRect.width() - PanelSize.width(), PanelPos.x()); + PanelPos.ry() = Math::Clamp(0, ScreenRect.height() - PanelSize.height(), PanelPos.y()); + + // Create widget geometry + QRect PanelRect(PanelPos, PanelSize); + setGeometry(PanelRect); + + // Jump to the currently-selected resource + QModelIndex Index = mModel.InitialIndex(); + QModelIndex ProxyIndex = mProxyModel.mapFromSource(Index); + + mpUI->ResourceTableView->scrollTo(ProxyIndex, QAbstractItemView::PositionAtCenter); + mpUI->ResourceTableView->selectionModel()->setCurrentIndex(ProxyIndex, QItemSelectionModel::ClearAndSelect); + + // Show + show(); + mpUI->SearchBar->setFocus(); +} + +CSelectResourcePanel::~CSelectResourcePanel() +{ + delete mpUI; +} + +// Slots +void CSelectResourcePanel::FocusChanged(QWidget*, QWidget *pNew) +{ + // Destroy when the panel loses focus + if (pNew != this && !isAncestorOf(pNew)) + deleteLater(); +} + +void CSelectResourcePanel::SearchStringChanged(QString SearchString) +{ + mProxyModel.SetSearchString(SearchString); +} + +void CSelectResourcePanel::ResourceClicked(QModelIndex Index) +{ + QModelIndex SourceIndex = mProxyModel.mapToSource(Index); + CResourceEntry *pEntry = mModel.EntryForIndex(SourceIndex); + mpSelector->SetResource(pEntry); + close(); +} diff --git a/src/Editor/Widgets/CSelectResourcePanel.h b/src/Editor/Widgets/CSelectResourcePanel.h new file mode 100644 index 00000000..f2ea0067 --- /dev/null +++ b/src/Editor/Widgets/CSelectResourcePanel.h @@ -0,0 +1,31 @@ +#ifndef CSELECTRESOURCEPANEL_H +#define CSELECTRESOURCEPANEL_H + +#include +#include "CFilteredResourceModel.h" +#include "CResourceSelector.h" + +namespace Ui { +class CSelectResourcePanel; +} + +class CSelectResourcePanel : public QWidget +{ + Q_OBJECT + Ui::CSelectResourcePanel *mpUI; + CResourceSelector *mpSelector; + + CFilteredResourceModel mModel; + CFilteredResourceProxyModel mProxyModel; + +public: + explicit CSelectResourcePanel(CResourceSelector *pSelector); + ~CSelectResourcePanel(); + +public slots: + void FocusChanged(QWidget *pOld, QWidget *pNew); + void SearchStringChanged(QString SearchString); + void ResourceClicked(QModelIndex Index); +}; + +#endif // CSELECTRESOURCEPANEL_H diff --git a/src/Editor/Widgets/CSelectResourcePanel.ui b/src/Editor/Widgets/CSelectResourcePanel.ui new file mode 100644 index 00000000..e49fe89d --- /dev/null +++ b/src/Editor/Widgets/CSelectResourcePanel.ui @@ -0,0 +1,95 @@ + + + CSelectResourcePanel + + + + 0 + 0 + 360 + 500 + + + + Qt::StrongFocus + + + Form + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Search... + + + + + + + + 9 + + + + Qt::NoFocus + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + false + + + false + + + true + + + false + + + 20 + + + + + + + + CTimedLineEdit + QLineEdit +
Editor/Widgets/CTimedLineEdit.h
+
+
+ + +
diff --git a/src/Editor/WorldEditor/CWorldEditor.cpp b/src/Editor/WorldEditor/CWorldEditor.cpp index ff0487a6..b9b1615c 100644 --- a/src/Editor/WorldEditor/CWorldEditor.cpp +++ b/src/Editor/WorldEditor/CWorldEditor.cpp @@ -606,8 +606,9 @@ void CWorldEditor::OnPropertyModified(IProperty *pProp) if (pProp->Type() == eAssetProperty) { CAssetTemplate *pAsset = static_cast(pProp->Template()); + const CResTypeFilter& rkFilter = pAsset->TypeFilter(); - if (pAsset->AcceptsExtension("CMDL") || pAsset->AcceptsExtension("ANCS") || pAsset->AcceptsExtension("CHAR")) + if (rkFilter.Accepts(eModel) || rkFilter.Accepts(eAnimSet) || rkFilter.Accepts(eCharacter)) SelectionModified(); } else if (pProp->Type() == eCharacterProperty) diff --git a/src/Editor/icons/ArrowD_16px.png b/src/Editor/icons/ArrowD_16px.png new file mode 100644 index 0000000000000000000000000000000000000000..9e9a93e4858c871f981f0d5f5a7fb542583f3c4f GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6(mh=qLp07O|2W?u-_&{6;DWU^o!HR%~s|ut7r4BXWLZp<52Z?d4(@W-}<)QwcK4SXfr{EVU>p1Z>R28K0qrOJYD@< J);T3K0RT*2JfQ#p literal 0 HcmV?d00001