1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/univ/radiobox.cpp 
   3 // Purpose:     wxRadioBox implementation 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2000 SciTech Software, Inc. (www.scitechsoft.com) 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #include "wx/wxprec.h" 
  28 #include "wx/radiobox.h" 
  31     #include "wx/dcclient.h" 
  32     #include "wx/radiobut.h" 
  33     #include "wx/validate.h" 
  34     #include "wx/arrstr.h" 
  37 #include "wx/tooltip.h" 
  39 #include "wx/univ/theme.h" 
  40 #include "wx/univ/renderer.h" 
  41 #include "wx/univ/inphand.h" 
  42 #include "wx/univ/colschem.h" 
  44 // ---------------------------------------------------------------------------- 
  46 // ---------------------------------------------------------------------------- 
  48 static const int BUTTON_BORDER_X 
= 2; 
  49 static const int BUTTON_BORDER_Y 
= 4; 
  51 static const int BOX_BORDER_X 
= 2; 
  52 static const int BOX_BORDER_Y 
= 2; 
  54 // ---------------------------------------------------------------------------- 
  55 // wxRadioBox event handler 
  56 // ---------------------------------------------------------------------------- 
  58 class wxRadioHookHandler 
: public wxEvtHandler
 
  61     wxRadioHookHandler(wxRadioBox 
*radio
) { m_radio 
= radio
; } 
  63     virtual bool ProcessEvent(wxEvent
& event
) 
  65         // we intercept the command events from radio buttons 
  66         if ( event
.GetEventType() == wxEVT_COMMAND_RADIOBUTTON_SELECTED 
) 
  68             m_radio
->OnRadioButton(event
); 
  70         else if ( event
.GetEventType() == wxEVT_KEY_DOWN 
) 
  72             if ( m_radio
->OnKeyDown((wxKeyEvent 
&)event
) ) 
  79         return GetNextHandler()->ProcessEvent(event
); 
  86 // ============================================================================ 
  88 // ============================================================================ 
  90 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox
, wxControl
) 
  92 // ---------------------------------------------------------------------------- 
  93 // wxRadioBox creation 
  94 // ---------------------------------------------------------------------------- 
  96 void wxRadioBox::Init() 
 101 wxRadioBox::wxRadioBox(wxWindow 
*parent
, wxWindowID id
, const wxString
& title
, 
 102                        const wxPoint
& pos
, const wxSize
& size
, 
 103                        const wxArrayString
& choices
, 
 104                        int majorDim
, long style
, 
 105                        const wxValidator
& val
, const wxString
& name
) 
 107     wxCArrayString 
chs(choices
); 
 111     (void)Create(parent
, id
, title
, pos
, size
, chs
.GetCount(), 
 112                  chs
.GetStrings(), majorDim
, style
, val
, name
); 
 115 bool wxRadioBox::Create(wxWindow 
*parent
, 
 117                         const wxString
& title
, 
 120                         const wxArrayString
& choices
, 
 123                         const wxValidator
& val
, 
 124                         const wxString
& name
) 
 126     wxCArrayString 
chs(choices
); 
 128     return Create(parent
, id
, title
, pos
, size
, chs
.GetCount(), 
 129                   chs
.GetStrings(), majorDim
, style
, val
, name
); 
 132 bool wxRadioBox::Create(wxWindow 
*parent
, 
 134                         const wxString
& title
, 
 138                         const wxString 
*choices
, 
 141                         const wxValidator
& wxVALIDATOR_PARAM(val
), 
 142                         const wxString
& name
) 
 144     // for compatibility with the other ports which don't handle (yet?) 
 145     // wxRA_LEFTTORIGHT and wxRA_TOPTOBOTTOM flags, we add them ourselves if 
 147     if ( !(style 
& (wxRA_LEFTTORIGHT 
| wxRA_TOPTOBOTTOM
)) ) 
 149         // horizontal radiobox use left to right layout 
 150         if ( style 
& wxRA_HORIZONTAL 
) 
 152             style 
|= wxRA_LEFTTORIGHT
; 
 154         else if ( style 
& wxRA_VERTICAL 
) 
 156             style 
|= wxRA_TOPTOBOTTOM
; 
 160             wxFAIL_MSG( _T("you must specify wxRA_XXX style!") ); 
 163             style 
= wxRA_HORIZONTAL 
| wxRA_LEFTTORIGHT
; 
 167     if ( !wxStaticBox::Create(parent
, id
, title
, pos
, size
, style
, name
) ) 
 172 #endif // wxUSE_VALIDATORS 
 176     // majorDim default value is 0 which means make one row/column 
 177     SetMajorDim(majorDim 
== 0 ? n 
: majorDim
, style
); 
 179     if ( size 
== wxDefaultSize 
) 
 181         SetClientSize(DoGetBestClientSize()); 
 184     // Need to move the radiobox in order to move the radio buttons 
 185     wxPoint actualPos 
