]>
Commit | Line | Data |
---|---|---|
0e320a79 DW |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Name: menuitem.cpp | |
3 | // Purpose: wxMenuItem implementation | |
75f11ad7 DW |
4 | // Author: David Webster |
5 | // Modified by: | |
6 | // Created: 10/10/98 | |
0e320a79 | 7 | // RCS-ID: $Id$ |
75f11ad7 | 8 | // Copyright: (c) David Webster |
65571936 | 9 | // Licence: wxWindows licence |
0e320a79 DW |
10 | /////////////////////////////////////////////////////////////////////////////// |
11 | ||
12 | // ============================================================================ | |
13 | // headers & declarations | |
14 | // ============================================================================ | |
15 | ||
7a0d28d8 SN |
16 | #ifdef __GNUG__ |
17 | #pragma implementation "menuitem.h" | |
18 | #endif | |
19 | ||
75f11ad7 DW |
20 | // For compilers that support precompilation, includes "wx.h". |
21 | #include "wx/wxprec.h" | |
22 | ||
23 | #ifndef WX_PRECOMP | |
24 | #include "wx/font.h" | |
25 | #include "wx/bitmap.h" | |
26 | #include "wx/settings.h" | |
27 | #include "wx/font.h" | |
28 | #include "wx/window.h" | |
29 | #include "wx/accel.h" | |
30 | #include "wx/menu.h" | |
31 | #include "wx/string.h" | |
32 | #endif | |
33 | ||
0e320a79 | 34 | #include "wx/menuitem.h" |
75f11ad7 DW |
35 | #include "wx/log.h" |
36 | ||
c5fb56c0 DW |
37 | #if wxUSE_ACCEL |
38 | #include "wx/accel.h" | |
39 | #endif // wxUSE_ACCEL | |
40 | ||
75f11ad7 DW |
41 | #include "wx/os2/private.h" |
42 | ||
43 | // --------------------------------------------------------------------------- | |
c5fb56c0 | 44 | // macro |
75f11ad7 DW |
45 | // --------------------------------------------------------------------------- |
46 | ||
c5fb56c0 | 47 | // hide the ugly cast |
75f11ad7 | 48 | #define GetHMenuOf(menu) ((HMENU)menu->GetHMenu()) |
0e320a79 | 49 | |
c5fb56c0 DW |
50 | // conditional compilation |
51 | #if wxUSE_OWNER_DRAWN | |
52 | #define OWNER_DRAWN_ONLY( code ) if ( IsOwnerDrawn() ) code | |
53 | #else // !wxUSE_OWNER_DRAWN | |
54 | #define OWNER_DRAWN_ONLY( code ) | |
55 | #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN | |
56 | ||
0e320a79 DW |
57 | // ============================================================================ |
58 | // implementation | |
59 | // ============================================================================ | |
60 | ||
61 | // ---------------------------------------------------------------------------- | |
62 | // dynamic classes implementation | |
63 | // ---------------------------------------------------------------------------- | |
64 | ||
4a46a5df | 65 | IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject) |
0e320a79 DW |
66 | |
67 | // ---------------------------------------------------------------------------- | |
68 | // wxMenuItem | |
69 | // ---------------------------------------------------------------------------- | |
70 | ||
71 | // ctor & dtor | |
72 | // ----------- | |
73 | ||
22e90769 DW |
74 | wxMenuItem::wxMenuItem( |
75 | wxMenu* pParentMenu | |
76 | , int nId | |
ab4fece8 DW |
77 | , const wxString& rsText |
78 | , const wxString& rsHelp | |
79 | , wxItemKind eKind | |
22e90769 DW |
80 | , wxMenu* pSubMenu |
81 | ) | |
ab4fece8 DW |
82 | : wxMenuItemBase( pParentMenu |
83 | ,nId | |
3a7c1253 | 84 | ,wxPMTextToLabel(rsText) |
ab4fece8 DW |
85 | ,rsHelp |
86 | ,eKind | |
87 | ,pSubMenu | |
88 | ) | |
75f11ad7 | 89 | #if wxUSE_OWNER_DRAWN |
3a7c1253 | 90 | , wxOwnerDrawn( wxPMTextToLabel(rsText) |
ab4fece8 | 91 | ,eKind == wxITEM_CHECK |
22e90769 | 92 | ) |
c5fb56c0 | 93 | #endif // owner drawn |
0e320a79 | 94 | { |
22e90769 | 95 | wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent")); |
8635b0db DW |
96 | memset(&m_vMenuData, '\0', sizeof(m_vMenuData)); |
97 | m_vMenuData.id = (USHORT)nId; | |
75f11ad7 | 98 | |
f95255e2 DW |
99 | Init(); |
100 | } // end of wxMenuItem::wxMenuItem | |
101 | ||
102 | wxMenuItem::wxMenuItem( | |
103 | wxMenu* pParentMenu | |
104 | , int nId | |
ab4fece8 DW |
105 | , const wxString& rsText |
106 | , const wxString& rsHelp | |
f95255e2 DW |
107 | , bool bIsCheckable |
108 | , wxMenu* pSubMenu | |
109 | ) | |
ab4fece8 DW |
110 | : wxMenuItemBase( pParentMenu |
111 | ,nId | |
3a7c1253 | 112 | ,wxPMTextToLabel(rsText) |
ab4fece8 DW |
113 | ,rsHelp |
114 | ,bIsCheckable ? wxITEM_CHECK : wxITEM_NORMAL | |
115 | ,pSubMenu | |
116 | ) | |
f95255e2 | 117 | #if wxUSE_OWNER_DRAWN |
3a7c1253 | 118 | , wxOwnerDrawn( wxPMTextToLabel(rsText) |
ab4fece8 | 119 | ,bIsCheckable |
f95255e2 DW |
120 | ) |
121 | #endif // owner drawn | |
122 | { | |
123 | wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent")); | |
938aa9c4 DW |
124 | memset(&m_vMenuData, '\0', sizeof(m_vMenuData)); |
125 | m_vMenuData.id = (USHORT)nId; | |
f95255e2 DW |
126 | |
127 | Init(); | |
128 | } // end of wxMenuItem::wxMenuItem | |
129 | ||
130 | void wxMenuItem::Init() | |
131 | { | |
ab4fece8 DW |
132 | m_vRadioGroup.m_nStart = -1; |
133 | m_bIsRadioGroupStart = FALSE; | |
22e90769 | 134 | |
f95255e2 | 135 | #if wxUSE_OWNER_DRAWN |
ab4fece8 DW |
136 | // |
137 | // Set default menu colors | |
138 | // | |
a756f210 | 139 | #define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c)) |
75f11ad7 DW |
140 | |
141 | SetTextColour(SYS_COLOR(MENUTEXT)); | |
142 | SetBackgroundColour(SYS_COLOR(MENU)); | |
143 | ||
ab4fece8 DW |
144 | // |
145 | // We don't want normal items be owner-drawn | |
146 | // | |
f95255e2 | 147 | ResetOwnerDrawn(); |
c9667cda | 148 | #undef SYS_COLOR |
d65c269b | 149 | |
ab4fece8 DW |
150 | // |
151 | // Tell the owner drawing code to to show the accel string as well | |
152 | // | |
f95255e2 DW |
153 | SetAccelString(m_text.AfterFirst(_T('\t'))); |
154 | #endif // wxUSE_OWNER_DRAWN | |
ab4fece8 | 155 | } // end of wxMenuItem::Init |
0e320a79 | 156 | |
75f11ad7 | 157 | wxMenuItem::~wxMenuItem() |
0e320a79 | 158 | { |
22e90769 | 159 | } // end of wxMenuItem::~wxMenuItem |
0e320a79 | 160 | |
22e90769 DW |
161 | // |
162 | // Misc | |
0e320a79 DW |
163 | // ---- |
164 | ||
22e90769 DW |
165 | // |
166 | // Return the id for calling Win32 API functions | |
167 | // | |
75f11ad7 DW |
168 | int wxMenuItem::GetRealId() const |
169 | { | |
c5fb56c0 | 170 | return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId(); |
22e90769 | 171 | } // end of wxMenuItem::GetRealId |
c5fb56c0 | 172 | |
22e90769 DW |
173 | // |
174 | // Get item state | |
c5fb56c0 | 175 | // -------------- |
c5fb56c0 DW |
176 | bool wxMenuItem::IsChecked() const |
177 | { | |
22e90769 DW |
178 | USHORT uFlag = SHORT1FROMMR(::WinSendMsg( GetHMenuOf(m_parentMenu) |
179 | ,MM_QUERYITEMATTR | |
180 | ,MPFROM2SHORT(GetId(), TRUE) | |
181 | ,MPFROMSHORT(MIA_CHECKED) | |
182 | )); | |
183 | ||
184 | return (uFlag & MIA_CHECKED); | |
185 | } // end of wxMenuItem::IsChecked | |
186 | ||
187 | wxString wxMenuItemBase::GetLabelFromText( | |
c9667cda | 188 | const wxString& rsText |
22e90769 | 189 | ) |
c5fb56c0 | 190 | { |
c9667cda DW |
191 | wxString sLabel; |
192 | ||
193 | for (const char* zPc = rsText.c_str(); *zPc; zPc++) | |
2b33b728 | 194 | { |
c9667cda | 195 | if (*zPc == wxT('~') || *zPc == wxT('&')) |
2b33b728 | 196 | { |
c9667cda DW |
197 | // |
198 | // '~' is the escape character for OS/2PM and '&' is the one for | |
77ffb593 | 199 | // wxWidgets - skip both of them |
c9667cda | 200 | // |
2b33b728 SN |
201 | continue; |
202 | } | |
c9667cda | 203 | sLabel += *zPc; |
2b33b728 | 204 | } |
c9667cda DW |
205 | return sLabel; |
206 | } // end of wxMenuItemBase::GetLabelFromText | |
75f11ad7 | 207 | |
598d8cac DW |
208 | // |
209 | // Radio group stuff | |
f95255e2 | 210 | // ----------------- |
598d8cac | 211 | // |
f95255e2 DW |
212 | void wxMenuItem::SetAsRadioGroupStart() |
213 | { | |
214 | m_bIsRadioGroupStart = TRUE; | |
215 | } // end of wxMenuItem::SetAsRadioGroupStart | |
216 | ||
217 | void wxMenuItem::SetRadioGroupStart( | |
218 | int nStart | |
219 | ) | |
220 | { | |
598d8cac DW |
221 | wxASSERT_MSG( !m_bIsRadioGroupStart |
222 | ,_T("should only be called for the next radio items") | |
223 | ); | |
f95255e2 DW |
224 | |
225 | m_vRadioGroup.m_nStart = nStart; | |
598d8cac | 226 | } // wxMenuItem::SetRadioGroupStart |
f95255e2 DW |
227 | |
228 | void wxMenuItem::SetRadioGroupEnd( | |
229 | int nEnd | |
230 | ) | |
231 | { | |
598d8cac DW |
232 | wxASSERT_MSG( m_bIsRadioGroupStart |
233 | ,_T("should only be called for the first radio item") | |
234 | ); | |
f95255e2 DW |
235 | m_vRadioGroup.m_nEnd = nEnd; |
236 | } // end of wxMenuItem::SetRadioGroupEnd | |
237 | ||
0e320a79 DW |
238 | // change item state |
239 | // ----------------- | |
240 | ||
22e90769 DW |
241 | void wxMenuItem::Enable( |
242 | bool bEnable | |
243 | ) | |
0e320a79 | 244 | { |
22e90769 | 245 | bool bOk; |
75f11ad7 | 246 | |
22e90769 DW |
247 | if (m_isEnabled == bEnable) |
248 | return; | |
249 | if (bEnable) | |
914589c2 DW |
250 | bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu) |
251 | ,MM_SETITEMATTR | |
252 | ,MPFROM2SHORT(GetRealId(), TRUE) | |
f6bcfd97 | 253 | ,MPFROM2SHORT(MIA_DISABLED, FALSE) |
914589c2 | 254 | ); |
22e90769 | 255 | else |
914589c2 DW |
256 | bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu) |
257 | ,MM_SETITEMATTR | |
258 | ,MPFROM2SHORT(GetRealId(), TRUE) | |
f6bcfd97 | 259 | ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED) |
914589c2 | 260 | ); |
22e90769 DW |
261 | if (!bOk) |
262 | { | |
c5fb56c0 | 263 | wxLogLastError("EnableMenuItem"); |
0e320a79 | 264 | } |
22e90769 DW |
265 | wxMenuItemBase::Enable(bEnable); |
266 | } // end of wxMenuItem::Enable | |
0e320a79 | 267 | |
22e90769 DW |
268 | void wxMenuItem::Check( |
269 | bool bCheck | |
270 | ) | |
0e320a79 | 271 | { |
22e90769 | 272 | bool bOk; |
75f11ad7 | 273 | |
d65c269b | 274 | wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") ); |
22e90769 | 275 | if (m_isChecked == bCheck) |
c5fb56c0 | 276 | return; |
f95255e2 | 277 | |
50b39f8f | 278 | HMENU hMenu = GetHmenuOf(m_parentMenu); |
598d8cac DW |
279 | |
280 | if (GetKind() == wxITEM_RADIO) | |
ab4fece8 DW |
281 | { |
282 | // | |
283 | // It doesn't make sense to uncheck a radio item - what would this do? | |
284 | // | |
285 | if (!bCheck) | |
286 | return; | |
287 | ||
288 | // | |
289 | // Get the index of this item in the menu | |
290 | // | |
291 | const wxMenuItemList& rItems = m_parentMenu->GetMenuItems(); | |
292 | int nPos = rItems.IndexOf(this); | |
ab4fece8 | 293 | |
598d8cac DW |
294 | wxCHECK_RET( nPos != wxNOT_FOUND |
295 | ,_T("menuitem not found in the menu items list?") | |
296 | ); | |
ab4fece8 DW |
297 | |
298 | // | |
299 | // Get the radio group range | |
300 | // | |
598d8cac DW |
301 | int nStart; |
302 | int nEnd; | |
ab4fece8 DW |
303 | |
304 | if (m_bIsRadioGroupStart) | |
305 | { | |
598d8cac DW |
306 | // |
307 | // We already have all information we need | |
308 | // | |
ab4fece8 | 309 | nStart = nPos; |
598d8cac | 310 | nEnd = m_vRadioGroup.m_nEnd; |
ab4fece8 | 311 | } |
598d8cac | 312 | else // next radio group item |
ab4fece8 DW |
313 | { |
314 | // | |
315 | // Get the radio group end from the start item | |
316 | // | |
317 | nStart = m_vRadioGroup.m_nStart; | |
318 | nEnd = rItems.Item(nStart)->GetData()->m_vRadioGroup.m_nEnd; | |
319 | } | |
320 | ||
321 | // | |
322 | // Also uncheck all the other items in this radio group | |
323 | // | |
324 | wxMenuItemList::Node* pNode = rItems.Item(nStart); | |
325 | ||
326 | for (int n = nStart; n <= nEnd && pNode; n++) | |
327 | { | |
ab4fece8 DW |
328 | if (n == nPos) |
329 | { | |
598d8cac DW |
330 | ::WinSendMsg( hMenu |
331 | ,MM_SETITEMATTR | |
332 | ,MPFROM2SHORT(n, TRUE) | |
333 | ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED) | |
334 | ); | |
ab4fece8 | 335 | } |
598d8cac | 336 | if (n != nPos) |
ab4fece8 | 337 | { |
598d8cac DW |
338 | pNode->GetData()->m_isChecked = FALSE; |
339 | ::WinSendMsg( hMenu | |
340 | ,MM_SETITEMATTR | |
341 | ,MPFROM2SHORT(n, TRUE) | |
342 | ,MPFROM2SHORT(MIA_CHECKED, FALSE) | |
343 | ); | |
ab4fece8 DW |
344 | } |
345 | pNode = pNode->GetNext(); | |
346 | } | |
347 | } | |
348 | else // check item | |
349 | { | |
350 | if (bCheck) | |
50b39f8f | 351 | bOk = (bool)::WinSendMsg( hMenu |
ab4fece8 DW |
352 | ,MM_SETITEMATTR |
353 | ,MPFROM2SHORT(GetRealId(), TRUE) | |
354 | ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED) | |
355 | ); | |
356 | else | |
50b39f8f | 357 | bOk = (bool)::WinSendMsg( hMenu |
ab4fece8 DW |
358 | ,MM_SETITEMATTR |
359 | ,MPFROM2SHORT(GetRealId(), TRUE) | |
360 | ,MPFROM2SHORT(MIA_CHECKED, FALSE) | |
361 | ); | |
362 | } | |
22e90769 DW |
363 | if (!bOk) |
364 | { | |
f6bcfd97 | 365 | wxLogLastError("CheckMenuItem"); |
75f11ad7 | 366 | } |
22e90769 DW |
367 | wxMenuItemBase::Check(bCheck); |
368 | } // end of wxMenuItem::Check | |
75f11ad7 | 369 | |
22e90769 DW |
370 | void wxMenuItem::SetText( |
371 | const wxString& rText | |
372 | ) | |
75f11ad7 | 373 | { |
22e90769 DW |
374 | // |
375 | // Don't do anything if label didn't change | |
376 | // | |
2b33b728 | 377 | |
3a7c1253 | 378 | wxString sText = wxPMTextToLabel(rText); |
50b39f8f | 379 | if (m_text == sText) |
75f11ad7 DW |
380 | return; |
381 | ||
50b39f8f DW |
382 | wxMenuItemBase::SetText(sText); |
383 | OWNER_DRAWN_ONLY(wxOwnerDrawn::SetName(sText)); | |
57ff8a87 DW |
384 | #if wxUSE_OWNER_DRAWN |
385 | SetAccelString(rText.AfterFirst(_T('\t'))); | |
386 | #endif // wxUSE_OWNER_DRAWN | |
22e90769 | 387 | |
50b39f8f | 388 | HWND hMenu = GetHmenuOf(m_parentMenu); |
22e90769 DW |
389 | |
390 | wxCHECK_RET(hMenu, wxT("menuitem without menu")); | |
75f11ad7 | 391 | |
c5fb56c0 DW |
392 | #if wxUSE_ACCEL |
393 | m_parentMenu->UpdateAccel(this); | |
394 | #endif // wxUSE_ACCEL | |
75f11ad7 | 395 | |
22e90769 DW |
396 | USHORT uId = GetRealId(); |
397 | MENUITEM vItem; | |
398 | USHORT uFlagsOld; | |
914589c2 | 399 | |
22e90769 DW |
400 | if (!::WinSendMsg( hMenu |
401 | ,MM_QUERYITEM | |
402 | ,MPFROM2SHORT(uId, TRUE) | |
403 | ,(MPARAM)&vItem | |
404 | )) | |
75f11ad7 DW |
405 | { |
406 | wxLogLastError("GetMenuState"); | |
407 | } | |
408 | else | |
409 | { | |
22e90769 DW |
410 | uFlagsOld = vItem.afStyle; |
411 | if (IsSubMenu()) | |
75f11ad7 | 412 | { |
22e90769 | 413 | uFlagsOld |= MIS_SUBMENU; |
75f11ad7 DW |
414 | } |
415 | ||
22e90769 | 416 | BYTE* pData; |
c5fb56c0 | 417 | |
75f11ad7 | 418 | #if wxUSE_OWNER_DRAWN |
22e90769 | 419 | if (IsOwnerDrawn()) |
75f11ad7 | 420 | { |
22e90769 DW |
421 | uFlagsOld |= MIS_OWNERDRAW; |
422 | pData = (BYTE*)this; | |
75f11ad7 DW |
423 | } |
424 | else | |
425 | #endif //owner drawn | |
426 | { | |
22e90769 | 427 | uFlagsOld |= MIS_TEXT; |
50b39f8f | 428 | pData = (BYTE*)sText.c_str(); |
22e90769 DW |
429 | } |
430 | ||
431 | // | |
432 | // Set the style | |
433 | // | |
434 | if (!::WinSendMsg( hMenu | |
435 | ,MM_SETITEM | |
436 | ,MPFROM2SHORT(uId, TRUE) | |
437 | ,(MPARAM)&vItem | |
438 | )) | |
439 | { | |
440 | wxLogLastError(wxT("ModifyMenu")); | |
75f11ad7 DW |
441 | } |
442 | ||
22e90769 DW |
443 | // |
444 | // Set the text | |
445 | // | |
446 | if (::WinSendMsg( hMenu | |
447 | ,MM_SETITEMTEXT | |
448 | ,MPFROMSHORT(uId) | |
449 | ,(MPARAM)pData | |
450 | )) | |
75f11ad7 DW |
451 | { |
452 | wxLogLastError(wxT("ModifyMenu")); | |
453 | } | |
454 | } | |
22e90769 | 455 | } // end of wxMenuItem::SetText |
0e320a79 | 456 | |
22e90769 DW |
457 | void wxMenuItem::SetCheckable( |
458 | bool bCheckable | |
459 | ) | |
c5fb56c0 | 460 | { |
22e90769 DW |
461 | wxMenuItemBase::SetCheckable(bCheckable); |
462 | OWNER_DRAWN_ONLY(wxOwnerDrawn::SetCheckable(bCheckable)); | |
463 | } // end of wxMenuItem::SetCheckable | |
c5fb56c0 DW |
464 | |
465 | // ---------------------------------------------------------------------------- | |
466 | // wxMenuItemBase | |
467 | // ---------------------------------------------------------------------------- | |
468 | ||
22e90769 DW |
469 | wxMenuItem* wxMenuItemBase::New( |
470 | wxMenu* pParentMenu | |
471 | , int nId | |
472 | , const wxString& rName | |
473 | , const wxString& rHelp | |
d65c269b | 474 | , wxItemKind kind |
22e90769 DW |
475 | , wxMenu* pSubMenu |
476 | ) | |
c5fb56c0 | 477 | { |
22e90769 DW |
478 | return new wxMenuItem( pParentMenu |
479 | ,nId | |
480 | ,rName | |
481 | ,rHelp | |
d65c269b | 482 | ,kind |
22e90769 DW |
483 | ,pSubMenu |
484 | ); | |
485 | } // end of wxMenuItemBase::New | |
486 |