Skip to content

Commit

Permalink
#5108: Add dialog and menu option to pick a file from the current pro…
Browse files Browse the repository at this point in the history
…ject (incl. PK4s)
  • Loading branch information
codereader committed Nov 18, 2020
1 parent 85f8cc0 commit df6d956
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 7 deletions.
1 change: 1 addition & 0 deletions install/menu.xml
Expand Up @@ -4,6 +4,7 @@
<menuItem name="new" caption="&amp;New Map" command="NewMap" />
<menuSeparator />
<menuItem name="open" caption="&amp;Open..." command="OpenMap" />
<menuItem name="openMapFromProject" caption="&amp;Open Map from Project..." command="OpenMapFromProject" />
<menuItem name="import" caption="&amp;Import map..." command="ImportMap" />
<menuItem name="loadprefab" caption="Import &amp;prefab..." command="LoadPrefab" />
<menuSeparator />
Expand Down
2 changes: 2 additions & 0 deletions radiant/ui/UserInterfaceModule.cpp
Expand Up @@ -59,6 +59,7 @@
#include "ui/brush/QuerySidesDialog.h"
#include "ui/brush/FindBrush.h"
#include "ui/mousetool/RegistrationHelper.h"
#include "ui/mapselector/MapSelector.h"

#include <wx/version.h>

Expand Down Expand Up @@ -408,6 +409,7 @@ void UserInterfaceModule::registerUICommands()
GlobalEventManager().addRegistryToggle("TogTexLock", RKEY_ENABLE_TEXTURE_LOCK);

GlobalCommandSystem().addCommand("LoadPrefab", ui::loadPrefabDialog);
GlobalCommandSystem().addCommand("OpenMapFromProject", ui::MapSelector::OpenMapFromProject);
}

void UserInterfaceModule::HandleTextureChanged(radiant::TextureChangedMessage& msg)
Expand Down
117 changes: 117 additions & 0 deletions radiant/ui/mapselector/MapSelector.cpp
@@ -0,0 +1,117 @@
#include "MapSelector.h"

#include "i18n.h"

#include <wx/sizer.h>
#include <wx/button.h>

namespace ui
{

// CONSTANTS
namespace
{
const char* const MAPSELECTOR_TITLE = N_("Choose Map File");
}

MapSelector::MapSelector() :
DialogBase(_(MAPSELECTOR_TITLE)),
_treeView(nullptr),
_handlingSelectionChange(false)
{
SetSizer(new wxBoxSizer(wxVERTICAL));

wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL);
GetSizer()->Add(vbox, 1, wxEXPAND | wxALL, 12);

setupTreeView(this);
vbox->Add(_treeView, 1, wxEXPAND);

wxStdDialogButtonSizer* buttonSizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
wxButton* reloadButton = new wxButton(this, wxID_ANY, _("Rescan"));
reloadButton->Bind(wxEVT_BUTTON, &MapSelector::onRescanPath, this);

buttonSizer->Prepend(reloadButton, 0, wxRIGHT, 32);

vbox->Add(buttonSizer, 0, wxALIGN_RIGHT | wxTOP, 12);

// Set the default size of the window
_position.connect(this);
_position.readPosition();

FitToScreen(0.5f, 0.6f);
}

int MapSelector::ShowModal()
{
// Populate the tree
populateTree();

// Enter the main loop
return DialogBase::ShowModal();
}

std::string MapSelector::ChooseMapFile()
{
auto* dialog = new MapSelector();
std::string returnValue = "";

if (dialog->ShowModal() == wxID_OK)
{
returnValue = dialog->getSelectedPath();
}

// Use the instance to select a model.
return returnValue;
}

void MapSelector::OpenMapFromProject(const cmd::ArgumentList& args)
{
auto mapPath = ChooseMapFile();

if (!mapPath.empty())
{
GlobalCommandSystem().executeCommand("OpenMap", mapPath);
}
}

// Helper function to create the TreeView
void MapSelector::setupTreeView(wxWindow* parent)
{
_treeView = wxutil::FileSystemView::Create(parent, wxBORDER_STATIC | wxDV_NO_HEADER);

// Get the extensions from all possible patterns (e.g. *.map or *.mapx)
FileTypePatterns patterns = GlobalFiletypes().getPatternsForType(filetype::TYPE_MAP);

std::set<std::string> fileExtensions;

for (const auto& pattern : patterns)
{
fileExtensions.insert(pattern.extension);
}

_treeView->SetFileExtensions(fileExtensions);
}

std::string MapSelector::getBaseFolder()
{
return ""; // use an empty path which resembles the VFS root
}

void MapSelector::populateTree()
{
_treeView->SetBasePath(getBaseFolder());
_treeView->Populate();
}

void MapSelector::onRescanPath(wxCommandEvent& ev)
{
populateTree();
}

std::string MapSelector::getSelectedPath()
{
return _treeView->GetSelectedPath();
}

}
57 changes: 57 additions & 0 deletions radiant/ui/mapselector/MapSelector.h
@@ -0,0 +1,57 @@
#pragma once

#include "icommandsystem.h"

