]> git.saurik.com Git - wxWidgets.git/blame - src/motif/menuitem.cpp
fix for assert when setting tooltip for a readonly combo
[wxWidgets.git] / src / motif / menuitem.cpp
CommitLineData
4bb6408c
JS
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// ============================================================================
9874b4ee 13// declarations
4bb6408c
JS
14// ============================================================================
15
9874b4ee
VZ
16#ifdef __GNUG__
17 #pragma implementation "menuitem.h"
18#endif
19
20// ----------------------------------------------------------------------------
21// headers
22// ----------------------------------------------------------------------------
23
4bb6408c
JS
24#include "wx/menu.h"
25#include "wx/menuitem.h"
50414e24
JS
26#include "wx/utils.h"
27#include "wx/frame.h"
28
338dd992
JJ
29#ifdef __VMS__
30#pragma message disable nosimpint
31#endif
50414e24
JS
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>
338dd992
JJ
41#ifdef __VMS__
42#pragma message enable nosimpint
43#endif
50414e24
JS
44
45#include "wx/motif/private.h"
46
9874b4ee
VZ
47// ----------------------------------------------------------------------------
48// functions prototypes
49// ----------------------------------------------------------------------------
50
51static void wxMenuItemCallback(Widget w, XtPointer clientData, XtPointer ptr);
52static void wxMenuItemArmCallback(Widget w, XtPointer clientData, XtPointer ptr);
53static void wxMenuItemDisarmCallback(Widget w, XtPointer clientData, XtPointer ptr);
4bb6408c
JS
54
55// ============================================================================
56// implementation
57// ============================================================================
58
59// ----------------------------------------------------------------------------
60// dynamic classes implementation
61// ----------------------------------------------------------------------------
62
9874b4ee 63 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
4bb6408c
JS
64
65// ----------------------------------------------------------------------------
66// wxMenuItem
67// ----------------------------------------------------------------------------
68
69// ctor & dtor
70// -----------
71
72wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id,
73 const wxString& strName, const wxString& strHelp,
74 bool bCheckable,
9874b4ee 75 wxMenu *pSubMenu)
4bb6408c 76{
9874b4ee
VZ
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;
2d120f83 91 m_buttonWidget = (WXWidget) NULL;
9874b4ee 92 m_topMenu = NULL;
4bb6408c
JS
93}
94
31528cd3 95wxMenuItem::~wxMenuItem()
4bb6408c
JS
96{
97}
98
99// misc
100// ----
101
102// delete the sub menu
103void wxMenuItem::DeleteSubMenu()
104{
9874b4ee 105 wxASSERT( m_subMenu != NULL );
31528cd3 106
9874b4ee
VZ
107 delete m_subMenu;
108 m_subMenu = NULL;
4bb6408c
JS
109}
110
111// change item state
112// -----------------
113
114void wxMenuItem::Enable(bool bDoEnable)
115{
9d08a1ed 116 if ( m_isEnabled != bDoEnable )
4bb6408c 117 {
9874b4ee
VZ
118 if ( !IsSubMenu() )
119 {
120 // normal menu item
2d120f83
JS
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 }
31528cd3 131
9874b4ee 132 wxMenuItemBase::Enable(bDoEnable);
4bb6408c 133 }
4bb6408c
JS
134}
135
136void wxMenuItem::Check(bool bDoCheck)
137{
2d120f83 138 wxCHECK_RET( IsCheckable(), "only checkable items may be checked" );
31528cd3 139
9874b4ee 140 if ( m_isChecked != bDoCheck )
50414e24 141 {
9874b4ee 142 if ( m_buttonWidget )
2d120f83 143 {
9874b4ee
VZ
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);
2d120f83 151 }
9874b4ee
VZ
152
153 wxMenuItemBase::Check(bDoCheck);
50414e24 154 }
50414e24
JS
155}
156
3b59cdbf
VZ
157/* static */
158wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
c71830c3 159{
c2754d29 160 return wxStripMenuCodes(text);
c71830c3
VZ
161}
162
c71830c3
VZ
163// ----------------------------------------------------------------------------
164// wxMenuItemBase
165// ----------------------------------------------------------------------------
166
167wxMenuItem *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// ----------------------------------------------------------------------------
50414e24
JS
180
181void wxMenuItem::CreateItem (WXWidget menu, wxMenuBar * menuBar, wxMenu * topMenu)
182{
2d120f83
JS
183 m_menuBar = menuBar;
184 m_topMenu = topMenu;
31528cd3 185
2d120f83 186 if (GetId() == -2)
50414e24 187 {
2d120f83 188 // Id=-2 identifies a Title item.
31528cd3 189 m_buttonWidget = (WXWidget) XtVaCreateManagedWidget
9874b4ee 190 (wxStripMenuCodes(m_text),
2d120f83 191 xmLabelGadgetClass, (Widget) menu, NULL);
50414e24 192 }
9874b4ee 193 else if ((!m_text.IsNull() && m_text != "") && (!m_subMenu))
50414e24 194 {
9874b4ee 195 wxString strName = wxStripMenuCodes(m_text);
2d120f83
JS
196 if (IsCheckable())
197 {
31528cd3 198 m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (strName,
2d120f83
JS
199 xmToggleButtonGadgetClass, (Widget) menu,
200 NULL);
201 XtVaSetValues ((Widget) m_buttonWidget, XmNset, (Boolean) IsChecked(), NULL);
202 }
203 else
31528cd3 204 m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (strName,
2d120f83
JS
205 xmPushButtonGadgetClass, (Widget) menu,
206 NULL);
9874b4ee 207 char mnem = wxFindMnemonic (m_text);
2d120f83
JS
208 if (mnem != 0)
209 XtVaSetValues ((Widget) m_buttonWidget, XmNmnemonic, mnem, NULL);
31528cd3 210
2d120f83
JS
211 //// TODO: proper accelerator treatment. What does wxFindAccelerator
212 //// look for?
9874b4ee 213 strName = m_text;
31528cd3 214 char *accel = wxFindAccelerator (strName);
2d120f83
JS
215 if (accel)
216 XtVaSetValues ((Widget) m_buttonWidget, XmNaccelerator, accel, NULL);
31528cd3 217
2d120f83 218 // TODO: What does this do?
31528cd3 219 XmString accel_str = wxFindAcceleratorText (strName);
2d120f83
JS
220 if (accel_str)
221 {
222 XtVaSetValues ((Widget) m_buttonWidget, XmNacceleratorText, accel_str, NULL);
223 XmStringFree (accel_str);
224 }
31528cd3 225
2d120f83
JS
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);
50414e24 244 }
2d120f83 245 else if (GetId() == -1)
50414e24 246 {
2d120f83
JS
247 m_buttonWidget = (WXWidget) XtVaCreateManagedWidget ("separator",
248 xmSeparatorGadgetClass, (Widget) menu, NULL);
50414e24 249 }
9874b4ee 250 else if (m_subMenu)
50414e24 251 {
9874b4ee
VZ
252 m_buttonWidget = m_subMenu->CreateMenu (menuBar, menu, topMenu, m_text, TRUE);
253 m_subMenu->SetButtonWidget(m_buttonWidget);
2d120f83
JS
254 XtAddCallback ((Widget) m_buttonWidget,
255 XmNcascadingCallback,
256 (XtCallbackProc) wxMenuItemArmCallback,
257 (XtPointer) this);
50414e24 258 }
2d120f83
JS
259 if (m_buttonWidget)
260 XtSetSensitive ((Widget) m_buttonWidget, (Boolean) IsEnabled());
50414e24
JS
261}
262
263void wxMenuItem::DestroyItem(bool full)
264{
2d120f83 265 if (GetId() == -2)
50414e24 266 {
9874b4ee 267 ; // Nothing
31528cd3 268
50414e24 269 }
9874b4ee 270 else if ((!m_text.IsNull() && (m_text != "")) && !m_subMenu)
50414e24 271 {
2d120f83
JS
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 }
50414e24 285 }
2d120f83 286 else if (GetId() == -1)
50414e24 287 {
9874b4ee 288 ; // Nothing
31528cd3 289
50414e24 290 }
2d120f83 291 else if (GetSubMenu())
50414e24 292 {
2d120f83
JS
293 if (m_buttonWidget)
294 {
295 XtRemoveCallback ((Widget) m_buttonWidget, XmNcascadingCallback,
296 wxMenuItemArmCallback, (XtPointer) this);
297 }
9874b4ee 298 m_subMenu->DestroyMenu(full);
2d120f83
JS
299 if (full)
300 m_buttonWidget = NULL;
50414e24 301 }
31528cd3 302
2d120f83 303 if (m_buttonWidget && full)
50414e24 304 {
2d120f83
JS
305 XtDestroyWidget ((Widget) m_buttonWidget);
306 m_buttonWidget = (WXWidget) 0;
50414e24
JS
307 }
308}
309
9874b4ee 310void wxMenuItem::SetText(const wxString& label)
50414e24 311{
2d120f83 312 char mnem = wxFindMnemonic (label);
31528cd3
VZ
313 wxString label2 = wxStripMenuCodes(label);
314
9874b4ee 315 m_text = label;
31528cd3 316
2d120f83 317 if (m_buttonWidget)
50414e24 318 {
31528cd3 319 wxXmString label_str(label2);
2d120f83 320 XtVaSetValues ((Widget) m_buttonWidget,
66cbc96d 321 XmNlabelString, label_str(),
2d120f83 322 NULL);
2d120f83
JS
323 if (mnem != 0)
324 XtVaSetValues ((Widget) m_buttonWidget, XmNmnemonic, mnem, NULL);
31528cd3 325 char *accel = wxFindAccelerator (label2);
2d120f83
JS
326 if (accel)
327 XtVaSetValues ((Widget) m_buttonWidget, XmNaccelerator, accel, NULL);
31528cd3
VZ
328
329 XmString accel_str = wxFindAcceleratorText (label2);
2d120f83 330 if (accel_str)
50414e24 331 {
2d120f83
JS
332 XtVaSetValues ((Widget) m_buttonWidget, XmNacceleratorText, accel_str, NULL);
333 XmStringFree (accel_str);
50414e24
JS
334 }
335 }
336}
337
9874b4ee
VZ
338// ----------------------------------------------------------------------------
339// Motif callbacks
340// ----------------------------------------------------------------------------
341
af111fc3
JS
342void wxMenuItemCallback (Widget WXUNUSED(w), XtPointer clientData,
343 XtPointer WXUNUSED(ptr))
50414e24 344{
2d120f83
JS
345 wxMenuItem *item = (wxMenuItem *) clientData;
346 if (item)
50414e24 347 {
2d120f83
JS
348 if (item->IsCheckable())
349 {
350 Boolean isChecked = FALSE;
351 XtVaGetValues ((Widget) item->GetButtonWidget(), XmNset, & isChecked, NULL);
9874b4ee
VZ
352
353 // only set the flag, don't actually check anything
354 item->wxMenuItemBase::Check(isChecked);
2d120f83
JS
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() );
31528cd3 361
2d120f83
JS
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() );
31528cd3 369
2d120f83
JS
370 item->GetTopMenu()->ProcessCommand (event);
371 }
50414e24
JS
372 }
373}
374
af111fc3
JS
375void wxMenuItemArmCallback (Widget WXUNUSED(w), XtPointer clientData,
376 XtPointer WXUNUSED(ptr))
50414e24 377{
2d120f83
JS
378 wxMenuItem *item = (wxMenuItem *) clientData;
379 if (item)
50414e24 380 {
2d120f83
JS
381 if (item->GetMenuBar() && item->GetMenuBar()->GetMenuBarFrame())
382 {
383 wxMenuEvent menuEvent(wxEVT_MENU_HIGHLIGHT, item->GetId());
384 menuEvent.SetEventObject(item->GetMenuBar()->GetMenuBarFrame());
31528cd3 385
2d120f83
JS
386 item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(menuEvent);
387 }
50414e24
JS
388 }
389}
390
31528cd3 391void
af111fc3
JS
392wxMenuItemDisarmCallback (Widget WXUNUSED(w), XtPointer clientData,
393 XtPointer WXUNUSED(ptr))
50414e24 394{
2d120f83
JS
395 wxMenuItem *item = (wxMenuItem *) clientData;
396 if (item)
50414e24 397 {
2d120f83
JS
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());
31528cd3 404
2d120f83
JS
405 item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(menuEvent);
406 }
50414e24
JS
407 }
408}
409