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 // get the id of the window 
  51     #define GET_WIN_ID(hwnd) ::GetWindowLong((HWND)hwnd, GWL_ID) 
  53     #define GET_WIN_ID(hwnd) ::GetWindowWord((HWND)hwnd, GWW_ID) 
  56 // wnd proc for radio buttons 
  58 LRESULT APIENTRY _EXPORT 
wxRadioBtnWndProc(HWND hWnd
, 
  64 // --------------------------------------------------------------------------- 
  66 // --------------------------------------------------------------------------- 
  68 // the pointer to standard radio button wnd proc 
  69 // static WNDPROC s_wndprocRadioBtn = (WNDPROC)NULL; 
  70 static WXFARPROC s_wndprocRadioBtn 
= (WXFARPROC
)NULL
; 
  72 // =========================================================================== 
  74 // =========================================================================== 
  76 // --------------------------------------------------------------------------- 
  78 // --------------------------------------------------------------------------- 
  80 int wxRadioBox::GetNumVer() const 
  82     if ( m_windowStyle 
& wxRA_SPECIFY_ROWS 
) 
  88         return (m_noItems 
+ m_majorDim 
- 1)/m_majorDim
; 
  92 int wxRadioBox::GetNumHor() const 
  94     if ( m_windowStyle 
& wxRA_SPECIFY_ROWS 
) 
  96         return (m_noItems 
+ m_majorDim 
- 1)/m_majorDim
; 
 104 bool wxRadioBox::MSWCommand(WXUINT param
, WXWORD id
) 
 106     if ( param 
== BN_CLICKED 
) 
 108         m_selectedButton 
= -1; 
 110         for ( int i 
= 0; i 
< m_noItems
; i
++ ) 
 112             if ( id 
== GET_WIN_ID(m_radioButtons
[i
]) ) 
 114                 m_selectedButton 
= i
; 
 120         wxASSERT_MSG( m_selectedButton 
!= -1, "click from alien button?" ); 
 122         wxCommandEvent 
event(wxEVT_COMMAND_RADIOBOX_SELECTED
, m_windowId
); 
 123         event
.SetInt( m_selectedButton 
); 
 124         event
.SetEventObject( this ); 
 125         ProcessCommand(event
); 
 133 #if WXWIN_COMPATIBILITY 
 134 wxRadioBox::wxRadioBox(wxWindow 
*parent
, wxFunction func
, const char *title
, 
 135         int x
, int y
, int width
, int height
, 
 136         int n
, char **choices
, 
 137         int majorDim
, long style
, const char *name
) 
 139     wxString 
*choices2 
= new wxString
[n
]; 
 140     for ( int i 
= 0; i 
< n
; i 
++) choices2
[i
] = choices
[i
]; 
 141     Create(parent
, -1, title
, wxPoint(x
, y
), wxSize(width
, height
), n
, choices2
, majorDim
, style
, 
 142             wxDefaultValidator
, name
); 
 150 wxRadioBox::wxRadioBox() 
 152     m_selectedButton 
= -1; 
 155     m_radioButtons 
= NULL
; 
 158     m_radioHeight 
= NULL
; 
 161 bool wxRadioBox::Create(wxWindow 
*parent
, wxWindowID id
, const wxString
& title
, 
 162         const wxPoint
& pos
, const wxSize
& size
, 
 163         int n
, const wxString choices
[], 
 164         int majorDim
, long style
, 
 165         const wxValidator
& val
, const wxString
& name
) 
 167     m_selectedButton 
= -1; 
 173     parent
->AddChild(this); 
 174     m_backgroundColour 
= parent
->GetBackgroundColour(); 
 175     m_foregroundColour 
= parent
->GetForegroundColour(); 
 177     m_windowStyle 
= (long&)style
; 
 185         m_windowId 
= NewControlId(); 
 192         m_majorDim 
= majorDim
; 
 193     m_noRowsOrCols 
= majorDim
; 
 195     long msStyle 
= GROUP_FLAGS
; 
 198     WXDWORD exStyle 
= Determine3DEffects(0, &want3D
); 
 199     // Even with extended styles, need to combine with WS_BORDER 
 200     // for them to look right. 
 202        if ( want3D || wxStyleHasBorder(m_windowStyle) ) 
 203        msStyle |= WS_BORDER; 
 206     HWND hwndParent 
= (HWND
)parent
->GetHWND(); 
 208     m_hWnd 
= (WXHWND
)::CreateWindowEx
 
 224         Ctl3dSubclassCtl((HWND
)m_hWnd
); 
 227 #endif // wxUSE_CTL3D 
 229     SetFont(parent
->GetFont()); 
 233     // Some radio boxes test consecutive id. 
 234     (void)NewControlId(); 
 235     m_radioButtons 
= new WXHWND
[n
]; 
 236     m_radioWidth 
= new int[n
]; 
 237     m_radioHeight 
= new int[n
]; 
 239     for (i 
= 0; i 
< n
; i
++) 
 241         m_radioWidth
[i
] = m_radioHeight
[i
] = -1; 
 243         if ( i 
== 0 && style 
== 0 ) 
 244             groupStyle 
= WS_GROUP
; 
 245         long newId 
= NewControlId(); 
 246         long msStyle 
= groupStyle 
| RADIO_FLAGS
; 
 248         HWND hwndBtn 
= CreateWindowEx(exStyle
, RADIO_CLASS
, 
 252                                       (HMENU
)newId
, wxGetInstance(), 
 255         m_radioButtons
[i
] = (WXHWND
)hwndBtn
; 
 256         SubclassRadioButton((WXHWND
)hwndBtn
); 
 258         wxFont
& font 
= GetFont(); 
 261             SendMessage(hwndBtn
, WM_SETFONT
, 
 262                         (WPARAM
)font
.GetResourceHandle(), 0L); 
 265         m_subControls
.Append((wxObject 
*)newId
); 
 268     // Create a dummy radio control to end the group. 
 269     (void)CreateWindowEx(0, RADIO_CLASS
, "", WS_GROUP 
| RADIO_FLAGS
, 
 270                          0, 0, 0, 0, hwndParent
, 
 271                          (HMENU
)NewControlId(), wxGetInstance(), NULL
); 
 275     SetSize(x
, y
, width
, height
); 
 280 wxRadioBox::~wxRadioBox() 
 282     m_isBeingDeleted 
= TRUE
; 
 287         for (i 
= 0; i 
< m_noItems
; i
++) 
 288             DestroyWindow((HWND
) m_radioButtons
[i
]); 
 289         delete[] m_radioButtons
; 
 292         delete[] m_radioWidth
; 
 294         delete[] m_radioHeight
; 
 296         ::DestroyWindow((HWND
) m_hWnd
); 
 301 wxString 
wxRadioBox::GetLabel(int item
) const 
 303     GetWindowText((HWND
)m_radioButtons
[item
], wxBuffer
, 300); 
 304     return wxString(wxBuffer
); 
 307 void wxRadioBox::SetLabel(int item
, const wxString
& label
) 
 309     m_radioWidth
[item
] = m_radioHeight
[item
] = -1; 
 310     SetWindowText((HWND
)m_radioButtons
[item
], (const char *)label
); 
 313 void wxRadioBox::SetLabel(int item
, wxBitmap 
*bitmap
) 
 316        m_radioWidth[item] = bitmap->GetWidth() + FB_MARGIN; 
 317        m_radioHeight[item] = bitmap->GetHeight() + FB_MARGIN; 
 321 int wxRadioBox::FindString(const wxString
& s
) const 
 324     for (i 
= 0; i 
< m_noItems
; i
++) 
 326         GetWindowText((HWND
) m_radioButtons
[i
], wxBuffer
, 1000); 
 333 void wxRadioBox::SetSelection(int N
) 
 335     wxCHECK_RET( (N 
>= 0) && (N 
< m_noItems
), "invalid radiobox index" ); 
 337     // Following necessary for Win32s, because Win32s translate BM_SETCHECK 
 338     if (m_selectedButton 
>= 0 && m_selectedButton 
< m_noItems
) 
 339         ::SendMessage((HWND
) m_radioButtons
[m_selectedButton
], BM_SETCHECK
, 0, 0L); 
 341     ::SendMessage((HWND
)m_radioButtons
[N
], BM_SETCHECK
, 1, 0L); 
 342     ::SetFocus((HWND
)m_radioButtons
[N
]); 
 344     m_selectedButton 
= N
; 
 347 // Get single selection, for single choice list items 
 348 int wxRadioBox::GetSelection() const 
 350     return m_selectedButton
; 
 353 // Find string for position 
 354 wxString 
wxRadioBox::GetString(int N
) const 
 356     return wxGetWindowText(m_radioButtons
[N
]); 
 359 // Restored old code. 
 360 void wxRadioBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
 362   int currentX
, currentY
; 
 363   GetPosition(¤tX
, ¤tY
); 
 367   if (x 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 369   if (y 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 376   int current_width
, cyf
; 
 379   wxGetCharSize(m_hWnd
, &cx1
, &cy1
, & GetFont()); 
 380   // Attempt to have a look coherent with other platforms: 
 381   // We compute the biggest toggle dim, then we align all 
 382   // items according this value. 
 387   for (i 
= 0 ; i 
< m_noItems
; i
++) 
 391     if (m_radioWidth
[i
]<0) 
 393       // It's a labelled toggle 
 394       GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300); 
 395       GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & GetFont()); 
 396       eachWidth 
= (int)(current_width 
+ RADIO_SIZE
); 
 397       eachHeight 
= (int)((3*cyf
)/2); 
 401       eachWidth 
= m_radioWidth
[i
]; 
 402       eachHeight 
= m_radioHeight
[i
]; 
 404     if (maxWidth
<eachWidth
) maxWidth 
= eachWidth
; 
 405     if (maxHeight
<eachHeight
) maxHeight 
= eachHeight
; 
 413     int nbHor 
= GetNumHor(), 
 416     // this formula works, but I don't know why. 
 417     // Please, be sure what you do if you modify it!! 
 418     if (m_radioWidth
[0]<0) 
 419       totHeight 
= (nbVer 
* maxHeight
) + cy1
/2; 
 421       totHeight 
= nbVer 
* (maxHeight
+cy1
/2); 
 422     totWidth  
= nbHor 
* (maxWidth
+cx1
); 
 425     // Requires a bigger group box in plain Windows 
 426     MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+(3*cy1
)/2,TRUE
); 
 428     MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+cy1
,TRUE
); 
 435   y_offset 
