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
);
405 wxString textRadioButton
;
409 int current_width
, cyf
;
412 wxGetCharSize(m_hWnd
, &cx1
, &cy1
, & this->GetFont());
414 // number of radio boxes in both directions
416 if (m_windowStyle
& wxRA_VERTICAL
)
419 nbHor
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
424 nbVer
= (m_noItems
+m_majorDim
-1)/m_majorDim
;
427 // Attempt to have a look coherent with other platforms:
428 // We compute the biggest toggle dim, then we align all
429 // items according this value.
430 int maxWidth
= width
,
433 // if we're given the width or height explicitly do not recalculate it, but
435 bool calcWidth
= maxWidth
== -1,
436 calcHeight
= maxHeight
== -1;
438 if ( calcWidth
|| calcHeight
)
440 // init vars to avoid compiler warnings, even if we don't use them
444 for ( int i
= 0 ; i
< m_noItems
; i
++ )
446 if ( m_radioWidth
[i
] < 0 )
448 // It's a labelled toggle
449 textRadioButton
= wxGetWindowText(m_radioButtons
[i
]);
450 GetTextExtent(textRadioButton
, ¤t_width
, &cyf
,
451 NULL
,NULL
, & this->GetFont());
454 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
456 eachHeight
= (int)((3*cyf
)/2);
461 eachWidth
= m_radioWidth
[i
] ;
463 eachHeight
= m_radioHeight
[i
] ;
466 if ( calcWidth
&& maxWidth
< eachWidth
)
467 maxWidth
= eachWidth
;
468 if ( calcHeight
&& maxHeight
< eachHeight
)
469 maxHeight
= eachHeight
;
474 maxHeight
= height
/nbVer
;
475 maxWidth
= width
/nbHor
;
483 // this formula works, but I don't know why.
484 // Please, be sure what you do if you modify it!!
485 if (m_radioWidth
[0]<0)
486 totHeight
= (nbVer
* maxHeight
) + cy1
/2 ;
488 totHeight
= nbVer
* (maxHeight
+cy1
/2) ;
489 totWidth
= nbHor
* (maxWidth
+cx1
) ;
492 // Requires a bigger group box in plain Windows
493 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+(3*cy1
)/2,TRUE
) ;
495 MoveWindow((HWND
) m_hWnd
,x_offset
,y_offset
,totWidth
+cx1
,totHeight
+cy1
,TRUE
) ;
502 y_offset
+= (int)(cy1
/2); // Fudge factor since buttons overlapped label
503 // JACS 2/12/93. CTL3D draws group label quite high.
505 int startX
= x_offset
;
506 int startY
= y_offset
;
508 for ( int i
= 0 ; i
< m_noItems
; i
++)
510 // Bidimensional radio adjustment
511 if (i
&&((i%m_majorDim
)==0)) // Why is this omitted for i = 0?
513 if (m_windowStyle
& wxRA_VERTICAL
)
516 x_offset
+= maxWidth
+ cx1
;
521 y_offset
+= maxHeight
;
522 if (m_radioWidth
[0]>0)
528 if (m_radioWidth
[i
]<0)
530 // It's a labeled item
531 textRadioButton
= wxGetWindowText(m_radioButtons
[i
]);
532 GetTextExtent(textRadioButton
, ¤t_width
, &cyf
,
533 NULL
,NULL
, & this->GetFont());
535 // How do we find out radio button bitmap size!!
536 // By adjusting them carefully, manually :-)
537 eachWidth
= (int)(current_width
+ RADIO_SIZE
);
538 eachHeight
= (int)((3*cyf
)/2);
542 eachWidth
= m_radioWidth
[i
] ;
543 eachHeight
= m_radioHeight
[i
] ;
546 MoveWindow((HWND
) m_radioButtons
[i
],x_offset
,y_offset
,eachWidth
,eachHeight
,TRUE
);
547 if (m_windowStyle
& wxRA_VERTICAL
)
549 y_offset
+= maxHeight
;
550 if (m_radioWidth
[0]>0)
554 x_offset
+= maxWidth
+ cx1
;
558 void wxRadioBox::GetSize(int *width
, int *height
) const
561 rect
.left
= -1; rect
.right
= -1; rect
.top
= -1; rect
.bottom
= -1;
564 wxFindMaxSize(m_hWnd
, &rect
);
567 for (i
= 0; i
< m_noItems
; i
++)
568 wxFindMaxSize(m_radioButtons
[i
], &rect
);
570 *width
= rect
.right
- rect
.left
;
571 *height
= rect
.bottom
- rect
.top
;
574 void wxRadioBox::GetPosition(int *x
, int *y
) const
576 wxWindow
*parent
= GetParent();
578 rect
.left
= -1; rect
.right
= -1; rect
.top
= -1; rect
.bottom
= -1;
581 for (i
= 0; i
< m_noItems
; i
++)
582 wxFindMaxSize(m_radioButtons
[i
], &rect
);
585 wxFindMaxSize(m_hWnd
, &rect
);
587 // Since we now have the absolute screen coords,
588 // if there's a parent we must subtract its top left corner
594 ::ScreenToClient((HWND
) parent
->GetHWND(), &point
);
596 // We may be faking the client origin.
597 // So a window that's really at (0, 30) may appear
598 // (to wxWin apps) to be at (0, 0).
601 wxPoint
pt(GetParent()->GetClientAreaOrigin());
610 wxString
wxRadioBox::GetLabel(void) const
614 GetWindowText((HWND
) m_hWnd
, wxBuffer
, 300);
615 return wxString(wxBuffer
);
617 else return wxString("");
620 void wxRadioBox::SetLabel(const wxString
& label
)
623 SetWindowText((HWND
) m_hWnd
, label
);
626 void wxRadioBox::SetFocus(void)
630 if (m_selectedButton
== -1)
631 ::SetFocus((HWND
) m_radioButtons
[0]);
633 ::SetFocus((HWND
) m_radioButtons
[m_selectedButton
]);
638 bool wxRadioBox::Show(bool show
)
646 ShowWindow((HWND
) m_hWnd
, cshow
);
648 for (i
= 0; i
< m_noItems
; i
++)
649 ShowWindow((HWND
) m_radioButtons
[i
], cshow
);
653 // Enable a specific button
654 void wxRadioBox::Enable(int item
, bool enable
)
657 wxWindow::Enable(enable
) ;
658 else if (item
< m_noItems
)
659 ::EnableWindow((HWND
) m_radioButtons
[item
], enable
);
662 // Enable all controls
663 void wxRadioBox::Enable(bool enable
)
665 wxControl::Enable(enable
);
668 for (i
= 0; i
< m_noItems
; i
++)
669 ::EnableWindow((HWND
) m_radioButtons
[i
], enable
);
672 // Show a specific button
673 void wxRadioBox::Show(int item
, bool show
)
676 wxRadioBox::Show(show
) ;
677 else if (item
< m_noItems
)
684 ShowWindow((HWND
) m_radioButtons
[item
], cshow
);
688 WXHBRUSH
wxRadioBox::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
,
689 WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
694 HBRUSH hbrush
= Ctl3dCtlColorEx(message
, wParam
, lParam
);
695 return (WXHBRUSH
) hbrush
;
699 if (GetParent()->GetTransparentBackground())
700 SetBkMode((HDC
) pDC
, TRANSPARENT
);
702 SetBkMode((HDC
) pDC
, OPAQUE
);
704 ::SetBkColor((HDC
) pDC
, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
705 ::SetTextColor((HDC
) pDC
, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue()));
707 wxBrush
*backgroundBrush
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
);
709 // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush
710 // has a zero usage count.
711 // backgroundBrush->RealizeResource();
712 return (WXHBRUSH
) backgroundBrush
->GetResourceHandle();
715 // For single selection items only
716 wxString
wxRadioBox::GetStringSelection (void) const
718 int sel
= GetSelection ();
720 return this->GetString (sel
);
725 bool wxRadioBox::SetStringSelection (const wxString
& s
)
727 int sel
= FindString (s
);
737 bool wxRadioBox::ContainsHWND(WXHWND hWnd
) const
740 for (i
= 0; i
< Number(); i
++)
741 if (GetRadioButtons()[i
] == hWnd
)
746 void wxRadioBox::Command (wxCommandEvent
& event
)
748 SetSelection (event
.m_commandInt
);
749 ProcessCommand (event
);
752 long wxRadioBox::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
754 if (nMsg
== WM_NCHITTEST
)
756 int xPos
= LOWORD(lParam
); // horizontal position of cursor
757 int yPos
= HIWORD(lParam
); // vertical position of cursor
759 ScreenToClient(&xPos
, &yPos
);
761 // Make sure you can drag by the top of the groupbox, but let
762 // other (enclosed) controls get mouse events also
764 return (long)HTCLIENT
;
767 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);