]>
Commit | Line | Data |
---|---|---|
2bda0e17 | 1 | ///////////////////////////////////////////////////////////////////////////// |
faa49bfd | 2 | // Name: src/msw/radiobox.cpp |
3ca6a5f0 | 3 | // Purpose: wxRadioBox implementation |
2bda0e17 KB |
4 | // Author: Julian Smart |
5 | // Modified by: | |
6 | // Created: 04/01/98 | |
7 | // RCS-ID: $Id$ | |
6c9a19aa | 8 | // Copyright: (c) Julian Smart |
65571936 | 9 | // Licence: wxWindows licence |
2bda0e17 KB |
10 | ///////////////////////////////////////////////////////////////////////////// |
11 | ||
e373f51b VZ |
12 | // =========================================================================== |
13 | // declarations | |
14 | // =========================================================================== | |
15 | ||
16 | // --------------------------------------------------------------------------- | |
17 | // headers | |
18 | // --------------------------------------------------------------------------- | |
19 | ||
2bda0e17 KB |
20 | // For compilers that support precompilation, includes "wx.h". |
21 | #include "wx/wxprec.h" | |
22 | ||
23 | #ifdef __BORLANDC__ | |
da07e033 | 24 | #pragma hdrstop |
2bda0e17 KB |
25 | #endif |
26 | ||
1e6feb95 VZ |
27 | #if wxUSE_RADIOBOX |
28 | ||
2bda0e17 | 29 | #ifndef WX_PRECOMP |
da07e033 VZ |
30 | #include "wx/bitmap.h" |
31 | #include "wx/brush.h" | |
32 | #include "wx/radiobox.h" | |
f6bcfd97 | 33 | #include "wx/settings.h" |
381dd4bf | 34 | #include "wx/log.h" |
2bda0e17 KB |
35 | #endif |
36 | ||
bd0a76e2 | 37 | #include "wx/msw/subwin.h" |
2bda0e17 | 38 | |
f048e32f | 39 | #if wxUSE_TOOLTIPS |
f048e32f VZ |
40 | #include "wx/tooltip.h" |
41 | #endif // wxUSE_TOOLTIPS | |
42 | ||
3ff066a4 | 43 | // TODO: wxCONSTRUCTOR |
bc9fb572 JS |
44 | #if 0 // wxUSE_EXTENDED_RTTI |
45 | WX_DEFINE_FLAGS( wxRadioBoxStyle ) | |
46 | ||
3ff066a4 | 47 | wxBEGIN_FLAGS( wxRadioBoxStyle ) |
bc9fb572 JS |
48 | // new style border flags, we put them first to |
49 | // use them for streaming out | |
3ff066a4 SC |
50 | wxFLAGS_MEMBER(wxBORDER_SIMPLE) |
51 | wxFLAGS_MEMBER(wxBORDER_SUNKEN) | |
52 | wxFLAGS_MEMBER(wxBORDER_DOUBLE) | |
53 | wxFLAGS_MEMBER(wxBORDER_RAISED) | |
54 | wxFLAGS_MEMBER(wxBORDER_STATIC) | |
55 | wxFLAGS_MEMBER(wxBORDER_NONE) | |
4d08943e | 56 | |
bc9fb572 | 57 | // old style border flags |
3ff066a4 SC |
58 | wxFLAGS_MEMBER(wxSIMPLE_BORDER) |
59 | wxFLAGS_MEMBER(wxSUNKEN_BORDER) | |
60 | wxFLAGS_MEMBER(wxDOUBLE_BORDER) | |
61 | wxFLAGS_MEMBER(wxRAISED_BORDER) | |
62 | wxFLAGS_MEMBER(wxSTATIC_BORDER) | |
cb0afb26 | 63 | wxFLAGS_MEMBER(wxBORDER) |
bc9fb572 JS |
64 | |
65 | // standard window styles | |
3ff066a4 SC |
66 | wxFLAGS_MEMBER(wxTAB_TRAVERSAL) |
67 | wxFLAGS_MEMBER(wxCLIP_CHILDREN) | |
68 | wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) | |
69 | wxFLAGS_MEMBER(wxWANTS_CHARS) | |
cb0afb26 | 70 | wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) |
3ff066a4 SC |
71 | wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) |
72 | wxFLAGS_MEMBER(wxVSCROLL) | |
73 | wxFLAGS_MEMBER(wxHSCROLL) | |
74 | ||
75 | wxFLAGS_MEMBER(wxRA_SPECIFY_COLS) | |
76 | wxFLAGS_MEMBER(wxRA_HORIZONTAL) | |
77 | wxFLAGS_MEMBER(wxRA_SPECIFY_ROWS) | |
78 | wxFLAGS_MEMBER(wxRA_VERTICAL) | |
79 | ||
80 | wxEND_FLAGS( wxRadioBoxStyle ) | |
bc9fb572 JS |
81 | |
82 | IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioBox, wxControl,"wx/radiobox.h") | |
83 | ||
3ff066a4 SC |
84 | wxBEGIN_PROPERTIES_TABLE(wxRadioBox) |
85 | wxEVENT_PROPERTY( Select , wxEVT_COMMAND_RADIOBOX_SELECTED , wxCommandEvent ) | |
86 | wxPROPERTY_FLAGS( WindowStyle , wxRadioBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style | |
87 | wxEND_PROPERTIES_TABLE() | |
bc9fb572 JS |
88 | |
89 | #else | |
d3acd369 | 90 | IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl) |
bc9fb572 | 91 | #endif |
2bda0e17 | 92 | |
066f1b7a | 93 | /* |
4d08943e WS |
94 | selection |
95 | content | |
96 | label | |
97 | dimension | |
98 | item | |
066f1b7a SC |
99 | */ |
100 | ||
e373f51b VZ |
101 | // --------------------------------------------------------------------------- |
102 | // private functions | |
103 | // --------------------------------------------------------------------------- | |
104 | ||
e373f51b VZ |
105 | // wnd proc for radio buttons |
106 | LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hWnd, | |
107 | UINT message, | |
108 | WPARAM wParam, | |
109 | LPARAM lParam); | |
110 | ||
111 | // --------------------------------------------------------------------------- | |
112 | // global vars | |
113 | // --------------------------------------------------------------------------- | |
114 | ||
115 | // the pointer to standard radio button wnd proc | |
457e6c54 | 116 | static WXFARPROC s_wndprocRadioBtn = (WXFARPROC)NULL; |
e373f51b VZ |
117 | |
118 | // =========================================================================== | |
119 | // implementation | |
120 | // =========================================================================== | |
121 | ||
122 | // --------------------------------------------------------------------------- | |
bd0a76e2 | 123 | // wxRadioBox creation |
e373f51b VZ |
124 | // --------------------------------------------------------------------------- |
125 | ||
2bda0e17 | 126 | // Radio box item |
bd0a76e2 | 127 | void wxRadioBox::Init() |
2bda0e17 | 128 | { |
bd0a76e2 | 129 | m_selectedButton = wxNOT_FOUND; |
da07e033 | 130 | m_radioButtons = NULL; |
e373f51b VZ |
131 | m_radioWidth = NULL; |
132 | m_radioHeight = NULL; | |
2bda0e17 KB |
133 | } |
134 | ||
f048e32f VZ |
135 | bool wxRadioBox::Create(wxWindow *parent, |
136 | wxWindowID id, | |
137 | const wxString& title, | |
138 | const wxPoint& pos, | |
139 | const wxSize& size, | |
140 | int n, | |
141 | const wxString choices[], | |
142 | int majorDim, | |
143 | long style, | |
144 | const wxValidator& val, | |
145 | const wxString& name) | |
2bda0e17 | 146 | { |
f048e32f | 147 | // common initialization |
bd0a76e2 | 148 | if ( !wxStaticBox::Create(parent, id, title, pos, size, style, name) ) |
4d08943e | 149 | return false; |
2bda0e17 | 150 | |
bd0a76e2 VZ |
151 | #if wxUSE_VALIDATORS |
152 | SetValidator(val); | |
153 | #else | |
154 | wxUnusedVar(val); | |
155 | #endif // wxUSE_VALIDATORS/!wxUSE_VALIDATORS | |
da07e033 | 156 | |
bd0a76e2 | 157 | m_radioButtons = new wxSubwindows(n); |
e373f51b VZ |
158 | m_radioWidth = new int[n]; |
159 | m_radioHeight = new int[n]; | |
f048e32f | 160 | |
f048e32f VZ |
161 | for ( int i = 0; i < n; i++ ) |
162 | { | |
163 | m_radioWidth[i] = | |
4d08943e | 164 | m_radioHeight[i] = wxDefaultCoord; |
d3acd369 | 165 | long styleBtn = BS_AUTORADIOBUTTON | WS_TABSTOP | WS_CHILD | WS_VISIBLE; |
1f621c2f | 166 | if ( i == 0 ) |
f048e32f VZ |
167 | styleBtn |= WS_GROUP; |
168 | ||
da07e033 | 169 | long newId = NewControlId(); |
da07e033 | 170 | |
f048e32f VZ |
171 | HWND hwndBtn = ::CreateWindow(_T("BUTTON"), |
172 | choices[i], | |
173 | styleBtn, | |
174 | 0, 0, 0, 0, // will be set in SetSize() | |
99c613c5 | 175 | GetHwndOf(parent), |
f048e32f VZ |
176 | (HMENU)newId, |
177 | wxGetInstance(), | |
e373f51b | 178 | NULL); |
2bda0e17 | 179 | |
f048e32f VZ |
180 | if ( !hwndBtn ) |
181 | { | |
f6bcfd97 | 182 | wxLogLastError(wxT("CreateWindow(radio btn)")); |
f048e32f | 183 | |
4d08943e | 184 | return false; |
f048e32f VZ |
185 | } |
186 | ||
bd0a76e2 | 187 | (*m_radioButtons)[i] = hwndBtn; |
42e69d6b | 188 | |
e373f51b | 189 | SubclassRadioButton((WXHWND)hwndBtn); |
2bda0e17 | 190 | |
f048e32f | 191 | m_subControls.Add(newId); |
da07e033 | 192 | } |
e373f51b | 193 | |
da07e033 | 194 | // Create a dummy radio control to end the group. |
f048e32f | 195 | (void)::CreateWindow(_T("BUTTON"), |
fda7962d | 196 | wxEmptyString, |
f048e32f | 197 | WS_GROUP | BS_AUTORADIOBUTTON | WS_CHILD, |
99c613c5 | 198 | 0, 0, 0, 0, GetHwndOf(parent), |
e373f51b | 199 | (HMENU)NewControlId(), wxGetInstance(), NULL); |
2bda0e17 | 200 | |
bd0a76e2 VZ |
201 | m_radioButtons->SetFont(GetFont()); |
202 | ||
64133c38 JS |
203 | #ifdef __WXWINCE__ |
204 | // Set the z-order correctly | |
d26e1ab2 | 205 | SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); |
64133c38 JS |
206 | #endif |
207 | ||
f3984afa | 208 | SetMajorDim(majorDim == 0 ? n : majorDim, style); |
da07e033 | 209 | SetSelection(0); |
f048e32f | 210 | SetSize(pos.x, pos.y, size.x, size.y); |
2bda0e17 | 211 | |
7a5a5718 RD |
212 | // Now that we have items determine what is the best size and set it. |
213 | SetBestSize(size); | |
4d08943e WS |
214 | |
215 | return true; | |
2bda0e17 | 216 | } |
2bda0e17 | 217 | |
584ad2a3 MB |
218 | bool wxRadioBox::Create(wxWindow *parent, |
219 | wxWindowID id, | |
220 | const wxString& title, | |
221 | const wxPoint& pos, | |
222 | const wxSize& size, | |
223 | const wxArrayString& choices, | |
224 | int majorDim, | |
225 | long style, | |
226 | const wxValidator& val, | |
227 | const wxString& name) | |
228 | { | |
229 | wxCArrayString chs(choices); | |
230 | return Create(parent, id, title, pos, size, chs.GetCount(), | |
231 | chs.GetStrings(), majorDim, style, val, name); | |
232 | } | |
233 | ||
e373f51b | 234 | wxRadioBox::~wxRadioBox() |
2bda0e17 | 235 | { |
4d08943e | 236 | m_isBeingDeleted = true; |
1eb20d4a | 237 | |
bd0a76e2 VZ |
238 | delete m_radioButtons; |
239 | delete[] m_radioWidth; | |
240 | delete[] m_radioHeight; | |
241 | } | |
242 | ||
243 | // NB: if this code is changed, wxGetWindowForHWND() which relies on having the | |
244 | // radiobox pointer in GWL_USERDATA for radio buttons must be updated too! | |
245 | void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn) | |
246 | { | |
247 | HWND hwndBtn = (HWND)hWndBtn; | |
248 | ||
249 | if ( !s_wndprocRadioBtn ) | |
250 | s_wndprocRadioBtn = (WXFARPROC)wxGetWindowProc(hwndBtn); | |
251 | ||
252 | wxSetWindowProc(hwndBtn, wxRadioBtnWndProc); | |
253 | wxSetWindowUserData(hwndBtn, this); | |
254 | } | |
255 | ||
256 | // ---------------------------------------------------------------------------- | |
257 | // events generation | |
258 | // ---------------------------------------------------------------------------- | |
259 | ||
260 | bool wxRadioBox::MSWCommand(WXUINT cmd, WXWORD id) | |
261 | { | |
262 | if ( cmd == BN_CLICKED ) | |
da07e033 | 263 | { |
bd0a76e2 VZ |
264 | if (id == GetId()) |
265 | return true; | |
266 | ||
267 | int selectedButton = wxNOT_FOUND; | |
268 | ||
aa61d352 VZ |
269 | const unsigned int count = GetCount(); |
270 | for ( unsigned int i = 0; i < count; i++ ) | |
bd0a76e2 VZ |
271 | { |
272 | if ( id == wxGetWindowId((*m_radioButtons)[i]) ) | |
273 | { | |
274 | selectedButton = i; | |
275 | ||
276 | break; | |
277 | } | |
278 | } | |
279 | ||
280 | if ( selectedButton == wxNOT_FOUND ) | |
281 | { | |
282 | // just ignore it - due to a hack with WM_NCHITTEST handling in our | |
283 | // wnd proc, we can receive dummy click messages when we click near | |
284 | // the radiobox edge (this is ugly but Julian wouldn't let me get | |
285 | // rid of this...) | |
286 | return false; | |
287 | } | |
288 | ||
289 | if ( selectedButton != m_selectedButton ) | |
290 | { | |
291 | m_selectedButton = selectedButton; | |
292 | ||
293 | SendNotificationEvent(); | |
294 | } | |
295 | //else: don't generate events when the selection doesn't change | |
296 | ||
297 | return true; | |
da07e033 | 298 | } |
bd0a76e2 VZ |
299 | else |
300 | return false; | |
301 | } | |
42e69d6b | 302 | |
bd0a76e2 VZ |
303 | void wxRadioBox::Command(wxCommandEvent & event) |
304 | { | |
687706f5 | 305 | SetSelection (event.GetInt()); |
bd0a76e2 VZ |
306 | SetFocus(); |
307 | ProcessCommand(event); | |
308 | } | |
2bda0e17 | 309 | |
bd0a76e2 VZ |
310 | void wxRadioBox::SendNotificationEvent() |
311 | { | |
312 | wxCommandEvent event(wxEVT_COMMAND_RADIOBOX_SELECTED, m_windowId); | |
313 | event.SetInt( m_selectedButton ); | |
aa61d352 | 314 | event.SetString(GetString(m_selectedButton)); |
bd0a76e2 VZ |
315 | event.SetEventObject( this ); |
316 | ProcessCommand(event); | |
2bda0e17 KB |
317 | } |
318 | ||
bd0a76e2 VZ |
319 | // ---------------------------------------------------------------------------- |
320 | // simple accessors | |
321 | // ---------------------------------------------------------------------------- | |
322 | ||
aa61d352 | 323 | unsigned int wxRadioBox::GetCount() const |
2bda0e17 | 324 | { |
bd0a76e2 VZ |
325 | return m_radioButtons->GetCount(); |
326 | } | |
d66a042c | 327 | |
aa61d352 | 328 | void wxRadioBox::SetString(unsigned int item, const wxString& label) |
bd0a76e2 | 329 | { |
789f6795 | 330 | wxCHECK_RET( IsValid(item), wxT("invalid radiobox index") ); |
e373f51b | 331 | |
bd0a76e2 VZ |
332 | m_radioWidth[item] = |
333 | m_radioHeight[item] = wxDefaultCoord; | |
2bda0e17 | 334 | |
bd0a76e2 | 335 | ::SetWindowText((*m_radioButtons)[item], label.c_str()); |
31582e4e RD |
336 | |
337 | InvalidateBestSize(); | |
2bda0e17 KB |
338 | } |
339 | ||
bd0a76e2 | 340 | void wxRadioBox::SetSelection(int N) |
2bda0e17 | 341 | { |
789f6795 | 342 | wxCHECK_RET( IsValid(N), wxT("invalid radiobox index") ); |
bd0a76e2 | 343 | |
27758ba7 VZ |
344 | // unselect the old button |
345 | if ( m_selectedButton != wxNOT_FOUND ) | |
346 | ::SendMessage((*m_radioButtons)[m_selectedButton], BM_SETCHECK, 0, 0L); | |
347 | ||
348 | // and select the new one | |
bd0a76e2 VZ |
349 | ::SendMessage((*m_radioButtons)[N], BM_SETCHECK, 1, 0L); |
350 | ||
351 | m_selectedButton = N; | |
2bda0e17 KB |
352 | } |
353 | ||
354 | // Find string for position | |
aa61d352 | 355 | wxString wxRadioBox::GetString(unsigned int item) const |
2bda0e17 | 356 | { |
789f6795 | 357 | wxCHECK_MSG( IsValid(item), wxEmptyString, |
1e6feb95 VZ |
358 | wxT("invalid radiobox index") ); |
359 | ||
bd0a76e2 VZ |
360 | return wxGetWindowText((*m_radioButtons)[item]); |
361 | } | |
362 | ||
363 | void wxRadioBox::SetFocus() | |
364 | { | |
365 | if ( GetCount() > 0 ) | |
366 | { | |
367 | ::SetFocus((*m_radioButtons)[m_selectedButton == wxNOT_FOUND | |
368 | ? 0 | |
369 | : m_selectedButton]); | |
370 | } | |
371 | } | |
372 | ||
373 | // Enable a specific button | |
aa61d352 | 374 | bool wxRadioBox::Enable(unsigned int item, bool enable) |
bd0a76e2 | 375 | { |
789f6795 | 376 | wxCHECK_MSG( IsValid(item), false, |
bd0a76e2 VZ |
377 | wxT("invalid item in wxRadioBox::Enable()") ); |
378 | ||
789f6795 WS |
379 | BOOL ret = ::EnableWindow((*m_radioButtons)[item], enable); |
380 | ||
3bfa7be9 VZ |
381 | return (ret == 0) != enable; |
382 | } | |
383 | ||
aa61d352 | 384 | bool wxRadioBox::IsItemEnabled(unsigned int item) const |
3bfa7be9 VZ |
385 | { |
386 | wxCHECK_MSG( IsValid(item), false, | |
f2be5580 | 387 | wxT("invalid item in wxRadioBox::IsItemEnabled()") ); |
3bfa7be9 VZ |
388 | |
389 | return ::IsWindowEnabled((*m_radioButtons)[item]) != 0; | |
2bda0e17 KB |
390 | } |
391 | ||
bd0a76e2 | 392 | // Show a specific button |
aa61d352 | 393 | bool wxRadioBox::Show(unsigned int item, bool show) |
bd0a76e2 | 394 | { |
789f6795 | 395 | wxCHECK_MSG( IsValid(item), false, |
bd0a76e2 VZ |
396 | wxT("invalid item in wxRadioBox::Show()") ); |
397 | ||
789f6795 WS |
398 | BOOL ret = ::ShowWindow((*m_radioButtons)[item], show ? SW_SHOW : SW_HIDE); |
399 | ||
3bfa7be9 VZ |
400 | bool changed = (ret != 0) != show; |
401 | if ( changed ) | |
402 | { | |
31582e4e | 403 | InvalidateBestSize(); |
3bfa7be9 VZ |
404 | } |
405 | ||
31582e4e | 406 | return changed; |
bd0a76e2 VZ |
407 | } |
408 | ||
aa61d352 | 409 | bool wxRadioBox::IsItemShown(unsigned int item) const |
3bfa7be9 VZ |
410 | { |
411 | wxCHECK_MSG( IsValid(item), false, | |
f2be5580 | 412 | wxT("invalid item in wxRadioBox::IsItemShown()") ); |
3bfa7be9 VZ |
413 | |
414 | // don't use IsWindowVisible() here because it would return false if the | |
415 | // radiobox itself is hidden while we want to only return false if this | |
416 | // button specifically is hidden | |
417 | return (::GetWindowLong((*m_radioButtons)[item], | |
418 | GWL_STYLE) & WS_VISIBLE) != 0; | |
419 | } | |
420 | ||
c670c855 VZ |
421 | #if wxUSE_TOOLTIPS |
422 | ||
423 | bool wxRadioBox::HasToolTips() const | |
424 | { | |
425 | return wxStaticBox::HasToolTips() || wxRadioBoxBase::HasItemToolTips(); | |
426 | } | |
427 | ||
428 | void wxRadioBox::DoSetItemToolTip(unsigned int item, wxToolTip *tooltip) | |
429 | { | |
430 | // we have already checked for the item to be valid in wxRadioBoxBase | |
431 | const HWND hwndRbtn = (*m_radioButtons)[item]; | |
432 | if ( tooltip != NULL ) | |
433 | tooltip->Add(hwndRbtn); | |
434 | else // unset the tooltip | |
435 | wxToolTip::Remove(hwndRbtn); | |
436 | } | |
437 | ||
438 | #endif // wxUSE_TOOLTIPS | |
439 | ||
bd0a76e2 VZ |
440 | WX_FORWARD_STD_METHODS_TO_SUBWINDOWS(wxRadioBox, wxStaticBox, m_radioButtons) |
441 | ||
3ca6a5f0 BP |
442 | // ---------------------------------------------------------------------------- |
443 | // size calculations | |
444 | // ---------------------------------------------------------------------------- | |
445 | ||
446 | wxSize wxRadioBox::GetMaxButtonSize() const | |
447 | { | |
448 | // calculate the max button size | |
449 | int widthMax = 0, | |
450 | heightMax = 0; | |
aa61d352 VZ |
451 | const unsigned int count = GetCount(); |
452 | for ( unsigned int i = 0 ; i < count; i++ ) | |
3ca6a5f0 BP |
453 | { |
454 | int width, height; | |
455 | if ( m_radioWidth[i] < 0 ) | |
456 | { | |
bd0a76e2 | 457 | GetTextExtent(wxGetWindowText((*m_radioButtons)[i]), &width, &height); |
3ca6a5f0 BP |
458 | |
459 | // adjust the size to take into account the radio box itself | |
460 | // FIXME this is totally bogus! | |
461 | width += RADIO_SIZE; | |
462 | height *= 3; | |
463 | height /= 2; | |
464 | } | |
465 | else | |
466 | { | |
467 | width = m_radioWidth[i]; | |
468 | height = m_radioHeight[i]; | |
469 | } | |
470 | ||
471 | if ( widthMax < width ) | |
472 | widthMax = width; | |
473 | if ( heightMax < height ) | |
474 | heightMax = height; | |
475 | } | |
476 | ||
477 | return wxSize(widthMax, heightMax); | |
478 | } | |
479 | ||
480 | wxSize wxRadioBox::GetTotalButtonSize(const wxSize& sizeBtn) const | |
481 | { | |
482 | // the radiobox should be big enough for its buttons | |
483 | int cx1, cy1; | |
7a5e53ab | 484 | wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont()); |
3ca6a5f0 BP |
485 | |
486 | int extraHeight = cy1; | |
487 | ||
21e0a4d5 VZ |
488 | int height = GetRowCount() * sizeBtn.y + cy1/2 + extraHeight; |
489 | int width = GetColumnCount() * (sizeBtn.x + cx1) + cx1; | |
3ca6a5f0 | 490 | |
c7fd6717 | 491 | // Add extra space under the label, if it exists. |
1a87edf2 | 492 | if (!wxControl::GetLabel().empty()) |
c7fd6717 JS |
493 | height += cy1/2; |
494 | ||
3ca6a5f0 BP |
495 | // and also wide enough for its label |
496 | int widthLabel; | |
9f8130d6 | 497 | GetTextExtent(wxStripMenuCodes(GetLabel()), &widthLabel, NULL); |
3ca6a5f0 BP |
498 | widthLabel += RADIO_SIZE; // FIXME this is bogus too |
499 | if ( widthLabel > width ) | |
500 | width = widthLabel; | |
501 | ||
502 | return wxSize(width, height); | |
503 | } | |
504 | ||
505 | wxSize wxRadioBox::DoGetBestSize() const | |
506 | { | |
31582e4e RD |
507 | wxSize best = GetTotalButtonSize(GetMaxButtonSize()); |
508 | CacheBestSize(best); | |
509 | return best; | |
3ca6a5f0 BP |
510 | } |
511 | ||
1f916a19 | 512 | // Restored old code. |
bfc6fde4 | 513 | void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags) |
1f916a19 | 514 | { |
4438caf4 VZ |
515 | int currentX, currentY; |
516 | GetPosition(¤tX, ¤tY); | |
c219cecc VZ |
517 | int widthOld, heightOld; |
518 | GetSize(&widthOld, &heightOld); | |
519 | ||
4438caf4 VZ |
520 | int xx = x; |
521 | int yy = y; | |
522 | ||
4d08943e | 523 | if (x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) |
4438caf4 | 524 | xx = currentX; |
4d08943e | 525 | if (y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) |
4438caf4 VZ |
526 | yy = currentY; |
527 | ||
99c613c5 JG |
528 | int y_offset = yy; |
529 | int x_offset = xx; | |
f048e32f | 530 | |
3ca6a5f0 | 531 | int cx1, cy1; |
7a5e53ab | 532 | wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont()); |
4438caf4 VZ |
533 | |
534 | // Attempt to have a look coherent with other platforms: We compute the | |
535 | // biggest toggle dim, then we align all items according this value. | |
3ca6a5f0 BP |
536 | wxSize maxSize = GetMaxButtonSize(); |
537 | int maxWidth = maxSize.x, | |
538 | maxHeight = maxSize.y; | |
4438caf4 | 539 | |
3ca6a5f0 BP |
540 | wxSize totSize = GetTotalButtonSize(maxSize); |
541 | int totWidth = totSize.x, | |
542 | totHeight = totSize.y; | |
543 | ||
544 | // only change our width/height if asked for | |
4d08943e | 545 | if ( width == wxDefaultCoord ) |
1f916a19 | 546 | { |
3ca6a5f0 BP |
547 | if ( sizeFlags & wxSIZE_AUTO_WIDTH ) |
548 | width = totWidth; | |
4438caf4 | 549 | else |
3ca6a5f0 | 550 | width = widthOld; |
1f916a19 | 551 | } |
1f916a19 | 552 | |
4d08943e | 553 | if ( height == wxDefaultCoord ) |
4438caf4 | 554 | { |
3ca6a5f0 BP |
555 | if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) |
556 | height = totHeight; | |
4438caf4 | 557 | else |
3ca6a5f0 BP |
558 | height = heightOld; |
559 | } | |
4438caf4 | 560 | |
7d86a2d4 | 561 | DoMoveWindow(xx, yy, width, height); |
c219cecc | 562 | |
3ca6a5f0 BP |
563 | // Now position all the buttons: the current button will be put at |
564 | // wxPoint(x_offset, y_offset) and the new row/column will start at | |
565 | // startX/startY. The size of all buttons will be the same wxSize(maxWidth, | |
566 | // maxHeight) except for the buttons in the last column which should extend | |
567 | // to the right border of radiobox and thus can be wider than this. | |
c219cecc | 568 | |
3ca6a5f0 | 569 | // Also, remember that wxRA_SPECIFY_COLS means that we arrange buttons in |
21e0a4d5 | 570 | // left to right order and GetMajorDim() is the number of columns while |
3ca6a5f0 | 571 | // wxRA_SPECIFY_ROWS means that the buttons are arranged top to bottom and |
21e0a4d5 | 572 | // GetMajorDim() is the number of rows. |
4438caf4 | 573 | |
3ca6a5f0 BP |
574 | x_offset += cx1; |
575 | y_offset += cy1; | |
1f916a19 | 576 | |
c7fd6717 | 577 | // Add extra space under the label, if it exists. |
1a87edf2 | 578 | if (!wxControl::GetLabel().empty()) |
c7fd6717 | 579 | y_offset += cy1/2; |
3ca6a5f0 | 580 | |
4438caf4 VZ |
581 | int startX = x_offset; |
582 | int startY = y_offset; | |
1f916a19 | 583 | |
aa61d352 VZ |
584 | const unsigned int count = GetCount(); |
585 | for (unsigned int i = 0; i < count; i++) | |
1f916a19 | 586 | { |
3ca6a5f0 BP |
587 | // the last button in the row may be wider than the other ones as the |
588 | // radiobox may be wider than the sum of the button widths (as it | |
589 | // happens, for example, when the radiobox label is very long) | |
590 | bool isLastInTheRow; | |
591 | if ( m_windowStyle & wxRA_SPECIFY_COLS ) | |
592 | { | |
593 | // item is the last in its row if it is a multiple of the number of | |
594 | // columns or if it is just the last item | |
aa61d352 | 595 | unsigned int n = i + 1; |
21e0a4d5 | 596 | isLastInTheRow = ((n % GetMajorDim()) == 0) || (n == count); |
3ca6a5f0 BP |
597 | } |
598 | else // wxRA_SPECIFY_ROWS | |
4438caf4 | 599 | { |
3ca6a5f0 | 600 | // item is the last in the row if it is in the last columns |
21e0a4d5 | 601 | isLastInTheRow = i >= (count/GetMajorDim())*GetMajorDim(); |
3ca6a5f0 BP |
602 | } |
603 | ||
604 | // is this the start of new row/column? | |
21e0a4d5 | 605 | if ( i && (i % GetMajorDim() == 0) ) |
3ca6a5f0 BP |
606 | { |
607 | if ( m_windowStyle & wxRA_SPECIFY_ROWS ) | |
4438caf4 | 608 | { |
3ca6a5f0 | 609 | // start of new column |
4438caf4 VZ |
610 | y_offset = startY; |
611 | x_offset += maxWidth + cx1; | |
612 | } | |
3ca6a5f0 | 613 | else // start of new row |
4438caf4 VZ |
614 | { |
615 | x_offset = startX; | |
616 | y_offset += maxHeight; | |
617 | if (m_radioWidth[0]>0) | |
618 | y_offset += cy1/2; | |
619 | } | |
620 | } | |
3ca6a5f0 BP |
621 | |
622 | int widthBtn; | |
623 | if ( isLastInTheRow ) | |
4438caf4 | 624 | { |
3ca6a5f0 BP |
625 | // make the button go to the end of radio box |
626 | widthBtn = startX + width - x_offset - 2*cx1; | |
627 | if ( widthBtn < maxWidth ) | |
628 | widthBtn = maxWidth; | |
4438caf4 VZ |
629 | } |
630 | else | |
631 | { | |
3ca6a5f0 BP |
632 | // normal button, always of the same size |
633 | widthBtn = maxWidth; | |
4438caf4 | 634 | } |
1f916a19 | 635 | |
bd0a76e2 VZ |
636 | // make all buttons of the same, maximal size - like this they cover |
637 | // the radiobox entirely and the radiobox tooltips are always shown | |
638 | // (otherwise they are not when the mouse pointer is in the radiobox | |
639 | // part not belonging to any radiobutton) | |
99c613c5 | 640 | DoMoveSibling((*m_radioButtons)[i], x_offset, y_offset, widthBtn, maxHeight); |
4438caf4 | 641 | |
3ca6a5f0 BP |
642 | // where do we put the next button? |
643 | if ( m_windowStyle & wxRA_SPECIFY_ROWS ) | |
4438caf4 | 644 | { |
3ca6a5f0 | 645 | // below this one |
4438caf4 VZ |
646 | y_offset += maxHeight; |
647 | if (m_radioWidth[0]>0) | |
648 | y_offset += cy1/2; | |
649 | } | |
650 | else | |
3ca6a5f0 BP |
651 | { |
652 | // to the right of this one | |
653 | x_offset += widthBtn + cx1; | |
654 | } | |
1f916a19 | 655 | } |
1f916a19 JS |
656 | } |
657 | ||
c3732409 VZ |
658 | // ---------------------------------------------------------------------------- |
659 | // radio box drawing | |
660 | // ---------------------------------------------------------------------------- | |
661 | ||
662 | #ifndef __WXWINCE__ | |
663 | ||
664 | WXHRGN wxRadioBox::MSWGetRegionWithoutChildren() | |
665 | { | |
666 | RECT rc; | |
667 | ::GetWindowRect(GetHwnd(), &rc); | |
668 | HRGN hrgn = ::CreateRectRgn(rc.left, rc.top, rc.right + 1, rc.bottom + 1); | |
669 | ||
aa61d352 VZ |
670 | const unsigned int count = GetCount(); |
671 | for ( unsigned int i = 0; i < count; ++i ) | |
c3732409 | 672 | { |
455c8f1d VZ |
673 | // don't clip out hidden children |
674 | if ( !IsItemShown(i) ) | |
675 | continue; | |
676 | ||
c3732409 VZ |
677 | ::GetWindowRect((*m_radioButtons)[i], &rc); |
678 | AutoHRGN hrgnchild(::CreateRectRgnIndirect(&rc)); | |
679 | ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF); | |
680 | } | |
681 | ||
682 | return (WXHRGN)hrgn; | |
683 | } | |
684 | ||
685 | #endif // __WXWINCE__ | |
686 | ||
e373f51b VZ |
687 | // --------------------------------------------------------------------------- |
688 | // window proc for radio buttons | |
689 | // --------------------------------------------------------------------------- | |
690 | ||
691 | LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd, | |
8614c467 | 692 | UINT message, |
e373f51b VZ |
693 | WPARAM wParam, |
694 | LPARAM lParam) | |
695 | { | |
8614c467 | 696 | switch ( message ) |
e373f51b | 697 | { |
8614c467 VZ |
698 | case WM_GETDLGCODE: |
699 | // we must tell IsDialogMessage()/our kbd processing code that we | |
700 | // want to process arrows ourselves because neither of them is | |
701 | // smart enough to handle arrows properly for us | |
702 | { | |
8ad6ad99 | 703 | long lDlgCode = ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, |
8614c467 | 704 | message, wParam, lParam); |
8ad6ad99 | 705 | |
8614c467 VZ |
706 | return lDlgCode | DLGC_WANTARROWS; |
707 | } | |
e373f51b | 708 | |
8614c467 | 709 | case WM_KEYDOWN: |
9a5ccab4 | 710 | { |
975b6bcf | 711 | wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd); |
f048e32f | 712 | |
8614c467 | 713 | wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") ); |
f048e32f | 714 | |
4d08943e | 715 | bool processed = true; |
f048e32f | 716 | |
e421922f | 717 | wxDirection dir; |
8614c467 VZ |
718 | switch ( wParam ) |
719 | { | |
720 | case VK_UP: | |
1e6feb95 | 721 | dir = wxUP; |
8614c467 | 722 | break; |
f048e32f | 723 | |
8614c467 | 724 | case VK_LEFT: |
1e6feb95 | 725 | dir = wxLEFT; |
8614c467 | 726 | break; |
f048e32f | 727 | |
8614c467 | 728 | case VK_DOWN: |
1e6feb95 | 729 | dir = wxDOWN; |
8614c467 | 730 | break; |
f048e32f | 731 | |
8614c467 | 732 | case VK_RIGHT: |
1e6feb95 | 733 | dir = wxRIGHT; |
8614c467 VZ |
734 | break; |
735 | ||
736 | default: | |
4d08943e | 737 | processed = false; |
1e6feb95 VZ |
738 | |
739 | // just to suppress the compiler warning | |
740 | dir = wxALL; | |
8614c467 VZ |
741 | } |
742 | ||
743 | if ( processed ) | |
f048e32f | 744 | { |
1e6feb95 VZ |
745 | int selOld = radiobox->GetSelection(); |
746 | int selNew = radiobox->GetNextItem | |
747 | ( | |
748 | selOld, | |
749 | dir, | |
750 | radiobox->GetWindowStyle() | |
751 | ); | |
3ca6a5f0 | 752 | |
8614c467 VZ |
753 | if ( selNew != selOld ) |
754 | { | |
755 | radiobox->SetSelection(selNew); | |
974931fe | 756 | radiobox->SetFocus(); |
8614c467 VZ |
757 | |
758 | // emulate the button click | |
759 | radiobox->SendNotificationEvent(); | |
9a5ccab4 | 760 | |
8614c467 VZ |
761 | return 0; |
762 | } | |
f048e32f | 763 | } |
9a5ccab4 | 764 | } |
21687069 VZ |
765 | break; |
766 | ||
1dab049c VZ |
767 | case WM_SETFOCUS: |
768 | case WM_KILLFOCUS: | |
769 | { | |
975b6bcf | 770 | wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd); |
1dab049c VZ |
771 | |
772 | wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") ); | |
773 | ||
774 | // if we don't do this, no focus events are generated for the | |
775 | // radiobox and, besides, we need to notify the parent about | |
776 | // the focus change, otherwise the focus handling logic in | |
777 | // wxControlContainer doesn't work | |
778 | if ( message == WM_SETFOCUS ) | |
779 | radiobox->HandleSetFocus((WXHWND)wParam); | |
780 | else | |
781 | radiobox->HandleKillFocus((WXHWND)wParam); | |
782 | } | |
783 | break; | |
784 | ||
bd0a76e2 | 785 | #ifndef __WXWINCE__ |
fac93396 | 786 | case WM_HELP: |
e421922f | 787 | { |
975b6bcf | 788 | wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd); |
fac93396 | 789 | |
e421922f | 790 | wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") ); |
fac93396 | 791 | |
bd0a76e2 VZ |
792 | bool processed = false; |
793 | ||
794 | wxEvtHandler * const handler = radiobox->GetEventHandler(); | |
fac93396 | 795 | |
e421922f | 796 | HELPINFO* info = (HELPINFO*) lParam; |
bd0a76e2 | 797 | if ( info->iContextType == HELPINFO_WINDOW ) |
fac93396 | 798 | { |
bd0a76e2 VZ |
799 | for ( wxWindow* subjectOfHelp = radiobox; |
800 | subjectOfHelp; | |
801 | subjectOfHelp = subjectOfHelp->GetParent() ) | |
e421922f | 802 | { |
bd0a76e2 VZ |
803 | wxHelpEvent helpEvent(wxEVT_HELP, |
804 | subjectOfHelp->GetId(), | |
805 | wxPoint(info->MousePos.x, | |
806 | info->MousePos.y)); | |
e421922f | 807 | helpEvent.SetEventObject(radiobox); |
bd0a76e2 VZ |
808 | if ( handler->ProcessEvent(helpEvent) ) |
809 | { | |
810 | processed = true; | |
811 | break; | |
812 | } | |
e421922f | 813 | } |
fac93396 | 814 | } |
e421922f VZ |
815 | else if (info->iContextType == HELPINFO_MENUITEM) |
816 | { | |
bd0a76e2 | 817 | wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId); |
e421922f | 818 | helpEvent.SetEventObject(radiobox); |
bd0a76e2 | 819 | processed = handler->ProcessEvent(helpEvent); |
e421922f | 820 | } |
bd0a76e2 VZ |
821 | |
822 | if ( processed ) | |
e421922f | 823 | return 0; |
e421922f | 824 | } |
c3732409 | 825 | break; |
bd0a76e2 | 826 | #endif // !__WXWINCE__ |
e373f51b VZ |
827 | } |
828 | ||
8ad6ad99 | 829 | return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, message, wParam, lParam); |
e373f51b | 830 | } |
42e69d6b | 831 | |
1e6feb95 | 832 | #endif // wxUSE_RADIOBOX |