+= (int)(cy1
/2); // Fudge factor since buttons overlapped label 
 436                             // JACS 2/12/93. CTL3D draws group label quite high. 
 438   int startX 
= x_offset
; 
 439   int startY 
= y_offset
; 
 441   for ( i 
= 0 ; i 
< m_noItems
; i
++) 
 443     // Bidimensional radio adjustment 
 444     if (i
&&((i%m_majorDim
)==0)) // Why is this omitted for i = 0? 
 446       if (m_windowStyle 
& wxRA_VERTICAL
) 
 449         x_offset 
+= maxWidth 
+ cx1
; 
 454         y_offset 
+= maxHeight
; 
 455         if (m_radioWidth
[0]>0) 
 461     if (m_radioWidth
[i
]<0) 
 463       // It's a labeled item 
 464       GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300); 
 465       GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & GetFont()); 
 467       // How do we find out radio button bitmap size!! 
 468       // By adjusting them carefully, manually :-) 
 469       eachWidth 
= (int)(current_width 
+ RADIO_SIZE
); 
 470       eachHeight 
= (int)((3*cyf
)/2); 
 474       eachWidth 
= m_radioWidth
[i
]; 
 475       eachHeight 
= m_radioHeight
[i
]; 
 478     MoveWindow((HWND
) m_radioButtons
[i
],x_offset
,y_offset
,eachWidth
,eachHeight
,TRUE
); 
 479     if (m_windowStyle 
& wxRA_SPECIFY_ROWS
) 
 481       y_offset 
