Skip to content

Commit

Permalink
#5231: Move MRU implementation to core and extract IMRUManager interf…
Browse files Browse the repository at this point in the history
…ace, leave MRU menu handling in the UI binary.

Move some Selection classes to libs/ folder.
More refactoring in Map class.
  • Loading branch information
codereader committed Jun 5, 2020
1 parent 0d0c1fe commit 2a3e4d5
Show file tree
Hide file tree
Showing 30 changed files with 473 additions and 168 deletions.
5 changes: 5 additions & 0 deletions include/imap.h
Expand Up @@ -8,6 +8,11 @@
// Registry setting for suppressing the map load progress dialog
const char* const RKEY_MAP_SUPPRESS_LOAD_STATUS_DIALOG = "user/ui/map/suppressMapLoadDialog";

// Whether to load the most recently used map on app startup
const char* const RKEY_LOAD_LAST_MAP = "user/ui/map/loadLastMap";

const char* const LOAD_PREFAB_AT_CMD = "LoadPrefabAt";

// Namespace forward declaration
class INamespace;
typedef std::shared_ptr<INamespace> INamespacePtr;
Expand Down
48 changes: 48 additions & 0 deletions include/imru.h
@@ -0,0 +1,48 @@
#pragma once

#include "imodule.h"
#include <sigc++/signal.h>

namespace map
{

const char* const LOAD_MRU_MAP_CMD = "LoadMRUMap";
const char* const LOAD_MRU_STATEMENT_FORMAT = "MRUOpen{0:d}";

class IMRUManager :
public RegisterableModule
{
public:
virtual ~IMRUManager() {}

typedef std::function<void(std::size_t index, const std::string & fileName)> ItemFunctor;

virtual std::size_t getMaxNumberOfItems() const = 0;

// Visits each item, ordered by the 0-based index
virtual void foreachItem(const ItemFunctor& functor) = 0;

// Inserts the given map filename at the top of the list
// Duplicates are relocated, the number of list items is constrained
virtual void insert(const std::string& fileName) = 0;

// Returns the filename of the last opened map, or "" if there doesn't exist one
virtual std::string getLastMapName() = 0;

virtual sigc::signal<void>& signal_MapListChanged() = 0;
};

}

const char* const MODULE_MRU_MANAGER = "MRUManager";

inline map::IMRUManager& GlobalMRU()
{
// Cache the reference locally
static map::IMRUManager& _manager(
*std::static_pointer_cast<map::IMRUManager>(
module::GlobalModuleRegistry().getModule(MODULE_MRU_MANAGER)
)
);
return _manager;
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
16 changes: 10 additions & 6 deletions radiant/camera/CamWnd.cpp
Expand Up @@ -7,6 +7,8 @@
#include "ieventmanager.h"
#include "imainframe.h"
#include "itextstream.h"
#include "iorthoview.h"
#include "icamera.h"

#include <time.h>
#include <fmt/format.h>
Expand Down Expand Up @@ -39,9 +41,9 @@ namespace
{
const std::size_t MSEC_PER_FRAME = 16;

const std::string FAR_CLIP_IN_TEXT = "Move far clip plane closer";
const std::string FAR_CLIP_OUT_TEXT = "Move far clip plane further away";
const std::string FAR_CLIP_DISABLED_TEXT = " (currently disabled in preferences)";
const char* const FAR_CLIP_IN_TEXT = N_("Move far clip plane closer");
const char* const FAR_CLIP_OUT_TEXT = N_("Move far clip plane further away");
const char* const FAR_CLIP_DISABLED_TEXT = N_(" (currently disabled in preferences)");
const char* const RKEY_SELECT_EPSILON = "user/ui/selectionEpsilon";
}

Expand Down Expand Up @@ -296,8 +298,8 @@ void CamWnd::setFarClipButtonSensitivity()
miscToolbar->EnableTool(clipPlaneOutButton->GetId(), enabled);

// Update tooltips so users know why they are disabled
clipPlaneInButton->SetShortHelp(FAR_CLIP_IN_TEXT + (enabled ? "" : FAR_CLIP_DISABLED_TEXT));
clipPlaneOutButton->SetShortHelp(FAR_CLIP_OUT_TEXT + (enabled ? "" : FAR_CLIP_DISABLED_TEXT));
clipPlaneInButton->SetShortHelp(fmt::format("{0}{1}", _(FAR_CLIP_IN_TEXT), (enabled ? "" : _(FAR_CLIP_DISABLED_TEXT))));
clipPlaneOutButton->SetShortHelp(fmt::format("{0}{1}", _(FAR_CLIP_OUT_TEXT), (enabled ? "" : _(FAR_CLIP_DISABLED_TEXT))));
}

