1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  21     #pragma implementation "radiobox.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  34     #include "wx/bitmap.h" 
  36     #include "wx/radiobox.h" 
  39 #include "wx/msw/private.h" 
  41 #if !USE_SHARED_LIBRARY 
  42     IMPLEMENT_DYNAMIC_CLASS(wxRadioBox
, wxControl
) 
  45 // --------------------------------------------------------------------------- 
  47 // --------------------------------------------------------------------------- 
  49 // wnd proc for radio buttons 
  51 LRESULT APIENTRY _EXPORT 
wxRadioBtnWndProc(HWND hWnd
, 
  56 // --------------------------------------------------------------------------- 
  58 // --------------------------------------------------------------------------- 
  60 // the pointer to standard radio button wnd proc 
  61 static WXFARPROC s_wndprocRadioBtn 
= (WXFARPROC
)NULL
; 
  65 // =========================================================================== 
  67 // =========================================================================== 
  69 // --------------------------------------------------------------------------- 
  71 // --------------------------------------------------------------------------- 
  73 int wxRadioBox::GetNumVer() const 
  75     if ( m_windowStyle 
& wxRA_SPECIFY_ROWS 
) 
  81         return (m_noItems 
+ m_majorDim 
- 1)/m_majorDim
; 
  85 int wxRadioBox::GetNumHor() const 
  87     if ( m_windowStyle 
& wxRA_SPECIFY_ROWS 
) 
  89         return (m_noItems 
+ m_majorDim 
- 1)/m_majorDim
; 
  97 bool wxRadioBox::MSWCommand(WXUINT cmd
, WXWORD id
) 
  99     if ( cmd 
== BN_CLICKED 
) 
 101         int selectedButton 
= -1; 
 103         for ( int i 
= 0; i 
< m_noItems
; i
++ ) 
 105             if ( id 
== wxGetWindowId(m_radioButtons
[i
]) ) 
 113         wxASSERT_MSG( selectedButton 
!= -1, _T("click from alien button?") ); 
 115         if ( selectedButton 
!= m_selectedButton 
) 
 117             m_selectedButton 
= selectedButton
; 
 119             SendNotificationEvent(); 
 121         //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
, 
 161         const wxValidator
& val
, const wxString
& name
) 
 163     m_selectedButton 
= -1; 
 169     parent
->AddChild(this); 
 170     m_backgroundColour 
= parent
->GetBackgroundColour(); 
 171     m_foregroundColour 
= parent
->GetForegroundColour(); 
 173     m_windowStyle 
= (long&)style
; 
 181         m_windowId 
= NewControlId(); 
 188         m_majorDim 
= majorDim
; 
 189     m_noRowsOrCols 
= majorDim
; 
 191     long msStyle 
= GROUP_FLAGS
; 
 194     WXDWORD exStyle 
= Determine3DEffects(0, &want3D
); 
 196     HWND hwndParent 
= (HWND
)parent
->GetHWND(); 
 198     m_hWnd 
= (WXHWND
)::CreateWindowEx
 
 214         Ctl3dSubclassCtl((HWND
)m_hWnd
); 
 217 #endif // wxUSE_CTL3D 
 219     SetFont(parent
->GetFont()); 
 223     // Some radio boxes test consecutive id. 
 224     (void)NewControlId(); 
 225     m_radioButtons 
= new WXHWND
[n
]; 
 226     m_radioWidth 
= new int[n
]; 
 227     m_radioHeight 
= new int[n
]; 
 229     for (i 
= 0; i 
< n
; i
++) 
 231         m_radioWidth
[i
] = m_radioHeight
[i
] = -1; 
 233         if ( i 
== 0 && style 
== 0 ) 
 234             groupStyle 
= WS_GROUP
; 
 235         long newId 
= NewControlId(); 
 236         long msStyle 
= groupStyle 
| RADIO_FLAGS
; 
 238         HWND hwndBtn 
