From d97287f636a17f564f7f228235dd6f3de50714ce Mon Sep 17 00:00:00 2001 From: codereader Date: Tue, 23 Mar 2021 20:44:54 +0100 Subject: [PATCH] #5568: Hide unrelated textures when looking for cube map textures, and vice versa when looking for regular textures --- radiant/CMakeLists.txt | 1 + radiant/ui/common/ImageFilePopulator.cpp | 139 ++++++++++++++++++++++ radiant/ui/common/ImageFilePopulator.h | 132 ++------------------ radiant/ui/common/ImageFileSelector.cpp | 42 ++++++- radiant/ui/common/ImageFileSelector.h | 30 ++++- radiant/ui/materials/MapExpressionEntry.h | 8 ++ tools/msvc/DarkRadiant.vcxproj | 1 + tools/msvc/DarkRadiant.vcxproj.filters | 3 + 8 files changed, 228 insertions(+), 128 deletions(-) create mode 100644 radiant/ui/common/ImageFilePopulator.cpp diff --git a/radiant/CMakeLists.txt b/radiant/CMakeLists.txt index 615c4244d9..1af5401ac7 100644 --- a/radiant/CMakeLists.txt +++ b/radiant/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(darkradiant ui/common/CommandEntry.cpp ui/common/DefinitionView.cpp ui/common/EntityChooser.cpp + ui/common/ImageFilePopulator.cpp ui/common/ImageFileSelector.cpp ui/common/MapPreview.cpp ui/common/MaterialPopulator.cpp diff --git a/radiant/ui/common/ImageFilePopulator.cpp b/radiant/ui/common/ImageFilePopulator.cpp new file mode 100644 index 0000000000..9184f7bf06 --- /dev/null +++ b/radiant/ui/common/ImageFilePopulator.cpp @@ -0,0 +1,139 @@ +#include "ImageFilePopulator.h" + +#include "ifilesystem.h" +#include "gamelib.h" +#include "string/case_conv.h" +#include "string/predicate.h" +#include "string/trim.h" +#include "os/path.h" +#include "wxutil/Bitmap.h" + +namespace ui +{ + +namespace +{ + const char* const TEXTURE_ICON = "icon_texture.png"; + const char* const FOLDER_ICON = "folder16.png"; +} + +class ImageFileFunctor : + public wxutil::VFSTreePopulator +{ +private: + const ImageFileSelector::Columns& _columns; + + wxIcon _fileIcon; + wxIcon _folderIcon; + + std::set _cubemapSuffixes; + +public: + // Constructor + ImageFileFunctor(const wxutil::TreeModel::Ptr& treeStore, + const ImageFileSelector::Columns& columns) : + VFSTreePopulator(treeStore), + _columns(columns), + _cubemapSuffixes({ "_nx", "_ny", "_nz", "_px", "_py", "_pz", + "_forward", "_back", "_left", "_right", "_up", "_down" }) + { + _fileIcon.CopyFromBitmap(wxutil::GetLocalBitmap(TEXTURE_ICON)); + _folderIcon.CopyFromBitmap(wxutil::GetLocalBitmap(FOLDER_ICON)); + } + + void addFile(const vfs::FileInfo& fileInfo) + { + const std::string ddsPrefix = "dds/"; + std::string fullPath = fileInfo.fullPath(); + + // Sort into the tree and set the values + addPath(fullPath, [&](wxutil::TreeModel::Row& row, const std::string& path, + const std::string& leafName, bool isFolder) + { + // The map expressions don't need any file extensions + auto imageFilePath = os::removeExtension(path); + + // Cut off the dds prefix, it won't be valid when set in a material + if (string::istarts_with(path, ddsPrefix)) + { + imageFilePath = imageFilePath.substr(ddsPrefix.length()); + } + + bool isCubeMapTexture = false; + + // For cubemaps, cut off the suffixes + if (string::istarts_with(imageFilePath, "env/")) + { + auto underscorePos = imageFilePath.find_last_of('_'); + + if (underscorePos != std::string::npos) + { + auto suffix = imageFilePath.substr(underscorePos); + string::to_lower(suffix); + + if (_cubemapSuffixes.count(suffix) != 0) + { + imageFilePath = imageFilePath.substr(0, imageFilePath.length() - suffix.length()); + isCubeMapTexture = true; + } + } + } + + row[_columns.iconAndName] = wxVariant(wxDataViewIconText(leafName, isFolder ? _folderIcon : _fileIcon)); + row[_columns.leafName] = leafName; + row[_columns.fullName] = imageFilePath; + row[_columns.isFolder] = isFolder; + row[_columns.isFavourite] = false; + row[_columns.isCubeMapTexture] = isCubeMapTexture; + + row.SendItemAdded(); + }); + } +}; + +ImageFilePopulator::ImageFilePopulator(const ImageFileSelector::Columns& columns) : + ThreadedResourceTreePopulator(columns), + _columns(columns) +{ + auto texTypes = game::current::getNodes(GKEY_IMAGE_TYPES); + + for (const auto& node : texTypes) + { + // Get the file extension, store it as lowercase + std::string extension = node.getContent(); + _extensions.emplace(string::to_lower_copy(extension)); + } +} + +ImageFilePopulator::~ImageFilePopulator() +{ + EnsureStopped(); +} + +void ImageFilePopulator::PopulateModel(const wxutil::TreeModel::Ptr& model) +{ + ImageFileFunctor functor(model, _columns); + + GlobalFileSystem().forEachFile( + "", "*", + [&](const vfs::FileInfo& fileInfo) + { + ThrowIfCancellationRequested(); + + if (_extensions.count(string::to_lower_copy(os::getExtension(fileInfo.name))) == 0) + { + return; + } + + functor.addFile(fileInfo); + }, + 99 + ); +} + +void ImageFilePopulator::SortModel(const wxutil::TreeModel::Ptr& model) +{ + model->SortModelFoldersFirst(_columns.iconAndName, _columns.isFolder); +} + +} diff --git a/radiant/ui/common/ImageFilePopulator.h b/radiant/ui/common/ImageFilePopulator.h index fd5157d416..71f4a54772 100644 --- a/radiant/ui/common/ImageFilePopulator.h +++ b/radiant/ui/common/ImageFilePopulator.h @@ -1,150 +1,32 @@ #pragma once #include "ifilesystem.h" -#include "gamelib.h" -#include "string/case_conv.h" -#include "string/predicate.h" -#include "string/trim.h" -#include "os/path.h" #include "wxutil/dataview/ThreadedResourceTreePopulator.h" #include "wxutil/dataview/ResourceTreeView.h" #include "wxutil/dataview/VFSTreePopulator.h" -#include "wxutil/Bitmap.h" -namespace ui -{ +#include "ImageFileSelector.h" -namespace -{ - const char* const TEXTURE_ICON = "icon_texture.png"; - const char* const FOLDER_ICON = "folder16.png"; -} - -class ImageFileFunctor : - public wxutil::VFSTreePopulator +namespace ui { -private: - const wxutil::ResourceTreeView::Columns& _columns; - - wxIcon _fileIcon; - wxIcon _folderIcon; - - std::set _cubemapSuffixes; - -public: - // Constructor - ImageFileFunctor(const wxutil::TreeModel::Ptr& treeStore, - const wxutil::ResourceTreeView::Columns& columns) : - VFSTreePopulator(treeStore), - _columns(columns), - _cubemapSuffixes({ "_nx", "_ny", "_nz", "_px", "_py", "_pz", - "_forward", "_back", "_left", "_right", "_up", "_down" }) - { - _fileIcon.CopyFromBitmap(wxutil::GetLocalBitmap(TEXTURE_ICON)); - _folderIcon.CopyFromBitmap(wxutil::GetLocalBitmap(FOLDER_ICON)); - } - - void addFile(const vfs::FileInfo& fileInfo) - { - const std::string ddsPrefix = "dds/"; - std::string fullPath = fileInfo.fullPath(); - - // Sort the shader into the tree and set the values - addPath(fullPath, [&](wxutil::TreeModel::Row& row, const std::string& path, - const std::string& leafName, bool isFolder) - { - // The map expressions don't need any file extensions - auto imageFilePath = os::removeExtension(path); - - // Cut off the dds prefix, it won't be valid when set in a material - if (string::istarts_with(path, ddsPrefix)) - { - imageFilePath = imageFilePath.substr(ddsPrefix.length()); - } - - // For cubemaps, cut off the suffixes - if (string::istarts_with(imageFilePath, "env/")) - { - auto underscorePos = imageFilePath.find_last_of('_'); - - if (underscorePos != std::string::npos) - { - auto suffix = imageFilePath.substr(underscorePos); - string::to_lower(suffix); - - if (_cubemapSuffixes.count(suffix) != 0) - { - imageFilePath = imageFilePath.substr(0, imageFilePath.length() - suffix.length()); - } - } - } - - row[_columns.iconAndName] = wxVariant(wxDataViewIconText(leafName, isFolder ? _folderIcon : _fileIcon)); - row[_columns.leafName] = leafName; - row[_columns.fullName] = imageFilePath; - row[_columns.isFolder] = isFolder; - row[_columns.isFavourite] = false; - - row.SendItemAdded(); - }); - } -}; class ImageFilePopulator final : public wxutil::ThreadedResourceTreePopulator { private: - const wxutil::ResourceTreeView::Columns& _columns; + const ImageFileSelector::Columns& _columns; const char* const GKEY_IMAGE_TYPES = "/filetypes/texture//extension"; std::set _extensions; public: // Construct and initialise variables - ImageFilePopulator(const wxutil::ResourceTreeView::Columns& columns) : - ThreadedResourceTreePopulator(columns), - _columns(columns) - { - auto texTypes = game::current::getNodes(GKEY_IMAGE_TYPES); - - for (const auto& node : texTypes) - { - // Get the file extension, store it as lowercase - std::string extension = node.getContent(); - _extensions.emplace(string::to_lower_copy(extension)); - } - } + ImageFilePopulator(const ImageFileSelector::Columns& columns); - ~ImageFilePopulator() - { - EnsureStopped(); - } + ~ImageFilePopulator(); protected: - void PopulateModel(const wxutil::TreeModel::Ptr& model) override - { - ImageFileFunctor functor(model, _columns); - - GlobalFileSystem().forEachFile( - "", "*", - [&](const vfs::FileInfo& fileInfo) - { - ThrowIfCancellationRequested(); - - if (_extensions.count(string::to_lower_copy(os::getExtension(fileInfo.name))) == 0) - { - return; - } - - functor.addFile(fileInfo); - }, - 99 - ); - } - - void SortModel(const wxutil::TreeModel::Ptr& model) override - { - model->SortModelFoldersFirst(_columns.iconAndName, _columns.isFolder); - } + void PopulateModel(const wxutil::TreeModel::Ptr& model) override; + void SortModel(const wxutil::TreeModel::Ptr& model) override; }; } diff --git a/radiant/ui/common/ImageFileSelector.cpp b/radiant/ui/common/ImageFileSelector.cpp index 84c3235a39..9306b840e9 100644 --- a/radiant/ui/common/ImageFileSelector.cpp +++ b/radiant/ui/common/ImageFileSelector.cpp @@ -10,6 +10,41 @@ namespace const char* const WINDOW_TITLE = N_("Select Image File"); } +class ImageFileTreeView final : + public wxutil::ResourceTreeView +{ +private: + const ImageFileSelector::Columns& _columns; + + int _textureTypesToShow; + +public: + ImageFileTreeView(wxWindow* parent, const ImageFileSelector::Columns& columns) : + ResourceTreeView(parent, columns, wxDV_NO_HEADER), + _columns(columns) + {} + + void SetVisibleTextureTypes(int typesToShow) + { + _textureTypesToShow = typesToShow; + } + +protected: + bool IsTreeModelRowVisible(wxutil::TreeModel::Row& row) override + { + bool isCubeMap = row[_columns.isCubeMapTexture].getBool(); + + if (!row[_columns.isFolder].getBool() && + isCubeMap && (_textureTypesToShow & ImageFileSelector::TextureType::CubeMap) == 0 || + !isCubeMap && (_textureTypesToShow & ImageFileSelector::TextureType::Map) == 0) + { + return false; + } + + return ResourceTreeView::IsTreeModelRowVisible(row); + } +}; + ImageFileSelector::ImageFileSelector(wxWindow* parent, wxTextCtrl* targetControl) : DialogBase(_(WINDOW_TITLE), parent), _okButton(nullptr), @@ -17,7 +52,7 @@ ImageFileSelector::ImageFileSelector(wxWindow* parent, wxTextCtrl* targetControl { SetSizer(new wxBoxSizer(wxVERTICAL)); - _treeView = new wxutil::ResourceTreeView(this, _columns, wxDV_NO_HEADER); + _treeView = new ImageFileTreeView(this, _columns); _treeView->AppendIconTextColumn(_("File"), _columns.iconAndName.getColumnIndex(), wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE); @@ -75,6 +110,11 @@ std::string ImageFileSelector::GetSelectedImageFilePath() return row[_columns.fullName]; } +void ImageFileSelector::SetVisibleTextureTypes(int typesToShow) +{ + _treeView->SetVisibleTextureTypes(typesToShow); +} + void ImageFileSelector::onTreeSelectionChanged(wxDataViewEvent& ev) { auto item = _treeView->GetSelection(); diff --git a/radiant/ui/common/ImageFileSelector.h b/radiant/ui/common/ImageFileSelector.h index 7d0f242103..9775bbef46 100644 --- a/radiant/ui/common/ImageFileSelector.h +++ b/radiant/ui/common/ImageFileSelector.h @@ -8,15 +8,39 @@ namespace ui { +class ImageFileTreeView; + /** * Modal dialog to select an image file (TGA, DDS, etc.) from the VFS */ class ImageFileSelector : public wxutil::DialogBase { +public: + // The texture type to look for + struct TextureType + { + enum + { + Map = 1 << 0, + CubeMap = 1 << 1, + }; + }; + + struct Columns : + public wxutil::ResourceTreeView::Columns + { + Columns() : + wxutil::ResourceTreeView::Columns(), + isCubeMapTexture(add(wxutil::TreeModel::Column::Boolean)) + {} + + wxutil::TreeModel::Column isCubeMapTexture; + }; + private: - wxutil::ResourceTreeView::Columns _columns; - wxutil::ResourceTreeView* _treeView; + Columns _columns; + ImageFileTreeView* _treeView; wxButton* _okButton; wxTextCtrl* _targetControl; @@ -31,6 +55,8 @@ class ImageFileSelector : // Returns the path of the selected image file std::string GetSelectedImageFilePath(); + void SetVisibleTextureTypes(int typeToShow); + private: void onTreeSelectionChanged(wxDataViewEvent& ev); }; diff --git a/radiant/ui/materials/MapExpressionEntry.h b/radiant/ui/materials/MapExpressionEntry.h index f7d08193a1..2f80604ee6 100644 --- a/radiant/ui/materials/MapExpressionEntry.h +++ b/radiant/ui/materials/MapExpressionEntry.h @@ -50,10 +50,18 @@ class MapExpressionEntry : } private: + bool isLookingForCubeMap() + { + return GetValue().StartsWith("env/"); + } + void onBrowseButtonClick(wxCommandEvent& ev) { auto selector = new ImageFileSelector(this, _textEntry); + selector->SetVisibleTextureTypes(isLookingForCubeMap() ? + ImageFileSelector::TextureType::CubeMap : ImageFileSelector::TextureType::Map); + if (_windowToPlaceDialogsOn != nullptr) { selector->SetPosition(_windowToPlaceDialogsOn->GetScreenPosition()); diff --git a/tools/msvc/DarkRadiant.vcxproj b/tools/msvc/DarkRadiant.vcxproj index 7f00638d89..d5c866b631 100644 --- a/tools/msvc/DarkRadiant.vcxproj +++ b/tools/msvc/DarkRadiant.vcxproj @@ -233,6 +233,7 @@ + diff --git a/tools/msvc/DarkRadiant.vcxproj.filters b/tools/msvc/DarkRadiant.vcxproj.filters index d9f91540bd..ddfcd3442f 100644 --- a/tools/msvc/DarkRadiant.vcxproj.filters +++ b/tools/msvc/DarkRadiant.vcxproj.filters @@ -709,6 +709,9 @@ src\ui\common + + src\ui\common +