strooka wrote:i couldnt manage that with the options db, cause having problems with the >> operator.
[...]
Maybe i should save à String representation of the HotKeys in the options db.
I could create à wrapper func that gets them from the options db and initializes an element in the map m_hotkey_list. then it would Be saved to file.
Have a look at StreamableColor in ClientUI.h. OptionsDB already can store arbitrary structures if you define the appropriate operator >> and operator << to export as or be initialized from text. This should be doable for HotKey as well, for reasonabl definitions of HotKey. I'm also suspect it's what's causing your "problems with the >> operator", the meaning of which is unclear from the post.
Don't pass std::string by value when you could pass it by const reference. There are several cases where you've declared a function that takes an std::string by value.
You don't need to redefine SetOptionFunctor for strings as part of HotKeyManager. If hotkey options are to be stored as just strings then you could use the existing sting SetOptionFunctor. However this shouldn't matter, as there should be a separate UI wiget for binding hotkeys to commands that doesn't involve just a text edit box. This widget could include an edit box to display the results, but should be treated as a separate control with custom-designed interactivity for the setting of the hotkeys.
The HotKey and HotKeyManager classes need some reorganizing...
Currently you use HotKeyManager::InsertHotKey in the initialization of MapWnd. This won't work properly in general, because there could be more than one UI class instance created, and this would attempt to add "hotkeys" every time one is constructed, leading to duplication.
Instead, there should be a "AddCommand" function in the HotKeyManager. This would be used in a function in an anonymous namespace of various source files, like the OptionsDB option-adding code, except that all you'd do is call GetHotKeyManager().AddCommand(...) to add a new command, and it's not necessary to do the complicated store-and-process later business that's done for AddOptions and RegisterOptions.
The use of the AddCommand function would be to tell the HotKeyManager to add a "command". A command being in the HKM would mean that the HKM internally stores a boost::signal object that can be accessed by calling HotKeyManager::GetCommandSignal(const std::string& signal_name). This signal would emit whenever the appropriate keypress is detected, and various UI classes would use GG::Connect to connect the signal to a function to respond to it.
Adding a command to the KHM would also involve specifying:
* An internal name by which it is tracked. This would be like "UI.hotkey.map-zoom-in". The command would be looked up later by this name.
* A player-readable name stringtable entry. This would be like "HOTKEY_MAP_ZOOM_IN", which would be the name of a string in the stringtable that would be have associated translated text to describe the command to players, which might look like "Zoom in map".
* An (optional) default hotkey to bind to the command. This could be omitted to have no default hotkey bound to the command, or could be a HotKey object. This default would apply unless the player overrode the setting.
The signals would be stored within the HKM like so:
declare a few typedefs:
Code: Select all
typedef boost::signal<void()> SignalType;
typedef boost::shared_ptr<SignalType> SignalPointerType;
typedef std::map<std::string, SignalPointerType> SignalMapType;
and the HKM would have a map to store the signals:
Code: Select all
SignalMapType m_sig_map; // command signals, indexed by code-name
In HotKeyManager::AddCommand, the signal would be created and stored in this map. It has to be stored as a shared_ptr since boost::signal is noncopyable.
Code: Select all
m_sig_map[command_name] = SignalPointerType(new SignalType()); // add a new signal to the map
Then in HotKeyManager::GetCommandSignal, you'd look up the signal in the map, and return it, or throw if no such signal existed.
Code: Select all
// get a signal by name, ensuring such a signal exists.
SignalMapType::const_iterator it = m_sig_map.find(command_name);
if (it == sig_map.end())
throw std::runtime_error("attempted to get nonexistant signal");
SignalType& test_signal = *(it->second);
return test_signal;
An alternative to throwing would be to return a reference to a separate HotKeyManager class static signal that will never emit.
GetCommandSignal would be called in UI class initialization code, and would be used in a GG::Connect call, like any other signal.
For reference, this is very similar to how OptionsDB::OptionChangedSignal(const std::string& option_name) works, which returns a signal that is emitted whenever the indicated option is changed, or throws if not such option exists. A notable difference is that OptionsDB stores Options instead of shared_ptr<boost::signal<void()> >, which also gets around the issues of the boost::signal istelf being noncopyable.
HotKeyManager would also internally deal with all the issues of connecting keyboard accelerator signals to various command signals to which various hotkeys have been bound.
HotKey only needs to be something like:
Code: Select all
struct HotKey {
HotKey(...);
GG::Key key;
GG::Flags<GG::ModKey> mod_keys;
};
std::ostream& operator<<(std::ostream& os, const HotKey& hotkey);
std::istream& operator>>(std::istream& is, HotKey& hotkey);
since all the signals stuff will be handled within the HKM.
Also, when adding a command, the HKM should also register an option with the OptionsDB to store and retreive the HotKey to bind to the command. The default bound hotkey would come form the default keypress, if specified in AddCommand. In any case, the actual bound hotkey should be the one retreived from the OptionsDB. If this hasn't been changed by the user, it will be the default hotkey, but could also be something different.
Doing this this way avoid having to template over UI classes, and avoids issues of needing to track the lifetime of UI classes to be sure you're not dereferencing invalid pointers to objects that have been deleted, and avoids the need to manually track pointers to UI objects entirely, or the need for all hotkeyed commands to be defined through pointers to UI objects (which shouldn't necessarily be the case).