1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      David Webster 
   8 // Copyright:   (c) David Webster 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  18     #include "wx/wxchar.h" 
  19     #include "wx/string.h" 
  20     #include "wx/bitmap.h" 
  22     #include "wx/radiobox.h" 
  25 #include "wx/os2/private.h" 
  27 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox
, wxControl
) 
  29 // --------------------------------------------------------------------------- 
  31 // --------------------------------------------------------------------------- 
  33 // wnd proc for radio buttons 
  34 MRESULT 
wxRadioBtnWndProc(HWND hWnd
, 
  39 // --------------------------------------------------------------------------- 
  41 // --------------------------------------------------------------------------- 
  43 // the pointer to standard radio button wnd proc 
  44 static s_wndprocRadioBtn 
= NULL
; 
  46 // =========================================================================== 
  48 // =========================================================================== 
  50 // --------------------------------------------------------------------------- 
  52 // --------------------------------------------------------------------------- 
  54 int wxRadioBox::GetCount() const 
  59 int wxRadioBox::GetColumnCount() const 
  64 int wxRadioBox::GetRowCount() const 
  69 int wxRadioBox::GetNumVer() const 
  71     if ( m_windowStyle 
& wxRA_SPECIFY_ROWS 
) 
  77         return (m_noItems 
+ m_majorDim 
- 1)/m_majorDim
; 
  81 int wxRadioBox::GetNumHor() const 
  83     if ( m_windowStyle 
& wxRA_SPECIFY_ROWS 
) 
  85         return (m_noItems 
+ m_majorDim 
- 1)/m_majorDim
; 
  93 bool wxRadioBox::OS2Command(WXUINT cmd
, WXWORD id
) 
  97     if ( cmd == BN_CLICKED ) 
  99         int selectedButton = -1; 
 101         for ( int i = 0; i < m_noItems; i++ ) 
 103             if ( id == wxGetWindowId(m_radioButtons[i]) ) 
 111         wxASSERT_MSG( selectedButton != -1, wxT("click from alien button?") ); 
 113         if ( selectedButton != m_selectedButton ) 
 115             m_selectedButton = selectedButton; 
 117             SendNotificationEvent(); 
 119         //else: don't generate events when the selection doesn't change 
 129 #if WXWIN_COMPATIBILITY 
 130 wxRadioBox::wxRadioBox(wxWindow 
*parent
, wxFunction func
, const char *title
, 
 131         int x
, int y
, int width
, int height
, 
 132         int n
, char **choices
, 
 133         int majorDim
, long style
, const char *name
) 
 135     wxString 
*choices2 
= new wxString
[n
]; 
 136     for ( int i 
= 0; i 
< n
; i 
++) choices2
[i
] = choices
[i
]; 
 137     Create(parent
, -1, title
, wxPoint(x
, y
), wxSize(width
, height
), n
, choices2
, majorDim
, style
, 
 138             wxDefaultValidator
, name
); 
 146 wxRadioBox::wxRadioBox() 
 148     m_selectedButton 
= -1; 
 151     m_radioButtons 
= NULL
; 
 154     m_radioHeight 
= NULL
; 
 157 bool wxRadioBox::Create(wxWindow 
*parent
, wxWindowID id
, const wxString
& title
, 
 158         const wxPoint
& pos
, const wxSize
& size
, 
 159         int n
, const wxString choices
[], 
 160         int majorDim
, long style
, 
 162         const wxValidator
& val
, const wxString
& name
) 
 165     m_selectedButton 
= -1; 
 172     parent
->AddChild(this); 
 173     m_backgroundColour 
= parent
->GetBackgroundColour(); 
 174     m_foregroundColour 
= parent
->GetForegroundColour(); 
 176     m_windowStyle 
= (long&)style
; 
 184         m_windowId 
= NewControlId(); 
 191         m_majorDim 
= majorDim
; 
 192     m_noRowsOrCols 
= majorDim
; 
 194     long msStyle 
= 0; // TODO: GROUP_FLAGS; 
 197     WXDWORD exStyle 
= Determine3DEffects(0, &want3D
); 
 199     HWND hwndParent 
= (HWND
)parent
->GetHWND(); 
 201     m_hWnd = (WXHWND)::CreateWindowEx 
 217         Ctl3dSubclassCtl((HWND)m_hWnd); 
 220 #endif // wxUSE_CTL3D 
 222     SetFont(parent
->GetFont()); 
 226     // Some radio boxes test consecutive id. 
 227     (void)NewControlId(); 
 228     m_radioButtons 
= new WXHWND
[n
]; 
 229     m_radioWidth 
= new int[n
]; 
 230     m_radioHeight 
= new int[n
]; 
 232     for (i 
= 0; i 
< n
; i
++) 
 236         m_radioWidth[i] = m_radioHeight[i] = -1; 
 238         if ( i == 0 && style == 0 ) 
 239             groupStyle = WS_GROUP; 
 240         long newId = NewControlId(); 
 241         long msStyle = groupStyle | RADIO_FLAGS; 
 243         HWND hwndBtn = CreateWindowEx(exStyle, RADIO_CLASS, 
 247                                       (HMENU)newId, wxGetInstance(), 
 250         m_radioButtons[i] = (WXHWND)hwndBtn; 
 252         SubclassRadioButton((WXHWND)hwndBtn); 
 254         wxFont& font = GetFont(); 
 257             SendMessage(hwndBtn, WM_SETFONT, 
 258                         (WPARAM)font.GetResourceHandle(), 0L); 
 261         m_subControls.Append((wxObject *)(WXDWORD)(WXWORD)newId); 
 265     // Create a dummy radio control to end the group. 
 266 //    (void)CreateWindowEx(0, RADIO_CLASS, wxT(""), WS_GROUP | RADIO_FLAGS, 
 267 //                         0, 0, 0, 0, hwndParent, 
 268 //                         (HMENU)NewControlId(), wxGetInstance(), NULL); 
 272     SetSize(x
, y
, width
, height
); 
 277 wxRadioBox::~wxRadioBox() 
 279     m_isBeingDeleted 
= TRUE
; 
 286         for (i = 0; i < m_noItems; i++) 
 287             ::DestroyWindow((HWND)m_radioButtons[i]); 
 288         delete[] m_radioButtons; 
 293         delete[] m_radioWidth
; 
 295         delete[] m_radioHeight
; 
 299 void wxRadioBox::SetString(int item
, const wxString
& label
) 
 301     wxCHECK_RET( item 
>= 0 && item 
< m_noItems
, wxT("invalid radiobox index") ); 
 303     m_radioWidth
[item
] = m_radioHeight
[item
] = -1; 
 304     ::WinSetWindowText((HWND
)m_radioButtons
[item
], label
.c_str()); 
 307 wxString 
wxRadioBox::GetLabel(int item
) const 
 309     wxCHECK_MSG( item 
>= 0 && item 
< m_noItems
, wxT(""), wxT("invalid radiobox index") ); 
 311     return wxGetWindowText(m_radioButtons
[item
]); 
 314 void wxRadioBox::SetLabel(int item
, const wxString
& label
) 
 316     wxCHECK_RET( item 
>= 0 && item 
< m_noItems
, wxT("invalid radiobox index") ); 
 318     m_radioWidth
[item
] = m_radioHeight
[item
] = -1; 
 319 // TODO:    SetWindowText((HWND)m_radioButtons[item], label.c_str()); 
 322 void wxRadioBox::SetLabel(int item
, wxBitmap 
*bitmap
) 
 325        m_radioWidth[item] = bitmap->GetWidth() + FB_MARGIN; 
 326        m_radioHeight[item] = bitmap->GetHeight() + FB_MARGIN; 
 328     wxFAIL_MSG(wxT("not implemented")); 
 331 int wxRadioBox::FindString(const wxString
& s
) const 
 333     for (int i 
= 0; i 
< m_noItems
; i
++) 
 335         if ( s 
== wxGetWindowText(m_radioButtons
[i
]) ) 
 342 void wxRadioBox::SetSelection(int N
) 
 344     wxCHECK_RET( (N 
>= 0) && (N 
< m_noItems
), wxT("invalid radiobox index") ); 
 346     // Following necessary for Win32s, because Win32s translate BM_SETCHECK 
 349     if (m_selectedButton >= 0 && m_selectedButton < m_noItems) 
 350         ::SendMessage((HWND) m_radioButtons[m_selectedButton], BM_SETCHECK, 0, 0L); 
 352     ::SendMessage((HWND)m_radioButtons[N], BM_SETCHECK, 1, 0L); 
 353     ::SetFocus((HWND)m_radioButtons[N]); 
 355     m_selectedButton 
= N
; 
 358 // Get single selection, for single choice list items 
 359 int wxRadioBox::GetSelection() const 
 361     return m_selectedButton
; 
 364 // Find string for position 
 365 wxString 
wxRadioBox::GetString(int N
) const 
 367     return wxGetWindowText(m_radioButtons
[N
]); 
 370 // Restored old code. 
 371 void wxRadioBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
 373     int currentX
, currentY
; 
 374     GetPosition(¤tX
, ¤tY
); 
 375     int widthOld
, heightOld
; 
 376     GetSize(&widthOld
, &heightOld
); 
 381     if (x 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 383     if (y 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 390     int current_width
, cyf
; 
 393     wxGetCharSize(m_hWnd
, &cx1
, &cy1
, & GetFont()); 
 395     // Attempt to have a look coherent with other platforms: We compute the 
 396     // biggest toggle dim, then we align all items according this value. 
 401     for (i 
= 0 ; i 
< m_noItems
; i
++) 
 405         if (m_radioWidth
[i
]<0) 
 407             // It's a labelled toggle 
 408             buf 
= wxGetWindowText(m_radioButtons
[i
]); 
 409             GetTextExtent(buf
, ¤t_width
, &cyf
); 
 410             eachWidth 
= (int)(current_width 
+ RADIO_SIZE
); 
 411             eachHeight 
= (int)((3*cyf
)/2); 
 415             eachWidth 
= m_radioWidth
[i
]; 
 416             eachHeight 
= m_radioHeight
[i
]; 
 419         if (maxWidth
<eachWidth
) 
 420             maxWidth 
= eachWidth
; 
 421         if (maxHeight
<eachHeight
) 
 422             maxHeight 
= eachHeight
; 
 430         int nbHor 
= GetNumHor(), 
 433         // this formula works, but I don't know why. 
 434         // Please, be sure what you do if you modify it!! 
 435         if (m_radioWidth
[0]<0) 
 436             totHeight 
= (nbVer 
* maxHeight
) + cy1
/2; 
 438             totHeight 
= nbVer 
* (maxHeight
+cy1
/2); 
 439         totWidth  
= nbHor 
* (maxWidth
+cx1
); 
 441         int extraHeight 
= cy1
; 
 443         // only change our width/height if asked for 
 446             if ( sizeFlags 
& wxSIZE_AUTO_WIDTH 
) 
 447                 width 
= totWidth 
+ cx1
; 
 454             if ( sizeFlags 
& wxSIZE_AUTO_HEIGHT 
) 
 455                 height 
= totHeight 
+ extraHeight
; 
 460 // TODO:  MoveWindow(GetHwnd(), x_offset, y_offset, width, height, TRUE); 
 466     int startX 
= x_offset
; 
 467     int startY 
= y_offset
; 
 469     for ( i 
= 0 ; i 
< m_noItems
; i
++) 
 471         // Bidimensional radio adjustment 
 472         if (i
&&((i%m_majorDim
)==0)) // Why is this omitted for i = 0? 
 474             if (m_windowStyle 
& wxRA_VERTICAL
) 
 477                 x_offset 
+= maxWidth 
+ cx1
; 
 482                 y_offset 
+= maxHeight
; 
 483                 if (m_radioWidth
[0]>0) 
 489         if (m_radioWidth
[i
]<0) 
 491             // It's a labeled item 
 492             buf 
= wxGetWindowText(m_radioButtons
[i
]); 
 493             GetTextExtent(buf
, ¤t_width
, &cyf
); 
 495             // How do we find out radio button bitmap size!! 
 496             // By adjusting them carefully, manually :-) 
 497             eachWidth 
= (int)(current_width 
+ RADIO_SIZE
); 
 498             eachHeight 
= (int)((3*cyf
)/2); 
 502             eachWidth 
= m_radioWidth
[i
]; 
 503             eachHeight 
= m_radioHeight
[i
]; 
 508         MoveWindow((HWND)m_radioButtons[i], x_offset, y_offset, 
 509                    eachWidth, eachHeight, 
 512         if (m_windowStyle 
& wxRA_SPECIFY_ROWS
) 
 514             y_offset 
+= maxHeight
; 
 515             if (m_radioWidth
[0]>0) 
 519             x_offset 
+= maxWidth 
+ cx1
; 
 523 void wxRadioBox::GetSize(int *width
, int *height
) const 
 526     rect
.xLeft 
= -1; rect
.xRight 
= -1; rect
.yTop 
= -1; rect
.yBottom 
= -1; 
 529         wxFindMaxSize(m_hWnd
, &rect
); 
 532     for (i 
= 0; i 
< m_noItems
; i
++) 
 533         wxFindMaxSize(m_radioButtons
[i
], &rect
); 
 535     *width 
= rect
.xRight 
- rect
.xLeft
; 
 536     *height 
= rect
.yBottom 
- rect
.yTop
; 
 539 void wxRadioBox::GetPosition(int *x
, int *y
) const 
 541     wxWindow 
*parent 
= GetParent(); 
 543     rect
.xLeft 
= -1; rect
.xRight 
= -1; rect
.yTop 
= -1; rect
.yBottom 
= -1; 
 546     for (i 
= 0; i 
< m_noItems
; i
++) 
 547         wxFindMaxSize(m_radioButtons
[i
], &rect
); 
 550         wxFindMaxSize(m_hWnd
, &rect
); 
 552     // Since we now have the absolute screen coords, 
 553     // if there's a parent we must subtract its top left corner 
 555     point
.x 
= rect
.xLeft
; 
 561         ::ScreenToClient((HWND) parent->GetHWND(), &point); 
 564     // We may be faking the client origin. 
 565     // So a window that's really at (0, 30) may appear 
 566     // (to wxWin apps) to be at (0, 0). 
 569         wxPoint 
pt(GetParent()->GetClientAreaOrigin()); 
 578 void wxRadioBox::SetFocus() 
 584         if (m_selectedButton == -1) 
 585             ::SetFocus((HWND) m_radioButtons[0]); 
 587             ::SetFocus((HWND) m_radioButtons[m_selectedButton]); 
 592 bool wxRadioBox::Show(bool show
) 
 594     if ( !wxControl::Show(show
) ) 
 597     int nCmdShow 
= 0; // TODO: show ? SW_SHOW : SW_HIDE; 
 598     for ( int i 
= 0; i 
< m_noItems
; i
++ ) 
 600 // TODO:        ::ShowWindow((HWND)m_radioButtons[i], nCmdShow); 
 606 // Enable a specific button 
 607 void wxRadioBox::Enable(int item
, bool enable
) 
 609     wxCHECK_RET( item 
>= 0 && item 
< m_noItems
, 
 610                  wxT("invalid item in wxRadioBox::Enable()") ); 
 612 // TODO: ::EnableWindow((HWND) m_radioButtons[item], enable); 
 615 // Enable all controls 
 616 bool wxRadioBox::Enable(bool enable
) 
 618     if ( !wxControl::Enable(enable
) ) 
 623     for (int i = 0; i < m_noItems; i++) 
 624         ::EnableWindow((HWND) m_radioButtons[i], enable); 
 629 // Show a specific button 
 630 void wxRadioBox::Show(int item
, bool show
) 
 632     wxCHECK_RET( item 
>= 0 && item 
< m_noItems
, 
 633                  wxT("invalid item in wxRadioBox::Show()") ); 
 635 // TODO:    ::ShowWindow((HWND)m_radioButtons[item], show ? SW_SHOW : SW_HIDE); 
 638 WXHBRUSH 
wxRadioBox::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
, 
 639         WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
) 
 643     if (GetParent()->GetTransparentBackground()) 
 644         SetBkMode((HDC) pDC, TRANSPARENT); 
 646         SetBkMode((HDC) pDC, OPAQUE); 
 648     ::SetBkColor((HDC) pDC, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); 
 649     ::SetTextColor((HDC) pDC, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue())); 
 651     wxBrush 
*backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
); 
 653     return (WXHBRUSH
) backgroundBrush
->GetResourceHandle(); 
 656 // For single selection items only 
 657 wxString 
wxRadioBox::GetStringSelection() const 
 660     int sel 
= GetSelection(); 
 662         result 
= GetString(sel
); 
 667 bool wxRadioBox::SetStringSelection(const wxString
& s
) 
 669     int sel 
= FindString (s
); 
 679 bool wxRadioBox::ContainsHWND(WXHWND hWnd
) const 
 682     for (i 
= 0; i 
< Number(); i
++) 
 684         if (GetRadioButtons()[i
] == hWnd
) 
 691 void wxRadioBox::Command (wxCommandEvent 
& event
) 
 693     SetSelection (event
.m_commandInt
); 
 694     ProcessCommand (event
); 
 697 void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn
) 
 699     HWND hwndBtn 
= (HWND
)hWndBtn
; 
 703     if ( !s_wndprocRadioBtn ) 
 704         s_wndprocRadioBtn = (WXFARPROC)::GetWindowLong(hwndBtn, GWL_WNDPROC); 
 706     // No GWL_USERDATA in Win16, so omit this subclassing. 
 707     ::SetWindowLong(hwndBtn, GWL_WNDPROC, (long)wxRadioBtnWndProc); 
 708     ::SetWindowLong(hwndBtn, GWL_USERDATA, (long)this); 
 712 void wxRadioBox::SendNotificationEvent() 
 714     wxCommandEvent 
event(wxEVT_COMMAND_RADIOBOX_SELECTED
, m_windowId
); 
 715     event
.SetInt( m_selectedButton 
); 
 716     event
.SetString( GetString(m_selectedButton
) ); 
 717     event
.SetEventObject( this ); 
 718     ProcessCommand(event
); 
 721 // --------------------------------------------------------------------------- 
 722 // window proc for radio buttons 
 723 // --------------------------------------------------------------------------- 
 725 MRESULT 
wxRadioBtnWndProc(HWND hwnd
, 
 730     bool processed 
= TRUE
; 
 731 //    if ( msg != WM_KEYDOWN ) 
 732 //        processed = FALSE; 
 736         wxRadioBox 
*radiobox 
= NULL
; // TODO: (wxRadioBox *)::GetWindowLong(hwnd, GWL_USERDATA); 
 738         wxCHECK_MSG( radiobox
, 0, wxT("radio button without radio box?") ); 
 740         int sel 
= radiobox
->GetSelection(); 
 751                 sel -= radiobox->GetNumVer(); 
 759                 sel += radiobox->GetNumVer(); 
 764                     wxNavigationKeyEvent event; 
 765                     event.SetDirection(!(::GetKeyState(VK_SHIFT) & 0x100)); 
 766                     event.SetWindowChange(FALSE); 
 767                     event.SetEventObject(radiobox); 
 769                     if ( radiobox->GetEventHandler()->ProcessEvent(event) ) 
 780             if ( sel 
>= 0 && sel 
< radiobox
->Number() ) 
 782                 radiobox
->SetSelection(sel
); 
 784                 // emulate the button click 
 785                 radiobox
->SendNotificationEvent(); 
 793         return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, msg, wParam, lParam);