void CamWnd::constructGUIComponents()
Expand Down Expand Up @@ -488,7 +490,9 @@ void CamWnd::jumpToObject(SelectionTest& selectionTest) {
AABB found = finder.getNode()->worldAABB();

// Focus the view at the center of the found AABB
map::Map::focusViews(found.origin, getCameraAngles());
// Set the camera and the views to the given point
GlobalCameraManager().focusCamera(found.origin, getCameraAngles());
GlobalXYWndManager().setOrigin(found.origin);
}
}

Expand Down
5 changes: 3 additions & 2 deletions radiant/map/StartupMapLoader.cpp
@@ -1,6 +1,7 @@
#include "StartupMapLoader.h"

#include "imodule.h"
#include "imap.h"
#include "igl.h"
#include "irender.h"
#include "iregistry.h"
Expand Down Expand Up @@ -53,11 +54,11 @@ void StartupMapLoader::onRadiantStartup()
{
loadMapSafe(mapToLoad);
}
else
else if (registry::getValue<bool>(RKEY_LOAD_LAST_MAP))
{
std::string lastMap = GlobalMRU().getLastMapName();

if (GlobalMRU().loadLastMap() && !lastMap.empty() && os::fileOrDirExists(lastMap))
if (!lastMap.empty() && os::fileOrDirExists(lastMap))
{
loadMapSafe(lastMap);
}
Expand Down
18 changes: 18 additions & 0 deletions radiant/ui/MapCommands.cpp
@@ -0,0 +1,18 @@
#include "MapCommands.h"

#include "prefabselector/PrefabSelector.h"

namespace ui
{

void loadPrefabDialog(const cmd::ArgumentList& args)
{
auto result = PrefabSelector::ChoosePrefab();

if (!result.prefabPath.empty())
{
GlobalCommandSystem().executeCommand(LOAD_PREFAB_AT_CMD, Vector3(0, 0, 0));
}
}

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

#include "icommandsystem.h"

namespace ui
{

void loadPrefabDialog(const cmd::ArgumentList& args);

}
9 changes: 9 additions & 0 deletions radiant/ui/UserInterfaceModule.cpp
Expand Up @@ -4,6 +4,7 @@
#include "ilayer.h"
#include "ifilter.h"
#include "ientity.h"
#include "imru.h"
#include "ibrush.h"
#include "ipatch.h"
#include "iorthocontextmenu.h"
Expand All @@ -18,6 +19,7 @@

#include "module/StaticModule.h"

#include "MapCommands.h"
#include "ui/aas/AasControlDialog.h"
#include "ui/prefdialog/GameSetupDialog.h"
#include "ui/layers/LayerOrthoContextMenuItem.h"
Expand Down Expand Up @@ -87,6 +89,7 @@ const StringSet& UserInterfaceModule::getDependencies() const
_dependencies.insert(MODULE_ENTITY);
_dependencies.insert(MODULE_EVENTMANAGER);
_dependencies.insert(MODULE_RADIANT_CORE);
_dependencies.insert(MODULE_MRU_MANAGER);
}

return _dependencies;
Expand Down Expand Up @@ -165,6 +168,8 @@ void UserInterfaceModule::initialiseModule(const ApplicationContext& ctx)
AasControlDialog::Init();

SelectionSetToolmenu::Init();

_mruMenu.reset(new MRUMenu);
}

void UserInterfaceModule::shutdownModule()
Expand All @@ -180,6 +185,8 @@ void UserInterfaceModule::shutdownModule()
_eClassColourManager.reset();
_mapFileProgressHandler.reset();
_autoSaveRequestHandler.reset();

_mruMenu.reset();
}

void UserInterfaceModule::handleCommandExecutionFailure(radiant::CommandExecutionFailedMessage& msg)
Expand Down Expand Up @@ -327,6 +334,8 @@ void UserInterfaceModule::registerUICommands()
GlobalEventManager().addRegistryToggle("ToggleSnapRotationPivot", "user/ui/snapRotationPivotToGrid");
GlobalEventManager().addRegistryToggle("ToggleOffsetClones", "user/ui/offsetClonedObjects");
GlobalEventManager().addRegistryToggle("ToggleFreeObjectRotation", RKEY_FREE_OBJECT_ROTATION);

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

