Radium Engine  1.5.0
KeyMappingManager.hpp
1 #pragma once
2 
3 #include <QXmlStreamWriter>
4 #include <QtGui/QKeyEvent>
5 #include <QtGui/QMouseEvent>
6 #include <QtXml/QtXml>
7 
8 #include <Gui/RaGui.hpp>
9 
10 #include <Core/Utils/Index.hpp>
11 #include <Core/Utils/Log.hpp>
12 #include <Core/Utils/Observable.hpp>
13 #include <Core/Utils/Singleton.hpp>
14 #include <Core/Utils/StdOptional.hpp>
15 
16 namespace Ra {
17 namespace Gui {
22 class RA_GUI_API KeyMappingManager : public Ra::Core::Utils::ObservableVoid
23 {
24  RA_SINGLETON_INTERFACE( KeyMappingManager );
25 
26  public:
29  {
30  public:
34  EventBinding() = default;
35 
40  EventBinding( Qt::MouseButtons buttons,
41  Qt::KeyboardModifiers modifiers,
42  int key,
43  bool wheel = false ) :
44  m_buttons { buttons }, m_modifiers { modifiers }, m_key { key }, m_wheel { wheel } {}
45 
49  explicit EventBinding( Qt::MouseButtons buttons,
50  Qt::KeyboardModifiers modifiers = Qt::NoModifier ) :
51  m_buttons { buttons }, m_modifiers { modifiers } {}
52 
56  explicit EventBinding( int key, Qt::KeyboardModifiers modifiers = Qt::NoModifier ) :
57  m_modifiers { modifiers }, m_key { key } {}
58 
62  explicit EventBinding( bool wheel, Qt::KeyboardModifiers modifiers = Qt::NoModifier ) :
63  m_modifiers { modifiers }, m_wheel { wheel } {}
64 
65  bool isMouseEvent() { return m_buttons != Qt::NoButton; }
66  bool isWheelEvent() { return m_wheel; }
67  bool isKeyEvent() { return !isMouseEvent() && !isWheelEvent(); }
68  bool operator<( const EventBinding& b ) const;
69 
70  // public data member, since there isn't any write access getter from KeyMappingManager
71  Qt::MouseButtons m_buttons { Qt::NoButton };
72  Qt::KeyboardModifiers m_modifiers { Qt::NoModifier };
73  // only one key
74  int m_key { -1 };
75  bool m_wheel { false };
76  };
77 
78  using KeyMappingAction = Ra::Core::Utils::Index;
79  using Context = Ra::Core::Utils::Index;
80 
83  void loadConfiguration( const std::string& filename = {} );
84 
88  bool saveConfiguration( const std::string& filename = {} );
89 
91  void reloadConfiguration();
92 
93  std::string getLoadedFilename() { return m_file->fileName().toStdString(); }
94 
101  KeyMappingAction getAction( const Context& context,
102  const Qt::MouseButtons& buttons,
103  const Qt::KeyboardModifiers& modifiers,
104  int key,
105  bool wheel = false );
106  KeyMappingAction
107  getAction( const Context& context, const QEvent* event, int key, bool wheel = false );
108  KeyMappingAction getAction( const Context& context, const EventBinding& binding );
109 
112  std::optional<EventBinding> getBinding( const Context& context, KeyMappingAction action );
113 
116  KeyMappingAction addAction( const Context& context, const std::string& actionName );
117 
120  KeyMappingAction
121  addAction( const Context& context, const EventBinding& binding, const std::string& actionName );
122 
126  void setActionBinding( const Context& context,
127  const EventBinding& binding,
128  const KeyMappingAction& action );
129 
136  Context addContext( const std::string& contextName );
137 
141  Context getContext( const std::string& contextName );
142 
148  KeyMappingAction getAction( const Context& context, const std::string& actionName );
149 
151  std::string getActionName( const Context& context, const KeyMappingAction& action );
152 
154  std::string getContextName( const Context& context );
155 
157  int addListener( Observable::Observer callback );
158 
161  void removeListener( int callbackId );
162 
164  std::string getHelpText();
165 
168  static std::string enumNamesFromMouseButtons( const Qt::MouseButtons& buttons );
169 
172  static std::string enumNamesFromKeyboardModifiers( const Qt::KeyboardModifiers& modifiers );
173 
177  static EventBinding createEventBindingFromStrings( const std::string& buttonsString = "",
178  const std::string& modifiersString = "",
179  const std::string& keyString = "",
180  const std::string& wheelString = "" );
181 
182  private:
183  KeyMappingManager();
184  ~KeyMappingManager();
185 
187  void saveNode( QXmlStreamWriter& stream, const QDomNode& domNode );
188  void saveKeymap( QXmlStreamWriter& stream );
189 
190  void loadConfigurationInternal( const QDomDocument& domDocument );
191  void loadConfigurationTagsInternal( QDomElement& node );
192  KeyMappingAction loadConfigurationMappingInternal( const std::string& context,
193  const std::string& keyString,
194  const std::string& modifiersString,
195  const std::string& buttonsString,
196  const std::string& wheelString,
197  const std::string& actionName );
198 
202  static Qt::KeyboardModifiers getQtModifiersValue( const std::string& modifierString );
203 
207  static Qt::MouseButtons getQtMouseButtonsValue( const std::string& buttonsString );
208  static int getKeyCode( const std::string& keyString );
209 
210  std::string m_defaultConfigFile;
211  QFile* m_file;
212 
213  using EventBindingMap = std::map<EventBinding, KeyMappingAction>;
214  using ContextNameMap = std::map<std::string, Context>;
215  using ActionNameMap = std::map<std::string, Ra::Core::Utils::Index>;
216 
217  ContextNameMap m_contextNameToIndex;
218  std::vector<ActionNameMap> m_actionNameToIndex;
219  std::vector<EventBindingMap> m_bindingToAction;
220 };
221 
238 template <typename T>
240 {
241  public:
242  static inline KeyMappingManager::Context getContext() { return m_keyMappingContext; }
243 
247  static inline void configureKeyMapping() { T::configureKeyMapping_impl(); }
248 
249  protected:
250  T& self() { return static_cast<T&>( *this ); }
251  static inline void setContext( const KeyMappingManager::Context& c ) {
252  m_keyMappingContext = c;
253  }
254 
255  private:
256  static KeyMappingManager::Context m_keyMappingContext;
257 };
258 
260 template <typename T>
261 KeyMappingManager::Context KeyMappingManageable<T>::m_keyMappingContext;
262 
270 {
271  public:
272  using Context = KeyMappingManager::Context;
273  using KeyMappingAction = KeyMappingManager::KeyMappingAction;
274  using Callback = std::function<void( QEvent* )>;
275 
279  inline explicit KeyMappingCallbackManager( Context context );
280 
284  inline void addEventCallback( KeyMappingAction action, Callback callback );
285 
291  addActionAndCallback( const std::string& actionName,
292  const KeyMappingManager::EventBinding& binding,
293  Callback callback );
294 
298  inline bool triggerEventCallback( QEvent* event, int key, bool wheel = false );
299 
303  inline bool triggerEventCallback( KeyMappingAction action, QEvent* event );
304 
305  private:
306  std::map<KeyMappingAction, Callback> m_keymappingCallbacks;
307  Context m_context;
308 };
309 
310 /******************************************************************************/
311 /* inlines ********************************************************************/
312 /******************************************************************************/
313 
314 inline bool KeyMappingManager::EventBinding::operator<( const EventBinding& b ) const {
315  return ( m_buttons < b.m_buttons ) ||
316  ( ( m_buttons == b.m_buttons ) && ( m_modifiers < b.m_modifiers ) ) ||
317  ( ( m_buttons == b.m_buttons ) && ( m_modifiers == b.m_modifiers ) &&
318  ( m_key < b.m_key ) ) ||
319  ( ( m_buttons == b.m_buttons ) && ( m_modifiers == b.m_modifiers ) &&
320  ( m_key == b.m_key ) && ( m_wheel < b.m_wheel ) );
321 }
322 
324  m_context { context } {}
325 
326 inline void KeyMappingCallbackManager::addEventCallback( KeyMappingAction action,
327  Callback callback ) {
328  m_keymappingCallbacks[action] = callback;
329 }
330 
332 KeyMappingCallbackManager::addActionAndCallback( const std::string& actionName,
333  const KeyMappingManager::EventBinding& binding,
334  Callback callback ) {
335 
336  auto mgr = KeyMappingManager::getInstance();
337  auto action = mgr->addAction( m_context, binding, actionName );
338  addEventCallback( action, callback );
339  return action;
340 }
341 
342 inline bool KeyMappingCallbackManager::triggerEventCallback( KeyMappingAction actionIndex,
343  QEvent* event ) {
344  auto itr = m_keymappingCallbacks.find( actionIndex );
345  if ( itr == m_keymappingCallbacks.end() ) return false;
346  itr->second( event );
347  return true;
348 }
349 
350 inline bool KeyMappingCallbackManager::triggerEventCallback( QEvent* event, int key, bool wheel ) {
351  auto mgr = KeyMappingManager::getInstance();
352  auto actionIndex = mgr->getAction( m_context, event, key, wheel );
353  return triggerEventCallback( actionIndex, event );
354 }
355 
356 } // namespace Gui
357 } // namespace Ra
std::function< void(Args...)> Observer
Observer functor type.
Definition: Observable.hpp:37
This class manage a collection of binding/callback associated with a context.
bool triggerEventCallback(QEvent *event, int key, bool wheel=false)
void addEventCallback(KeyMappingAction action, Callback callback)
KeyMappingManager::KeyMappingAction addActionAndCallback(const std::string &actionName, const KeyMappingManager::EventBinding &binding, Callback callback)
KeyMappingManageable decorator to use as CRTP.
Inner class to store event binding.
EventBinding(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, int key, bool wheel=false)
EventBinding(bool wheel, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
EventBinding(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
EventBinding(int key, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
An utility class used to map a (combination of) key / modifiers / mouse buttons to a specific action....
Ra::Core::Utils::Index KeyMappingAction
handle to an action
Ra::Core::Utils::Index Context
handle to a Context
Definition: Cage.cpp:3