= CreateWindowEx(exStyle
, RADIO_CLASS
, 
 242                                       (HMENU
)newId
, wxGetInstance(), 
 245         m_radioButtons
[i
] = (WXHWND
)hwndBtn
; 
 247         SubclassRadioButton((WXHWND
)hwndBtn
); 
 249         wxFont
& font 
= GetFont(); 
 252             SendMessage(hwndBtn
, WM_SETFONT
, 
 253                         (WPARAM
)font
.GetResourceHandle(), 0L); 
 256         m_subControls
.Append((wxObject 
*)(WXWORD
)newId
); 
 259     // Create a dummy radio control to end the group. 
 260     (void)CreateWindowEx(0, RADIO_CLASS
, _T(""), WS_GROUP 
| RADIO_FLAGS
, 
 261                          0, 0, 0, 0, hwndParent
, 
 262                          (HMENU
)NewControlId(), wxGetInstance(), NULL
); 
 266     SetSize(x
, y
, width
, height
); 
 271 wxRadioBox::~wxRadioBox() 
 273     m_isBeingDeleted 
= TRUE
; 
 278         for (i 
= 0; i 
< m_noItems
; i
++) 
 279             ::DestroyWindow((HWND
)m_radioButtons
[i
]); 
 280         delete[] m_radioButtons
; 
 284         delete[] m_radioWidth
; 
 286         delete[] m_radioHeight
; 
 290 wxString 
wxRadioBox::GetLabel(int item
) const 
 292     wxCHECK_MSG( item 
>= 0 && item 
< m_noItems
, _T(""), _T("invalid radiobox index") ); 
 294     return wxGetWindowText(m_radioButtons
[item
]); 
 297 void wxRadioBox::SetLabel(int item
, const wxString
& label
) 
 299     wxCHECK_RET( item 
>= 0 && item 
< m_noItems
, _T("invalid radiobox index") ); 
 301     m_radioWidth
[item
] = m_radioHeight
[item
] = -1; 
 302     SetWindowText((HWND
)m_radioButtons
[item
], label
.c_str()); 
 305 void wxRadioBox::SetLabel(int item
, wxBitmap 
*bitmap
) 
 308        m_radioWidth[item] = bitmap->GetWidth() + FB_MARGIN; 
 309        m_radioHeight[item] = bitmap->GetHeight() + FB_MARGIN; 
 311     wxFAIL_MSG(_T("not implemented")); 
 314 int wxRadioBox::FindString(const wxString
& s
) const 
 316     for (int i 
= 0; i 
< m_noItems
; i
++) 
 318         if ( s 
== wxGetWindowText(m_radioButtons
[i
]) ) 
 325 void wxRadioBox::SetSelection(int N
) 
 327     wxCHECK_RET( (N 
>= 0) && (N 
< m_noItems
), _T("invalid radiobox index") ); 
 329     // Following necessary for Win32s, because Win32s translate BM_SETCHECK 
 330     if (m_selectedButton 
>= 0 && m_selectedButton 
< m_noItems
) 
 331         ::SendMessage((HWND
) m_radioButtons
[m_selectedButton
], BM_SETCHECK
, 0, 0L); 
 333     ::SendMessage((HWND
)m_radioButtons
[N
], BM_SETCHECK
, 1, 0L); 
 334     ::SetFocus((HWND
)m_radioButtons
[N
]); 
 336     m_selectedButton 
= N
; 
 339 // Get single selection, for single choice list items 
 340 int wxRadioBox::GetSelection() const 
 342     return m_selectedButton
; 
 345 // Find string for position 
 346 wxString 
wxRadioBox::GetString(int N
) const 
 348     return wxGetWindowText(m_radioButtons
[N
]); 
 351 // Restored old code. 
 352 void wxRadioBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
 354   int currentX
, currentY
; 
 355   GetPosition(¤tX
, ¤tY
); 
 359   if (x 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 361   if (y 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 368   int current_width
, cyf
; 
 371   wxGetCharSize(m_hWnd
, &cx1
, &cy1
, & GetFont()); 
 372   // Attempt to have a look coherent with other platforms: 
 373   // We compute the biggest toggle dim, then we align all 
 374   // items according this value. 
 379   for (i 
= 0 ; i 
< m_noItems
; i
++) 
 383     if (m_radioWidth
[i
]<0) 
 385       // It's a labelled toggle 
 386       GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300); 
 387       GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & GetFont()); 
 388       eachWidth 
= (int)(current_width 
+ RADIO_SIZE
); 
 389       eachHeight 
= (int)((3*cyf
)/2); 
 393       eachWidth 
= m_radioWidth
[i
]; 
 394       eachHeight 
= m_radioHeight
[i
]; 
 396     if (maxWidth
<eachWidth
) maxWidth 
= eachWidth
; 
 397     if (maxHeight
<eachHeight
) maxHeight 
= eachHeight
; 
 405     int nbHor 
= GetNumHor(), 
 408     // this formula works, but I don't know why. 
 409     // Please, be sure what you do if you modify it!! 
 410     if (m_radioWidth
[0]<0) 
 411       totHeight 
= (nbVer 
* maxHeight
) + cy1
/2; 
 413       totHeight 
= nbVer 
* (maxHeight
+cy1
/2); 
 414     totWidth  
= nbHor 
* (maxWidth
+cx1
); 
 417     // Requires a bigger group box in plain Windows 
 418     MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+(3*cy1
)/2,TRUE
); 
 420     MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+cy1
