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
, & this->GetFont());
466 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
468 eachHeight
= (int)((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
) ;
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
) ;
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)
540 if (m_radioWidth
[i
]<0)
542 // It's a labeled item
543 textRadioButton
= wxGetWindowText(m_radioButtons
[i
]);
544 GetTextExtent(textRadioButton
, ¤t_width
, &cyf
,
545 NULL
,NULL
, & this->GetFont());
547 // How do we find out radio button bitmap size!!
548 // By adjusting them carefully, manually :-)
549 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
550 eachHeight
= (int)((3*cyf
)/2);
554 eachWidth
= m_radioWidth
[i
] ;
555 eachHeight
= m_radioHeight
[i
] ;
558 MoveWindow((HWND
) m_radioButtons
[i
],x_offset
,y_offset
,eachWidth
,eachHeight
,TRUE
);
559 if (m_windowStyle
& wxRA_SPECIFY_ROWS
)
561 y_offset
+= maxHeight
;
562 if (m_radioWidth
[0]>0)
566 x_offset
+= maxWidth
+ cx1
;
571 // Restored old code.
572 void wxRadioBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
574 int currentX
, currentY
;
575 GetPosition(¤tX
, ¤tY
);
579 if (x
== -1 || (sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
581 if (y
== -1 || (sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
588 int current_width
, cyf
;
591 wxGetCharSize(m_hWnd
, &cx1
, &cy1
, & GetFont());
592 // Attempt to have a look coherent with other platforms:
593 // We compute the biggest toggle dim, then we align all
594 // items according this value.
599 for (i
= 0 ; i
< m_noItems
; i
++)
603 if (m_radioWidth
[i
]<0)
605 // It's a labelled toggle
606 GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300);
607 GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & GetFont());
608 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
609 eachHeight
= (int)((3*cyf
)/2);
613 eachWidth
= m_radioWidth
[i
] ;
614 eachHeight
= m_radioHeight
[i
] ;
616 if (maxWidth
<eachWidth
) maxWidth
= eachWidth
;
617 if (maxHeight
<eachHeight
) maxHeight
= eachHeight
;
627 if (m_windowStyle
& wxRA_SPECIFY_ROWS
)
630 nbHor
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
635 nbVer
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
638 // this formula works, but I don't know why.
639 // Please, be sure what you do if you modify it!!
640 if (m_radioWidth
[0]<0)
641 totHeight
= (nbVer
* maxHeight
) + cy1
/2 ;
643 totHeight
= nbVer
* (maxHeight
+cy1
/2) ;
644 totWidth
= nbHor
* (maxWidth
+cx1
) ;
647 // Requires a bigger group box in plain Windows
648 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+(3*cy1
)/2,TRUE
) ;
650 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+cy1
,TRUE
) ;
657 y_offset
+= (int)(cy1
/2); // Fudge factor since buttons overlapped label
658 // JACS 2/12/93. CTL3D draws group label quite high.
660 int startX
= x_offset
;
661 int startY
= y_offset
;
663 for ( i
= 0 ; i
< m_noItems
; i
++)
665 // Bidimensional radio adjustment
666 if (i
&&((i%m_majorDim
)==0)) // Why is this omitted for i = 0?
668 if (m_windowStyle
& wxRA_VERTICAL
)
671 x_offset
+= maxWidth
+ cx1
;
676 y_offset
+= maxHeight
;
677 if (m_radioWidth
[0]>0)
683 if (m_radioWidth
[i
]<0)
685 // It's a labeled item
686 GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300);
687 GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & GetFont());
689 // How do we find out radio button bitmap size!!
690 // By adjusting them carefully, manually :-)
691 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
692 eachHeight
= (int)((3*cyf
)/2);
696 eachWidth
= m_radioWidth
[i
] ;
697 eachHeight
= m_radioHeight
[i
] ;
700 MoveWindow((HWND
) m_radioButtons
[i
],x_offset
,y_offset
,eachWidth
,eachHeight
,TRUE
);
701 if (m_windowStyle
& wxRA_SPECIFY_ROWS
)
703 y_offset
+= maxHeight
;
704 if (m_radioWidth
[0]>0)
708 x_offset
+= maxWidth
+ cx1
;
713 void wxRadioBox::GetSize(int *width
, int *height
) const
716 rect
.left
= -1; rect
.right
= -1; rect
.top
= -1; rect
.bottom
= -1;
719 wxFindMaxSize(m_hWnd
, &rect
);
722 for (i
= 0; i
< m_noItems
; i
++)
723 wxFindMaxSize(m_radioButtons
[i
], &rect
);
725 *width
= rect
.right
- rect
.left
;
726 *height
= rect
.bottom
- rect
.top
;
729 void wxRadioBox::GetPosition(int *x
, int *y
) const
731 wxWindow
*parent
= GetParent();
733 rect
.left
= -1; rect
.right
= -1; rect
.top
= -1; rect
.bottom
= -1;
736 for (i
= 0; i
< m_noItems
; i
++)
737 wxFindMaxSize(m_radioButtons
[i
], &rect
);
740 wxFindMaxSize(m_hWnd
, &rect
);
742 // Since we now have the absolute screen coords,
743 // if there's a parent we must subtract its top left corner
749 ::ScreenToClient((HWND
) parent
->GetHWND(), &point
);
751 // We may be faking the client origin.
752 // So a window that's really at (0, 30) may appear
753 // (to wxWin apps) to be at (0, 0).
756 wxPoint
pt(GetParent()->GetClientAreaOrigin());
765 wxString
wxRadioBox::GetLabel(void) const
769 GetWindowText((HWND
) m_hWnd
, wxBuffer
, 300);
770 return wxString(wxBuffer
);
772 else return wxString("");
775 void wxRadioBox::SetLabel(const wxString
& label
)
778 SetWindowText((HWND
) m_hWnd
, label
);
781 void wxRadioBox::SetFocus(void)
785 if (m_selectedButton
== -1)
786 ::SetFocus((HWND
) m_radioButtons
[0]);
788 ::SetFocus((HWND
) m_radioButtons
[m_selectedButton
]);
793 bool wxRadioBox::Show(bool show
)
802 ShowWindow((HWND
) m_hWnd
, cshow
);
804 for (i
= 0; i
< m_noItems
; i
++)
805 ShowWindow((HWND
) m_radioButtons
[i
], cshow
);
809 // Enable a specific button
810 void wxRadioBox::Enable(int item
, bool enable
)
813 wxWindow::Enable(enable
) ;
814 else if (item
< m_noItems
)
815 ::EnableWindow((HWND
) m_radioButtons
[item
], enable
);
818 // Enable all controls
819 void wxRadioBox::Enable(bool enable
)
821 wxControl::Enable(enable
);
824 for (i
= 0; i
< m_noItems
; i
++)
825 ::EnableWindow((HWND
) m_radioButtons
[i
], enable
);
828 // Show a specific button
829 void wxRadioBox::Show(int item
, bool show
)
832 wxRadioBox::Show(show
) ;
833 else if (item
< m_noItems
)
840 ShowWindow((HWND
) m_radioButtons
[item
], cshow
);
844 WXHBRUSH
wxRadioBox::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
,
845 WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
850 HBRUSH hbrush
= Ctl3dCtlColorEx(message
, wParam
, lParam
);
851 return (WXHBRUSH
) hbrush
;
855 if (GetParent()->GetTransparentBackground())
856 SetBkMode((HDC
) pDC
, TRANSPARENT
);
858 SetBkMode((HDC
) pDC
, OPAQUE
);
860 ::SetBkColor((HDC
) pDC
, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
861 ::SetTextColor((HDC
) pDC
, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue()));
863 wxBrush
*backgroundBrush
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
);
865 // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush
866 // has a zero usage count.
867 // backgroundBrush->RealizeResource();
868 return (WXHBRUSH
) backgroundBrush
->GetResourceHandle();
871 // For single selection items only
872 wxString
wxRadioBox::GetStringSelection (void) const
874 int sel
= GetSelection ();
876 return this->GetString (sel
);
881 bool wxRadioBox::SetStringSelection (const wxString
& s
)
883 int sel
= FindString (s
);
893 bool wxRadioBox::ContainsHWND(WXHWND hWnd
) const
896 for (i
= 0; i
< Number(); i
++)
897 if (GetRadioButtons()[i
] == hWnd
)
902 void wxRadioBox::Command (wxCommandEvent
& event
)
904 SetSelection (event
.m_commandInt
);
905 ProcessCommand (event
);
908 long wxRadioBox::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
910 if (nMsg
== WM_NCHITTEST
)
912 int xPos
= LOWORD(lParam
); // horizontal position of cursor
913 int yPos
= HIWORD(lParam
); // vertical position of cursor
915 ScreenToClient(&xPos
, &yPos
);
917 // Make sure you can drag by the top of the groupbox, but let
918 // other (enclosed) controls get mouse events also
920 return (long)HTCLIENT
;
923 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);