From 137c10f28f1bed227576b2070b65e43d78cc8a62 Mon Sep 17 00:00:00 2001 From: Aruki Date: Wed, 12 Jul 2017 20:45:14 -0600 Subject: [PATCH] Major resource browser UI overhaul --- src/Core/GameProject/CPackage.cpp | 2 +- src/Editor/CEditorApplication.cpp | 17 +- src/Editor/CEditorApplication.h | 4 +- src/Editor/Editor.pro | 6 +- src/Editor/Icons.qrc | 4 + .../ResourceBrowser/CResourceBrowser.cpp | 196 ++++--- src/Editor/ResourceBrowser/CResourceBrowser.h | 21 +- .../ResourceBrowser/CResourceBrowser.ui | 537 +++++++++--------- .../ResourceBrowser/CResourceDelegate.cpp | 130 +++++ .../ResourceBrowser/CResourceDelegate.h | 22 + .../ResourceBrowser/CResourceTableModel.h | 55 +- src/Editor/Widgets/CSelectResourcePanel.cpp | 2 +- src/Editor/Widgets/CSelectResourcePanel.h | 2 +- src/Editor/WorldEditor/CWorldEditor.cpp | 33 +- src/Editor/WorldEditor/CWorldEditor.h | 2 +- src/Editor/WorldEditor/CWorldEditor.ui | 26 +- src/Editor/icons/Gear_16px.png | Bin 0 -> 230 bytes src/Editor/icons/Gear_24px.png | Bin 0 -> 273 bytes src/Editor/icons/Tree_16px.png | Bin 0 -> 129 bytes src/Editor/icons/Tree_24px.png | Bin 0 -> 139 bytes 20 files changed, 607 insertions(+), 452 deletions(-) create mode 100644 src/Editor/ResourceBrowser/CResourceDelegate.cpp create mode 100644 src/Editor/ResourceBrowser/CResourceDelegate.h create mode 100644 src/Editor/icons/Gear_16px.png create mode 100644 src/Editor/icons/Gear_24px.png create mode 100644 src/Editor/icons/Tree_16px.png create mode 100644 src/Editor/icons/Tree_24px.png diff --git a/src/Core/GameProject/CPackage.cpp b/src/Core/GameProject/CPackage.cpp index 5626aacc..56e08013 100644 --- a/src/Core/GameProject/CPackage.cpp +++ b/src/Core/GameProject/CPackage.cpp @@ -262,7 +262,7 @@ void CPackage::Cook(IProgressNotifier *pProgress) // Note: Compressed asset data can be stored in multiple blocks. Normally, the only assets that make use of this are textures, // which can store each separate component of the file (header, palette, image data) in separate blocks. However, some textures // are stored in one block, and I've had no luck figuring out why. The game doesn't generally seem to care whether textures use - // multiple blocks or not, so for the sake of complicity we compress everything to one block. + // multiple blocks or not, so for the sake of simplicity we compress everything to one block. Pak.WriteFourCC( FOURCC('CMPD') ); Pak.WriteLong(1); Pak.WriteLong(0xA0000000 | CompressedSize); diff --git a/src/Editor/CEditorApplication.cpp b/src/Editor/CEditorApplication.cpp index 199b3e5b..9f8e7696 100644 --- a/src/Editor/CEditorApplication.cpp +++ b/src/Editor/CEditorApplication.cpp @@ -18,7 +18,6 @@ CEditorApplication::CEditorApplication(int& rArgc, char **ppArgv) : QApplication(rArgc, ppArgv) , mpActiveProject(nullptr) , mpWorldEditor(nullptr) - , mpResourceBrowser(nullptr) , mpProjectDialog(nullptr) { mLastUpdate = CTimer::GlobalTime(); @@ -36,7 +35,6 @@ CEditorApplication::~CEditorApplication() void CEditorApplication::InitEditor() { mpWorldEditor = new CWorldEditor(); - mpResourceBrowser = new CResourceBrowser(mpWorldEditor); mpProjectDialog = new CProjectSettingsDialog(mpWorldEditor); mpWorldEditor->showMaximized(); } @@ -54,7 +52,6 @@ bool CEditorApplication::CloseAllEditors() if (!mpWorldEditor->CloseWorld()) return false; - mpResourceBrowser->close(); mpProjectDialog->close(); return true; } @@ -202,8 +199,6 @@ bool CEditorApplication::CookPackageList(QList PackageList) bool CEditorApplication::RebuildResourceDatabase() { - bool BrowserIsOpen = mpResourceBrowser->isVisible(); - // Make sure all editors are closed if (mpActiveProject && CloseAllEditors()) { @@ -225,13 +220,6 @@ bool CEditorApplication::RebuildResourceDatabase() mpActiveProject = pProj; emit ActiveProjectChanged(pProj); - // If the resource browser was open before, then reopen it now - if (BrowserIsOpen) - { - mpResourceBrowser->show(); - mpResourceBrowser->raise(); - } - UICommon::InfoMsg(mpWorldEditor, "Success", "Resource database rebuilt successfully!"); return true; } @@ -302,3 +290,8 @@ void CEditorApplication::OnEditorClose() mpActiveProject->ResourceStore()->DestroyUnreferencedResources(); } } + +CResourceBrowser* CEditorApplication::ResourceBrowser() const +{ + return mpWorldEditor->ResourceBrowser(); +} diff --git a/src/Editor/CEditorApplication.h b/src/Editor/CEditorApplication.h index 6c86e8c6..ed25d493 100644 --- a/src/Editor/CEditorApplication.h +++ b/src/Editor/CEditorApplication.h @@ -21,7 +21,6 @@ class CEditorApplication : public QApplication CGameProject *mpActiveProject; CWorldEditor *mpWorldEditor; - CResourceBrowser *mpResourceBrowser; CProjectSettingsDialog *mpProjectDialog; QVector mEditorWindows; QMap mEditingMap; @@ -45,10 +44,11 @@ public: bool RebuildResourceDatabase(); + CResourceBrowser* ResourceBrowser() const; + // Accessors inline CGameProject* ActiveProject() const { return mpActiveProject; } inline CWorldEditor* WorldEditor() const { return mpWorldEditor; } - inline CResourceBrowser* ResourceBrowser() const { return mpResourceBrowser; } inline CProjectSettingsDialog* ProjectDialog() const { return mpProjectDialog; } inline EGame CurrentGame() const { return mpActiveProject ? mpActiveProject->Game() : eUnknownGame; } diff --git a/src/Editor/Editor.pro b/src/Editor/Editor.pro index be567953..c5b621c9 100644 --- a/src/Editor/Editor.pro +++ b/src/Editor/Editor.pro @@ -185,7 +185,8 @@ HEADERS += \ IProgressNotifierUI.h \ CUIRelay.h \ Widgets/CSelectResourcePanel.h \ - Widgets/CFilteredResourceModel.h + Widgets/CFilteredResourceModel.h \ + ResourceBrowser/CResourceDelegate.h # Source Files SOURCES += \ @@ -253,7 +254,8 @@ SOURCES += \ WorldEditor/CPoiMapSidebar.cpp \ WorldEditor/CWorldEditorSidebar.cpp \ CProgressDialog.cpp \ - Widgets/CSelectResourcePanel.cpp + Widgets/CSelectResourcePanel.cpp \ + ResourceBrowser/CResourceDelegate.cpp # UI Files FORMS += \ diff --git a/src/Editor/Icons.qrc b/src/Editor/Icons.qrc index d987b9a4..bc472903 100644 --- a/src/Editor/Icons.qrc +++ b/src/Editor/Icons.qrc @@ -73,5 +73,9 @@ icons/World_16px.png icons/PoiSymbol_24px.png icons/ArrowD_16px.png + icons/Tree_16px.png + icons/Tree_24px.png + icons/Gear_16px.png + icons/Gear_24px.png diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.cpp b/src/Editor/ResourceBrowser/CResourceBrowser.cpp index 548a0fb7..a2182208 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.cpp +++ b/src/Editor/ResourceBrowser/CResourceBrowser.cpp @@ -1,6 +1,7 @@ #include "CResourceBrowser.h" #include "ui_CResourceBrowser.h" #include "CProgressDialog.h" +#include "CResourceDelegate.h" #include "Editor/CEditorApplication.h" #include #include @@ -11,22 +12,25 @@ #include CResourceBrowser::CResourceBrowser(QWidget *pParent) - : QDialog(pParent) + : QWidget(pParent) , mpUI(new Ui::CResourceBrowser) , mpSelectedEntry(nullptr) , mpStore(nullptr) , mpSelectedDir(nullptr) - , mAssetListMode(true) + , mEditorStore(false) + , mAssetListMode(false) , mSearching(false) { mpUI->setupUi(this); - setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint); -#if PUBLIC_RELEASE - // Hide store select combo box in public release build; we don't want users to edit the editor store - mpUI->StoreLabel->setHidden(true); - mpUI->StoreComboBox->setHidden(true); -#endif + // Hide sorting combo box for now. The size isn't displayed on the UI so this isn't really useful for the end user. + mpUI->SortComboBox->hide(); + + // Configure display mode buttons + QButtonGroup *pModeGroup = new QButtonGroup(this); + pModeGroup->addButton(mpUI->ResourceTreeButton); + pModeGroup->addButton(mpUI->ResourceListButton); + pModeGroup->setExclusive(true); // Set up table models mpModel = new CResourceTableModel(this); @@ -36,8 +40,9 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) QHeaderView *pHeader = mpUI->ResourceTableView->horizontalHeader(); pHeader->setSectionResizeMode(0, QHeaderView::Stretch); - pHeader->resizeSection(1, 215); - pHeader->resizeSection(2, 75); + + mpDelegate = new CResourceBrowserDelegate(this); + mpUI->ResourceTableView->setItemDelegate(mpDelegate); // Set up directory tree model mpDirectoryModel = new CVirtualDirectoryModel(this); @@ -70,35 +75,49 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) CreateFilterCheckboxes(); - // Set up Import Names menu - QMenu *pImportNamesMenu = new QMenu(this); - mpUI->ImportNamesButton->setMenu(pImportNamesMenu); + // Set up the options menu + QMenu *pOptionsMenu = new QMenu(this); + QMenu *pImportMenu = pOptionsMenu->addMenu("Import Names"); + pOptionsMenu->addAction("Export Names", this, SLOT(ExportAssetNames())); + pOptionsMenu->addSeparator(); - QAction *pImportFromContentsTxtAction = new QAction("Import from Pak Contents List", this); - pImportNamesMenu->addAction(pImportFromContentsTxtAction); + pImportMenu->addAction("Asset Name Map", this, SLOT(ImportAssetNameMap())); + pImportMenu->addAction("Package Contents List", this, SLOT(ImportPackageContentsList())); + pImportMenu->addAction("Generate Asset Names", this, SLOT(GenerateAssetNames())); - QAction *pImportFromAssetNameMapAction = new QAction("Import from Asset Name Map", this); - pImportNamesMenu->addAction(pImportFromAssetNameMapAction); + QAction *pDisplayAssetIDsAction = new QAction("Display Asset IDs", this); + pDisplayAssetIDsAction->setCheckable(true); + connect(pDisplayAssetIDsAction, SIGNAL(toggled(bool)), this, SLOT(SetAssetIdDisplayEnabled(bool))); + pOptionsMenu->addAction(pDisplayAssetIDsAction); - QAction *pGenerateAssetNamesAction = new QAction("Generate Asset Names", this); - pImportNamesMenu->addAction(pGenerateAssetNamesAction); -#if PUBLIC_RELEASE - pGenerateAssetNamesAction->setVisible(false); + pOptionsMenu->addAction("Rebuild Database", this, SLOT(RebuildResourceDB())); + mpUI->OptionsToolButton->setMenu(pOptionsMenu); + +#if !PUBLIC_RELEASE + // Only add the store menu in debug builds. We don't want end users editing the editor store. + pOptionsMenu->addSeparator(); + QMenu *pStoreMenu = pOptionsMenu->addMenu("Set Store"); + QAction *pProjStoreAction = pStoreMenu->addAction("Project Store", this, SLOT(SetProjectStore())); + QAction *pEdStoreAction = pStoreMenu->addAction("Editor Store", this, SLOT(SetEditorStore())); + + pProjStoreAction->setCheckable(true); + pProjStoreAction->setChecked(true); + pEdStoreAction->setCheckable(true); + + QActionGroup *pGroup = new QActionGroup(this); + pGroup->addAction(pProjStoreAction); + pGroup->addAction(pEdStoreAction); #endif // Set up connections - connect(mpUI->StoreComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateStore())); connect(mpUI->SearchBar, SIGNAL(textChanged(QString)), this, SLOT(OnSearchStringChanged())); - connect(mpUI->DisplayTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnDisplayModeChanged(int))); + connect(mpUI->ResourceTreeButton, SIGNAL(pressed()), this, SLOT(SetResourceTreeView())); + connect(mpUI->ResourceListButton, SIGNAL(pressed()), this, SLOT(SetResourceListView())); connect(mpUI->SortComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSortModeChanged(int))); connect(mpUI->DirectoryTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex,QModelIndex))); connect(mpUI->ResourceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnDoubleClickTable(QModelIndex))); connect(mpUI->ResourceTableView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnResourceSelectionChanged(QModelIndex, QModelIndex))); - connect(pImportFromContentsTxtAction, SIGNAL(triggered()), this, SLOT(OnImportPakContentsTxt())); - connect(pImportFromAssetNameMapAction, SIGNAL(triggered()), this, SLOT(OnImportNamesFromAssetNameMap())); - connect(pGenerateAssetNamesAction, SIGNAL(triggered()), this, SLOT(OnGenerateAssetNames())); - connect(mpUI->ExportNamesButton, SIGNAL(clicked()), this, SLOT(ExportAssetNames())); - connect(mpUI->RebuildDatabaseButton, SIGNAL(clicked(bool)), this, SLOT(RebuildResourceDB())); + connect(mpProxyModel, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), mpUI->ResourceTableView, SLOT(resizeRowsToContents())); connect(&mUpdateFilterTimer, SIGNAL(timeout()), this, SLOT(UpdateFilter())); connect(mpFilterAllBox, SIGNAL(toggled(bool)), this, SLOT(OnFilterTypeBoxTicked(bool))); connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(UpdateStore())); @@ -113,23 +132,21 @@ void CResourceBrowser::SelectResource(CResourceEntry *pEntry) { ASSERT(pEntry); - // Clear search - mpUI->SearchBar->clear(); - UpdateFilter(); - // Select target directory SelectDirectory(pEntry->Directory()); - // Select resource - int Row = mpModel->GetIndexForEntry(pEntry).row(); - mpUI->ResourceTableView->selectionModel()->clearSelection(); - - for (int iCol = 0; iCol < mpModel->columnCount(QModelIndex()); iCol++) + // Clear search + if (!mpUI->SearchBar->text().isEmpty()) { - QModelIndex Index = mpModel->index(Row, iCol, QModelIndex()); - QModelIndex ProxyIndex = mpProxyModel->mapFromSource(Index); - mpUI->ResourceTableView->selectionModel()->setCurrentIndex(ProxyIndex, QItemSelectionModel::Select); + mpUI->SearchBar->clear(); + UpdateFilter(); } + + // Select resource + QModelIndex SourceIndex = mpModel->GetIndexForEntry(pEntry); + QModelIndex ProxyIndex = mpProxyModel->mapFromSource(SourceIndex); + mpUI->ResourceTableView->selectionModel()->select(ProxyIndex, QItemSelectionModel::ClearAndSelect); + mpUI->ResourceTableView->scrollTo(ProxyIndex, QAbstractItemView::PositionAtCenter); } void CResourceBrowser::SelectDirectory(CVirtualDirectory *pDir) @@ -185,13 +202,7 @@ void CResourceBrowser::CreateFilterCheckboxes() void CResourceBrowser::RefreshResources() { // Fill resource table - mpModel->FillEntryList(mpSelectedDir, InAssetListMode()); - - // Mark directories to span all three columns - mpUI->ResourceTableView->clearSpans(); - - for (u32 iDir = 0; iDir < mpModel->NumDirectories(); iDir++) - mpUI->ResourceTableView->setSpan(iDir, 0, 1, 3); + mpModel->FillEntryList(mpSelectedDir, mAssetListMode); } void CResourceBrowser::RefreshDirectories() @@ -232,37 +243,16 @@ void CResourceBrowser::UpdateDescriptionLabel() mpUI->TableDescriptionLabel->setText(Desc); } -void CResourceBrowser::UpdateStore() +void CResourceBrowser::SetResourceTreeView() { - int StoreIndex = mpUI->StoreComboBox->currentIndex(); - - CGameProject *pProj = gpEdApp->ActiveProject(); - CResourceStore *pProjStore = (pProj ? pProj->ResourceStore() : nullptr); - CResourceStore *pNewStore = (StoreIndex == 0 ? pProjStore : gpEditorStore); - - if (mpStore != pNewStore) - { - mpStore = pNewStore; - - // Refresh type filter list - CreateFilterCheckboxes(); - - // Refresh directory tree - mpDirectoryModel->SetRoot(mpStore ? mpStore->RootDirectory() : nullptr); - QModelIndex RootIndex = mpDirectoryModel->index(0, 0, QModelIndex()); - mpUI->DirectoryTreeView->expand(RootIndex); - mpUI->DirectoryTreeView->clearSelection(); - OnDirectorySelectionChanged(QModelIndex(), QModelIndex()); - } + mAssetListMode = false; + RefreshResources(); } -void CResourceBrowser::OnDisplayModeChanged(int Index) +void CResourceBrowser::SetResourceListView() { - bool OldIsAssetList = InAssetListMode(); - mAssetListMode = Index == 0; - - if (InAssetListMode() != OldIsAssetList) - RefreshResources(); + mAssetListMode = true; + RefreshResources(); } void CResourceBrowser::OnSortModeChanged(int Index) @@ -314,9 +304,49 @@ void CResourceBrowser::OnResourceSelectionChanged(const QModelIndex& rkNewIndex, emit SelectedResourceChanged(mpSelectedEntry); } -void CResourceBrowser::OnImportPakContentsTxt() +void CResourceBrowser::SetAssetIdDisplayEnabled(bool Enable) { - QStringList PathList = UICommon::OpenFilesDialog(this, "Open pak contents list", "*.pak.contents.txt"); + mpDelegate->SetDisplayAssetIDs(Enable); + mpUI->ResourceTableView->repaint(); +} + +void CResourceBrowser::UpdateStore() +{ + CGameProject *pProj = gpEdApp->ActiveProject(); + CResourceStore *pProjStore = (pProj ? pProj->ResourceStore() : nullptr); + CResourceStore *pNewStore = (mEditorStore ? gpEditorStore : pProjStore); + + if (mpStore != pNewStore) + { + mpStore = pNewStore; + + // Refresh type filter list + CreateFilterCheckboxes(); + + // Refresh directory tree + mpDirectoryModel->SetRoot(mpStore ? mpStore->RootDirectory() : nullptr); + QModelIndex RootIndex = mpDirectoryModel->index(0, 0, QModelIndex()); + mpUI->DirectoryTreeView->expand(RootIndex); + mpUI->DirectoryTreeView->clearSelection(); + OnDirectorySelectionChanged(QModelIndex(), QModelIndex()); + } +} + +void CResourceBrowser::SetProjectStore() +{ + mEditorStore = false; + UpdateStore(); +} + +void CResourceBrowser::SetEditorStore() +{ + mEditorStore = true; + UpdateStore(); +} + +void CResourceBrowser::ImportPackageContentsList() +{ + QStringList PathList = UICommon::OpenFilesDialog(this, "Open package contents list", "*.pak.contents.txt"); if (PathList.isEmpty()) return; SelectDirectory(nullptr); @@ -327,7 +357,7 @@ void CResourceBrowser::OnImportPakContentsTxt() RefreshDirectories(); } -void CResourceBrowser::OnGenerateAssetNames() +void CResourceBrowser::GenerateAssetNames() { SelectDirectory(nullptr); @@ -338,7 +368,7 @@ void CResourceBrowser::OnGenerateAssetNames() // Temporarily set root to null to ensure the window doesn't access the resource store while we're running. mpDirectoryModel->SetRoot(mpStore->RootDirectory()); - QFuture Future = QtConcurrent::run(&GenerateAssetNames, mpStore->Project()); + QFuture Future = QtConcurrent::run(&::GenerateAssetNames, mpStore->Project()); Dialog.WaitForResults(Future); RefreshResources(); @@ -347,7 +377,7 @@ void CResourceBrowser::OnGenerateAssetNames() UICommon::InfoMsg(this, "Complete", "Asset name generation complete!"); } -void CResourceBrowser::OnImportNamesFromAssetNameMap() +void CResourceBrowser::ImportAssetNameMap() { CAssetNameMap Map( mpStore->Game() ); bool LoadSuccess = Map.LoadAssetNames(); @@ -410,7 +440,7 @@ void CResourceBrowser::ExportAssetNames() void CResourceBrowser::RebuildResourceDB() { - if (UICommon::YesNoQuestion(this, "Rebuild resource database", "Are you sure you want to rebuild the resource database?")) + if (UICommon::YesNoQuestion(this, "Rebuild resource database", "Are you sure you want to rebuild the resource database? This will take a while.")) { gpEdApp->RebuildResourceDatabase(); } @@ -418,15 +448,9 @@ void CResourceBrowser::RebuildResourceDB() void CResourceBrowser::UpdateFilter() { - bool OldIsAssetList = InAssetListMode(); QString SearchText = mpUI->SearchBar->text(); mSearching = !SearchText.isEmpty(); - if (InAssetListMode() != OldIsAssetList) - { - RefreshResources(); - } - UpdateDescriptionLabel(); mpProxyModel->SetSearchString( TO_TSTRING(mpUI->SearchBar->text()) ); mpProxyModel->invalidate(); diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.h b/src/Editor/ResourceBrowser/CResourceBrowser.h index e479b118..1fbb80a3 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.h +++ b/src/Editor/ResourceBrowser/CResourceBrowser.h @@ -1,11 +1,11 @@ #ifndef CRESOURCEBROWSER_H #define CRESOURCEBROWSER_H +#include "CResourceDelegate.h" #include "CResourceProxyModel.h" #include "CResourceTableModel.h" #include "CVirtualDirectoryModel.h" #include -#include #include #include @@ -13,7 +13,7 @@ namespace Ui { class CResourceBrowser; } -class CResourceBrowser : public QDialog +class CResourceBrowser : public QWidget { Q_OBJECT Ui::CResourceBrowser *mpUI; @@ -21,9 +21,11 @@ class CResourceBrowser : public QDialog CResourceStore *mpStore; CResourceTableModel *mpModel; CResourceProxyModel *mpProxyModel; + CResourceBrowserDelegate *mpDelegate; CVirtualDirectory *mpSelectedDir; CVirtualDirectoryModel *mpDirectoryModel; QTimer mUpdateFilterTimer; + bool mEditorStore; bool mAssetListMode; bool mSearching; @@ -56,16 +58,21 @@ public slots: void RefreshResources(); void RefreshDirectories(); void UpdateDescriptionLabel(); - void UpdateStore(); - void OnDisplayModeChanged(int Index); + void SetResourceTreeView(); + void SetResourceListView(); void OnSortModeChanged(int Index); void OnSearchStringChanged(); void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex); void OnDoubleClickTable(QModelIndex Index); void OnResourceSelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex); - void OnImportPakContentsTxt(); - void OnGenerateAssetNames(); - void OnImportNamesFromAssetNameMap(); + void SetAssetIdDisplayEnabled(bool Enable); + + void UpdateStore(); + void SetProjectStore(); + void SetEditorStore(); + void ImportPackageContentsList(); + void GenerateAssetNames(); + void ImportAssetNameMap(); void ExportAssetNames(); void RebuildResourceDB(); void UpdateFilter(); diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.ui b/src/Editor/ResourceBrowser/CResourceBrowser.ui index 2f0c5b0b..00056209 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.ui +++ b/src/Editor/ResourceBrowser/CResourceBrowser.ui @@ -1,293 +1,308 @@ CResourceBrowser - + 0 0 - 789 - 577 + 435 + 639 Resource Browser - + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + - + + + 3 + + + + + + 1 + 0 + + + + + 32 + 32 + + + + ... + + + + :/icons/Gear_16px.png:/icons/Gear_16px.png + + + + 16 + 16 + + + + QToolButton::InstantPopup + + + Qt::NoArrow + + + + + + + + 5 + 0 + + + + Search + + + true + + + + + + + + 0 + 0 + + + + + + + + :/icons/Tree_24px.png:/icons/Tree_24px.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + 0 + 0 + + + + + + + + :/icons/Instances.png:/icons/Instances.png + + + + 24 + 24 + + + + true + + + + + + + + 5 + 0 + + + + + Sort by Name + + + + + Sort by Size + + + + + + + + - - 1 + + 0 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Store: - - - - - - - - 1 - 0 - - - - - Project - - - - - Editor - - - - - - - - - - - 5 - 0 - - - - Search - - - - - - - - Asset List - - - - - Filesystem - - - - - - - - - 5 - 0 - - - - - Sort by Name - - - - - Sort by Size - - - - - - - - - 0 - 1 - - - - true - - - - - 0 - 0 - 189 - 117 - - - - - - - - - - 0 - 2 - - - - - 10 - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::SingleSelection - - - - 16 - 16 - - - - QAbstractItemView::ScrollPerPixel - - - 12 - - - false - - - - - - - Import Names - - - - - - - Export Names - - - - - - - Rebuild Database - - - - + + + 8 + + + + + - - - - 3 - 0 - + + + Qt::Horizontal - - - 0 + + + + + + + 0 + 1 + + + + + 16777215 + 200 + + + + true + + + + + 0 + 0 + 209 + 190 + + + + + + + + + + 0 + 2 + + + + + 8 + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::SingleSelection + + + + 16 + 16 + + + + QAbstractItemView::ScrollPerPixel + + + 12 + + + false + + + + + + + + + 0 + 0 + - - 0 + + + 8 + - - 0 + + QAbstractItemView::NoEditTriggers - - 0 + + true - - 0 + + QAbstractItemView::ExtendedSelection - - - - - 8 - - - - - - - - - - - - 3 - 0 - - - - - 10 - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - QAbstractItemView::ScrollPerPixel - - - QAbstractItemView::ScrollPerPixel - - - true - - - false - - - false - - - 21 - - - 21 - - - - + + QAbstractItemView::SelectRows + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + true + + + false + + + false + + - + + + diff --git a/src/Editor/ResourceBrowser/CResourceDelegate.cpp b/src/Editor/ResourceBrowser/CResourceDelegate.cpp new file mode 100644 index 00000000..64fe53c8 --- /dev/null +++ b/src/Editor/ResourceBrowser/CResourceDelegate.cpp @@ -0,0 +1,130 @@ +#include "CResourceDelegate.h" +#include "CResourceProxyModel.h" +#include "CResourceTableModel.h" +#include + +#include + +struct SResDelegateInfo +{ + QFont NameFont; + QFont InfoFont; + QFontMetrics NameFontMetrics; + QFontMetrics InfoFontMetrics; + QPen NamePen; + QPen InfoPen; + int Margin; + int Spacing; + + SResDelegateInfo() + : NameFontMetrics(NameFont), InfoFontMetrics(InfoFont) {} +}; +SResDelegateInfo GetDelegateInfo(const QStyleOptionViewItem& rkOption) +{ + SResDelegateInfo Info; + + Info.NameFont = rkOption.font; + Info.NameFont.setPointSize( rkOption.font.pointSize() + 1 ); + Info.NameFontMetrics = QFontMetrics(Info.NameFont); + + Info.InfoFont = rkOption.font; + Info.InfoFont.setPointSize( rkOption.font.pointSize() - 1 ); + Info.InfoFontMetrics = QFontMetrics(Info.InfoFont); + + Info.NamePen = QPen(rkOption.palette.text(), 1.f); + + Info.InfoPen = QPen(rkOption.palette.text(), 1.f); + Info.InfoPen.setColor( Info.InfoPen.color().darker(140) ); + + Info.Margin = 3; + Info.Spacing = 3; + + return Info; +} + +QSize CResourceBrowserDelegate::sizeHint(const QStyleOptionViewItem& rkOption, const QModelIndex&) const +{ + // Get string info + SResDelegateInfo Info = GetDelegateInfo(rkOption); + + // Calculate height + int Height = (Info.Margin * 2) + Info.NameFontMetrics.height() + Info.Spacing + Info.InfoFontMetrics.height(); + return QSize(0, Height); +} + +void CResourceBrowserDelegate::paint(QPainter *pPainter, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const +{ + const CResourceProxyModel *pkProxy = qobject_cast(rkIndex.model()); + ASSERT(pkProxy != nullptr); + + const CResourceTableModel *pkModel = qobject_cast(pkProxy->sourceModel()); + ASSERT(pkModel != nullptr); + + // Get resource entry + QModelIndex SourceIndex = pkProxy->mapToSource(rkIndex); + CResourceEntry *pEntry = pkModel->IndexEntry(SourceIndex); + + // Initialize + SResDelegateInfo Info = GetDelegateInfo(rkOption); + QRect InnerRect = rkOption.rect.adjusted(Info.Margin, Info.Margin, -Info.Margin, -Info.Margin); + QPoint PainterPos = InnerRect.topLeft(); + + // Draw icon + QVariant IconVariant = rkIndex.model()->data(rkIndex, Qt::DecorationRole); + + if (IconVariant != QVariant::Invalid) + { + QIcon Icon = IconVariant.value(); + + // Determine icon size. Ideally 24x24 if we have space, but downscale if we don't + int IdealIconSize = 24; + int IconSize = Math::Min(InnerRect.height(), IdealIconSize); + + // Adjust icon position so it's centered in the ideal rect + QPoint IconPos = PainterPos; + IconPos.rx() += (IdealIconSize - IconSize) / 2; + IconPos.ry() += (InnerRect.height() - IconSize) / 2; + + // Paint the icon + QRect IconRect(IconPos, QSize(IconSize, IconSize)); + Icon.paint(pPainter, IconRect); + + PainterPos.rx() += IdealIconSize + Info.Spacing + Info.Spacing; + } + + // Calculate rects + if (!pEntry) + PainterPos.ry() += (InnerRect.height() - Info.NameFontMetrics.height()) / 2; + + int ResNameWidth = InnerRect.width() - (PainterPos.x() - InnerRect.left()); + QSize ResNameSize(ResNameWidth, Info.NameFontMetrics.height()); + QRect ResNameRect = QRect(PainterPos, ResNameSize); + PainterPos.ry() += ResNameRect.height() + Info.Spacing; + + int ResInfoWidth = ResNameWidth; + QSize ResInfoSize(ResInfoWidth, Info.InfoFontMetrics.height()); + QRect ResInfoRect = QRect(PainterPos, ResInfoSize); + + // Draw resource name + QString ResName = pkModel->data(SourceIndex, Qt::DisplayRole).toString(); + QString ElidedName = Info.NameFontMetrics.elidedText(ResName, Qt::ElideRight, ResNameWidth); + + pPainter->setFont(Info.NameFont); + pPainter->setPen(Info.NamePen); + pPainter->drawText(ResNameRect, ElidedName); + + // Draw resource info string + if (pEntry) + { + QString ResInfo = TO_QSTRING( pEntry->TypeInfo()->TypeName() ); + + if (mDisplayAssetIDs) + ResInfo.prepend( TO_QSTRING(pEntry->ID().ToString()) + " | " ); + + QString ElidedResInfo = Info.InfoFontMetrics.elidedText(ResInfo, Qt::ElideRight, ResInfoWidth); + + pPainter->setFont(Info.InfoFont); + pPainter->setPen(Info.InfoPen); + pPainter->drawText(ResInfoRect, ElidedResInfo); + } +} diff --git a/src/Editor/ResourceBrowser/CResourceDelegate.h b/src/Editor/ResourceBrowser/CResourceDelegate.h new file mode 100644 index 00000000..13cc3152 --- /dev/null +++ b/src/Editor/ResourceBrowser/CResourceDelegate.h @@ -0,0 +1,22 @@ +#ifndef CRESOURCEBROWSERDELEGATE_H +#define CRESOURCEBROWSERDELEGATE_H + +#include + +class CResourceBrowserDelegate : public QStyledItemDelegate +{ + bool mDisplayAssetIDs; + +public: + CResourceBrowserDelegate(QObject *pParent = 0) + : QStyledItemDelegate(pParent) + , mDisplayAssetIDs(false) + {} + + QSize sizeHint(const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const; + void paint(QPainter *pPainter, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const; + + inline void SetDisplayAssetIDs(bool Display) { mDisplayAssetIDs = Display; } +}; + +#endif // CRESOURCEBROWSERDELEGATE_H diff --git a/src/Editor/ResourceBrowser/CResourceTableModel.h b/src/Editor/ResourceBrowser/CResourceTableModel.h index e0f78fc3..262c543a 100644 --- a/src/Editor/ResourceBrowser/CResourceTableModel.h +++ b/src/Editor/ResourceBrowser/CResourceTableModel.h @@ -15,6 +15,7 @@ class CResourceTableModel : public QAbstractTableModel QList mDirectories; QList mEntries; + QMap mEntryIndexMap; bool mHasParent; public: @@ -29,19 +30,17 @@ public: int columnCount(const QModelIndex& /*rkParent*/) const { - return 3; + return 1; } QVariant data(const QModelIndex& rkIndex, int Role) const { - u32 Col = rkIndex.column(); + if (rkIndex.column() != 0) + return QVariant::Invalid; // Directory if (IsIndexDirectory(rkIndex)) { - if (Col != 0) - return QVariant::Invalid; - CVirtualDirectory *pDir = IndexDirectory(rkIndex); if (Role == Qt::DisplayRole || Role == Qt::ToolTipRole) @@ -58,46 +57,23 @@ public: CResourceEntry *pEntry = IndexEntry(rkIndex); if (Role == Qt::DisplayRole) - { - if (Col == 0) - { - return TO_QSTRING(pEntry->Name()); - } - - if (Col == 1) - { - return TO_QSTRING(pEntry->TypeInfo()->TypeName()); - } - - if (Col == 2) - { - u64 Size = pEntry->Size(); - return Size ? TO_QSTRING( TString::FileSizeString(pEntry->Size()) ) : ""; - } - } + return TO_QSTRING(pEntry->Name()); else if (Role == Qt::ToolTipRole) return TO_QSTRING(pEntry->CookedAssetPath(true)); - else if (Role == Qt::TextAlignmentRole && rkIndex.column() == 2) - return Qt::AlignRight; + else if (Role == Qt::DecorationRole) + return QIcon(":/icons/Sphere Preview.png"); return QVariant::Invalid; } QModelIndex GetIndexForEntry(CResourceEntry *pEntry) const { - for (int iRes = 0; iRes < mEntries.size(); iRes++) - { - if (mEntries[iRes] == pEntry) - { - QModelIndex Out = index(mDirectories.size() + iRes, 0); - ASSERT(IndexEntry(Out) == pEntry); - return Out; - } - } - - return QModelIndex(); + if (mEntryIndexMap.contains(pEntry)) + return index(mEntryIndexMap[pEntry] + mDirectories.size(), 0, QModelIndex()); + else + return QModelIndex(); } CResourceEntry* IndexEntry(const QModelIndex& rkIndex) const @@ -122,6 +98,7 @@ public: mEntries.clear(); mDirectories.clear(); + mEntryIndexMap.clear(); mHasParent = false; if (pDir) @@ -143,7 +120,10 @@ public: CResourceEntry *pEntry = pDir->ResourceByIndex(iRes); if (pEntry->TypeInfo()->IsVisibleInBrowser() && !pEntry->IsHidden()) + { + mEntryIndexMap[pEntry] = mEntries.size(); mEntries << pEntry; + } } } @@ -163,7 +143,10 @@ protected: CResourceEntry *pEntry = pDir->ResourceByIndex(iRes); if (pEntry->TypeInfo()->IsVisibleInBrowser() && !pEntry->IsHidden()) - mEntries << pDir->ResourceByIndex(iRes); + { + mEntryIndexMap[pEntry] = mEntries.size(); + mEntries << pEntry; + } } for (u32 iDir = 0; iDir < pDir->NumSubdirectories(); iDir++) diff --git a/src/Editor/Widgets/CSelectResourcePanel.cpp b/src/Editor/Widgets/CSelectResourcePanel.cpp index 983db28b..0fe9919b 100644 --- a/src/Editor/Widgets/CSelectResourcePanel.cpp +++ b/src/Editor/Widgets/CSelectResourcePanel.cpp @@ -6,7 +6,7 @@ #include CSelectResourcePanel::CSelectResourcePanel(CResourceSelector *pSelector) - : QWidget(pSelector) + : QFrame(pSelector) , mpUI(new Ui::CSelectResourcePanel) , mpSelector(pSelector) , mModel(pSelector) diff --git a/src/Editor/Widgets/CSelectResourcePanel.h b/src/Editor/Widgets/CSelectResourcePanel.h index f2ea0067..7dc51e9d 100644 --- a/src/Editor/Widgets/CSelectResourcePanel.h +++ b/src/Editor/Widgets/CSelectResourcePanel.h @@ -9,7 +9,7 @@ namespace Ui { class CSelectResourcePanel; } -class CSelectResourcePanel : public QWidget +class CSelectResourcePanel : public QFrame { Q_OBJECT Ui::CSelectResourcePanel *mpUI; diff --git a/src/Editor/WorldEditor/CWorldEditor.cpp b/src/Editor/WorldEditor/CWorldEditor.cpp index b9b1615c..6ee2afff 100644 --- a/src/Editor/WorldEditor/CWorldEditor.cpp +++ b/src/Editor/WorldEditor/CWorldEditor.cpp @@ -110,26 +110,6 @@ CWorldEditor::CWorldEditor(QWidget *parent) mpCollisionDialog = new CCollisionRenderSettingsDialog(this, this); - // Resource Browser button - QPushButton *pBrowserButton = new QPushButton(this); - pBrowserButton->setText("Resource Browser"); - connect(pBrowserButton, SIGNAL(pressed()), this, SLOT(OpenResourceBrowser())); - - QPalette Palette = pBrowserButton->palette(); - QBrush ButtonBrush = Palette.button(); - ButtonBrush.setColor( UICommon::kImportantButtonColor ); - Palette.setBrush(QPalette::Button, ButtonBrush); - pBrowserButton->setPalette(Palette); - - QFont BrowserButtonFont = pBrowserButton->font(); - BrowserButtonFont.setPointSize( BrowserButtonFont.pointSize() + 3 ); - pBrowserButton->setFont(BrowserButtonFont); - - QWidget *pSpacerWidget = new QWidget(this); - pSpacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - ui->MainToolBar->addWidget(pSpacerWidget); - ui->MainToolBar->addWidget(pBrowserButton); - // "Open Recent" menu mpOpenRecentMenu = new QMenu(this); ui->ActionOpenRecent->setMenu(mpOpenRecentMenu); @@ -183,7 +163,6 @@ CWorldEditor::CWorldEditor(QWidget *parent) connect(ui->ActionLink, SIGNAL(toggled(bool)), this, SLOT(OnLinkButtonToggled(bool))); connect(ui->ActionUnlink, SIGNAL(triggered()), this, SLOT(OnUnlinkClicked())); - connect(ui->ActionResourceBrowser, SIGNAL(triggered()), this, SLOT(OpenResourceBrowser())); connect(ui->ActionEditLayers, SIGNAL(triggered()), this, SLOT(EditLayers())); connect(ui->ActionDrawWorld, SIGNAL(triggered()), this, SLOT(ToggleDrawWorld())); @@ -353,6 +332,11 @@ bool CWorldEditor::HasAnyScriptNodesSelected() const return false; } +CResourceBrowser* CWorldEditor::ResourceBrowser() const +{ + return ui->ResourceBrowser; +} + CSceneViewport* CWorldEditor::Viewport() const { return ui->MainViewport; @@ -543,13 +527,6 @@ void CWorldEditor::OpenProjectSettings() pDialog->raise(); } -void CWorldEditor::OpenResourceBrowser() -{ - CResourceBrowser *pBrowser = gpEdApp->ResourceBrowser(); - pBrowser->show(); - pBrowser->raise(); -} - void CWorldEditor::OnActiveProjectChanged(CGameProject *pProj) { ui->ActionProjectSettings->setEnabled( pProj != nullptr ); diff --git a/src/Editor/WorldEditor/CWorldEditor.h b/src/Editor/WorldEditor/CWorldEditor.h index aa3e7873..349f4ff1 100644 --- a/src/Editor/WorldEditor/CWorldEditor.h +++ b/src/Editor/WorldEditor/CWorldEditor.h @@ -89,6 +89,7 @@ public: inline CGameArea* ActiveArea() const { return mpArea; } inline EGame CurrentGame() const { return gpEdApp->CurrentGame(); } inline CLinkDialog* LinkDialog() const { return mpLinkDialog; } + CResourceBrowser* ResourceBrowser() const; CSceneViewport* Viewport() const; inline void SetWorldDir(QString WorldDir) { mWorldDir = (QDir(WorldDir).exists() ? WorldDir : ""); } @@ -116,7 +117,6 @@ public slots: void ChangeEditMode(EWorldEditorMode Mode); void SetRenderingMergedWorld(bool RenderMerged); void OpenProjectSettings(); - void OpenResourceBrowser(); void OnActiveProjectChanged(CGameProject *pProj); void OnLinksModified(const QList& rkInstances); diff --git a/src/Editor/WorldEditor/CWorldEditor.ui b/src/Editor/WorldEditor/CWorldEditor.ui index d87a995e..307df539 100644 --- a/src/Editor/WorldEditor/CWorldEditor.ui +++ b/src/Editor/WorldEditor/CWorldEditor.ui @@ -14,27 +14,25 @@ - - - 3 - + - 3 + 0 - 3 + 0 - 3 + 0 - 3 + 0 Qt::Horizontal + @@ -340,7 +338,6 @@ Tools - @@ -735,11 +732,6 @@ Close Project - - - Resource Browser - - true @@ -794,6 +786,12 @@
Editor/CSceneViewport.h
1 + + CResourceBrowser + QWidget +
Editor/ResourceBrowser/CResourceBrowser.h
+ 1 +
diff --git a/src/Editor/icons/Gear_16px.png b/src/Editor/icons/Gear_16px.png new file mode 100644 index 0000000000000000000000000000000000000000..627b5363277242113e19ff0d23d210a5dd66892d GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6)_S@)hG?Acop_M9*+78hE`v$J zEDlZX|C9FL4V$4JBH*Fh!JZ?><~%`YQSF>9a(CzE^QJ9lQ@piTynFexrc|d6&eN^z zb*wf{XTD@y?3PrlVR`kXKtxbO{NIY1*(^G;PCXVyMKa1xUm|)IMurJ*-}1Y*P)%xc z_Dpq!`*-Xc%z6trS6u42mY`9gbfiI9d2y0MN8h72v!C8v_==-t{c^tS2u2P2Lt2d+ emi||be5#Aag5F5}AK@UU$QxK&U`nNbQiNEcrK^>F&2|y}g za7tuk2^b1u6vhJ<#f<{928`Q!?$jQr$>N|Exm}BIb=TA zp$Q4mbbc+9IV2b=7ix*TkrAz1tuQ1LFuz<2@AW*k4uk@@oB(|Fq!jDx+lZtaUvo>k zWowHjAV7PMK5SK7cM8`p3wO9R>@HxJtuZ1`a?#$od#YU X+-=6O_$2v%00000NkvXXu0mjfyH02T literal 0 HcmV?d00001 diff --git a/src/Editor/icons/Tree_16px.png b/src/Editor/icons/Tree_16px.png new file mode 100644 index 0000000000000000000000000000000000000000..444a78d6bcb5ae661b4082ecf863fb225b5086d3 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6JUm?-Lp07O|2V&4cj@=@cmE&! zpg!Sj1J8eB2EiC97W?Gj27`y{p58v1;f!g*I^7KQ@0TzKiqlL0;aLI|mvr c^Zrm|kiDd)|HFRDKcJZmp00i_>zopr05fSU%K!iX literal 0 HcmV?d00001 diff --git a/src/Editor/icons/Tree_24px.png b/src/Editor/icons/Tree_24px.png new file mode 100644 index 0000000000000000000000000000000000000000..8428b1967e0e3b89bb31feb843185cc9b7e00fd0 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iAWs*^5R22vKh8Tyr6_nGes}Gz zefj_P!}A^Nn9VvaG^~+fu@}D7kabx9klBF;^>4V^H?Z{_IJS&Y{*TWr-u)YH8@zgX n@WD&AAltJJOO|IwWic>p)QU)8>=9rDn$FgTe~DWM4fUt=