+= maxHeight
; 
 482       if (m_radioWidth
[0]>0) 
 486       x_offset 
+= maxWidth 
+ cx1
; 
 491 void wxRadioBox::GetSize(int *width
, int *height
) const 
 494     rect
.left 
= -1; rect
.right 
= -1; rect
.top 
= -1; rect
.bottom 
= -1; 
 497         wxFindMaxSize(m_hWnd
, &rect
); 
 500     for (i 
= 0; i 
< m_noItems
; i
++) 
 501         wxFindMaxSize(m_radioButtons
[i
], &rect
); 
 503     *width 
= rect
.right 
- rect
.left
; 
 504     *height 
= rect
.bottom 
- rect
.top
; 
 507 void wxRadioBox::GetPosition(int *x
, int *y
) const 
 509     wxWindow 
*parent 
= GetParent(); 
 511     rect
.left 
= -1; rect
.right 
= -1; rect
.top 
= -1; rect
.bottom 
= -1; 
 514     for (i 
= 0; i 
< m_noItems
; i
++) 
 515         wxFindMaxSize(m_radioButtons
[i
], &rect
); 
 518         wxFindMaxSize(m_hWnd
, &rect
); 
 520     // Since we now have the absolute screen coords, 
 521     // if there's a parent we must subtract its top left corner 
 527         ::ScreenToClient((HWND
) parent
->GetHWND(), &point
); 
 529     // We may be faking the client origin. 
 530     // So a window that's really at (0, 30) may appear 
 531     // (to wxWin apps) to be at (0, 0). 
 534         wxPoint 
