replaced wxMoveWindowDeferred() with wxWindow::DoMoveSibling()
[wxWidgets.git] / src / msw / radiobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/radiobox.cpp
3 // Purpose: wxRadioBox implementation
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "radiobox.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_RADIOBOX
32
33 #ifndef WX_PRECOMP
34 #include "wx/bitmap.h"
35 #include "wx/brush.h"
36 #include "wx/radiobox.h"
37 #include "wx/settings.h"
38 #include "wx/log.h"
39 #endif
40
41 #include "wx/msw/subwin.h"
42
43 #if wxUSE_TOOLTIPS
44 #if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__)
45 #include <commctrl.h>
46 #endif
47 #include "wx/tooltip.h"
48 #endif // wxUSE_TOOLTIPS
49
50 // TODO: wxCONSTRUCTOR
51 #if 0 // wxUSE_EXTENDED_RTTI
52 WX_DEFINE_FLAGS( wxRadioBoxStyle )
53
54 wxBEGIN_FLAGS( wxRadioBoxStyle )
55 // new style border flags, we put them first to
56 // use them for streaming out
57 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
58 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
59 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
60 wxFLAGS_MEMBER(wxBORDER_RAISED)
61 wxFLAGS_MEMBER(wxBORDER_STATIC)
62 wxFLAGS_MEMBER(wxBORDER_NONE)
63
64 // old style border flags
65 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
66 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
67 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
68 wxFLAGS_MEMBER(wxRAISED_BORDER)
69 wxFLAGS_MEMBER(wxSTATIC_BORDER)
70 wxFLAGS_MEMBER(wxBORDER)
71
72 // standard window styles
73 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
74 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
75 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
76 wxFLAGS_MEMBER(wxWANTS_CHARS)
77 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
78 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
79 wxFLAGS_MEMBER(wxVSCROLL)
80 wxFLAGS_MEMBER(wxHSCROLL)
81
82 wxFLAGS_MEMBER(wxRA_SPECIFY_COLS)
83 wxFLAGS_MEMBER(wxRA_HORIZONTAL)
84 wxFLAGS_MEMBER(wxRA_SPECIFY_ROWS)
85 wxFLAGS_MEMBER(wxRA_VERTICAL)
86
87 wxEND_FLAGS( wxRadioBoxStyle )
88
89 IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioBox, wxControl,"wx/radiobox.h")
90
91 wxBEGIN_PROPERTIES_TABLE(wxRadioBox)
92 wxEVENT_PROPERTY( Select , wxEVT_COMMAND_RADIOBOX_SELECTED , wxCommandEvent )
93 wxPROPERTY_FLAGS( WindowStyle , wxRadioBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
94 wxEND_PROPERTIES_TABLE()
95
96 #else
97 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
98 #endif
99
100 /*
101 selection
102 content
103 label
104 dimension
105 item
106 */
107
108 // ---------------------------------------------------------------------------
109 // private functions
110 // ---------------------------------------------------------------------------
111
112 // wnd proc for radio buttons
113 LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hWnd,
114 UINT message,
115 WPARAM wParam,
116 LPARAM lParam);
117
118 // ---------------------------------------------------------------------------
119 // global vars
120 // ---------------------------------------------------------------------------
121
122 // the pointer to standard radio button wnd proc
123 static WXFARPROC s_wndprocRadioBtn = (WXFARPROC)NULL;
124
125 // ===========================================================================
126 // implementation
127 // ===========================================================================
128
129 // ---------------------------------------------------------------------------
130 // wxRadioBox creation
131 // ---------------------------------------------------------------------------
132
133 // Radio box item
134 void wxRadioBox::Init()
135 {
136 m_selectedButton = wxNOT_FOUND;
137 m_radioButtons = NULL;
138 m_majorDim = 0;
139 m_radioWidth = NULL;
140 m_radioHeight = NULL;
141 }
142
143 bool wxRadioBox::Create(wxWindow *parent,
144 wxWindowID id,
145 const wxString& title,
146 const wxPoint& pos,
147 const wxSize& size,
148 int n,
149 const wxString choices[],
150 int majorDim,
151 long style,
152 const wxValidator& val,
153 const wxString& name)
154 {
155 // initialize members
156 m_majorDim = majorDim == 0 ? n : majorDim;
157
158 // common initialization
159 if ( !wxStaticBox::Create(parent, id, title, pos, size, style, name) )
160 return false;
161
162 #if wxUSE_VALIDATORS
163 SetValidator(val);
164 #else
165 wxUnusedVar(val);
166 #endif // wxUSE_VALIDATORS/!wxUSE_VALIDATORS
167
168 m_radioButtons = new wxSubwindows(n);
169 m_radioWidth = new int[n];
170 m_radioHeight = new int[n];
171
172 for ( int i = 0; i < n; i++ )
173 {
174 m_radioWidth[i] =
175 m_radioHeight[i] = wxDefaultCoord;
176 long styleBtn = BS_AUTORADIOBUTTON | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
177 if ( i == 0 )
178 styleBtn |= WS_GROUP;
179
180 long newId = NewControlId();
181
182 HWND hwndBtn = ::CreateWindow(_T("BUTTON"),
183 choices[i],
184 styleBtn,
185 0, 0, 0, 0, // will be set in SetSize()
186 GetHwnd(),
187 (HMENU)newId,
188 wxGetInstance(),
189 NULL);
190
191 if ( !hwndBtn )
192 {
193 wxLogLastError(wxT("CreateWindow(radio btn)"));
194
195 return false;
196 }
197
198 (*m_radioButtons)[i] = hwndBtn;
199
200 SubclassRadioButton((WXHWND)hwndBtn);
201
202 m_subControls.Add(newId);
203 }
204
205 // Create a dummy radio control to end the group.
206 (void)::CreateWindow(_T("BUTTON"),
207 wxEmptyString,
208 WS_GROUP | BS_AUTORADIOBUTTON | WS_CHILD,
209 0, 0, 0, 0, GetHwnd(),
210 (HMENU)NewControlId(), wxGetInstance(), NULL);
211
212 m_radioButtons->SetFont(GetFont());
213
214 #ifdef __WXWINCE__
215 // Set the z-order correctly
216 SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
217 #endif
218
219 SetSelection(0);
220 SetSize(pos.x, pos.y, size.x, size.y);
221
222 // Now that we have items determine what is the best size and set it.
223 SetBestSize(size);
224
225 return true;
226 }
227
228 bool wxRadioBox::Create(wxWindow *parent,
229 wxWindowID id,
230 const wxString& title,
231 const wxPoint& pos,
232 const wxSize& size,
233 const wxArrayString& choices,
234 int majorDim,
235 long style,
236 const wxValidator& val,
237 const wxString& name)
238 {
239 wxCArrayString chs(choices);
240 return Create(parent, id, title, pos, size, chs.GetCount(),
241 chs.GetStrings(), majorDim, style, val, name);
242 }
243
244 wxRadioBox::~wxRadioBox()
245 {
246 m_isBeingDeleted = true;
247
248 delete m_radioButtons;
249 delete[] m_radioWidth;
250 delete[] m_radioHeight;
251 }
252
253 // NB: if this code is changed, wxGetWindowForHWND() which relies on having the
254 // radiobox pointer in GWL_USERDATA for radio buttons must be updated too!
255 void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn)
256 {
257 HWND hwndBtn = (HWND)hWndBtn;
258
259 if ( !s_wndprocRadioBtn )
260 s_wndprocRadioBtn = (WXFARPROC)wxGetWindowProc(hwndBtn);
261
262 wxSetWindowProc(hwndBtn, wxRadioBtnWndProc);
263 wxSetWindowUserData(hwndBtn, this);
264 }
265
266 // ----------------------------------------------------------------------------
267 // events generation
268 // ----------------------------------------------------------------------------
269
270 bool wxRadioBox::MSWCommand(WXUINT cmd, WXWORD id)
271 {
272 if ( cmd == BN_CLICKED )
273 {
274 if (id == GetId())
275 return true;
276
277 int selectedButton = wxNOT_FOUND;
278
279 int count = GetCount();
280 for ( int i = 0; i < count; i++ )
281 {
282 if ( id == wxGetWindowId((*m_radioButtons)[i]) )
283 {
284 selectedButton = i;
285
286 break;
287 }
288 }
289
290 if ( selectedButton == wxNOT_FOUND )
291 {
292 // just ignore it - due to a hack with WM_NCHITTEST handling in our
293 // wnd proc, we can receive dummy click messages when we click near
294 // the radiobox edge (this is ugly but Julian wouldn't let me get
295 // rid of this...)
296 return false;
297 }
298
299 if ( selectedButton != m_selectedButton )
300 {
301 m_selectedButton = selectedButton;
302
303 SendNotificationEvent();
304 }
305 //else: don't generate events when the selection doesn't change
306
307 return true;
308 }
309 else
310 return false;
311 }
312
313 void wxRadioBox::Command(wxCommandEvent & event)
314 {
315 SetSelection (event.GetInt());
316 SetFocus();
317 ProcessCommand(event);
318 }
319
320 void wxRadioBox::SendNotificationEvent()
321 {
322 wxCommandEvent event(wxEVT_COMMAND_RADIOBOX_SELECTED, m_windowId);
323 event.SetInt( m_selectedButton );
324 event.SetString( GetString(m_selectedButton) );
325 event.SetEventObject( this );
326 ProcessCommand(event);
327 }
328
329 // ----------------------------------------------------------------------------
330 // simple accessors
331 // ----------------------------------------------------------------------------
332
333 int wxRadioBox::GetCount() const
334 {
335 return m_radioButtons->GetCount();
336 }
337
338 // returns the number of rows
339 int wxRadioBox::GetNumVer() const
340 {
341 if ( m_windowStyle & wxRA_SPECIFY_ROWS )
342 {
343 return m_majorDim;
344 }
345 else
346 {
347 return (GetCount() + m_majorDim - 1)/m_majorDim;
348 }
349 }
350
351 // returns the number of columns
352 int wxRadioBox::GetNumHor() const
353 {
354 if ( m_windowStyle & wxRA_SPECIFY_ROWS )
355 {
356 return (GetCount() + m_majorDim - 1)/m_majorDim;
357 }
358 else
359 {
360 return m_majorDim;
361 }
362 }
363
364 void wxRadioBox::SetString(int item, const wxString& label)
365 {
366 wxCHECK_RET( IsValid(item), wxT("invalid radiobox index") );
367
368 m_radioWidth[item] =
369 m_radioHeight[item] = wxDefaultCoord;
370
371 ::SetWindowText((*m_radioButtons)[item], label.c_str());
372
373 InvalidateBestSize();
374 }
375
376 void wxRadioBox::SetSelection(int N)
377 {
378 wxCHECK_RET( IsValid(N), wxT("invalid radiobox index") );
379
380 // unselect the old button
381 if ( m_selectedButton != wxNOT_FOUND )
382 ::SendMessage((*m_radioButtons)[m_selectedButton], BM_SETCHECK, 0, 0L);
383
384 // and select the new one
385 ::SendMessage((*m_radioButtons)[N], BM_SETCHECK, 1, 0L);
386
387 m_selectedButton = N;
388 }
389
390 // Find string for position
391 wxString wxRadioBox::GetString(int item) const
392 {
393 wxCHECK_MSG( IsValid(item), wxEmptyString,
394 wxT("invalid radiobox index") );
395
396 return wxGetWindowText((*m_radioButtons)[item]);
397 }
398
399 void wxRadioBox::SetFocus()
400 {
401 if ( GetCount() > 0 )
402 {
403 ::SetFocus((*m_radioButtons)[m_selectedButton == wxNOT_FOUND
404 ? 0
405 : m_selectedButton]);
406 }
407 }
408
409 // Enable a specific button
410 bool wxRadioBox::Enable(int item, bool enable)
411 {
412 wxCHECK_MSG( IsValid(item), false,
413 wxT("invalid item in wxRadioBox::Enable()") );
414
415 BOOL ret = ::EnableWindow((*m_radioButtons)[item], enable);
416
417 return (ret == 0) == enable;
418 }
419
420 // Show a specific button
421 bool wxRadioBox::Show(int item, bool show)
422 {
423 wxCHECK_MSG( IsValid(item), false,
424 wxT("invalid item in wxRadioBox::Show()") );
425
426 BOOL ret = ::ShowWindow((*m_radioButtons)[item], show ? SW_SHOW : SW_HIDE);
427
428 bool changed = (ret != 0) == show;
429 if( changed )
430 InvalidateBestSize();
431 return changed;
432 }
433
434 WX_FORWARD_STD_METHODS_TO_SUBWINDOWS(wxRadioBox, wxStaticBox, m_radioButtons)
435
436 // ----------------------------------------------------------------------------
437 // size calculations
438 // ----------------------------------------------------------------------------
439
440 wxSize wxRadioBox::GetMaxButtonSize() const
441 {
442 // calculate the max button size
443 int widthMax = 0,
444 heightMax = 0;
445 const int count = GetCount();
446 for ( int i = 0 ; i < count; i++ )
447 {
448 int width, height;
449 if ( m_radioWidth[i] < 0 )
450 {
451 GetTextExtent(wxGetWindowText((*m_radioButtons)[i]), &width, &height);
452
453 // adjust the size to take into account the radio box itself
454 // FIXME this is totally bogus!
455 width += RADIO_SIZE;
456 height *= 3;
457 height /= 2;
458 }
459 else
460 {
461 width = m_radioWidth[i];
462 height = m_radioHeight[i];
463 }
464
465 if ( widthMax < width )
466 widthMax = width;
467 if ( heightMax < height )
468 heightMax = height;
469 }
470
471 return wxSize(widthMax, heightMax);
472 }
473
474 wxSize wxRadioBox::GetTotalButtonSize(const wxSize& sizeBtn) const
475 {
476 // the radiobox should be big enough for its buttons
477 int cx1, cy1;
478 wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont());
479
480 int extraHeight = cy1;
481
482 int height = GetNumVer() * sizeBtn.y + cy1/2 + extraHeight;
483 int width = GetNumHor() * (sizeBtn.x + cx1) + cx1;
484
485 // Add extra space under the label, if it exists.
486 if (!wxControl::GetLabel().empty())
487 height += cy1/2;
488
489 // and also wide enough for its label
490 int widthLabel;
491 GetTextExtent(GetTitle(), &widthLabel, NULL);
492 widthLabel += RADIO_SIZE; // FIXME this is bogus too
493 if ( widthLabel > width )
494 width = widthLabel;
495
496 return wxSize(width, height);
497 }
498
499 wxSize wxRadioBox::DoGetBestSize() const
500 {
501 wxSize best = GetTotalButtonSize(GetMaxButtonSize());
502 CacheBestSize(best);
503 return best;
504 }
505
506 // Restored old code.
507 void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
508 {
509 int currentX, currentY;
510 GetPosition(&currentX, &currentY);
511 int widthOld, heightOld;
512 GetSize(&widthOld, &heightOld);
513
514 int xx = x;
515 int yy = y;
516
517 if (x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
518 xx = currentX;
519 if (y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
520 yy = currentY;
521
522 int y_offset = 0;
523 int x_offset = 0;
524
525 int cx1, cy1;
526 wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont());
527
528 // Attempt to have a look coherent with other platforms: We compute the
529 // biggest toggle dim, then we align all items according this value.
530 wxSize maxSize = GetMaxButtonSize();
531 int maxWidth = maxSize.x,
532 maxHeight = maxSize.y;
533
534 wxSize totSize = GetTotalButtonSize(maxSize);
535 int totWidth = totSize.x,
536 totHeight = totSize.y;
537
538 // only change our width/height if asked for
539 if ( width == wxDefaultCoord )
540 {
541 if ( sizeFlags & wxSIZE_AUTO_WIDTH )
542 width = totWidth;
543 else
544 width = widthOld;
545 }
546
547 if ( height == wxDefaultCoord )
548 {
549 if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
550 height = totHeight;
551 else
552 height = heightOld;
553 }
554
555 DoMoveWindow(xx, yy, width, height);
556
557 // Now position all the buttons: the current button will be put at
558 // wxPoint(x_offset, y_offset) and the new row/column will start at
559 // startX/startY. The size of all buttons will be the same wxSize(maxWidth,
560 // maxHeight) except for the buttons in the last column which should extend
561 // to the right border of radiobox and thus can be wider than this.
562
563 // Also, remember that wxRA_SPECIFY_COLS means that we arrange buttons in
564 // left to right order and m_majorDim is the number of columns while
565 // wxRA_SPECIFY_ROWS means that the buttons are arranged top to bottom and
566 // m_majorDim is the number of rows.
567
568 x_offset += cx1;
569 y_offset += cy1;
570
571 // Add extra space under the label, if it exists.
572 if (!wxControl::GetLabel().empty())
573 y_offset += cy1/2;
574
575 int startX = x_offset;
576 int startY = y_offset;
577
578 const int count = GetCount();
579 for ( int i = 0; i < count; i++ )
580 {
581 // the last button in the row may be wider than the other ones as the
582 // radiobox may be wider than the sum of the button widths (as it
583 // happens, for example, when the radiobox label is very long)
584 bool isLastInTheRow;
585 if ( m_windowStyle & wxRA_SPECIFY_COLS )
586 {
587 // item is the last in its row if it is a multiple of the number of
588 // columns or if it is just the last item
589 int n = i + 1;
590 isLastInTheRow = ((n % m_majorDim) == 0) || (n == count);
591 }
592 else // wxRA_SPECIFY_ROWS
593 {
594 // item is the last in the row if it is in the last columns
595 isLastInTheRow = i >= (count/m_majorDim)*m_majorDim;
596 }
597
598 // is this the start of new row/column?
599 if ( i && (i % m_majorDim == 0) )
600 {
601 if ( m_windowStyle & wxRA_SPECIFY_ROWS )
602 {
603 // start of new column
604 y_offset = startY;
605 x_offset += maxWidth + cx1;
606 }
607 else // start of new row
608 {
609 x_offset = startX;
610 y_offset += maxHeight;
611 if (m_radioWidth[0]>0)
612 y_offset += cy1/2;
613 }
614 }
615
616 int widthBtn;
617 if ( isLastInTheRow )
618 {
619 // make the button go to the end of radio box
620 widthBtn = startX + width - x_offset - 2*cx1;
621 if ( widthBtn < maxWidth )
622 widthBtn = maxWidth;
623 }
624 else
625 {
626 // normal button, always of the same size
627 widthBtn = maxWidth;
628 }
629
630 // make all buttons of the same, maximal size - like this they cover
631 // the radiobox entirely and the radiobox tooltips are always shown
632 // (otherwise they are not when the mouse pointer is in the radiobox
633 // part not belonging to any radiobutton)
634 ::MoveWindow((*m_radioButtons)[i],
635 x_offset, y_offset, widthBtn, maxHeight,
636 TRUE);
637
638 // where do we put the next button?
639 if ( m_windowStyle & wxRA_SPECIFY_ROWS )
640 {
641 // below this one
642 y_offset += maxHeight;
643 if (m_radioWidth[0]>0)
644 y_offset += cy1/2;
645 }
646 else
647 {
648 // to the right of this one
649 x_offset += widthBtn + cx1;
650 }
651 }
652 }
653
654 // ----------------------------------------------------------------------------
655 // radio box drawing
656 // ----------------------------------------------------------------------------
657
658 #ifndef __WXWINCE__
659
660 WXHRGN wxRadioBox::MSWGetRegionWithoutChildren()
661 {
662 RECT rc;
663 ::GetWindowRect(GetHwnd(), &rc);
664 HRGN hrgn = ::CreateRectRgn(rc.left, rc.top, rc.right + 1, rc.bottom + 1);
665
666 const size_t count = GetCount();
667 for ( size_t i = 0; i < count; ++i )
668 {
669 ::GetWindowRect((*m_radioButtons)[i], &rc);
670 AutoHRGN hrgnchild(::CreateRectRgnIndirect(&rc));
671 ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF);
672 }
673
674 return (WXHRGN)hrgn;
675 }
676
677 WXLRESULT
678 wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
679 {
680 // FIXME: Without this, the radiobox corrupts other controls as it moves
681 // in a dynamic layout. Refreshing causes flicker, but it's better than
682 // leaving droppings. Note that for some reason, wxStaticBox doesn't need
683 // this (perhaps because it has no real children?)
684 if ( nMsg == WM_MOVE )
685 {
686 WXLRESULT res = wxControl::MSWWindowProc(nMsg, wParam, lParam);
687 wxRect rect = GetRect();
688 GetParent()->Refresh(true, & rect);
689 return res;
690 }
691
692 return wxStaticBox::MSWWindowProc(nMsg, wParam, lParam);
693 }
694
695 #endif // __WXWINCE__
696
697 // ---------------------------------------------------------------------------
698 // window proc for radio buttons
699 // ---------------------------------------------------------------------------
700
701 LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd,
702 UINT message,
703 WPARAM wParam,
704 LPARAM lParam)
705 {
706 switch ( message )
707 {
708 case WM_GETDLGCODE:
709 // we must tell IsDialogMessage()/our kbd processing code that we
710 // want to process arrows ourselves because neither of them is
711 // smart enough to handle arrows properly for us
712 {
713 long lDlgCode = ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd,
714 message, wParam, lParam);
715
716 return lDlgCode | DLGC_WANTARROWS;
717 }
718
719 #if wxUSE_TOOLTIPS
720 case WM_NOTIFY:
721 {
722 NMHDR* hdr = (NMHDR *)lParam;
723 if ( hdr->code == TTN_NEEDTEXT )
724 {
725 wxRadioBox *
726 radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);
727
728 wxCHECK_MSG( radiobox, 0,
729 wxT("radio button without radio box?") );
730
731 wxToolTip *tooltip = radiobox->GetToolTip();
732 if ( tooltip )
733 {
734 TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam;
735 ttt->lpszText = (wxChar *)tooltip->GetTip().c_str();
736 }
737
738 // processed
739 return 0;
740 }
741 }
742 break;
743 #endif // wxUSE_TOOLTIPS
744
745 case WM_KEYDOWN:
746 {
747 wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);
748
749 wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );
750
751 bool processed = true;
752
753 wxDirection dir;
754 switch ( wParam )
755 {
756 case VK_UP:
757 dir = wxUP;
758 break;
759
760 case VK_LEFT:
761 dir = wxLEFT;
762 break;
763
764 case VK_DOWN:
765 dir = wxDOWN;
766 break;
767
768 case VK_RIGHT:
769 dir = wxRIGHT;
770 break;
771
772 default:
773 processed = false;
774
775 // just to suppress the compiler warning
776 dir = wxALL;
777 }
778
779 if ( processed )
780 {
781 int selOld = radiobox->GetSelection();
782 int selNew = radiobox->GetNextItem
783 (
784 selOld,
785 dir,
786 radiobox->GetWindowStyle()
787 );
788
789 if ( selNew != selOld )
790 {
791 radiobox->SetSelection(selNew);
792 radiobox->SetFocus();
793
794 // emulate the button click
795 radiobox->SendNotificationEvent();
796
797 return 0;
798 }
799 }
800 }
801 break;
802
803 case WM_SETFOCUS:
804 case WM_KILLFOCUS:
805 {
806 wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);
807
808 wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );
809
810 // if we don't do this, no focus events are generated for the
811 // radiobox and, besides, we need to notify the parent about
812 // the focus change, otherwise the focus handling logic in
813 // wxControlContainer doesn't work
814 if ( message == WM_SETFOCUS )
815 radiobox->HandleSetFocus((WXHWND)wParam);
816 else
817 radiobox->HandleKillFocus((WXHWND)wParam);
818 }
819 break;
820
821 #ifndef __WXWINCE__
822 case WM_HELP:
823 {
824 wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);
825
826 wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );
827
828 bool processed = false;
829
830 wxEvtHandler * const handler = radiobox->GetEventHandler();
831
832 HELPINFO* info = (HELPINFO*) lParam;
833 if ( info->iContextType == HELPINFO_WINDOW )
834 {
835 for ( wxWindow* subjectOfHelp = radiobox;
836 subjectOfHelp;
837 subjectOfHelp = subjectOfHelp->GetParent() )
838 {
839 wxHelpEvent helpEvent(wxEVT_HELP,
840 subjectOfHelp->GetId(),
841 wxPoint(info->MousePos.x,
842 info->MousePos.y));
843 helpEvent.SetEventObject(radiobox);
844 if ( handler->ProcessEvent(helpEvent) )
845 {
846 processed = true;
847 break;
848 }
849 }
850 }
851 else if (info->iContextType == HELPINFO_MENUITEM)
852 {
853 wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
854 helpEvent.SetEventObject(radiobox);
855 processed = handler->ProcessEvent(helpEvent);
856 }
857
858 if ( processed )
859 return 0;
860 }
861 break;
862 #endif // !__WXWINCE__
863 }
864
865 return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, message, wParam, lParam);
866 }
867
868 #endif // wxUSE_RADIOBOX
869