1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "radiobox.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
26 #include "wx/bitmap.h"
28 #include "wx/radiobox.h"
31 #include "wx/msw/private.h"
33 #if !USE_SHARED_LIBRARY
34 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox
, wxControl
)
37 bool wxRadioBox::MSWCommand(WXUINT param
, WXWORD id
)
39 if (param
== BN_CLICKED
)
43 for (i
= 0; i
< m_noItems
; i
++)
44 if (id
== GetWindowLong((HWND
) m_radioButtons
[i
], GWL_ID
))
48 for (i
= 0; i
< m_noItems
; i
++)
49 if (id
== GetWindowWord((HWND
) m_radioButtons
[i
], GWW_ID
))
53 wxCommandEvent
event(wxEVT_COMMAND_RADIOBOX_SELECTED
, m_windowId
);
54 event
.SetInt( m_selectedButton
);
55 event
.SetEventObject( this );
56 ProcessCommand(event
);
62 #if WXWIN_COMPATIBILITY
63 wxRadioBox::wxRadioBox(wxWindow
*parent
, wxFunction func
, const char *title
,
64 int x
, int y
, int width
, int height
,
65 int n
, char **choices
,
66 int majorDim
, long style
, const char *name
)
68 wxString
*choices2
= new wxString
[n
];
69 for ( int i
= 0; i
< n
; i
++) choices2
[i
] = choices
[i
];
70 Create(parent
, -1, title
, wxPoint(x
, y
), wxSize(width
, height
), n
, choices2
, majorDim
, style
,
71 wxDefaultValidator
, name
);
79 wxRadioBox::wxRadioBox(void)
81 m_selectedButton
= -1;
84 m_radioButtons
= NULL
;
87 m_radioHeight
= NULL
;
90 bool wxRadioBox::Create(wxWindow
*parent
, wxWindowID id
, const wxString
& title
,
91 const wxPoint
& pos
, const wxSize
& size
,
92 int n
, const wxString choices
[],
93 int majorDim
, long style
,
94 const wxValidator
& val
, const wxString
& name
)
96 m_selectedButton
= -1;
102 parent
->AddChild(this);
103 m_backgroundColour
= parent
->GetBackgroundColour() ;
104 m_foregroundColour
= parent
->GetForegroundColour() ;
106 m_windowStyle
= (long&)style
;
114 m_windowId
= NewControlId();
118 m_noRowsOrCols
= majorDim
;
121 else // Seemed to make sense to put this 'else' here... (RD)
122 m_majorDim
= majorDim
;
124 long msStyle
= GROUP_FLAGS
;
127 WXDWORD exStyle
= Determine3DEffects(0, &want3D
) ;
128 // Even with extended styles, need to combine with WS_BORDER
129 // for them to look right.
131 if ( want3D || wxStyleHasBorder(m_windowStyle) )
132 msStyle |= WS_BORDER;
136 HWND the_handle
= (HWND
) parent
->GetHWND() ;
138 m_hWnd
= (WXHWND
)::CreateWindowEx
154 Ctl3dSubclassCtl((HWND
)m_hWnd
);
159 SetFont(parent
->GetFont());
161 SubclassWin((WXHWND
)m_hWnd
);
163 // Some radio boxes test consecutive id.
164 (void)NewControlId() ;
165 m_radioButtons
= new WXHWND
[n
];
166 m_radioWidth
= new int[n
] ;
167 m_radioHeight
= new int[n
] ;
169 for (i
= 0; i
< n
; i
++)
171 m_radioWidth
[i
] = m_radioHeight
[i
] = -1 ;
173 if (i
== 0 && style
==0)
174 groupStyle
= WS_GROUP
;
175 long newId
= NewControlId();
176 long msStyle
= groupStyle
| RADIO_FLAGS
;
178 m_radioButtons
[i
] = (WXHWND
) CreateWindowEx(exStyle
, RADIO_CLASS
, choices
[i
],
180 the_handle
, (HMENU
)newId
, wxGetInstance(), NULL
);
184 Ctl3dSubclassCtl((HWND
) m_hWnd
);
190 SendMessage((HWND
)m_radioButtons
[i
],WM_SETFONT
,
191 (WPARAM
)GetFont().GetResourceHandle(),0L);
193 m_subControls
.Append((wxObject
*)newId
);
196 // Create a dummy radio control to end the group.
197 (void)CreateWindowEx(0, RADIO_CLASS
, "", WS_GROUP
|RADIO_FLAGS
, 0,0,0,0, the_handle
, (HMENU
)NewControlId(), wxGetInstance(), NULL
);
201 SetSize(x
, y
, width
, height
);
207 bool wxRadioBox::Create(wxWindow
*parent
, wxWindowID id
, const wxString
& title
,
208 const wxPoint
& pos
, const wxSize
& size
,
209 int n
, const wxBitmap
*choices
[],
210 int majorDim
, long style
,
211 const wxValidator
& val
, const wxString
& name
)
213 m_selectedButton
= -1;
220 parent
->AddChild(this);
221 m_backgroundColour
= parent
->GetBackgroundColour() ;
222 m_foregroundColour
= parent
->GetForegroundColour() ;
224 m_windowStyle
= (long&)style
;
232 m_windowId
= NewControlId();
237 m_noRowsOrCols
= majorDim
;
240 m_majorDim
= majorDim
;
243 long msStyle
= GROUP_FLAGS
;
246 WXDWORD exStyle
= Determine3DEffects(0, &want3D
) ;
247 // Even with extended styles, need to combine with WS_BORDER
248 // for them to look right.
249 if ( want3D
|| wxStyleHasBorder(m_windowStyle
) )
250 msStyle
|= WS_BORDER
;
252 m_hWnd
= (WXHWND
) CreateWindowEx((DWORD
) exStyle
, GROUP_CLASS
, (title
== "" ? NULL
: (const char *)title
),
255 (HWND
) parent
->GetHWND(), (HMENU
) m_windowId
, wxGetInstance(), NULL
) ;
257 the_handle
= (HWND
) parent
->GetHWND();
262 Ctl3dSubclassCtl((HWND
) m_hWnd
);
267 SetFont(parent
->GetFont());
269 // Subclass again for purposes of dialog editing mode
270 SubclassWin((WXHWND
)m_hWnd
);
272 (void)NewControlId() ;
273 m_radioButtons
= new WXHWND
[n
];
274 m_radioWidth
= new int[n
] ;
275 m_radioHeight
= new int[n
] ;
278 for (i
= 0; i
< n
; i
++)
281 if (i
== 0 && style
==0)
282 groupStyle
= WS_GROUP
;
283 long newId
= NewControlId();
284 m_radioWidth
[i
] = ((wxBitmap
*)choices
[i
])->GetWidth();
285 m_radioHeight
[i
] = ((wxBitmap
*)choices
[i
])->GetHeight();
287 sprintf(tmp
,"Toggle%d",i
) ;
288 long msStyle
= groupStyle
| RADIO_FLAGS
;
289 m_radioButtons
[i
] = (WXHWND
) CreateWindowEx(exStyle
, RADIO_CLASS
, tmp
,
291 the_handle
, (HMENU
)newId
, wxhInstance
, NULL
);
295 Ctl3dSubclassCtl((HWND
) m_hWnd
);
299 m_subControls
.Append((wxObject
*)newId
);
301 // Create a dummy radio control to end the group.
302 (void)CreateWindowEx(0, RADIO_CLASS
, "", WS_GROUP
|RADIO_FLAGS
, 0,0,0,0, the_handle
, (HMENU
)NewControlId(), wxGetInstance(), NULL
);
306 SetSize(x
, y
, width
, height
);
312 wxRadioBox::~wxRadioBox(void)
314 m_isBeingDeleted
= TRUE
;
319 for (i
= 0; i
< m_noItems
; i
++)
320 DestroyWindow((HWND
) m_radioButtons
[i
]);
321 delete[] m_radioButtons
;
324 delete[] m_radioWidth
;
326 delete[] m_radioHeight
;
328 ::DestroyWindow((HWND
) m_hWnd
) ;
333 wxString
wxRadioBox::GetLabel(int item
) const
335 GetWindowText((HWND
)m_radioButtons
[item
], wxBuffer
, 300);
336 return wxString(wxBuffer
);
339 void wxRadioBox::SetLabel(int item
, const wxString
& label
)
341 m_radioWidth
[item
] = m_radioHeight
[item
] = -1 ;
342 SetWindowText((HWND
)m_radioButtons
[item
], (const char *)label
);
345 void wxRadioBox::SetLabel(int item
, wxBitmap
*bitmap
)
348 m_radioWidth[item] = bitmap->GetWidth() + FB_MARGIN ;
349 m_radioHeight[item] = bitmap->GetHeight() + FB_MARGIN ;
353 int wxRadioBox::FindString(const wxString
& s
) const
356 for (i
= 0; i
< m_noItems
; i
++)
358 GetWindowText((HWND
) m_radioButtons
[i
], wxBuffer
, 1000);
365 void wxRadioBox::SetSelection(int N
)
367 if ((N
< 0) || (N
>= m_noItems
))
370 // Following necessary for Win32s, because Win32s translate BM_SETCHECK
371 if (m_selectedButton
>= 0 && m_selectedButton
< m_noItems
)
372 SendMessage((HWND
) m_radioButtons
[m_selectedButton
], BM_SETCHECK
, 0, 0L);
374 SendMessage((HWND
) m_radioButtons
[N
], BM_SETCHECK
, 1, 0L);
375 m_selectedButton
= N
;
378 // Get single selection, for single choice list items
379 int wxRadioBox::GetSelection(void) const
381 return m_selectedButton
;
384 // Find string for position
385 wxString
wxRadioBox::GetString(int N
) const
387 GetWindowText((HWND
) m_radioButtons
[N
], wxBuffer
, 1000);
388 return wxString(wxBuffer
);
391 /* NOTE. The contributed code to size the group box according to the
392 * given size simply didn't work (try it in e.g. Dialog Editor)
393 * so sorry, I'm removing it. If you reinstate it, please make sure
394 * it's bullet-proof in Dialog Editor. Meanwhile, it's better to have it
395 * working with a calculated size, than supposedly flexibly but
396 * actually broken. This is rather important when it comes to releasing
397 * stable software. Suggestion: if you modify this, rewrite it completely.
402 void wxRadioBox::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
404 int currentX
, currentY
;
405 GetPosition(¤tX
, ¤tY
);
409 if (x
== -1 || (sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
411 if (y
== -1 || (sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
414 AdjustForParentClientOrigin(xx
, yy
, sizeFlags
);
416 wxString textRadioButton
;
420 int current_width
, cyf
;
423 wxGetCharSize(m_hWnd
, &cx1
, &cy1
, & this->GetFont());
425 // number of radio boxes in both directions
427 if (m_windowStyle
& wxRA_SPECIFY_ROWS
)
430 nbHor
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
435 nbVer
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
438 // Attempt to have a look coherent with other platforms:
439 // We compute the biggest toggle dim, then we align all
440 // items according this value.
441 int maxWidth
= width
,
444 // if we're given the width or height explicitly do not recalculate it, but
447 bool calcWidth
= maxWidth
== -1,
448 calcHeight
= maxHeight
== -1;
450 if ( calcWidth
|| calcHeight
)
452 // init vars to avoid compiler warnings, even if we don't use them
456 for ( int i
= 0 ; i
< m_noItems
; i
++ )
458 if ( m_radioWidth
[i
] < 0 )
460 // It's a labelled toggle
461 textRadioButton
= wxGetWindowText(m_radioButtons
[i
]);
462 GetTextExtent(textRadioButton
, ¤t_width
, &cyf
,
463 NULL
, NULL
, &GetFont());
466 eachWidth
= current_width
+ RADIO_SIZE
;
468 eachHeight
= (3*cyf
)/2;
473 eachWidth
= m_radioWidth
[i
] ;
475 eachHeight
= m_radioHeight
[i
] ;
478 if ( calcWidth
&& maxWidth
< eachWidth
)
479 maxWidth
= eachWidth
;
480 if ( calcHeight
&& maxHeight
< eachHeight
)
481 maxHeight
= eachHeight
;
486 maxHeight
= height
/nbVer
;
487 maxWidth
= width
/nbHor
;
495 // this formula works, but I don't know why.
496 // Please, be sure what you do if you modify it!!
497 if (m_radioWidth
[0]<0)
498 totHeight
= (nbVer
* maxHeight
) + cy1
/2 ;
500 totHeight
= nbVer
* (maxHeight
+cy1
/2) ;
501 totWidth
= nbHor
* (maxWidth
+cx1
) ;
503 #if !defined(__WIN32__) && (!wxUSE_CTL3D)
504 // Requires a bigger group box in plain Windows
505 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+(3*cy1
)/2,TRUE
) ;
507 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+cy1
,TRUE
) ;
513 #if !defined(__WIN32__) && (!wxUSE_CTL3D)
514 y_offset
+= (int)(cy1
/2); // Fudge factor since buttons overlapped label
515 // JACS 2/12/93. CTL3D draws group label quite high.
517 int startX
= x_offset
;
518 int startY
= y_offset
;
520 for ( int i
= 0 ; i
< m_noItems
; i
++)
522 // Bidimensional radio adjustment
523 if (i
&&((i%m_majorDim
)==0)) // Why is this omitted for i = 0?
525 if (m_windowStyle
& wxRA_SPECIFY_ROWS
)
528 x_offset
+= maxWidth
+ cx1
;
533 y_offset
+= maxHeight
;
534 if (m_radioWidth
[0]>0)
542 if ( m_radioWidth
[i
] < 0 )
544 // It's a labeled item
545 textRadioButton
= wxGetWindowText(m_radioButtons
[i
]);
546 GetTextExtent(textRadioButton
, ¤t_width
, &cyf
,
547 NULL
,NULL
, & this->GetFont());
549 eachWidth
= current_width
+ RADIO_SIZE
;
550 eachHeight
= (3*cyf
)/2;
554 eachWidth
= m_radioWidth
[i
] ;
555 eachHeight
= m_radioHeight
[i
] ;
558 MoveWindow((HWND
)m_radioButtons
[i
], x_offset
, y_offset
,
559 eachWidth
,eachHeight
,TRUE
);
560 if ( m_windowStyle
& wxRA_VERTICAL
)
561 if (m_windowStyle
& wxRA_SPECIFY_ROWS
)
563 y_offset
+= maxHeight
;
564 if ( m_radioWidth
[0] > 0 )
569 x_offset
+= maxWidth
+ cx1
;
575 // Restored old code.
576 void wxRadioBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
578 int currentX
, currentY
;
579 GetPosition(¤tX
, ¤tY
);
583 if (x
== -1 || (sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
585 if (y
== -1 || (sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
592 int current_width
, cyf
;
595 wxGetCharSize(m_hWnd
, &cx1
, &cy1
, & GetFont());
596 // Attempt to have a look coherent with other platforms:
597 // We compute the biggest toggle dim, then we align all
598 // items according this value.
603 for (i
= 0 ; i
< m_noItems
; i
++)
607 if (m_radioWidth
[i
]<0)
609 // It's a labelled toggle
610 GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300);
611 GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & GetFont());
612 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
613 eachHeight
= (int)((3*cyf
)/2);
617 eachWidth
= m_radioWidth
[i
] ;
618 eachHeight
= m_radioHeight
[i
] ;
620 if (maxWidth
<eachWidth
) maxWidth
= eachWidth
;
621 if (maxHeight
<eachHeight
) maxHeight
= eachHeight
;
631 if (m_windowStyle
& wxRA_SPECIFY_ROWS
)
634 nbHor
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
639 nbVer
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
642 // this formula works, but I don't know why.
643 // Please, be sure what you do if you modify it!!
644 if (m_radioWidth
[0]<0)
645 totHeight
= (nbVer
* maxHeight
) + cy1
/2 ;
647 totHeight
= nbVer
* (maxHeight
+cy1
/2) ;
648 totWidth
= nbHor
* (maxWidth
+cx1
) ;
651 // Requires a bigger group box in plain Windows
652 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+(3*cy1
)/2,TRUE
) ;
654 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+cy1
,TRUE
) ;
661 y_offset
+= (int)(cy1
/2); // Fudge factor since buttons overlapped label
662 // JACS 2/12/93. CTL3D draws group label quite high.
664 int startX
= x_offset
;
665 int startY
= y_offset
;
667 for ( i
= 0 ; i
< m_noItems
; i
++)
669 // Bidimensional radio adjustment
670 if (i
&&((i%m_majorDim
)==0)) // Why is this omitted for i = 0?
672 if (m_windowStyle
& wxRA_VERTICAL
)
675 x_offset
+= maxWidth
+ cx1
;
680 y_offset
+= maxHeight
;
681 if (m_radioWidth
[0]>0)
687 if (m_radioWidth
[i
]<0)
689 // It's a labeled item
690 GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300);
691 GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & GetFont());
693 // How do we find out radio button bitmap size!!
694 // By adjusting them carefully, manually :-)
695 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
696 eachHeight
= (int)((3*cyf
)/2);
700 eachWidth
= m_radioWidth
[i
] ;
701 eachHeight
= m_radioHeight
[i
] ;
704 MoveWindow((HWND
) m_radioButtons
[i
],x_offset
,y_offset
,eachWidth
,eachHeight
,TRUE
);
705 if (m_windowStyle
& wxRA_SPECIFY_ROWS
)
707 y_offset
+= maxHeight
;
708 if (m_radioWidth
[0]>0)
712 x_offset
+= maxWidth
+ cx1
;
717 void wxRadioBox::GetSize(int *width
, int *height
) const
720 rect
.left
= -1; rect
.right
= -1; rect
.top
= -1; rect
.bottom
= -1;
723 wxFindMaxSize(m_hWnd
, &rect
);
726 for (i
= 0; i
< m_noItems
; i
++)
727 wxFindMaxSize(m_radioButtons
[i
], &rect
);
729 *width
= rect
.right
- rect
.left
;
730 *height
= rect
.bottom
- rect
.top
;
733 void wxRadioBox::GetPosition(int *x
, int *y
) const
735 wxWindow
*parent
= GetParent();
737 rect
.left
= -1; rect
.right
= -1; rect
.top
= -1; rect
.bottom
= -1;
740 for (i
= 0; i
< m_noItems
; i
++)
741 wxFindMaxSize(m_radioButtons
[i
], &rect
);
744 wxFindMaxSize(m_hWnd
, &rect
);
746 // Since we now have the absolute screen coords,
747 // if there's a parent we must subtract its top left corner
753 ::ScreenToClient((HWND
) parent
->GetHWND(), &point
);
755 // We may be faking the client origin.
756 // So a window that's really at (0, 30) may appear
757 // (to wxWin apps) to be at (0, 0).
760 wxPoint
pt(GetParent()->GetClientAreaOrigin());
769 wxString
wxRadioBox::GetLabel(void) const
773 GetWindowText((HWND
) m_hWnd
, wxBuffer
, 300);
774 return wxString(wxBuffer
);
776 else return wxString("");
779 void wxRadioBox::SetLabel(const wxString
& label
)
782 SetWindowText((HWND
) m_hWnd
, label
);
785 void wxRadioBox::SetFocus(void)
789 if (m_selectedButton
== -1)
790 ::SetFocus((HWND
) m_radioButtons
[0]);
792 ::SetFocus((HWND
) m_radioButtons
[m_selectedButton
]);
797 bool wxRadioBox::Show(bool show
)
806 ShowWindow((HWND
) m_hWnd
, cshow
);
808 for (i
= 0; i
< m_noItems
; i
++)
809 ShowWindow((HWND
) m_radioButtons
[i
], cshow
);
813 // Enable a specific button
814 void wxRadioBox::Enable(int item
, bool enable
)
817 wxWindow::Enable(enable
) ;
818 else if (item
< m_noItems
)
819 ::EnableWindow((HWND
) m_radioButtons
[item
], enable
);
822 // Enable all controls
823 void wxRadioBox::Enable(bool enable
)
825 wxControl::Enable(enable
);
828 for (i
= 0; i
< m_noItems
; i
++)
829 ::EnableWindow((HWND
) m_radioButtons
[i
], enable
);
832 // Show a specific button
833 void wxRadioBox::Show(int item
, bool show
)
836 wxRadioBox::Show(show
) ;
837 else if (item
< m_noItems
)
844 ShowWindow((HWND
) m_radioButtons
[item
], cshow
);
848 WXHBRUSH
wxRadioBox::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
,
849 WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
854 HBRUSH hbrush
= Ctl3dCtlColorEx(message
, wParam
, lParam
);
855 return (WXHBRUSH
) hbrush
;
859 if (GetParent()->GetTransparentBackground())
860 SetBkMode((HDC
) pDC
, TRANSPARENT
);
862 SetBkMode((HDC
) pDC
, OPAQUE
);
864 ::SetBkColor((HDC
) pDC
, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
865 ::SetTextColor((HDC
) pDC
, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue()));
867 wxBrush
*backgroundBrush
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
);
869 // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush
870 // has a zero usage count.
871 // backgroundBrush->RealizeResource();
872 return (WXHBRUSH
) backgroundBrush
->GetResourceHandle();
875 // For single selection items only
876 wxString
wxRadioBox::GetStringSelection (void) const
878 int sel
= GetSelection ();
880 return this->GetString (sel
);
885 bool wxRadioBox::SetStringSelection (const wxString
& s
)
887 int sel
= FindString (s
);
897 bool wxRadioBox::ContainsHWND(WXHWND hWnd
) const
900 for (i
= 0; i
< Number(); i
++)
901 if (GetRadioButtons()[i
] == hWnd
)
906 void wxRadioBox::Command (wxCommandEvent
& event
)
908 SetSelection (event
.m_commandInt
);
909 ProcessCommand (event
);
912 long wxRadioBox::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
914 if (nMsg
== WM_NCHITTEST
)
916 int xPos
= LOWORD(lParam
); // horizontal position of cursor
917 int yPos
= HIWORD(lParam
); // vertical position of cursor
919 ScreenToClient(&xPos
, &yPos
);
921 // Make sure you can drag by the top of the groupbox, but let
922 // other (enclosed) controls get mouse events also
924 return (long)HTCLIENT
;
927 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);