pt(GetParent()->GetClientAreaOrigin()); 
 543 wxString 
wxRadioBox::GetLabel() const 
 547         GetWindowText((HWND
) m_hWnd
, wxBuffer
, 300); 
 548         return wxString(wxBuffer
); 
 550     else return wxString(""); 
 553 void wxRadioBox::SetLabel(const wxString
& label
) 
 556         SetWindowText((HWND
) m_hWnd
, label
); 
 559 void wxRadioBox::SetFocus() 
 563         if (m_selectedButton 
== -1) 
 564             ::SetFocus((HWND
) m_radioButtons
[0]); 
 566             ::SetFocus((HWND
) m_radioButtons
[m_selectedButton
]); 
 571 bool wxRadioBox::Show(bool show
) 
 580         ShowWindow((HWND
) m_hWnd
, cshow
); 
 582     for (i 
= 0; i 
< m_noItems
; i
++) 
 583         ShowWindow((HWND
) m_radioButtons
[i
], cshow
); 
 587 // Enable a specific button 
 588 void wxRadioBox::Enable(int item
, bool enable
) 
 591         wxWindow::Enable(enable
); 
 592     else if (item 
< m_noItems
) 
 593         ::EnableWindow((HWND
) m_radioButtons
[item
], enable
); 
 596 // Enable all controls 
 597 void wxRadioBox::Enable(bool enable
) 
 599     wxControl::Enable(enable
); 
 602     for (i 
= 0; i 
< m_noItems
; i
++) 
 603         ::EnableWindow((HWND
) m_radioButtons
[i
], enable
); 
 606 // Show a specific button 
 607 void wxRadioBox::Show(int item
, bool show
) 
 610         wxRadioBox::Show(show
); 
 611     else if (item 
< m_noItems
) 
 618         ShowWindow((HWND
) m_radioButtons
[item
], cshow
); 
 622 WXHBRUSH 
wxRadioBox::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
, 
 623         WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
) 
 628         HBRUSH hbrush 