= GetPosition(); 
 186     wxSize actualSize 
= GetSize(); 
 187     DoMoveWindow(actualPos
.x
, actualPos
.y
, actualSize
.x
, actualSize
.y
); 
 189     // radiobox should already have selection so select at least one item 
 195 wxRadioBox::~wxRadioBox() 
 197     // remove the event handlers we pushed on them from all buttons and delete 
 198     // the buttons themselves: this must be done as the user code expects them 
 199     // to disappear now and not some time later when they will be deleted by 
 200     // our (common) parent 
 201     unsigned int count 
= m_buttons
.GetCount(); 
 202     for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
 204         m_buttons
[n
]->PopEventHandler(true /* delete it */); 
 210 // ---------------------------------------------------------------------------- 
 212 // ---------------------------------------------------------------------------- 
 214 void wxRadioBox::Append(int count
, const wxString 
*choices
) 
 219     wxWindow 
*parent 
= GetParent(); 
 220     m_buttons
.Alloc(count
); 
 221     for ( int n 
= 0; n 
< count
; n
++ ) 
 223         // make the first button in the box the start of new group by giving it 
 225         wxRadioButton 
*btn 
= new wxRadioButton(parent
, wxID_ANY
, choices
[n
], 
 228                                                n 
== 0 ? wxRB_GROUP 
: 0); 
 230         // we want to get the events from the buttons to translate it into 
 231         btn
->PushEventHandler(new wxRadioHookHandler(this)); 
 236 // ---------------------------------------------------------------------------- 
 238 // ---------------------------------------------------------------------------- 
 240 void wxRadioBox::SetSelection(int n
) 
 242     wxCHECK_RET( IsValid(n
), _T("invalid index in wxRadioBox::SetSelection") ); 
 246     wxRadioButton 
*btn 
= m_buttons
[n
]; 
 248     // the selected button is always focused in the radiobox 
 251     // this will also unselect the previously selected button in our group 
 255 int wxRadioBox::GetSelection() const 
 260 void wxRadioBox::SendRadioEvent() 
 262     wxCHECK_RET( m_selection 
!= -1, _T("no active radio button") ); 
 264     wxCommandEvent 
event(wxEVT_COMMAND_RADIOBOX_SELECTED
, GetId()); 
 265     InitCommandEvent(event
); 
 266     event
.SetInt(m_selection
); 
 267     event
.SetString(GetString(m_selection
)); 
 272 void wxRadioBox::OnRadioButton(wxEvent
& event
) 
 274     int n 
= m_buttons
.Index((wxRadioButton 
*)event
.GetEventObject()); 
 275     wxCHECK_RET( n 
!= wxNOT_FOUND
, _T("click from alien radio button") ); 
 282 // ---------------------------------------------------------------------------- 
 283 // methods forwarded to the buttons 
 284 // ---------------------------------------------------------------------------- 
 286 wxString 
wxRadioBox::GetString(unsigned int n
) const 
 288     wxCHECK_MSG( IsValid(n
), wxEmptyString
, 
 289                  _T("invalid index in wxRadioBox::GetString") ); 
 291     return m_buttons
[n
]->GetLabel(); 
 294 void wxRadioBox::SetString(unsigned int n
, const wxString
& label
) 
 296     wxCHECK_RET( IsValid(n
), _T("invalid index in wxRadioBox::SetString") ); 
 298     m_buttons
[n
]->SetLabel(label
); 
 301 bool wxRadioBox::Enable(unsigned int n
, bool enable
) 
 303     wxCHECK_MSG( IsValid(n
), false, _T("invalid index in wxRadioBox::Enable") ); 
 305     return m_buttons
[n
]->Enable(enable
); 
 308 bool wxRadioBox::IsItemEnabled(unsigned int n
) const 
 310     wxCHECK_MSG( IsValid(n
), false, _T("invalid index in wxRadioBox::IsItemEnabled") ); 
 312     return m_buttons
[n
]->IsEnabled(); 
 315 bool wxRadioBox::Show(unsigned int n
, bool show
) 
 317     wxCHECK_MSG( IsValid(n
), false, _T("invalid index in wxRadioBox::Show") ); 
 319     return m_buttons
[n
]->Show(show
); 
 322 bool wxRadioBox::IsItemShown(unsigned int n
) const 
 324     wxCHECK_MSG( IsValid(n
), false, _T("invalid index in wxRadioBox::IsItemShown") ); 
 326     return m_buttons