void UserInterfaceModule::HandleTextureChanged(radiant::TextureChangedMessage& msg)
Expand Down
3 changes: 3 additions & 0 deletions radiant/ui/UserInterfaceModule.h
Expand Up @@ -13,6 +13,7 @@
#include "messages/CommandExecutionFailed.h"
#include "messages/TextureChanged.h"
#include "messages/NotificationMessage.h"
#include "ui/mru/MRUMenu.h"

namespace ui
{
Expand Down Expand Up @@ -40,6 +41,8 @@ class UserInterfaceModule :
std::size_t _textureChangedListener;
std::size_t _notificationListener;

std::unique_ptr<MRUMenu> _mruMenu;

public:
// RegisterableModule
const std::string & getName() const override;
Expand Down
129 changes: 129 additions & 0 deletions radiant/ui/mru/MRUMenu.h
@@ -0,0 +1,129 @@
#pragma once

#include "imru.h"
#include "iuimanager.h"

#include <list>
#include <sigc++/connection.h>
#include <sigc++/functors/mem_fun.h>
#include <fmt/format.h>
#include "string/convert.h"

namespace ui
{

namespace
{
const char* const RECENT_FILES_CAPTION = N_("Recently used Maps");
}

class MRUMenu
{
private:
sigc::connection _mruUpdateConn;

public:
MRUMenu()
{
_mruUpdateConn = GlobalMRU().signal_MapListChanged().connect(
sigc::mem_fun(*this, &MRUMenu::onMRUListChanged)
);

constructMenu();
}

~MRUMenu()
{
clearMenu();

_mruUpdateConn.disconnect();
}

private:
void clearMenu()
{
IMenuManager& menuManager = GlobalUIManager().getMenuManager();

// Remove all items from the menu
for (std::size_t i = GlobalMRU().getMaxNumberOfItems(); i > 0; i--)
{
menuManager.remove("main/file/MRU" + string::to_string(i));
}

menuManager.remove("main/file/mruempty");
}

void updateMenu()
{
clearMenu();

std::vector<std::string> filenames(GlobalMRU().getMaxNumberOfItems());

GlobalMRU().foreachItem([&](std::size_t index, const std::string& filename)
{
filenames.emplace_back(filename);
});

// Get the menumanager
IMenuManager& menuManager = GlobalUIManager().getMenuManager();

if (filenames.empty())
{
// Create the "empty" MRU menu item (the desensitised one)
menuManager.insert(
"main/file/mruseparator",
"mruempty",
ui::menuItem,
RECENT_FILES_CAPTION,
"", // empty icon
"" // empty event
);

return;
}

// Add one item for each filename in the MRU list
for (std::size_t index = 0; index < filenames.size(); ++index)
{
// The default string to be loaded into the widget (i.e. "inactive")
std::string filename = filenames[index];

std::string label = string::to_string(index + 1) + " - " + filename;

auto statement = fmt::format(map::LOAD_MRU_STATEMENT_FORMAT, index + 1);

// Create the menu item
menuManager.insert(
"main/file/mruseparator",
"MRU" + string::to_string(index + 1),
ui::menuItem,
label,
"", // empty icon
statement
);
}
}

void constructMenu()
{
// Insert the last separator to split the MRU file list from the "Exit" command.
GlobalUIManager().getMenuManager().insert(
"main/file/exit",
"mruseparator",
ui::menuSeparator,
"", // empty caption
"", // empty icon
"" // empty command
);

// Call the update routine to load the values into the widgets
updateMenu();
}

void onMRUListChanged()
{
updateMenu();
}
};

}
14 changes: 4 additions & 10 deletions radiant/ui/mru/MRUMenuItem.h
Expand Up @@ -6,10 +6,8 @@
// Forward declaration
class wxMenuItem;

namespace ui {

// Forward declaration
class MRU;
namespace ui
{

/* greebo: An MRUMenuItem holds the information of a single menu entry,
* this consists mainly of the map filename and the MRU number.
Expand All @@ -20,15 +18,12 @@ class MRUMenuItem
// The filename behind this item
std::string _mapFilename;

// The reference to the main class for loading maps and stuff
MRU& _mru;

// The number of this MRU item to be displayed
unsigned int _index;

public:
// Constructor
MRUMenuItem(const std::string& mapFilename, ui::MRU& _mru, unsigned int index);
MRUMenuItem(const std::string& mapFilename, unsigned int index);

// Copy Constructor
MRUMenuItem(const ui::MRUMenuItem& other);
Expand All @@ -41,7 +36,6 @@ class MRUMenuItem
const std::string& getMapFilename() const;

int getIndex() const;

}; // class MRUMenuItem
};

} // namespace ui

0 comments on commit 2a3e4d5

Please sign in to comment.