= Ctl3dCtlColorEx(message
, wParam
, lParam
); 
 629         return (WXHBRUSH
) hbrush
; 
 633     if (GetParent()->GetTransparentBackground()) 
 634         SetBkMode((HDC
) pDC
, TRANSPARENT
); 
 636         SetBkMode((HDC
) pDC
, OPAQUE
); 
 638     ::SetBkColor((HDC
) pDC
, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); 
 639     ::SetTextColor((HDC
) pDC
, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue())); 
 641     wxBrush 
*backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
); 
 643     // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush 
 644     // has a zero usage count. 
 645     //  backgroundBrush->RealizeResource(); 
 646     return (WXHBRUSH
) backgroundBrush
->GetResourceHandle(); 
 649 // For single selection items only 
 650 wxString 
wxRadioBox::GetStringSelection() const 
 653     int sel 
= GetSelection(); 
 655         result 
= GetString(sel
); 
 660 bool wxRadioBox::SetStringSelection(const wxString
& s
) 
 662     int sel 
= FindString (s
); 
 672 bool wxRadioBox::ContainsHWND(WXHWND hWnd
) const 
 675     for (i 
= 0; i 
< Number(); i
++) 
 676         if (GetRadioButtons()[i
] == hWnd
) 
 681 void wxRadioBox::Command (wxCommandEvent 
& event
) 
 683     SetSelection (event
.m_commandInt
); 
 684     ProcessCommand (event
); 
 687 long wxRadioBox::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 689     if (nMsg 
== WM_NCHITTEST
) 
 691         int xPos 
= LOWORD(lParam
);  // horizontal position of cursor 
 692         int yPos 
= HIWORD(lParam
);  // vertical position of cursor 
 694         ScreenToClient(&xPos
, &yPos
); 
 696         // Make sure you can drag by the top of the groupbox, but let 
 697         // other (enclosed) controls get mouse events also 
 699             return (long)HTCLIENT
; 
 702     return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
 705 void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn
) 
 707     HWND hwndBtn 
= (HWND
)hWndBtn
; 
 709     if ( !s_wndprocRadioBtn 
) 
 710         s_wndprocRadioBtn 
= (WXFARPROC
)::GetWindowLong(hwndBtn
, GWL_WNDPROC
); 
 711 //        s_wndprocRadioBtn = (WNDPROC)::GetWindowLong(hwndBtn, GWL_WNDPROC); 
 713     // No GWL_USERDATA in Win16, so omit this subclassing. 
 715     ::SetWindowLong(hwndBtn
, GWL_WNDPROC
, (long)wxRadioBtnWndProc
); 
 716     ::SetWindowLong(hwndBtn
, GWL_USERDATA
, (long)this); 
 720 // --------------------------------------------------------------------------- 
 721 // window proc for radio buttons 
 722 // --------------------------------------------------------------------------- 
 726 LRESULT APIENTRY _EXPORT 
wxRadioBtnWndProc(HWND hwnd
, 
 731     bool processed 
= TRUE
; 
 732     if ( msg 
!= WM_KEYDOWN 
) 
 737         wxRadioBox 
*radiobox 
= (wxRadioBox 
*)::GetWindowLong(hwnd
, GWL_USERDATA
); 
 739         wxCHECK_MSG( radiobox
, 0, "radio button without radio box?" ); 
 741         int sel 
= radiobox
->GetSelection(); 
 750                 sel 
-= radiobox
->GetNumVer(); 
 758                 sel 
+= radiobox
->GetNumVer(); 
 763                     wxNavigationKeyEvent event
; 
 764                     event
.SetDirection(!(::GetKeyState(VK_SHIFT
) & 0x100)); 
 765                     event
.SetWindowChange(FALSE
); 
 766                     event
.SetEventObject(radiobox
); 
 768                     if ( radiobox
->GetEventHandler()->ProcessEvent(event
) ) 
 779             if ( sel 
>= 0 && sel 
< radiobox
->Number() ) 
 780                 radiobox
->SetSelection(sel
); 
 785         return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn
, hwnd
, msg
, wParam
, lParam
);