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