All Classes Functions Typedefs
MFDButtonPage.hpp
1 // ==============================================================
2 // ORBITER AUX LIBRARY: Multiple Buttons Pages
3 // http://sf.net/projects/enjomitchsorbit
4 // Part of the ORBITER SDK
5 //
6 // Copyright (C) 2012 Szymon "Enjo" Ender
7 //
8 // All rights reserved
9 //
10 // Multiple Buttons Pages is free software: you can redistribute it
11 // and/or modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation, either version
13 // 3 of the License, or (at your option) any later version.
14 //
15 // Multiple Buttons Pages is distributed in the hope that it will
16 // be useful, but WITHOUT ANY WARRANTY; without even the implied
17 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 // See the GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with Multiple Vessels Support. If not, see
22 // <http://www.gnu.org/licenses/>.
23 // ==============================================================
24 
25 #ifndef MFDButtonPage_H
26 #define MFDButtonPage_H
27 
28 #include <OrbiterSDK.h>
29 #include <map>
30 #include <vector>
31 
32 namespace EnjoLib
33 {
34 namespace MFDGoodies
35 {
37 
42 template <class MFDClass>
44 {
45  public:
47  MFDButtonPage();
49  virtual ~MFDButtonPage();
50 
52 
71  void SwitchPage( MFDClass * mfdInstance ) const;
72 
74 
85  void SelectPage( MFDClass * mfdInstance, int pageIndex ) const;
86 
88 
100  bool ConsumeButton( MFDClass * mfdInstance, int button, int event ) const;
101 
103 
116  bool ConsumeKeyBuffered( MFDClass * mfdInstance, DWORD key ) const;
117 
119 
133  bool ConsumeKeyImmediate( MFDClass * mfdInstance, char * kstate ) const;
134 
136 
146  int ButtonMenu (const MFDBUTTONMENU **menu) const;
147 
149 
159  char * ButtonLabel (int button) const;
160 
161  protected:
163 
167  virtual bool SearchForKeysInOtherPages() const = 0;
168 
170  typedef void (MFDClass::* MFDFunctionPtr)(void);
171 
173 
192  void RegisterFunction( const std::string & label, DWORD key,
193  MFDFunctionPtr funLClick, MFDFunctionPtr funRClick = NULL );
194 
196 
204  void RegisterFunctionCont( const std::string & label, DWORD key,
205  MFDFunctionPtr funLClick, MFDFunctionPtr funRClick = NULL );
206 
208 
223  void RegisterPage( const MFDBUTTONMENU * menu, int size );
224 
225  private:
226 
228  struct Page
229  {
230  const MFDBUTTONMENU * m_menu;
231  int m_menuSize;
232  std::vector<std::string> m_labels;
233  std::vector<bool> m_continuousClick;
234  std::vector<MFDFunctionPtr> m_buttonsLeftClick;
235  std::vector<MFDFunctionPtr> m_buttonsRightClick;
236  std::map<DWORD, MFDFunctionPtr> m_keys;
237  std::map<DWORD, bool> m_continuousKey;
238  };
239 
240  bool PressKey( MFDClass * mfdInstance, DWORD key ) const;
241  void RegisterFuncPriv( bool continuous, const std::string & label, DWORD key,
242  MFDFunctionPtr funLClick, MFDFunctionPtr funRClick);
243 
244  std::vector<Page> m_pages;
245  mutable size_t m_i;
246 };
247 
248 // Public:
249 template <class MFDClass>
251 : m_i(0)
252 {
253 }
254 
255 template <class MFDClass>
257 
258 template <class MFDClass>
259 void MFDButtonPage<MFDClass>::SwitchPage( MFDClass * mfdInstance ) const
260 {
261  m_i = (++m_i) % m_pages.size(); // increment index, but not beyond the size
262  mfdInstance->InvalidateButtons(); // redraw buttons
263 }
264 
265 template <class MFDClass>
266 void MFDButtonPage<MFDClass>::SelectPage( MFDClass * mfdInstance, int pageIndex ) const
267 {
268  if (pageIndex >= 0 && pageIndex < (int)m_pages.size())
269  {
270  m_i = pageIndex;
271  mfdInstance->InvalidateButtons(); // redraw buttons
272  }
273  else
274  sprintf_s(oapiDebugString(), 512, "MFDButtonPage::SwitchPage():"
275  " Page index %d is beyond pages size %d!", pageIndex, m_pages.size());
276 }
277 
278 template <class MFDClass>
279 bool MFDButtonPage<MFDClass>::ConsumeButton( MFDClass * mfdInstance, int button, int event ) const
280 {
281  if ( button >= (int)m_pages.at(m_i).m_buttonsLeftClick.size())
282  return false;
283 
284  if (event & PANEL_MOUSE_LBDOWN ||
285  (event & PANEL_MOUSE_LBPRESSED && m_pages.at(m_i).m_continuousClick[button]) )
286  { // Left mouse button just clicked
287  (mfdInstance->*(m_pages.at(m_i).m_buttonsLeftClick[button]))(); // Call the function
288  return true;
289  }
290  else if ( event & PANEL_MOUSE_RBDOWN ||
291  ( event & PANEL_MOUSE_RBPRESSED && m_pages.at(m_i).m_continuousClick[button] ) )
292  {
293  MFDFunctionPtr fun = m_pages.at(m_i).m_buttonsRightClick[button];
294  if ( fun ) // If function was registered at all
295  {
296  (mfdInstance->*(fun))(); // Call the function
297  return true;
298  }
299  }
300  return false;
301 }
302 
303 template <class MFDClass>
304 bool MFDButtonPage<MFDClass>::ConsumeKeyBuffered( MFDClass * mfdInstance, DWORD key ) const
305 {
306  // First search for the key on this page
307  std::map<DWORD, bool>::const_iterator it = m_pages.at(m_i).m_continuousKey.find(key);
308  if (it != m_pages.at(m_i).m_continuousKey.end() && ! it->second )
309  return PressKey(mfdInstance, key);
310 
311  if ( SearchForKeysInOtherPages() )
312  {
313  // Then, if required, search in other pages
314  for ( size_t j = 0; j < m_pages.size(); ++j )
315  {
316  if ( m_i == j )
317  continue; // The current page was already queried
318  std::map<DWORD, bool>::const_iterator it = m_pages.at(j).m_continuousKey.find(key);
319  if (it != m_pages.at(j).m_continuousKey.end() && ! it->second )
320  return PressKey(mfdInstance, key);
321  }
322  }
323  return false;
324 }
325 
326 template <class MFDClass>
327 bool MFDButtonPage<MFDClass>::ConsumeKeyImmediate( MFDClass * mfdInstance, char * kstate ) const
328 {
329  for (std::map<DWORD, bool>::const_iterator it = m_pages.at(m_i).m_continuousKey.begin();
330  it != m_pages.at(m_i).m_continuousKey.end(); ++it)
331  {
332  if ( KEYDOWN(kstate, it->first ) && it->second )
333  return PressKey(mfdInstance, it->first);
334  }
335 
336  if ( SearchForKeysInOtherPages() )
337  {
338  for ( size_t j = 0; j < m_pages.size(); ++j )
339  {
340  if ( m_i == j )
341  continue; // The current page was already queried
342 
343  for (std::map<DWORD, bool>::const_iterator it = m_pages.at(j).m_continuousKey.begin();
344  it != m_pages.at(j).m_continuousKey.end(); ++it)
345  {
346  if ( KEYDOWN(kstate, it->first ) && it->second )
347  return PressKey(mfdInstance, it->first);
348  }
349  }
350  }
351  return false;
352 }
353 
354 template <class MFDClass>
355 int MFDButtonPage<MFDClass>::ButtonMenu (const MFDBUTTONMENU **menu) const
356 {
357  if ( menu ) *menu = m_pages.at(m_i).m_menu; // pass the static menu to the parameric pointer
358  return m_pages.at(m_i).m_menuSize;
359 }
360 
361 template <class MFDClass>
363 {
364  return (bt < (int)m_pages.at(m_i).m_labels.size() ?
365  (char*)m_pages.at(m_i).m_labels[bt].c_str() : NULL);
366 }
367 
368 // Protected:
369 template <class MFDClass>
370 void MFDButtonPage<MFDClass>::RegisterFunction( const std::string & label, DWORD key,
371  MFDFunctionPtr funLClick, MFDFunctionPtr funRClick )
372 {
373  RegisterFuncPriv( false, label, key, funLClick, funRClick);
374 }
375 
376 template <class MFDClass>
377 void MFDButtonPage<MFDClass>::RegisterFunctionCont( const std::string & label, DWORD key,
378  MFDFunctionPtr funLClick, MFDFunctionPtr funRClick )
379 {
380  RegisterFuncPriv( true, label, key, funLClick, funRClick);
381 }
382 
383 template <class MFDClass>
384 void MFDButtonPage<MFDClass>::RegisterPage( const MFDBUTTONMENU * menu, int size )
385 {
386  Page p;
387  p.m_menu = menu;
388  p.m_menuSize = size;
389  m_pages.push_back(p);
390 }
391 
392 // Private:
393 template <class MFDClass>
394 bool MFDButtonPage<MFDClass>::PressKey( MFDClass * mfdInstance, DWORD key ) const
395 {
396  // First search for the key on this page
397  std::map<DWORD, MFDFunctionPtr>::const_iterator it = m_pages.at(m_i).m_keys.find(key);
398  if (it != m_pages.at(m_i).m_keys.end() )
399  {
400  (mfdInstance->*(it->second))(); // Call the function
401  return true;
402  }
403 
404  if ( SearchForKeysInOtherPages() )
405  {
406  // Then, if required, search in other pages
407  for ( size_t j = 0; j < m_pages.size(); ++j )
408  {
409  if ( m_i == j )
410  continue; // The current page was already queried
411  std::map<DWORD, MFDFunctionPtr>::const_iterator it = m_pages.at(j).m_keys.find(key);
412  if (it != m_pages.at(j).m_keys.end() )
413  {
414  (mfdInstance->*(it->second))(); // Call the function
415  return true;
416  }
417  }
418  }
419  return false;
420 }
421 
422 template <class MFDClass>
423 void MFDButtonPage<MFDClass>::RegisterFuncPriv( bool continuous, const std::string & label, DWORD key,
424  MFDFunctionPtr funLClick, MFDFunctionPtr funRClick)
425 {
426  if ( m_pages.empty() )
427  {
428  sprintf_s(oapiDebugString(), 512, "MFDButtonPage::RegisterFuncPriv(): No pages registered yet!");
429  return;
430  }
431  Page & p = m_pages.back();
432  p.m_labels.push_back(label);
433  p.m_continuousClick.push_back(continuous);
434  p.m_buttonsLeftClick.push_back(funLClick);
435  p.m_buttonsRightClick.push_back(funRClick);
436  p.m_keys[key] = funLClick;
437  p.m_continuousKey[key] = continuous;
438 }
439 }
440 }
441 
442 #endif // MFDButtonPage_H