,TRUE
); 
 427   y_offset 
+= (int)(cy1
/2); // Fudge factor since buttons overlapped label 
 428                             // JACS 2/12/93. CTL3D draws group label quite high. 
 430   int startX 
= x_offset
; 
 431   int startY 
= y_offset
; 
 433   for ( i 
= 0 ; i 
< m_noItems
; i
++) 
 435     // Bidimensional radio adjustment 
 436     if (i
&&((i%m_majorDim
)==0)) // Why is this omitted for i = 0? 
 438       if (m_windowStyle 
& wxRA_VERTICAL
) 
 441         x_offset 
+= maxWidth 
+ cx1
; 
 446         y_offset 
+= maxHeight
; 
 447         if (m_radioWidth
[0]>0) 
 453     if (m_radioWidth
[i
]<0) 
 455       // It's a labeled item 
 456       GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300); 
 457       GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & GetFont()); 
 459       // How do we find out radio button bitmap size!! 
 460       // By adjusting them carefully, manually :-) 
 461       eachWidth 
= (int)(current_width 
+ RADIO_SIZE
); 
 462       eachHeight 
= (int)((3*cyf
)/2); 
 466       eachWidth 
= m_radioWidth
[i
]; 
 467       eachHeight 
= m_radioHeight
[i
]; 
 470     MoveWindow((HWND
) m_radioButtons
[i
],x_offset
,y_offset
,eachWidth
,eachHeight
,TRUE
); 
 471     if (m_windowStyle 
& wxRA_SPECIFY_ROWS
) 
 473       y_offset 
+= maxHeight
; 
 474       if (m_radioWidth
[0]>0) 
 478       x_offset 
+= maxWidth 
+ cx1
; 
 483 void wxRadioBox::GetSize(int *width
, int *height
) const 
 486     rect
.left 
= -1; rect
.right 
= -1; rect
.top 
= -1; rect
.bottom 
= -1; 
 489         wxFindMaxSize(m_hWnd
, &rect
); 
 492     for (i 
= 0; i 
< m_noItems
; i
++) 
 493         wxFindMaxSize(m_radioButtons
[i
], &rect
); 
 495     *width 
= rect
.right 
- rect
.left
; 
 496     *height 
= rect
.bottom 
- rect
.top
; 
 499 void wxRadioBox::GetPosition(int *x
, int *y
) const 
 501     wxWindow 
*parent 
= GetParent(); 
 503     rect
.left 
= -1; rect
.right 
= -1; rect
.top 
= -1; rect
.bottom 
= -1; 
 506     for (i 
= 0; i 
< m_noItems
; i
++) 
 507         wxFindMaxSize(m_radioButtons
[i
], &rect
); 
 510         wxFindMaxSize(m_hWnd
, &rect
); 
 512     // Since we now have the absolute screen coords, 
 513     // if there's a parent we must subtract its top left corner 
 519         ::ScreenToClient((HWND
) parent
->GetHWND(), &point
); 
 521     // We may be faking the client origin. 
 522     // So a window that's really at (0, 30) may appear 
 523     // (to wxWin apps) to be at (0, 0). 
 526         wxPoint 
pt(GetParent()->GetClientAreaOrigin()); 
 535 void wxRadioBox::SetFocus() 
 539         if (m_selectedButton 
== -1) 
 540             ::SetFocus((HWND
) m_radioButtons
[0]); 
 542             ::SetFocus((HWND
) m_radioButtons
[m_selectedButton
]); 
 547 bool wxRadioBox::Show(bool show
) 
 549     if ( !wxControl::Show(show
) ) 
 552     int nCmdShow 
= show 
? SW_SHOW 
: SW_HIDE
; 
 553     for ( int i 
= 0; i 
< m_noItems
; i
++ ) 
 555         ::ShowWindow((HWND
)m_radioButtons
[i
], nCmdShow
); 
 561 // Enable a specific button 
 562 void wxRadioBox::Enable(int item
, bool enable
) 
 564     wxCHECK_RET( item 
>= 0 && item 
< m_noItems
, 
 565                  _T("invalid item in wxRadioBox::Enable()") ); 
 567     ::EnableWindow((HWND
) m_radioButtons
[item
], enable
); 
 570 // Enable all controls 
 571 bool wxRadioBox::Enable(bool enable
) 
 573     if ( !wxControl::Enable(enable
) ) 
 576     for (int i 
= 0; i 
< m_noItems
; i
++) 
 577         ::EnableWindow((HWND
) m_radioButtons
[i
], enable
); 
 582 // Show a specific button 
 583 void wxRadioBox::Show(int item
, bool show
) 
 585     wxCHECK_RET( item 
>= 0 && item 
< m_noItems
, 
 586                  _T("invalid item in wxRadioBox::Show()") ); 
 588     ::ShowWindow((HWND
)m_radioButtons
[item
], show 
? SW_SHOW 
: SW_HIDE
); 
 591 WXHBRUSH 
