NCBI C++ ToolKit
ui_command.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ui_command.cpp 42251 2019-01-22 13:56:07Z filippov $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Andrey Yazhuk
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 
34 
35 #include <wx/artprov.h>
36 #include <wx/accel.h>
37 #include <wx/menu.h>
38 #include <wx/frame.h>
39 #include <wx/toolbar.h>
40 #include <wx/aui/auibar.h>
41 
42 
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 /// CUICommand
48  string menu_label,
49  string name,
50  string icon_alias,
51  string hint,
52  string description,
53  string help_id,
54  wxItemKind kind)
55 : CUIObject(name, icon_alias, hint, description, help_id),
56  m_CmdID(cmd_id),
57  m_MenuLabel(menu_label),
58  m_Kind(kind)
59 {
60  _ASSERT( ! m_MenuLabel.empty() || m_Kind == wxITEM_SEPARATOR );
61 }
62 
63 
65 : CUIObject(cmd),
66  m_CmdID(cmd.m_CmdID),
67  m_MenuLabel(cmd.m_MenuLabel),
68  m_Kind(cmd.m_Kind)
69 {
70  _ASSERT( ! m_MenuLabel.empty());
71 
72  if(cmd.m_Accelerators.get()) {
73  // make a copy of the container
74  m_Accelerators.reset(new TAccelerators(*cmd.m_Accelerators.get()));
75  }
76 }
77 
78 
80 {
81 }
82 
83 
85 {
86  m_CmdID = cmd_id;
87 
88  TAccelerators* accels = m_Accelerators.get();
89  if(accels ) {
90  // update command id in accelerators
91  for( size_t i = 0; i < accels->size(); i++ ) {
92  wxAcceleratorEntry& entry = (*accels)[i];
93  entry.Set(entry.GetFlags(), entry.GetKeyCode(), cmd_id);
94  }
95  }
96 }
97 
98 
99 void CUICommand::AddAccelerator(int flags, int key_code)
100 {
101  if( ! m_Accelerators.get()) {
102  m_Accelerators.reset(new TAccelerators);
103  }
104  m_Accelerators->push_back(wxAcceleratorEntry(flags, key_code, m_CmdID));
105 }
106 
107 
109 {
110  return m_CmdID;
111 }
112 
113 
114 const string& CUICommand::GetMenuLabel() const
115 {
116  return m_MenuLabel;
117 }
118 
119 
121 {
122  return m_Accelerators.get();
123 }
124 
125 
126 wxMenuItem* CUICommand::AppendMenuItem( wxMenu& menu ) const
127 {
128  return AppendMenuItem( menu, m_Kind );
129 }
130 
131 
132 wxMenuItem* CUICommand::AppendMenuItem( wxMenu& menu, wxItemKind kind ) const
133 {
134  _ASSERT( ! m_MenuLabel.empty() );
135 
136  if( kind == wxITEM_RADIO ){
137  if( menu.GetMenuItemCount() == 0 ){
138  UseDefaultMarginWidth( menu );
139  }
140  }
141 
142  wxMenuItem* item =
143  wxMenuItem::New(&menu, m_CmdID, ToWxString(m_MenuLabel), ToWxString(m_Hint), kind);
144 
145  // If we do not set the first item as owner draw
146  // We get draw problems with mixed owner/system draw on MSWIN
147  // What happens on other platforms not checked
148  // plus
149  // Attempt to avoid bug in wxWidgets 2.9
150  // causing improper error log posts
151  // 'SetMenuItemInfo' failed with error 0x000005b0 (a menu item was not found.)
152 
153 #if wxUSE_OWNER_DRAWN
154  item->SetOwnerDrawn();
155 #endif
156 
157  if( ! m_IconAlias.empty() ){
158  wxBitmap image = wxArtProvider::GetBitmap( ToWxString(m_IconAlias) );
159  item->SetBitmap( image );
160  SetMenuItemMarginWidth( item, &image );
161  }
162 
163  menu.Append(item);
164 
165  return item;
166 }
167 
168 
169 ///////////////////////////////////////////////////////////////////////////////
170 /// CUICommandRegistry
171 
173 
174 static const int kDefHashSize = 111;
175 
177 {
178  return sm_TheRegistry;
179 }
180 
181 
183 : m_NextID(start_id),
184  m_IDToCommand(kDefHashSize)
185 {
186 }
187 
188 
190 {
192  delete it->second;
193  }
194  m_IDToCommand.clear();
195 }
196 
197 
199 {
200  _ASSERT(cmd);
201  if(cmd) {
202  TCmdID cmd_id = cmd->GetCmdID();
203 
204  if(cmd_id == eCmdInvalid) {
205  // need to assign id
206  cmd->SetCmdID(m_NextID);
207  ++m_NextID;
208  } else {
209  _ASSERT(cmd_id > 0 && cmd_id < 0xFFFF); // wxWidgets requirement
210 
211  TIDToCommand::const_iterator it = m_IDToCommand.find(cmd_id);
212  bool exists = (it != m_IDToCommand.end());
213  if(exists) {
214  ERR_POST("CUICommandRegistry::RegisterCommand() - attempty to register command " <<
215  cmd->GetLabel() << " with id" << cmd_id << " that is already in use - ");
216  ERR_POST("\n\tpreviously registered as " << it->second->GetMenuLabel());
217  _ASSERT(false);
218  delete cmd;
219  return eCmdInvalid;
220  }
221  }
222  m_IDToCommand[cmd_id] = cmd;
223 
224  // register accelerators
225  const CUICommand::TAccelerators* accels = cmd->GetAccelerators();
226  if(accels) {
227  ITERATE(CUICommand::TAccelerators, it, *accels) {
228  AddAccelerator(*it);
229  }
230  }
231  return cmd_id;
232  }
233 
234  return eCmdInvalid;
235 }
236 
237 
239  string menu_label,
240  string label,
241  string icon_alias,
242  string hint,
243  string description,
244  string help_id,
245  wxItemKind kind)
246 {
247  CUICommand* cmd = new CUICommand(cmd_id, menu_label, label, icon_alias,
248  hint, description, help_id, kind);
249  int id = RegisterCommand(cmd);
250  if(id == eCmdInvalid) {
251  delete cmd; // not registered - delete command
252  }
253  return id;
254 }
255 
256 
258 {
259  TIDToCommand::const_iterator it = m_IDToCommand.find( cmd_id );
260  return (it == m_IDToCommand.end()) ? NULL : it->second;
261 }
262 
264 {
266  if( it->second->GetName() == name ){
267  return it->second;
268  }
269  }
270 
271  return NULL;
272 }
273 
274 void CUICommandRegistry::AddAccelerator(const wxAcceleratorEntry& entry)
275 {
276  // accumulate entries in m_AccelEntries
277  m_AccelEntries.push_back(entry);
278 }
279 
280 
282 {
283  if(frame) {
284  // disconnect Frame from m_AccelEntries
285  frame->SetAcceleratorTable(wxNullAcceleratorTable);
286 
287  int n = (int)m_AccelEntries.size();
288  wxAcceleratorEntry* entries = &*m_AccelEntries.begin();
289 
290  wxAcceleratorTable accel_table( n, entries );
291 
292  frame->SetAcceleratorTable( accel_table ); // apply the new table
293  } else {
294  _ASSERT(false);
295  ERR_POST("CUICommandRegistry::ApplyAccelerators() - frame = NULL, cannot apply accelerators");
296  }
297 }
298 
299 
300 wxMenuItem* CUICommandRegistry::AppendMenuItem( wxMenu& menu, TCmdID cmd_id ) const
301 {
302  // -1 == wxITEM_SEPARATOR is used here as default value
303  // (see below).
304  return AppendMenuItem( menu, cmd_id, (wxItemKind)-1 );
305 }
306 
307 
308 wxMenuItem* CUICommandRegistry::AppendMenuItem( wxMenu& menu, TCmdID cmd_id, wxItemKind kind ) const
309 {
310  if( cmd_id == wxID_SEPARATOR ){
311  return menu.AppendSeparator();
312 
313  } else {
314  const CUICommand* cmd = FindCommandByID( cmd_id );
315  if( cmd ){
316  if( kind == -1 ){ // wxITEM_SEPARATOR
317  return cmd->AppendMenuItem( menu );
318  } else {
319  return cmd->AppendMenuItem( menu, kind );
320  }
321  } else {
322  ERR_POST("CUICommandRegistry::AppendMenuItem() cannot find command " << cmd_id);
323  _ASSERT(false);
324  return NULL;
325  }
326  }
327 }
328 
329 
330 void CUICommandRegistry::AppendMenuItems(wxMenu& menu, const TCmdID* cmd_ids, int count) const
331 {
332  for( int i = 0; i < count; i++ ) {
333  TCmdID cmd_id = cmd_ids[i];
334  AppendMenuItem(menu, cmd_id);
335  }
336 }
337 
338 
339 void CUICommandRegistry::AppendMenuItems(wxMenu& menu, const vector<TCmdID> cmd_ids) const
340 {
341  for( size_t i = 0; i < cmd_ids.size(); i++ ) {
342  TCmdID cmd_id = cmd_ids[i];
343  AppendMenuItem(menu, cmd_id);
344  }
345 }
346 
347 ////////////////////////////////////////////////////////////////////////////////
348 /// creates hierarchy of wxMenuItem objects from the array of SwxMenuItemRec descriptors
350 {
351  if( !items ) return NULL;
352 
353  bool insideNcbi = RunningInsideNCBI();
354 
355  auto visF = [insideNcbi](const SwxMenuItemRec* item)->bool
356  { return ((insideNcbi && item->IsInternal()) || (!insideNcbi && item->IsExternal()) || item->IsBoth()); };
357 
358  typedef pair<wxMenu*, wxString> TPair;
359 
360  vector<TPair> path; //
361  const SwxMenuItemRec* p_rec = items;
362 
363  while( p_rec ){
364  if( p_rec->IsSubMenu() ){
365  // create submenu and add to the path
366  wxString s = ToWxString(p_rec->m_Label);
367  if (path.empty()) {
368  path.push_back(TPair(new wxMenu, s));
369  }
370  else {
371  wxMenu* submenu = path.back().first;
372  if (submenu && visF(p_rec))
373  path.push_back(TPair(new wxMenu, s));
374  else
375  path.push_back(TPair(nullptr, s));
376  }
377 
378  } else if( p_rec->IsSubMenuEnd() ){
379  // end current Submenu and eject it from path
380  TPair pair = path.back();
381  path.pop_back(); // eject
382 
383  if (pair.first) {
384  wxMenu* submenu = path.back().first;
385  submenu->Append(wxID_ANY, pair.second, pair.first);
386  }
387 
388  _ASSERT( !path.empty() );
389 
390  } else if( p_rec->IsMenuEnd() ){
391  // the last menu - return
392  TPair pair = path.back();
393  path.pop_back();
394 
395  _ASSERT( path.empty() ); // all submenus were closed
396 
397  return pair.first;
398 
399  } else if( p_rec->m_Type == SwxMenuItemRec::eSeparator ){
400  // add separator
401  wxMenu* submenu = path.back().first;
402  if (submenu && visF(p_rec)) {
403  wxMenuItem* item =
404  wxMenuItem::New(submenu, wxID_SEPARATOR, ToWxString(p_rec->m_Label));
405  // If we do not set the fisrt item as owner draw
406  // We get draw problems with mixed owner/system draw on MSWIN
407  // What happens on other platforms not checked
408 #if wxUSE_OWNER_DRAWN
409  item->SetOwnerDrawn();
410 #endif
411  submenu->Append(item);
412  }
413  } else if( p_rec->m_Type == SwxMenuItemRec::eDefaultItem ){
414  // add command item
415  wxMenu* submenu = path.back().first;
416  if (submenu && visF(p_rec))
417  AppendMenuItem( *submenu, p_rec->m_CommandID );
418 
419  } else if( p_rec->m_Type == SwxMenuItemRec::eNormalItem ){
420  // add command item
421  wxMenu* submenu = path.back().first;
422  if (submenu && visF(p_rec))
423  AppendMenuItem(*submenu, p_rec->m_CommandID, wxITEM_NORMAL);
424 
425  } else if( p_rec->m_Type == SwxMenuItemRec::eCheckItem ){
426  // add command item
427  wxMenu* submenu = path.back().first;
428  if (submenu && visF(p_rec))
429  AppendMenuItem(*submenu, p_rec->m_CommandID, wxITEM_CHECK);
430 
431  } else if( p_rec->m_Type == SwxMenuItemRec::eRadioItem ){
432  // add command item
433  wxMenu* submenu = path.back().first;
434  if (submenu && visF(p_rec))
435  AppendMenuItem(*submenu, p_rec->m_CommandID, wxITEM_RADIO);
436 
437  } else {
438  // unexpected
439  _ASSERT(false);
440  }
441  p_rec++;
442  }
443 
444  return NULL;
445 }
446 
447 
448 void CUICommandRegistry::AppendTool(wxToolBar& tool_bar, TCmdID cmd_id)
449 {
450  TIDToCommand::iterator it = m_IDToCommand.find(cmd_id);
451  if(it != m_IDToCommand.end()) {
452  const CUICommand* cmd = it->second;
453 
454  wxBitmap image;
455  const string& alias = cmd->GetIconAlias();
456  if( ! alias.empty()) {
457  image = wxArtProvider::GetBitmap(ToWxString(alias));
458  }
459  tool_bar.AddTool(cmd->GetCmdID(),
460  wxT(""),
461  image,
462  ToWxString(cmd->GetHint()));
463 
464  const string& descr = cmd->GetDescription();
465  if( ! descr.empty()) {
466  tool_bar.SetToolLongHelp(cmd_id, ToWxString(descr));
467  }
468  } else {
469  ERR_POST("CUICommandRegistry::AppendTool() - command with id " <<
470  cmd_id << " is not registered.");
471  _ASSERT(false);
472  }
473 }
474 
475 void CUICommandRegistry::AppendTool(wxAuiToolBar& tool_bar, TCmdID cmd_id)
476 {
477  TIDToCommand::iterator it = m_IDToCommand.find(cmd_id);
478  if(it != m_IDToCommand.end()) {
479  const CUICommand* cmd = it->second;
480 
481  wxBitmap image;
482  const string& alias = cmd->GetIconAlias();
483  if( ! alias.empty()) {
484  image = wxArtProvider::GetBitmap(ToWxString(alias));
485  }
486  tool_bar.AddTool(cmd->GetCmdID(),
487  wxT(""),
488  image,
489  ToWxString(cmd->GetHint()));
490 
491  const string& descr = cmd->GetDescription();
492  if( ! descr.empty()) {
493  tool_bar.SetToolLongHelp(cmd_id, ToWxString(descr));
494  }
495  } else {
496  ERR_POST("CUICommandRegistry::AppendTool() - command with id " <<
497  cmd_id << " is not registered.");
498  _ASSERT(false);
499  }
500 }
501 
502 
503 
CUICommandRegistry is a centralized registry where all application commands should be registered.
Definition: ui_command.hpp:146
static CUICommandRegistry & GetInstance()
the main instance associated with the application
Definition: ui_command.cpp:176
wxMenu * CreateMenu(const SwxMenuItemRec *items)
create a menu from a static definition (see WX_*_MENU macros)
Definition: ui_command.cpp:349
void AppendTool(wxToolBar &tool_bar, TCmdID cmd_id)
Definition: ui_command.cpp:448
int RegisterCommand(CUICommand *cmd)
assumes ownership of the given object returns a command id (useful when registry is used for auto id ...
Definition: ui_command.cpp:198
CUICommandRegistry(TCmdID start_id)
Definition: ui_command.cpp:182
std::unordered_map< int, CUICommand * > TIDToCommand
Definition: ui_command.hpp:200
const CUICommand * FindCommandByID(TCmdID cmd_id) const
returns CUICommand object or NULL
Definition: ui_command.cpp:257
TIDToCommand m_IDToCommand
Definition: ui_command.hpp:205
virtual ~CUICommandRegistry()
Definition: ui_command.cpp:189
void ApplyAccelerators(wxWindow *frame)
apply accumulated accelerators to the specifed frame
Definition: ui_command.cpp:281
void AddAccelerator(const wxAcceleratorEntry &entry)
Definition: ui_command.cpp:274
const CUICommand * FindCommandByName(string name) const
It is expensive function so use it wisely.
Definition: ui_command.cpp:263
static CUICommandRegistry sm_TheRegistry
CUICommandRegistry.
Definition: ui_command.hpp:202
void AppendMenuItems(wxMenu &menu, const TCmdID *cmd_ids, int count) const
Definition: ui_command.cpp:330
vector< wxAcceleratorEntry > m_AccelEntries
Definition: ui_command.hpp:208
wxMenuItem * AppendMenuItem(wxMenu &menu, TCmdID cmd_id) const
Definition: ui_command.cpp:300
CUICommand.
Definition: ui_command.hpp:79
TCmdID m_CmdID
Definition: ui_command.hpp:115
string m_MenuLabel
Definition: ui_command.hpp:116
const TAccelerators * GetAccelerators() const
Definition: ui_command.cpp:120
const string & GetMenuLabel() const
Definition: ui_command.cpp:114
unique_ptr< TAccelerators > m_Accelerators
Definition: ui_command.hpp:120
wxMenuItem * AppendMenuItem(wxMenu &menu) const
Definition: ui_command.cpp:126
CUICommand(TCmdID cmd_id, string menu_label, string name, string icon_alias, string hint=kEmptyStr, string description=kEmptyStr, string help_id=kEmptyStr, wxItemKind kind=wxITEM_NORMAL)
CUICommand.
Definition: ui_command.cpp:47
void SetCmdID(TCmdID cmd_id)
the class inherits set/get methods from CUIObject
Definition: ui_command.cpp:84
vector< wxAcceleratorEntry > TAccelerators
a collection of wxWidget-style accelerator definitions
Definition: ui_command.hpp:82
void AddAccelerator(int flags, int key_code)
Definition: ui_command.cpp:99
int GetCmdID() const
Definition: ui_command.cpp:108
wxItemKind m_Kind
Definition: ui_command.hpp:117
CUIObject - default mix-in implementation of IUIObject.
Definition: ui_object.hpp:81
static uch flags
SStaticPair< const char *, const char * > TPair
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define NULL
Definition: ncbistd.hpp:225
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
string m_Hint
Definition: ui_object.hpp:116
string m_IconAlias
Definition: ui_object.hpp:115
int TCmdID
@ eCmdInvalid
marks menu end in array initializers
Definition: command.hpp:64
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static const char label[]
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
int i
yy_size_t n
#define wxT(x)
Definition: muParser.cpp:41
static static static wxID_ANY
Template structure SStaticPair is simlified replacement of STL pair<> Main reason of introducing this...
Definition: static_set.hpp:60
first_type first
Definition: static_set.hpp:64
second_type second
Definition: static_set.hpp:65
TCmdID m_CommandID
Definition: ui_command.hpp:230
bool IsMenuEnd() const
Definition: ui_command.hpp:242
const char * m_Label
Definition: ui_command.hpp:229
bool IsSubMenu() const
Definition: ui_command.hpp:234
bool IsSubMenuEnd() const
Definition: ui_command.hpp:238
#define _ASSERT
static const int kDefHashSize
Definition: ui_command.cpp:174
static wxAcceleratorEntry entries[3]
void SetMenuItemMarginWidth(wxMenuItem *item, wxBitmap *bmp)
Set margin width for menu item.
Definition: wx_utils.cpp:709
void UseDefaultMarginWidth(wxMenu &menu)
Using default menu item margin width.
Definition: wx_utils.cpp:693
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
bool RunningInsideNCBI()
Definition: wx_utils.cpp:1335
Modified on Sun Apr 21 03:43:29 2024 by modify_doxy.py rev. 669887