wxMenuItem::GetLabelFromText() added/documented, bug in wxMenu::FindItem() fixed
[wxWidgets.git] / src / motif / menuitem.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: menuitem.cpp
3 // Purpose: wxMenuItem implementation
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 #ifdef __GNUG__
17 #pragma implementation "menuitem.h"
18 #endif
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 #include "wx/menu.h"
25 #include "wx/menuitem.h"
26 #include "wx/utils.h"
27 #include "wx/frame.h"
28
29 #ifdef __VMS__
30 #pragma message disable nosimpint
31 #endif
32 #include <Xm/Label.h>
33 #include <Xm/LabelG.h>
34 #include <Xm/CascadeBG.h>
35 #include <Xm/CascadeB.h>
36 #include <Xm/SeparatoG.h>
37 #include <Xm/PushBG.h>
38 #include <Xm/ToggleB.h>
39 #include <Xm/ToggleBG.h>
40 #include <Xm/RowColumn.h>
41 #ifdef __VMS__
42 #pragma message enable nosimpint
43 #endif
44
45 #include "wx/motif/private.h"
46
47 // ----------------------------------------------------------------------------
48 // functions prototypes
49 // ----------------------------------------------------------------------------
50
51 static void wxMenuItemCallback(Widget w, XtPointer clientData, XtPointer ptr);
52 static void wxMenuItemArmCallback(Widget w, XtPointer clientData, XtPointer ptr);
53 static void wxMenuItemDisarmCallback(Widget w, XtPointer clientData, XtPointer ptr);
54
55 // ============================================================================
56 // implementation
57 // ============================================================================
58
59 // ----------------------------------------------------------------------------
60 // dynamic classes implementation
61 // ----------------------------------------------------------------------------
62
63 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
64
65 // ----------------------------------------------------------------------------
66 // wxMenuItem
67 // ----------------------------------------------------------------------------
68
69 // ctor & dtor
70 // -----------
71
72 wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id,
73 const wxString& strName, const wxString& strHelp,
74 bool bCheckable,
75 wxMenu *pSubMenu)
76 {
77 wxASSERT_MSG( pParentMenu != NULL, wxT("menuitem should have a menu") );
78
79 // common init
80 m_parentMenu = pParentMenu;
81 m_subMenu = pSubMenu;
82 m_id = id;
83 m_isEnabled = TRUE;
84 m_isChecked = FALSE;
85 m_help = strHelp;
86 m_isCheckable = bCheckable;
87 m_text = strName;
88
89 // Motif-specific
90 m_menuBar = NULL;
91 m_buttonWidget = (WXWidget) NULL;
92 m_topMenu = NULL;
93 }
94
95 wxMenuItem::~wxMenuItem()
96 {
97 }
98
99 // misc
100 // ----
101
102 // delete the sub menu
103 void wxMenuItem::DeleteSubMenu()
104 {
105 wxASSERT( m_subMenu != NULL );
106
107 delete m_subMenu;
108 m_subMenu = NULL;
109 }
110
111 // change item state
112 // -----------------
113
114 void wxMenuItem::Enable(bool bDoEnable)
115 {
116 if ( m_isEnabled != bDoEnable )
117 {
118 if ( !IsSubMenu() )
119 {
120 // normal menu item
121 if (m_buttonWidget)
122 XtSetSensitive( (Widget) m_buttonWidget, (Boolean) bDoEnable);
123 }
124 else // submenu
125 {
126 // Maybe we should apply this to all items in the submenu?
127 // Or perhaps it works anyway.
128 if (m_buttonWidget)
129 XtSetSensitive( (Widget) m_buttonWidget, (Boolean) bDoEnable);
130 }
131
132 wxMenuItemBase::Enable(bDoEnable);
133 }
134 }
135
136 void wxMenuItem::Check(bool bDoCheck)
137 {
138 wxCHECK_RET( IsCheckable(), "only checkable items may be checked" );
139
140 if ( m_isChecked != bDoCheck )
141 {
142 if ( m_buttonWidget )
143 {
144 wxASSERT_MSG( XtIsSubclass((Widget)m_buttonWidget,
145 xmToggleButtonGadgetClass),
146 wxT("checkable menu item must be a toggle button") );
147
148 XtVaSetValues((Widget)m_buttonWidget,
149 XmNset, (Boolean)bDoCheck,
150 NULL);
151 }
152
153 wxMenuItemBase::Check(bDoCheck);
154 }
155 }
156
157 /* static */
158 wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
159 {
160 return wxStripMenuCodes(m_text);
161 }
162
163 // ----------------------------------------------------------------------------
164 // wxMenuItemBase
165 // ----------------------------------------------------------------------------
166
167 wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu,
168 int id,
169 const wxString& name,
170 const wxString& help,
171 bool isCheckable,
172 wxMenu *subMenu)
173 {
174 return new wxMenuItem(parentMenu, id, name, help, isCheckable, subMenu);
175 }
176
177 // ----------------------------------------------------------------------------
178 // Motif-specific
179 // ----------------------------------------------------------------------------
180
181 void wxMenuItem::CreateItem (WXWidget menu, wxMenuBar * menuBar, wxMenu * topMenu)
182 {
183 m_menuBar = menuBar;
184 m_topMenu = topMenu;
185
186 if (GetId() == -2)
187 {
188 // Id=-2 identifies a Title item.
189 m_buttonWidget = (WXWidget) XtVaCreateManagedWidget
190 (wxStripMenuCodes(m_text),
191 xmLabelGadgetClass, (Widget) menu, NULL);
192 }
193 else if ((!m_text.IsNull() && m_text != "") && (!m_subMenu))
194 {
195 wxString strName = wxStripMenuCodes(m_text);
196 if (IsCheckable())
197 {
198 m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (strName,
199 xmToggleButtonGadgetClass, (Widget) menu,
200 NULL);
201 XtVaSetValues ((Widget) m_buttonWidget, XmNset, (Boolean) IsChecked(), NULL);
202 }
203 else
204 m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (strName,
205 xmPushButtonGadgetClass, (Widget) menu,
206 NULL);
207 char mnem = wxFindMnemonic (m_text);
208 if (mnem != 0)
209 XtVaSetValues ((Widget) m_buttonWidget, XmNmnemonic, mnem, NULL);
210
211 //// TODO: proper accelerator treatment. What does wxFindAccelerator
212 //// look for?
213 strName = m_text;
214 char *accel = wxFindAccelerator (strName);
215 if (accel)
216 XtVaSetValues ((Widget) m_buttonWidget, XmNaccelerator, accel, NULL);
217
218 // TODO: What does this do?
219 XmString accel_str = wxFindAcceleratorText (strName);
220 if (accel_str)
221 {
222 XtVaSetValues ((Widget) m_buttonWidget, XmNacceleratorText, accel_str, NULL);
223 XmStringFree (accel_str);
224 }
225
226 if (IsCheckable())
227 XtAddCallback ((Widget) m_buttonWidget,
228 XmNvalueChangedCallback,
229 (XtCallbackProc) wxMenuItemCallback,
230 (XtPointer) this);
231 else
232 XtAddCallback ((Widget) m_buttonWidget,
233 XmNactivateCallback,
234 (XtCallbackProc) wxMenuItemCallback,
235 (XtPointer) this);
236 XtAddCallback ((Widget) m_buttonWidget,
237 XmNarmCallback,
238 (XtCallbackProc) wxMenuItemArmCallback,
239 (XtPointer) this);
240 XtAddCallback ((Widget) m_buttonWidget,
241 XmNdisarmCallback,
242 (XtCallbackProc) wxMenuItemDisarmCallback,
243 (XtPointer) this);
244 }
245 else if (GetId() == -1)
246 {
247 m_buttonWidget = (WXWidget) XtVaCreateManagedWidget ("separator",
248 xmSeparatorGadgetClass, (Widget) menu, NULL);
249 }
250 else if (m_subMenu)
251 {
252 m_buttonWidget = m_subMenu->CreateMenu (menuBar, menu, topMenu, m_text, TRUE);
253 m_subMenu->SetButtonWidget(m_buttonWidget);
254 XtAddCallback ((Widget) m_buttonWidget,
255 XmNcascadingCallback,
256 (XtCallbackProc) wxMenuItemArmCallback,
257 (XtPointer) this);
258 }
259 if (m_buttonWidget)
260 XtSetSensitive ((Widget) m_buttonWidget, (Boolean) IsEnabled());
261 }
262
263 void wxMenuItem::DestroyItem(bool full)
264 {
265 if (GetId() == -2)
266 {
267 ; // Nothing
268
269 }
270 else if ((!m_text.IsNull() && (m_text != "")) && !m_subMenu)
271 {
272 if (m_buttonWidget)
273 {
274 if (IsCheckable())
275 XtRemoveCallback ((Widget) m_buttonWidget, XmNvalueChangedCallback,
276 wxMenuItemCallback, (XtPointer) this);
277 else
278 XtRemoveCallback ((Widget) m_buttonWidget, XmNactivateCallback,
279 wxMenuItemCallback, (XtPointer) this);
280 XtRemoveCallback ((Widget) m_buttonWidget, XmNarmCallback,
281 wxMenuItemArmCallback, (XtPointer) this);
282 XtRemoveCallback ((Widget) m_buttonWidget, XmNdisarmCallback,
283 wxMenuItemDisarmCallback, (XtPointer) this);
284 }
285 }
286 else if (GetId() == -1)
287 {
288 ; // Nothing
289
290 }
291 else if (GetSubMenu())
292 {
293 if (m_buttonWidget)
294 {
295 XtRemoveCallback ((Widget) m_buttonWidget, XmNcascadingCallback,
296 wxMenuItemArmCallback, (XtPointer) this);
297 }
298 m_subMenu->DestroyMenu(full);
299 if (full)
300 m_buttonWidget = NULL;
301 }
302
303 if (m_buttonWidget && full)
304 {
305 XtDestroyWidget ((Widget) m_buttonWidget);
306 m_buttonWidget = (WXWidget) 0;
307 }
308 }
309
310 void wxMenuItem::SetText(const wxString& label)
311 {
312 char mnem = wxFindMnemonic (label);
313 wxString label2 = wxStripMenuCodes(label);
314
315 m_text = label;
316
317 if (m_buttonWidget)
318 {
319 wxXmString label_str(label2);
320 XtVaSetValues ((Widget) m_buttonWidget,
321 XmNlabelString, label_str(),
322 NULL);
323 if (mnem != 0)
324 XtVaSetValues ((Widget) m_buttonWidget, XmNmnemonic, mnem, NULL);
325 char *accel = wxFindAccelerator (label2);
326 if (accel)
327 XtVaSetValues ((Widget) m_buttonWidget, XmNaccelerator, accel, NULL);
328
329 XmString accel_str = wxFindAcceleratorText (label2);
330 if (accel_str)
331 {
332 XtVaSetValues ((Widget) m_buttonWidget, XmNacceleratorText, accel_str, NULL);
333 XmStringFree (accel_str);
334 }
335 }
336 }
337
338 // ----------------------------------------------------------------------------
339 // Motif callbacks
340 // ----------------------------------------------------------------------------
341
342 void wxMenuItemCallback (Widget WXUNUSED(w), XtPointer clientData,
343 XtPointer WXUNUSED(ptr))
344 {
345 wxMenuItem *item = (wxMenuItem *) clientData;
346 if (item)
347 {
348 if (item->IsCheckable())
349 {
350 Boolean isChecked = FALSE;
351 XtVaGetValues ((Widget) item->GetButtonWidget(), XmNset, & isChecked, NULL);
352
353 // only set the flag, don't actually check anything
354 item->wxMenuItemBase::Check(isChecked);
355 }
356 if (item->GetMenuBar() && item->GetMenuBar()->GetMenuBarFrame())
357 {
358 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, item->GetId());
359 commandEvent.SetEventObject(item->GetMenuBar()->GetMenuBarFrame());
360 commandEvent.SetInt( item->GetId() );
361
362 item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(commandEvent);
363 }
364 else if (item->GetTopMenu())
365 {
366 wxCommandEvent event (wxEVT_COMMAND_MENU_SELECTED, item->GetId());
367 event.SetEventObject(item->GetTopMenu());
368 event.SetInt( item->GetId() );
369
370 item->GetTopMenu()->ProcessCommand (event);
371 }
372 }
373 }
374
375 void wxMenuItemArmCallback (Widget WXUNUSED(w), XtPointer clientData,
376 XtPointer WXUNUSED(ptr))
377 {
378 wxMenuItem *item = (wxMenuItem *) clientData;
379 if (item)
380 {
381 if (item->GetMenuBar() && item->GetMenuBar()->GetMenuBarFrame())
382 {
383 wxMenuEvent menuEvent(wxEVT_MENU_HIGHLIGHT, item->GetId());
384 menuEvent.SetEventObject(item->GetMenuBar()->GetMenuBarFrame());
385
386 item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(menuEvent);
387 }
388 }
389 }
390
391 void
392 wxMenuItemDisarmCallback (Widget WXUNUSED(w), XtPointer clientData,
393 XtPointer WXUNUSED(ptr))
394 {
395 wxMenuItem *item = (wxMenuItem *) clientData;
396 if (item)
397 {
398 if (item->GetMenuBar() && item->GetMenuBar()->GetMenuBarFrame())
399 {
400 // TODO: not sure this is correct, since -1 means something
401 // special to event system
402 wxMenuEvent menuEvent(wxEVT_MENU_HIGHLIGHT, -1);
403 menuEvent.SetEventObject(item->GetMenuBar()->GetMenuBarFrame());
404
405 item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(menuEvent);
406 }
407 }
408 }
409