[n
]->IsShown(); 
 329 // ---------------------------------------------------------------------------- 
 330 // methods forwarded to the static box 
 331 // ---------------------------------------------------------------------------- 
 333 bool wxRadioBox::Enable(bool enable
) 
 335     if ( !wxStaticBox::Enable(enable
) ) 
 338     // also enable/disable the buttons 
 339     const unsigned int count 
= m_buttons
.GetCount(); 
 340     for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
 348 bool wxRadioBox::Show(bool show
) 
 350     if ( !wxStaticBox::Show(show
) ) 
 353     // also show/hide the buttons 
 354     const unsigned int count 
= m_buttons
.GetCount(); 
 355     for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
 363 wxString 
wxRadioBox::GetLabel() const 
 365     return wxStaticBox::GetLabel(); 
 368 void wxRadioBox::SetLabel(const wxString
& label
) 
 370     wxStaticBox::SetLabel(label
); 
 374 void wxRadioBox::DoSetToolTip(wxToolTip 
*tooltip
) 
 376     wxControl::DoSetToolTip(tooltip
); 
 378     // Also set them for all Radio Buttons 
 379     const unsigned int count 
= m_buttons
.GetCount(); 
 380     for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
 383             m_buttons
[n
]->SetToolTip(tooltip
->GetTip()); 
 385             m_buttons
[n
]->SetToolTip(NULL
); 
 388 #endif // wxUSE_TOOLTIPS 
 390 // ---------------------------------------------------------------------------- 
 391 // buttons positioning 
 392 // ---------------------------------------------------------------------------- 
 394 wxSize 
wxRadioBox::GetMaxButtonSize() const 
 396     int widthMax
, heightMax
, width 
= 0, height 
= 0; 
 397     widthMax 
= heightMax 
= 0; 
 399     const unsigned int count 
= GetCount(); 
 400     for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
 402         m_buttons
[n
]->GetBestSize(&width
, &height
); 
 404         if ( width 
> widthMax 
) 
 406         if ( height 
> heightMax 
) 
 410     return wxSize(widthMax 
+ BUTTON_BORDER_X
, heightMax 
+ BUTTON_BORDER_Y
); 
 413 wxSize 
wxRadioBox::DoGetBestClientSize() const 
 415     wxSize sizeBtn 
= GetMaxButtonSize(); 
 417     sizeBtn
.x 
*= GetColumnCount(); 
 418     sizeBtn
.y 
*= GetRowCount(); 
 420     // add a border around all buttons 
 421     sizeBtn
.x 
+= 2*BOX_BORDER_X
; 
 422     sizeBtn
.y 
+= 2*BOX_BORDER_Y
; 
 424     // account for the area taken by static box 
 425     wxRect rect 
= GetBorderGeometry(); 
 426     sizeBtn
.x 
+= rect
.x 
+ rect
.width
; 
 427     sizeBtn
.y 
+= rect
.y 
+ rect
.height
; 
 432 void wxRadioBox::DoMoveWindow(int x0
, int y0
, int width
, int height
) 
 434     wxStaticBox::DoMoveWindow(x0
, y0
, width
, height
); 
 436     wxSize sizeBtn 
= GetMaxButtonSize(); 
 437     wxPoint ptOrigin 
= GetBoxAreaOrigin(); 
 438     wxPoint clientOrigin 
= GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0); 
 440     x0 
+= ptOrigin
.x 
+ BOX_BORDER_X 
- clientOrigin
.x
; 
 441     y0 
+= ptOrigin
.y 
+ BOX_BORDER_Y 
- clientOrigin
.y
; 
 446     const unsigned int count 
= GetCount(); 
 447     for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
 449         m_buttons
[n
]->SetSize(x
, y
, sizeBtn
.x
, sizeBtn
.y
); 
 451         if ( GetWindowStyle() & wxRA_TOPTOBOTTOM 
) 
 453             // from top to bottom 
 454             if ( (n 
+ 1) % GetRowCount() ) 
 456                 // continue in this column 
 461                 // start a new column 
 466         else // wxRA_LEFTTORIGHT: mirror the code above 
 468             // from left to right 
 469             if ( (n 
+ 1) % GetColumnCount() ) 
 471                 // continue in this row 
 484 // ---------------------------------------------------------------------------- 
 485 // keyboard navigation 
 486 // ---------------------------------------------------------------------------- 
 488 bool wxRadioBox::OnKeyDown(wxKeyEvent
& event
) 
 491     switch ( event
.GetKeyCode() ) 
 513     int selOld 
= GetSelection(); 
 514     int selNew 
= GetNextItem(selOld
, dir
, GetWindowStyle()); 
 515     if ( selNew 
!= selOld 
) 
 517         SetSelection(selNew
); 
 519         // emulate the button click 
 526 #endif // wxUSE_RADIOBOX