wxRadioBox::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
, 
 592         WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
) 
 597         HBRUSH hbrush 
= Ctl3dCtlColorEx(message
, wParam
, lParam
); 
 598         return (WXHBRUSH
) hbrush
; 
 602     if (GetParent()->GetTransparentBackground()) 
 603         SetBkMode((HDC
) pDC
, TRANSPARENT
); 
 605         SetBkMode((HDC
) pDC
, OPAQUE
); 
 607     ::SetBkColor((HDC
) pDC
, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); 
 608     ::SetTextColor((HDC
) pDC
, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue())); 
 610     wxBrush 
*backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
); 
 612     return (WXHBRUSH
) backgroundBrush
->GetResourceHandle(); 
 615 // For single selection items only 
 616 wxString 
wxRadioBox::GetStringSelection() const 
 619     int sel 
= GetSelection(); 
 621         result 
= GetString(sel
); 
 626 bool wxRadioBox::SetStringSelection(const wxString
& s
) 
 628     int sel 
= FindString (s
); 
 638 bool wxRadioBox::ContainsHWND(WXHWND hWnd
) const 
 641     for (i 
= 0; i 
< Number(); i
++) 
 643         if (GetRadioButtons()[i
] == hWnd
) 
 650 void wxRadioBox::Command (wxCommandEvent 
& event
) 
 652     SetSelection (event
.m_commandInt
); 
 653     ProcessCommand (event
); 
 656 long wxRadioBox::MSWWindowProc(WXUINT msg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 659     bool processed 
= FALSE
; 
 665                 int xPos 
= LOWORD(lParam
);  // horizontal position of cursor 
 666                 int yPos 
= HIWORD(lParam
);  // vertical position of cursor 
 668                 ScreenToClient(&xPos
, &yPos
); 
 670                 // Make sure you can drag by the top of the groupbox, but let 
 671                 // other (enclosed) controls get mouse events also 
 682         rc 
= wxControl::MSWWindowProc(msg
, wParam
, lParam
); 
 687 void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn
) 
 690     HWND hwndBtn 
= (HWND
)hWndBtn
; 
 692     if ( !s_wndprocRadioBtn 
) 
 693         s_wndprocRadioBtn 
= (WXFARPROC
)::GetWindowLong(hwndBtn
, GWL_WNDPROC
); 
 695     // No GWL_USERDATA in Win16, so omit this subclassing. 
 696     ::SetWindowLong(hwndBtn
, GWL_WNDPROC
, (long)wxRadioBtnWndProc
); 
 697     ::SetWindowLong(hwndBtn
, GWL_USERDATA
, (long)this); 
 701 void wxRadioBox::SendNotificationEvent() 
 703     wxCommandEvent 
event(wxEVT_COMMAND_RADIOBOX_SELECTED
, m_windowId
); 
 704     event
.SetInt( m_selectedButton 
); 
 705     event
.SetEventObject( this ); 
 706     ProcessCommand(event
); 
 709 // --------------------------------------------------------------------------- 
 710 // window proc for radio buttons 
 711 // --------------------------------------------------------------------------- 
 715 LRESULT APIENTRY _EXPORT 
wxRadioBtnWndProc(HWND hwnd
, 
 720     bool processed 
= TRUE
; 
 721     if ( msg 
!= WM_KEYDOWN 
) 
 726         wxRadioBox 
*radiobox 
= (wxRadioBox 
*)::GetWindowLong(hwnd
, GWL_USERDATA
); 
 728         wxCHECK_MSG( radiobox
, 0, _T("radio button without radio box?") ); 
 730         int sel 
= radiobox
->GetSelection(); 
 739                 sel 
-= radiobox
->GetNumVer(); 
 747                 sel 
+= radiobox
->GetNumVer(); 
 752                     wxNavigationKeyEvent event
; 
 753                     event
.SetDirection(!(::GetKeyState(VK_SHIFT
) & 0x100)); 
 754                     event
.SetWindowChange(FALSE
); 
 755                     event
.SetEventObject(radiobox
); 
 757                     if ( radiobox
->GetEventHandler()->ProcessEvent(event
) ) 
 768             if ( sel 
>= 0 && sel 
< radiobox
->Number() ) 
 770                 radiobox
->SetSelection(sel
); 
 772                 // emulate the button click 
 773                 radiobox
->SendNotificationEvent(); 
 779         return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn
, hwnd
, msg
, wParam
, lParam
);