#include "wxutil/dialog/DialogBase.h"
#include "wxutil/fsview/FileSystemView.h"
#include "wxutil/WindowPosition.h"

namespace ui
{

/// Dialog for browsing and selecting a map from (V)FS
class MapSelector :
public wxutil::DialogBase
{
private:
wxPanel* _dialogPanel;

// Main tree view with the folder hierarchy
wxutil::FileSystemView* _treeView;

// The window position tracker
wxutil::WindowPosition _position;

bool _handlingSelectionChange;

private:
// Private constructor, creates widgets
MapSelector();

// Helper functions to configure GUI components
void setupTreeView(wxWindow* parent);

// Populate the tree view with files
void populateTree();

// Get the path that should be used for map population
// This reflects the settings made by the user on the top of the selector window
std::string getBaseFolder();

// Return the selected map path
std::string getSelectedPath();

void onRescanPath(wxCommandEvent& ev);

public:
int ShowModal() override;

/**
* Display the Selector return the path of the file selected by the user.
*/
static std::string ChooseMapFile();

static void OpenMapFromProject(const cmd::ArgumentList& args);
};

}
23 changes: 16 additions & 7 deletions radiantcore/map/Map.cpp
Expand Up @@ -702,17 +702,26 @@ void Map::openMap(const cmd::ArgumentList& args)
}
else if (!candidate.empty())
{
// Next, try to look up the map in the regular maps path
fs::path mapsPath = GlobalGameManager().getMapPath();
fs::path fullMapPath = mapsPath / candidate;

if (os::fileOrDirExists(fullMapPath.string()))
// Try to open this file from the VFS (this will hit physical files
// in the active project as well as files in registered PK4)
if (GlobalFileSystem().openTextFile(candidate))
{
mapToLoad = fullMapPath.string();
mapToLoad = candidate;
}
else
{
throw cmd::ExecutionFailure(fmt::format(_("File doesn't exist: {0}"), fullMapPath.string()));
// Next, try to look up the map in the regular maps path
fs::path mapsPath = GlobalGameManager().getMapPath();
fs::path fullMapPath = mapsPath / candidate;

if (os::fileOrDirExists(fullMapPath.string()))
{
mapToLoad = fullMapPath.string();
}
else
{
throw cmd::ExecutionFailure(fmt::format(_("File doesn't exist: {0}"), candidate));
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions tools/msvc/DarkRadiant.vcxproj
Expand Up @@ -268,6 +268,7 @@
<ClCompile Include="..\..\radiant\ui\MapCommands.cpp" />
<ClCompile Include="..\..\radiant\ui\MapFileProgressHandler.cpp" />
<ClCompile Include="..\..\radiant\ui\mapinfo\LayerInfoTab.cpp" />
<ClCompile Include="..\..\radiant\ui\mapselector\MapSelector.cpp" />
<ClCompile Include="..\..\radiant\ui\modelexport\ExportAsModelDialog.cpp" />
<ClCompile Include="..\..\radiant\ui\modelexport\ExportCollisionModelDialog.cpp" />
<ClCompile Include="..\..\radiant\ui\modelselector\MaterialsList.cpp" />
Expand Down Expand Up @@ -454,6 +455,7 @@
<ClInclude Include="..\..\radiant\ui\MapCommands.h" />
<ClInclude Include="..\..\radiant\ui\MapFileProgressHandler.h" />
<ClInclude Include="..\..\radiant\ui\mapinfo\LayerInfoTab.h" />
<ClInclude Include="..\..\radiant\ui\mapselector\MapSelector.h" />
<ClInclude Include="..\..\radiant\ui\modelexport\ExportAsModelDialog.h" />
<ClInclude Include="..\..\radiant\ui\modelexport\ExportCollisionModelDialog.h" />
<ClInclude Include="..\..\radiant\ui\modelselector\MaterialsList.h" />
Expand Down
9 changes: 9 additions & 0 deletions tools/msvc/DarkRadiant.vcxproj.filters
Expand Up @@ -173,6 +173,9 @@
<Filter Include="src\ui\script">
<UniqueIdentifier>{28ae583f-8545-491c-abcc-5e459c3d357b}</UniqueIdentifier>
</Filter>
<Filter Include="src\ui\mapselector">
<UniqueIdentifier>{6ddb8b69-4e5a-4c82-b7d4-aa1306342340}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\radiant\main.cpp">
Expand Down Expand Up @@ -667,6 +670,9 @@
<ClCompile Include="..\..\radiant\ui\EntityClassColourManager.cpp">
<Filter>src\ui</Filter>
</ClCompile>
<ClCompile Include="..\..\radiant\ui\mapselector\MapSelector.cpp">
<Filter>src\ui\mapselector</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\radiant\camera\CameraSettings.h">
Expand Down Expand Up @@ -1284,6 +1290,9 @@
<ClInclude Include="..\..\radiant\ui\common\SoundShaderDefinitionView.h">
<Filter>src\ui\common</Filter>
</ClInclude>
<ClInclude Include="..\..\radiant\ui\mapselector\MapSelector.h">
<Filter>src\ui\mapselector</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\radiant\darkradiant.rc" />
Expand Down

0 comments on commit df6d956

Please sign in to comment.