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 void wxRadioBox::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
393 int currentX
, currentY
;
394 GetPosition(¤tX
, ¤tY
);
398 if (x
== -1 || (sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
400 if (y
== -1 || (sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
403 AdjustForParentClientOrigin(xx
, yy
, sizeFlags
);
409 int current_width
, cyf
;
412 wxGetCharSize(m_hWnd
, &cx1
, &cy1
, & this->GetFont());
413 // Attempt to have a look coherent with other platforms:
414 // We compute the biggest toggle dim, then we align all
415 // items according this value.
420 for (i
= 0 ; i
< m_noItems
; i
++)
424 if (m_radioWidth
[i
]<0)
426 // It's a labelled toggle
427 GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300);
428 GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & this->GetFont());
429 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
430 eachHeight
= (int)((3*cyf
)/2);
434 eachWidth
= m_radioWidth
[i
] ;
435 eachHeight
= m_radioHeight
[i
] ;
437 if (maxWidth
<eachWidth
) maxWidth
= eachWidth
;
438 if (maxHeight
<eachHeight
) maxHeight
= eachHeight
;
448 if (m_windowStyle
& wxRA_VERTICAL
)
451 nbHor
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
456 nbVer
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
459 // this formula works, but I don't know why.
460 // Please, be sure what you do if you modify it!!
461 if (m_radioWidth
[0]<0)
462 totHeight
= (nbVer
* maxHeight
) + cy1
/2 ;
464 totHeight
= nbVer
* (maxHeight
+cy1
/2) ;
465 totWidth
= nbHor
* (maxWidth
+cx1
) ;
468 // Requires a bigger group box in plain Windows
469 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+(3*cy1
)/2,TRUE
) ;
471 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+cy1
,TRUE
) ;
478 y_offset
+= (int)(cy1
/2); // Fudge factor since buttons overlapped label
479 // JACS 2/12/93. CTL3D draws group label quite high.
481 int startX
= x_offset
;
482 int startY
= y_offset
;
484 for ( i
= 0 ; i
< m_noItems
; i
++)
486 // Bidimensional radio adjustment
487 if (i
&&((i%m_majorDim
)==0)) // Why is this omitted for i = 0?
489 if (m_windowStyle
& wxRA_VERTICAL
)
492 x_offset
+= maxWidth
+ cx1
;
497 y_offset
+= maxHeight
;
498 if (m_radioWidth
[0]>0)
504 if (m_radioWidth
[i
]<0)
506 // It's a labeled item
507 GetWindowText((HWND
) m_radioButtons
[i
], buf
, 300);
508 GetTextExtent(buf
, ¤t_width
, &cyf
,NULL
,NULL
, & this->GetFont());
510 // How do we find out radio button bitmap size!!
511 // By adjusting them carefully, manually :-)
512 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
513 eachHeight
= (int)((3*cyf
)/2);
517 eachWidth
= m_radioWidth
[i
] ;
518 eachHeight
= m_radioHeight
[i
] ;
521 MoveWindow((HWND
) m_radioButtons
[i
],x_offset
,y_offset
,eachWidth
,eachHeight
,TRUE
);
522 if (m_windowStyle
& wxRA_VERTICAL
)
524 y_offset
+= maxHeight
;
525 if (m_radioWidth
[0]>0)
529 x_offset
+= maxWidth
+ cx1
;
533 void wxRadioBox::GetSize(int *width
, int *height
) const
536 rect
.left
= -1; rect
.right
= -1; rect
.top
= -1; rect
.bottom
= -1;
539 wxFindMaxSize(m_hWnd
, &rect
);
542 for (i
= 0; i
< m_noItems
; i
++)
543 wxFindMaxSize(m_radioButtons
[i
], &rect
);
545 *width
= rect
.right
- rect
.left
;
546 *height
= rect
.bottom
- rect
.top
;
549 void wxRadioBox::GetPosition(int *x
, int *y
) const
551 wxWindow
*parent
= GetParent();
553 rect
.left
= -1; rect
.right
= -1; rect
.top
= -1; rect
.bottom
= -1;
556 for (i
= 0; i
< m_noItems
; i
++)
557 wxFindMaxSize(m_radioButtons
[i
], &rect
);
560 wxFindMaxSize(m_hWnd
, &rect
);
562 // Since we now have the absolute screen coords,
563 // if there's a parent we must subtract its top left corner
569 ::ScreenToClient((HWND
) parent
->GetHWND(), &point
);
571 // We may be faking the client origin.
572 // So a window that's really at (0, 30) may appear
573 // (to wxWin apps) to be at (0, 0).
576 wxPoint
pt(GetParent()->GetClientAreaOrigin());
585 wxString
wxRadioBox::GetLabel(void) const
589 GetWindowText((HWND
) m_hWnd
, wxBuffer
, 300);
590 return wxString(wxBuffer
);
592 else return wxString("");
595 void wxRadioBox::SetLabel(const wxString
& label
)
598 SetWindowText((HWND
) m_hWnd
, label
);
601 void wxRadioBox::SetFocus(void)
605 if (m_selectedButton
== -1)
606 ::SetFocus((HWND
) m_radioButtons
[0]);
608 ::SetFocus((HWND
) m_radioButtons
[m_selectedButton
]);
613 bool wxRadioBox::Show(bool show
)
621 ShowWindow((HWND
) m_hWnd
, cshow
);
623 for (i
= 0; i
< m_noItems
; i
++)
624 ShowWindow((HWND
) m_radioButtons
[i
], cshow
);
628 // Enable a specific button
629 void wxRadioBox::Enable(int item
, bool enable
)
632 wxWindow::Enable(enable
) ;
633 else if (item
< m_noItems
)
634 ::EnableWindow((HWND
) m_radioButtons
[item
], enable
);
637 // Enable all controls
638 void wxRadioBox::Enable(bool enable
)
640 wxControl::Enable(enable
);
643 for (i
= 0; i
< m_noItems
; i
++)
644 ::EnableWindow((HWND
) m_radioButtons
[i
], enable
);
647 // Show a specific button
648 void wxRadioBox::Show(int item
, bool show
)
651 wxRadioBox::Show(show
) ;
652 else if (item
< m_noItems
)
659 ShowWindow((HWND
) m_radioButtons
[item
], cshow
);
663 WXHBRUSH
wxRadioBox::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
,
664 WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
669 HBRUSH hbrush
= Ctl3dCtlColorEx(message
, wParam
, lParam
);
670 return (WXHBRUSH
) hbrush
;
674 if (GetParent()->GetTransparentBackground())
675 SetBkMode((HDC
) pDC
, TRANSPARENT
);
677 SetBkMode((HDC
) pDC
, OPAQUE
);
679 ::SetBkColor((HDC
) pDC
, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
680 ::SetTextColor((HDC
) pDC
, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue()));
682 wxBrush
*backgroundBrush
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
);
684 // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush
685 // has a zero usage count.
686 // backgroundBrush->RealizeResource();
687 return (WXHBRUSH
) backgroundBrush
->GetResourceHandle();
690 // For single selection items only
691 wxString
wxRadioBox::GetStringSelection (void) const
693 int sel
= GetSelection ();
695 return this->GetString (sel
);
700 bool wxRadioBox::SetStringSelection (const wxString
& s
)
702 int sel
= FindString (s
);
712 bool wxRadioBox::ContainsHWND(WXHWND hWnd
) const
715 for (i
= 0; i
< Number(); i
++)
716 if (GetRadioButtons()[i
] == hWnd
)
721 void wxRadioBox::Command (wxCommandEvent
& event
)
723 SetSelection (event
.m_commandInt
);
724 ProcessCommand (event
);
727 long wxRadioBox::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
729 if (nMsg
== WM_NCHITTEST
)
731 int xPos
= LOWORD(lParam
); // horizontal position of cursor
732 int yPos
= HIWORD(lParam
); // vertical position of cursor
734 ScreenToClient(&xPos
, &yPos
);
736 // Make sure you can drag by the top of the groupbox, but let
737 // other (enclosed) controls get mouse events also
739 return (long)HTCLIENT
;
742 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);