]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/radiobox.cpp
compilation fix
[wxWidgets.git] / src / msw / radiobox.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: radiobox.cpp
3// Purpose: wxRadioBox
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "radiobox.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
32 #include <stdio.h>
33 #include "wx/setup.h"
34 #include "wx/bitmap.h"
35 #include "wx/brush.h"
36 #include "wx/radiobox.h"
37#endif
38
39#include "wx/msw/private.h"
40
41#if !USE_SHARED_LIBRARY
42 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
43#endif
44
45// ---------------------------------------------------------------------------
46// private functions
47// ---------------------------------------------------------------------------
48
49// get the id of the window
50#ifdef __WIN32__
51 #define GET_WIN_ID(hwnd) ::GetWindowLong((HWND)hwnd, GWL_ID)
52#else // Win16
53 #define GET_WIN_ID(hwnd) ::GetWindowWord((HWND)hwnd, GWW_ID)
54#endif // Win32/16
55
56// wnd proc for radio buttons
57LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hWnd,
58 UINT message,
59 WPARAM wParam,
60 LPARAM lParam);
61
62// ---------------------------------------------------------------------------
63// global vars
64// ---------------------------------------------------------------------------
65
66// the pointer to standard radio button wnd proc
67static WNDPROC s_wndprocRadioBtn = (WNDPROC)NULL;
68
69// ===========================================================================
70// implementation
71// ===========================================================================
72
73// ---------------------------------------------------------------------------
74// wxRadioBox
75// ---------------------------------------------------------------------------
76
77int wxRadioBox::GetNumVer() const
78{
79 if ( m_windowStyle & wxRA_SPECIFY_ROWS )
80 {
81 return m_majorDim;
82 }
83 else
84 {
85 return (m_noItems + m_majorDim - 1)/m_majorDim;
86 }
87}
88
89int wxRadioBox::GetNumHor() const
90{
91 if ( m_windowStyle & wxRA_SPECIFY_ROWS )
92 {
93 return (m_noItems + m_majorDim - 1)/m_majorDim;
94 }
95 else
96 {
97 return m_majorDim;
98 }
99}
100
101bool wxRadioBox::MSWCommand(WXUINT param, WXWORD id)
102{
103 if ( param == BN_CLICKED )
104 {
105 m_selectedButton = -1;
106
107 for ( int i = 0; i < m_noItems; i++ )
108 {
109 if ( id == GET_WIN_ID(m_radioButtons[i]) )
110 {
111 m_selectedButton = i;
112
113 break;
114 }
115 }
116
117 wxASSERT_MSG( m_selectedButton != -1, "click from alien button?" );
118
119 wxCommandEvent event(wxEVT_COMMAND_RADIOBOX_SELECTED, m_windowId);
120 event.SetInt( m_selectedButton );
121 event.SetEventObject( this );
122 ProcessCommand(event);
123
124 return TRUE;
125 }
126 else
127 return FALSE;
128}
129
130#if WXWIN_COMPATIBILITY
131wxRadioBox::wxRadioBox(wxWindow *parent, wxFunction func, const char *title,
132 int x, int y, int width, int height,
133 int n, char **choices,
134 int majorDim, long style, const char *name)
135{
136 wxString *choices2 = new wxString[n];
137 for ( int i = 0; i < n; i ++) choices2[i] = choices[i];
138 Create(parent, -1, title, wxPoint(x, y), wxSize(width, height), n, choices2, majorDim, style,
139 wxDefaultValidator, name);
140 Callback(func);
141 delete choices2;
142}
143
144#endif
145
146// Radio box item
147wxRadioBox::wxRadioBox()
148{
149 m_selectedButton = -1;
150 m_noItems = 0;
151 m_noRowsOrCols = 0;
152 m_radioButtons = NULL;
153 m_majorDim = 0;
154 m_radioWidth = NULL;
155 m_radioHeight = NULL;
156}
157
158bool wxRadioBox::Create(wxWindow *parent, wxWindowID id, const wxString& title,
159 const wxPoint& pos, const wxSize& size,
160 int n, const wxString choices[],
161 int majorDim, long style,
162 const wxValidator& val, const wxString& name)
163{
164 m_selectedButton = -1;
165 m_noItems = n;
166
167 SetName(name);
168 SetValidator(val);
169
170 parent->AddChild(this);
171 m_backgroundColour = parent->GetBackgroundColour();
172 m_foregroundColour = parent->GetForegroundColour();
173
174 m_windowStyle = (long&)style;
175
176 int x = pos.x;
177 int y = pos.y;
178 int width = size.x;
179 int height = size.y;
180
181 if (id == -1)
182 m_windowId = NewControlId();
183 else
184 m_windowId = id;
185
186 if ( majorDim == 0 )
187 m_majorDim = n;
188 else
189 m_majorDim = majorDim;
190 m_noRowsOrCols = majorDim;
191
192 long msStyle = GROUP_FLAGS;
193
194 bool want3D;
195 WXDWORD exStyle = Determine3DEffects(0, &want3D);
196 // Even with extended styles, need to combine with WS_BORDER
197 // for them to look right.
198 /*
199 if ( want3D || wxStyleHasBorder(m_windowStyle) )
200 msStyle |= WS_BORDER;
201 */
202
203 HWND hwndParent = (HWND)parent->GetHWND();
204
205 m_hWnd = (WXHWND)::CreateWindowEx
206 (
207 (DWORD)exStyle,
208 GROUP_CLASS,
209 title,
210 msStyle,
211 0, 0, 0, 0,
212 hwndParent,
213 (HMENU)m_windowId,
214 wxGetInstance(),
215 NULL
216 );
217
218#if wxUSE_CTL3D
219 if (want3D)
220 {
221 Ctl3dSubclassCtl((HWND)m_hWnd);
222 m_useCtl3D = TRUE;
223 }
224#endif // wxUSE_CTL3D
225
226 SetFont(parent->GetFont());
227
228 SubclassWin(m_hWnd);
229
230 // Some radio boxes test consecutive id.
231 (void)NewControlId();
232 m_radioButtons = new WXHWND[n];
233 m_radioWidth = new int[n];
234 m_radioHeight = new int[n];
235 int i;
236 for (i = 0; i < n; i++)
237 {
238 m_radioWidth[i] = m_radioHeight[i] = -1;
239 long groupStyle = 0;
240 if ( i == 0 && style == 0 )
241 groupStyle = WS_GROUP;
242 long newId = NewControlId();
243 long msStyle = groupStyle | RADIO_FLAGS;
244
245 HWND hwndBtn = CreateWindowEx(exStyle, RADIO_CLASS,
246 choices[i], msStyle,
247 0,0,0,0,
248 hwndParent,
249 (HMENU)newId, wxGetInstance(),
250 NULL);
251
252 m_radioButtons[i] = (WXHWND)hwndBtn;
253 SubclassRadioButton((WXHWND)hwndBtn);
254
255 wxFont& font = GetFont();
256 if ( font.Ok() )
257 {
258 SendMessage(hwndBtn, WM_SETFONT,
259 (WPARAM)font.GetResourceHandle(), 0L);
260 }
261
262 m_subControls.Append((wxObject *)newId);
263 }
264
265 // Create a dummy radio control to end the group.
266 (void)CreateWindowEx(0, RADIO_CLASS, "", WS_GROUP | RADIO_FLAGS,
267 0, 0, 0, 0, hwndParent,
268 (HMENU)NewControlId(), wxGetInstance(), NULL);
269
270 SetSelection(0);
271
272 SetSize(x, y, width, height);
273
274 return TRUE;
275}
276
277wxRadioBox::~wxRadioBox()
278{
279 m_isBeingDeleted = TRUE;
280
281 if (m_radioButtons)
282 {
283 int i;
284 for (i = 0; i < m_noItems; i++)
285 DestroyWindow((HWND) m_radioButtons[i]);
286 delete[] m_radioButtons;
287 }
288 if (m_radioWidth)
289 delete[] m_radioWidth;
290 if (m_radioHeight)
291 delete[] m_radioHeight;
292 if (m_hWnd)
293 ::DestroyWindow((HWND) m_hWnd);
294 m_hWnd = 0;
295
296}
297
298wxString wxRadioBox::GetLabel(int item) const
299{
300 GetWindowText((HWND)m_radioButtons[item], wxBuffer, 300);
301 return wxString(wxBuffer);
302}
303
304void wxRadioBox::SetLabel(int item, const wxString& label)
305{
306 m_radioWidth[item] = m_radioHeight[item] = -1;
307 SetWindowText((HWND)m_radioButtons[item], (const char *)label);
308}
309
310void wxRadioBox::SetLabel(int item, wxBitmap *bitmap)
311{
312 /*
313 m_radioWidth[item] = bitmap->GetWidth() + FB_MARGIN;
314 m_radioHeight[item] = bitmap->GetHeight() + FB_MARGIN;
315 */
316}
317
318int wxRadioBox::FindString(const wxString& s) const
319{
320 int i;
321 for (i = 0; i < m_noItems; i++)
322 {
323 GetWindowText((HWND) m_radioButtons[i], wxBuffer, 1000);
324 if (s == wxBuffer)
325 return i;
326 }
327 return -1;
328}
329
330void wxRadioBox::SetSelection(int N)
331{
332 wxCHECK_RET( (N >= 0) && (N < m_noItems), "invalid radiobox index" );
333
334 // Following necessary for Win32s, because Win32s translate BM_SETCHECK
335 if (m_selectedButton >= 0 && m_selectedButton < m_noItems)
336 ::SendMessage((HWND) m_radioButtons[m_selectedButton], BM_SETCHECK, 0, 0L);
337
338 ::SendMessage((HWND)m_radioButtons[N], BM_SETCHECK, 1, 0L);
339 ::SetFocus((HWND)m_radioButtons[N]);
340
341 m_selectedButton = N;
342}
343
344// Get single selection, for single choice list items
345int wxRadioBox::GetSelection() const
346{
347 return m_selectedButton;
348}
349
350// Find string for position
351wxString wxRadioBox::GetString(int N) const
352{
353 return wxGetWindowText(m_radioButtons[N]);
354}
355
356// Restored old code.
357void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
358{
359 int currentX, currentY;
360 GetPosition(&currentX, &currentY);
361 int xx = x;
362 int yy = y;
363
364 if (x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
365 xx = currentX;
366 if (y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
367 yy = currentY;
368
369 char buf[400];
370
371 int y_offset = yy;
372 int x_offset = xx;
373 int current_width, cyf;
374
375 int cx1,cy1;
376 wxGetCharSize(m_hWnd, &cx1, &cy1, & GetFont());
377 // Attempt to have a look coherent with other platforms:
378 // We compute the biggest toggle dim, then we align all
379 // items according this value.
380 int maxWidth = -1;
381 int maxHeight = -1;
382
383 int i;
384 for (i = 0 ; i < m_noItems; i++)
385 {
386 int eachWidth;
387 int eachHeight;
388 if (m_radioWidth[i]<0)
389 {
390 // It's a labelled toggle
391 GetWindowText((HWND) m_radioButtons[i], buf, 300);
392 GetTextExtent(buf, &current_width, &cyf,NULL,NULL, & GetFont());
393 eachWidth = (int)(current_width + RADIO_SIZE);
394 eachHeight = (int)((3*cyf)/2);
395 }
396 else
397 {
398 eachWidth = m_radioWidth[i];
399 eachHeight = m_radioHeight[i];
400 }
401 if (maxWidth<eachWidth) maxWidth = eachWidth;
402 if (maxHeight<eachHeight) maxHeight = eachHeight;
403 }
404
405 if (m_hWnd)
406 {
407 int totWidth;
408 int totHeight;
409
410 int nbHor = GetNumHor(),
411 nbVer = GetNumVer();
412
413 // this formula works, but I don't know why.
414 // Please, be sure what you do if you modify it!!
415 if (m_radioWidth[0]<0)
416 totHeight = (nbVer * maxHeight) + cy1/2;
417 else
418 totHeight = nbVer * (maxHeight+cy1/2);
419 totWidth = nbHor * (maxWidth+cx1);
420
421#if (!CTL3D)
422 // Requires a bigger group box in plain Windows
423 MoveWindow((HWND) m_hWnd,x_offset,y_offset,totWidth+cx1,totHeight+(3*cy1)/2,TRUE);
424#else
425 MoveWindow((HWND) m_hWnd,x_offset,y_offset,totWidth+cx1,totHeight+cy1,TRUE);
426#endif
427 x_offset += cx1;
428 y_offset += cy1;
429 }
430
431#if (!CTL3D)
432 y_offset += (int)(cy1/2); // Fudge factor since buttons overlapped label
433 // JACS 2/12/93. CTL3D draws group label quite high.
434#endif
435 int startX = x_offset;
436 int startY = y_offset;
437
438 for ( i = 0 ; i < m_noItems; i++)
439 {
440 // Bidimensional radio adjustment
441 if (i&&((i%m_majorDim)==0)) // Why is this omitted for i = 0?
442 {
443 if (m_windowStyle & wxRA_VERTICAL)
444 {
445 y_offset = startY;
446 x_offset += maxWidth + cx1;
447 }
448 else
449 {
450 x_offset = startX;
451 y_offset += maxHeight;
452 if (m_radioWidth[0]>0)
453 y_offset += cy1/2;
454 }
455 }
456 int eachWidth;
457 int eachHeight;
458 if (m_radioWidth[i]<0)
459 {
460 // It's a labeled item
461 GetWindowText((HWND) m_radioButtons[i], buf, 300);
462 GetTextExtent(buf, &current_width, &cyf,NULL,NULL, & GetFont());
463
464 // How do we find out radio button bitmap size!!
465 // By adjusting them carefully, manually :-)
466 eachWidth = (int)(current_width + RADIO_SIZE);
467 eachHeight = (int)((3*cyf)/2);
468 }
469 else
470 {
471 eachWidth = m_radioWidth[i];
472 eachHeight = m_radioHeight[i];
473 }
474
475 MoveWindow((HWND) m_radioButtons[i],x_offset,y_offset,eachWidth,eachHeight,TRUE);
476 if (m_windowStyle & wxRA_SPECIFY_ROWS)
477 {
478 y_offset += maxHeight;
479 if (m_radioWidth[0]>0)
480 y_offset += cy1/2;
481 }
482 else
483 x_offset += maxWidth + cx1;
484 }
485}
486
487
488void wxRadioBox::GetSize(int *width, int *height) const
489{
490 RECT rect;
491 rect.left = -1; rect.right = -1; rect.top = -1; rect.bottom = -1;
492
493 if (m_hWnd)
494 wxFindMaxSize(m_hWnd, &rect);
495
496 int i;
497 for (i = 0; i < m_noItems; i++)
498 wxFindMaxSize(m_radioButtons[i], &rect);
499
500 *width = rect.right - rect.left;
501 *height = rect.bottom - rect.top;
502}
503
504void wxRadioBox::GetPosition(int *x, int *y) const
505{
506 wxWindow *parent = GetParent();
507 RECT rect;
508 rect.left = -1; rect.right = -1; rect.top = -1; rect.bottom = -1;
509
510 int i;
511 for (i = 0; i < m_noItems; i++)
512 wxFindMaxSize(m_radioButtons[i], &rect);
513
514 if (m_hWnd)
515 wxFindMaxSize(m_hWnd, &rect);
516
517 // Since we now have the absolute screen coords,
518 // if there's a parent we must subtract its top left corner
519 POINT point;
520 point.x = rect.left;
521 point.y = rect.top;
522 if (parent)
523 {
524 ::ScreenToClient((HWND) parent->GetHWND(), &point);
525 }
526 // We may be faking the client origin.
527 // So a window that's really at (0, 30) may appear
528 // (to wxWin apps) to be at (0, 0).
529 if (GetParent())
530 {
531 wxPoint pt(GetParent()->GetClientAreaOrigin());
532 point.x -= pt.x;
533 point.y -= pt.y;
534 }
535
536 *x = point.x;
537 *y = point.y;
538}
539
540wxString wxRadioBox::GetLabel() const
541{
542 if (m_hWnd)
543 {
544 GetWindowText((HWND) m_hWnd, wxBuffer, 300);
545 return wxString(wxBuffer);
546 }
547 else return wxString("");
548}
549
550void wxRadioBox::SetLabel(const wxString& label)
551{
552 if (m_hWnd)
553 SetWindowText((HWND) m_hWnd, label);
554}
555
556void wxRadioBox::SetFocus()
557{
558 if (m_noItems > 0)
559 {
560 if (m_selectedButton == -1)
561 ::SetFocus((HWND) m_radioButtons[0]);
562 else
563 ::SetFocus((HWND) m_radioButtons[m_selectedButton]);
564 }
565
566}
567
568bool wxRadioBox::Show(bool show)
569{
570 m_isShown = show;
571 int cshow;
572 if (show)
573 cshow = SW_SHOW;
574 else
575 cshow = SW_HIDE;
576 if (m_hWnd)
577 ShowWindow((HWND) m_hWnd, cshow);
578 int i;
579 for (i = 0; i < m_noItems; i++)
580 ShowWindow((HWND) m_radioButtons[i], cshow);
581 return TRUE;
582}
583
584// Enable a specific button
585void wxRadioBox::Enable(int item, bool enable)
586{
587 if (item<0)
588 wxWindow::Enable(enable);
589 else if (item < m_noItems)
590 ::EnableWindow((HWND) m_radioButtons[item], enable);
591}
592
593// Enable all controls
594void wxRadioBox::Enable(bool enable)
595{
596 wxControl::Enable(enable);
597
598 int i;
599 for (i = 0; i < m_noItems; i++)
600 ::EnableWindow((HWND) m_radioButtons[i], enable);
601}
602
603// Show a specific button
604void wxRadioBox::Show(int item, bool show)
605{
606 if (item<0)
607 wxRadioBox::Show(show);
608 else if (item < m_noItems)
609 {
610 int cshow;
611 if (show)
612 cshow = SW_SHOW;
613 else
614 cshow = SW_HIDE;
615 ShowWindow((HWND) m_radioButtons[item], cshow);
616 }
617}
618
619WXHBRUSH wxRadioBox::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor,
620 WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
621{
622#if wxUSE_CTL3D
623 if ( m_useCtl3D )
624 {
625 HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam);
626 return (WXHBRUSH) hbrush;
627 }
628#endif
629
630 if (GetParent()->GetTransparentBackground())
631 SetBkMode((HDC) pDC, TRANSPARENT);
632 else
633 SetBkMode((HDC) pDC, OPAQUE);
634
635 ::SetBkColor((HDC) pDC, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
636 ::SetTextColor((HDC) pDC, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue()));
637
638 wxBrush *backgroundBrush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID);
639
640 // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush
641 // has a zero usage count.
642 // backgroundBrush->RealizeResource();
643 return (WXHBRUSH) backgroundBrush->GetResourceHandle();
644}
645
646// For single selection items only
647wxString wxRadioBox::GetStringSelection() const
648{
649 wxString result;
650 int sel = GetSelection();
651 if (sel > -1)
652 result = GetString(sel);
653
654 return result;
655}
656
657bool wxRadioBox::SetStringSelection(const wxString& s)
658{
659 int sel = FindString (s);
660 if (sel > -1)
661 {
662 SetSelection (sel);
663 return TRUE;
664 }
665 else
666 return FALSE;
667}
668
669bool wxRadioBox::ContainsHWND(WXHWND hWnd) const
670{
671 int i;
672 for (i = 0; i < Number(); i++)
673 if (GetRadioButtons()[i] == hWnd)
674 return TRUE;
675 return FALSE;
676}
677
678void wxRadioBox::Command (wxCommandEvent & event)
679{
680 SetSelection (event.m_commandInt);
681 ProcessCommand (event);
682}
683
684long wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
685{
686 if (nMsg == WM_NCHITTEST)
687 {
688 int xPos = LOWORD(lParam); // horizontal position of cursor
689 int yPos = HIWORD(lParam); // vertical position of cursor
690
691 ScreenToClient(&xPos, &yPos);
692
693 // Make sure you can drag by the top of the groupbox, but let
694 // other (enclosed) controls get mouse events also
695 if (yPos < 10)
696 return (long)HTCLIENT;
697 }
698
699 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
700}
701
702void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn)
703{
704 HWND hwndBtn = (HWND)hWndBtn;
705
706 if ( !s_wndprocRadioBtn )
707 s_wndprocRadioBtn = (WNDPROC)::GetWindowLong(hwndBtn, GWL_WNDPROC);
708
709 ::SetWindowLong(hwndBtn, GWL_WNDPROC, (long)wxRadioBtnWndProc);
710 ::SetWindowLong(hwndBtn, GWL_USERDATA, (long)this);
711}
712
713// ---------------------------------------------------------------------------
714// window proc for radio buttons
715// ---------------------------------------------------------------------------
716
717LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd,
718 UINT msg,
719 WPARAM wParam,
720 LPARAM lParam)
721{
722 bool processed = TRUE;
723 if ( msg != WM_KEYDOWN )
724 processed = FALSE;
725
726 if ( processed )
727 {
728 wxRadioBox *radiobox = (wxRadioBox *)::GetWindowLong(hwnd, GWL_USERDATA);
729
730 wxCHECK_MSG( radiobox, 0, "radio button without radio box?" );
731
732 int sel = radiobox->GetSelection();
733
734 switch ( wParam )
735 {
736 case VK_UP:
737 sel--;
738 break;
739
740 case VK_LEFT:
741 sel -= radiobox->GetNumVer();
742 break;
743
744 case VK_DOWN:
745 sel++;
746 break;
747
748 case VK_RIGHT:
749 sel += radiobox->GetNumVer();
750 break;
751
752 case VK_TAB:
753 {
754 wxNavigationKeyEvent event;
755 event.SetDirection(!(::GetKeyState(VK_SHIFT) & 0x100));
756 event.SetWindowChange(FALSE);
757 event.SetEventObject(radiobox);
758
759 if ( radiobox->GetEventHandler()->ProcessEvent(event) )
760 return 0;
761 }
762 // fall through
763
764 default:
765 processed = FALSE;
766 }
767
768 if ( processed )
769 {
770 if ( sel >= 0 && sel < radiobox->Number() )
771 radiobox->SetSelection(sel);
772 }
773 }
774
775 if ( !processed )
776 return ::CallWindowProc(s_wndprocRadioBtn, hwnd, msg, wParam, lParam);
777 else
778 return 0;
779}
780