Skip to content

Commit

Permalink
#5127: Migrate SoundChooser to use the ResourceTreeView classes
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Jan 2, 2021
1 parent ebc5c97 commit 07ee110
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 166 deletions.
7 changes: 6 additions & 1 deletion libs/wxutil/dataview/ResourceTreeView.cpp
Expand Up @@ -207,11 +207,13 @@ void ResourceTreeView::Clear()
_populator.reset();
_treeStore->Clear();
_emptyFavouritesLabel = wxDataViewItem();
_fullNameToSelectAfterPopulation.clear();
}

void ResourceTreeView::Populate(const IResourceTreePopulator::Ptr& populator)
{
// Try to keep the current selection intact after population
_fullNameToSelectAfterPopulation = GetSelectedFullname();

// Remove any data or running populators first
Clear();

Expand Down Expand Up @@ -243,6 +245,9 @@ void ResourceTreeView::_onTreeStorePopulationFinished(TreeModel::PopulationFinis
SetTreeModel(ev.GetTreeModel());
_populator.reset();

// Trigger a column size event on the first-level row
TriggerColumnSizeEvent();

if (_expandTopLevelItemsAfterPopulation)
{
ExpandTopLevelItems();
Expand Down
169 changes: 37 additions & 132 deletions radiant/uimanager/SoundChooser.cpp
Expand Up @@ -5,6 +5,7 @@
#include "isound.h"
#include "imainframe.h"

#include "wxutil/dataview/ThreadedResourceTreePopulator.h"
#include "wxutil/dataview/VFSTreePopulator.h"
#include "wxutil/menu/IconTextMenuItem.h"
#include "debugging/ScopedDebugTimer.h"
Expand Down Expand Up @@ -37,14 +38,14 @@ class SoundShaderPopulator :
public wxutil::VFSTreePopulator
{
private:
const SoundChooser::TreeColumns& _columns;
const wxutil::ResourceTreeView::Columns& _columns;

wxIcon _shaderIcon;
wxIcon _folderIcon;
public:
// Constructor
SoundShaderPopulator(wxutil::TreeModel::Ptr treeStore,
const SoundChooser::TreeColumns& columns) :
SoundShaderPopulator(const wxutil::TreeModel::Ptr& treeStore,
const wxutil::ResourceTreeView::Columns& columns) :
VFSTreePopulator(treeStore),
_columns(columns)
{
Expand Down Expand Up @@ -72,9 +73,11 @@ class SoundShaderPopulator :
addPath(fullPath, [&](wxutil::TreeModel::Row& row, const std::string& path,
const std::string& leafName, bool isFolder)
{
row[_columns.displayName] = wxVariant(
row[_columns.iconAndName] = wxVariant(
wxDataViewIconText(leafName, isFolder ? _folderIcon : _shaderIcon));
row[_columns.shaderName] = !isFolder ? shader.getName() : std::string();
auto actualLeafName = !isFolder ? shader.getName() : std::string();
row[_columns.leafName] = actualLeafName;
row[_columns.fullName] = actualLeafName;
row[_columns.isFolder] = isFolder;
row.SendItemAdded();
});
Expand All @@ -83,75 +86,52 @@ class SoundShaderPopulator :


// Local class for loading sound shader definitions in a separate thread
class SoundChooser::ThreadedSoundShaderLoader :
public wxThread
class ThreadedSoundShaderLoader :
public wxutil::ThreadedResourceTreePopulator
{
// Column specification struct
const SoundChooser::TreeColumns& _columns;

// The tree store to populate. We must operate on our own tree store, since
// updating the EntityClassChooser's tree store from a different thread
// wouldn't be safe
wxutil::TreeModel::Ptr _treeStore;

// The class to be notified on finish
wxEvtHandler* _finishedHandler;
const wxutil::ResourceTreeView::Columns& _columns;

public:

// Construct and initialise variables
ThreadedSoundShaderLoader(const SoundChooser::TreeColumns& cols,
wxEvtHandler* finishedHandler) :
wxThread(wxTHREAD_JOINABLE),
_columns(cols),
_finishedHandler(finishedHandler)
ThreadedSoundShaderLoader(const wxutil::ResourceTreeView::Columns& columns) :
ThreadedResourceTreePopulator(columns),
_columns(columns)
{}

~ThreadedSoundShaderLoader()
{
if (IsRunning())
{
Delete();
}
EnsureStopped();
}

// The worker function that will execute in the thread
ExitCode Entry()
void PopulateModel(const wxutil::TreeModel::Ptr& model) override
{
ScopedDebugTimer timer("ThreadedSoundShaderLoader::run()");

// Create new treestoree
_treeStore = new wxutil::TreeModel(_columns);

// Populate it with the list of sound shaders by using a visitor class.
SoundShaderPopulator visitor(_treeStore, _columns);

// Visit all sound shaders and collect them for later insertion
GlobalSoundManager().forEachShader(
std::bind(&SoundShaderPopulator::addShader, std::ref(visitor), std::placeholders::_1)
);

if (TestDestroy()) return static_cast<ExitCode>(0);
SoundShaderPopulator visitor(model, _columns);

// angua: Ensure sound shaders are sorted before giving them to the tree view
_treeStore->SortModelFoldersFirst(_columns.displayName, _columns.isFolder);

if (!TestDestroy())
// Visit all sound shaders and collect them for later insertion
GlobalSoundManager().forEachShader([&](const ISoundShader& shader)
{
wxQueueEvent(_finishedHandler, new wxutil::TreeModel::PopulationFinishedEvent(_treeStore));
}
ThrowIfCancellationRequested();
visitor.addShader(shader);
});
}

return static_cast<ExitCode>(0);
void SortModel(const wxutil::TreeModel::Ptr& model) override
{
// angua: Ensure sound shaders are sorted before giving them to the tree view
model->SortModelFoldersFirst(_columns.iconAndName, _columns.isFolder);
}
};

// Constructor
SoundChooser::SoundChooser(wxWindow* parent) :
DialogBase(_("Choose sound"), parent),
_treeStore(nullptr),
_treeView(nullptr),
_preview(new SoundShaderPreview(this)),
_loadingShaders(false)
_preview(new SoundShaderPreview(this))
{
SetSizer(new wxBoxSizer(wxVERTICAL));

Expand All @@ -175,26 +155,22 @@ SoundChooser::SoundChooser(wxWindow* parent) :

FitToScreen(0.5f, 0.7f);

// Connect the finish callback to load the treestore
Bind(wxutil::EV_TREEMODEL_POPULATION_FINISHED, &SoundChooser::_onTreeStorePopulationFinished, this);

// Load the shaders
loadSoundShaders();
}

// Create the tree view
wxWindow* SoundChooser::createTreeView(wxWindow* parent)
{
_treeStore = new wxutil::TreeModel(_columns);

// Tree view with single text icon column
_treeView = wxutil::TreeView::CreateWithModel(parent, _treeStore.get());
_treeView = new wxutil::ResourceTreeView(parent, _columns);

_treeView->AppendIconTextColumn(_("Soundshader"), _columns.displayName.getColumnIndex(),
_treeView->AppendIconTextColumn(_("Soundshader"), _columns.iconAndName.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);

// Use the TreeModel's full string search function
_treeView->AddSearchColumn(_columns.displayName);
_treeView->AddSearchColumn(_columns.iconAndName);
_treeView->SetExpandTopLevelItemsAfterPopulation(true);

// Get selection and connect the changed callback
_treeView->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, &SoundChooser::_onSelectionChange, this);
Expand All @@ -206,21 +182,7 @@ wxWindow* SoundChooser::createTreeView(wxWindow* parent)

void SoundChooser::loadSoundShaders()
{
// Clear the tree and display a new item
_treeStore->Clear();

wxutil::TreeModel::Row row = _treeStore->AddItem();
row[_columns.displayName] = wxVariant(wxDataViewIconText(_("Loading...")));
row[_columns.shaderName] = wxString();
row[_columns.isFolder] = false;

row.SendItemAdded();

_loadingShaders = true;

// Spawn a new thread to load the items
_shaderLoader.reset(new ThreadedSoundShaderLoader(_columns, this));
_shaderLoader->Run();
_treeView->Populate(std::make_shared<ThreadedSoundShaderLoader>(_columns));
}

const std::string& SoundChooser::getSelectedShader() const
Expand All @@ -231,26 +193,7 @@ const std::string& SoundChooser::getSelectedShader() const
// Set the selected sound shader, and focuses the treeview to the new selection
void SoundChooser::setSelectedShader(const std::string& shader)
{
// Select immediately if possible, otherwise remember class name for later
// selection
if (!_loadingShaders)
{
wxDataViewItem item = _treeStore->FindString(shader, _columns.shaderName);

if (item.IsOk())
{
_treeView->Select(item);
_treeView->EnsureVisible(item);
handleSelectionChange();

_shaderToSelect.clear();

return;
}
}

// Remember this for later code
_shaderToSelect = shader;
_treeView->SetSelectedFullname(shader);
}

void SoundChooser::handleSelectionChange()
Expand All @@ -259,11 +202,11 @@ void SoundChooser::handleSelectionChange()

if (item.IsOk())
{
wxutil::TreeModel::Row row(item, *_treeStore);
wxutil::TreeModel::Row row(item, *_treeView->GetTreeModel());

bool isFolder = row[_columns.isFolder].getBool();

_selectedShader = isFolder ? "" : static_cast<std::string>(row[_columns.shaderName]);
_selectedShader = isFolder ? "" : static_cast<std::string>(row[_columns.fullName]);
}
else
{
Expand All @@ -285,7 +228,7 @@ void SoundChooser::_onItemActivated(wxDataViewEvent& ev)

if (item.IsOk())
{
wxutil::TreeModel::Row row(item, *_treeStore);
wxutil::TreeModel::Row row(item, *_treeView->GetTreeModel());

bool isFolder = row[_columns.isFolder].getBool();

Expand All @@ -309,32 +252,6 @@ void SoundChooser::_onItemActivated(wxDataViewEvent& ev)
}
}

void SoundChooser::setTreeViewModel()
{
_treeView->AssociateModel(_treeStore.get());

// Trigger a column size event on the first-level row
_treeView->TriggerColumnSizeEvent();

// Pre-select the given class if requested by setSelectedShader()
if (!_shaderToSelect.empty())
{
assert(_treeStore);
setSelectedShader(_shaderToSelect);
}

// Make sure the top-level items are expanded
_treeView->ExpandTopLevelItems();
}

void SoundChooser::_onTreeStorePopulationFinished(wxutil::TreeModel::PopulationFinishedEvent& ev)
{
_loadingShaders = false;

_treeStore = ev.GetTreeModel();
setTreeViewModel();
}

void SoundChooser::_onContextMenu(wxDataViewEvent& ev)
{
_popupMenu->show(_treeView);
Expand Down Expand Up @@ -369,23 +286,11 @@ int SoundChooser::ShowModal()

void SoundChooser::_onReloadSounds(wxCommandEvent& ev)
{
// Remember the last selected shader
_shaderToSelect = getSelectedShader();

_preview->setSoundShader(std::string());

// Send the command to the SoundManager
// After parsing it will fire the sounds reloaded signal => onShadersReloaded()
GlobalCommandSystem().executeCommand("ReloadSounds");

_treeStore->Clear();

wxutil::TreeModel::Row row = _treeStore->AddItem();
row[_columns.displayName] = wxVariant(wxDataViewIconText(_("Loading...")));
row[_columns.shaderName] = wxString();
row[_columns.isFolder] = false;

row.SendItemAdded();
}

void SoundChooser::onShadersReloaded()
Expand Down
36 changes: 3 additions & 33 deletions radiant/uimanager/SoundChooser.h
Expand Up @@ -2,8 +2,7 @@

#include "iresourcechooser.h"
#include "wxutil/dialog/DialogBase.h"
#include "wxutil/dataview/TreeModel.h"
#include "wxutil/dataview/TreeView.h"
#include "wxutil/dataview/ResourceTreeView.h"
#include "wxutil/menu/PopupMenu.h"

#include "SoundShaderPreview.h"
Expand All @@ -21,61 +20,32 @@ class SoundChooser :
public wxutil::DialogBase,
public IResourceChooser
{
public:
// Treemodel definition
struct TreeColumns :
public wxutil::TreeModel::ColumnRecord
{
TreeColumns() :
displayName(add(wxutil::TreeModel::Column::IconText)),
shaderName(add(wxutil::TreeModel::Column::String)),
isFolder(add(wxutil::TreeModel::Column::Boolean))
{}

wxutil::TreeModel::Column displayName;
wxutil::TreeModel::Column shaderName;
wxutil::TreeModel::Column isFolder;
};

private:
TreeColumns _columns;

// Tree store for shaders, and the tree selection
wxutil::TreeModel::Ptr _treeStore;
wxutil::TreeView* _treeView;

class ThreadedSoundShaderLoader;
std::unique_ptr<ThreadedSoundShaderLoader> _shaderLoader; // PIMPL idiom
wxutil::ResourceTreeView::Columns _columns;
wxutil::ResourceTreeView* _treeView;

// The preview widget group
SoundShaderPreview* _preview;

// Last selected shader
std::string _selectedShader;

// For memorising what we need to pre-select once the population is done
std::string _shaderToSelect;

// Context menu
wxutil::PopupMenuPtr _popupMenu;

bool _loadingShaders;

sigc::connection _shadersReloaded;

private:

// Widget construction
wxWindow* createTreeView(wxWindow* parent);

void setTreeViewModel();
void loadSoundShaders();
void handleSelectionChange();

// callbacks
void _onSelectionChange(wxDataViewEvent& ev);
void _onItemActivated(wxDataViewEvent& ev);
void _onTreeStorePopulationFinished(wxutil::TreeModel::PopulationFinishedEvent& ev);
void _onContextMenu(wxDataViewEvent& ev);
void _onReloadSounds(wxCommandEvent& ev);

Expand Down

0 comments on commit 07ee110

Please sign in to comment.