1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/os2/radiobut.cpp
3// Purpose:     wxRadioButton
4// Author:      David Webster
5// Modified by:
6// Created:     10/12/99
7// RCS-ID:      $Id: radiobut.cpp 39567 2006-06-05 16:46:15Z ABX $
8// Copyright:   (c) David Webster
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16    #pragma hdrstop
17#endif
18
19#include "wx/radiobut.h"
20
21#ifndef WX_PRECOMP
22    #include <stdio.h>
23    #include "wx/brush.h"
24    #include "wx/dcscreen.h"
25    #include "wx/settings.h"
26#endif
27
28#include "wx/os2/private.h"
29
30IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
31
32extern void  wxAssociateWinWithHandle( HWND         hWnd
33                                      ,wxWindowOS2* pWin
34                                     );
35
36void wxRadioButton::Init()
37{
38    m_bFocusJustSet = false;
39} // end of wxRadioButton::Init
40
41void wxRadioButton::Command ( wxCommandEvent& rEvent )
42{
43    SetValue ((rEvent.GetInt() != 0) );
44    ProcessCommand (rEvent);
45} // end of wxRadioButton::Command
46
47bool wxRadioButton::Create( wxWindow* pParent,
48                            wxWindowID vId,
49                            const wxString& rsLabel,
50                            const wxPoint& rPos,
51                            const wxSize& rSize,
52                            long lStyle,
53                            const wxValidator& rValidator,
54                            const wxString& rsName )
55{
56    if ( !CreateControl( pParent
57                        ,vId
58                        ,rPos
59                        ,rSize
60                        ,lStyle
61                        ,rValidator
62                        ,rsName))
63        return false;
64
65    long                            lSstyle = WS_TABSTOP;
66
67    if (HasFlag(wxRB_GROUP))
68        lSstyle |= WS_GROUP;
69
70    //
71    // wxRB_SINGLE is a temporary workaround for the following problem: if you
72    // have 2 radiobuttons in the same group but which are not consecutive in
73    // the dialog, Windows can enter an infinite loop! The simplest way to
74    // reproduce it is to create radio button, then a panel and then another
75    // radio button: then checking the last button hangs the app.
76    //
77    // Ideally, we'd detect (and avoid) such situation automatically but for
78    // now, as I don't know how to do it, just allow the user to create
79    // BS_RADIOBUTTON buttons for such situations.
80    //
81    lSstyle |= HasFlag(wxRB_SINGLE) ? BS_RADIOBUTTON : BS_AUTORADIOBUTTON;
82
83    if (HasFlag(wxCLIP_SIBLINGS))
84        lSstyle |= WS_CLIPSIBLINGS;
85
86    if (!OS2CreateControl( _T("BUTTON")
87                          ,lSstyle
88                          ,rPos
89                          ,rSize
90                          ,rsLabel
91                          ,0
92                         ))
93        return false;
94
95    wxAssociateWinWithHandle(m_hWnd, this);
96    if (HasFlag(wxRB_GROUP))
97        SetValue(true);
98
99    SetFont(*wxSMALL_FONT);
100    SetSize( rPos.x, rPos.y, rSize.x, rSize.y );
101    return true;
102} // end of wxRadioButton::Create
103
104wxSize wxRadioButton::DoGetBestSize() const
105{
106    // We should probably compute snRadioSize but it seems to be a constant
107    // independent of its label's font size and not made available by OS/2.
108    static int                      snRadioSize = RADIO_SIZE;
109
110    wxString                        sStr = wxGetWindowText(GetHwnd());
111    int                             nRadioWidth;
112    int                             nRadioHeight;
113
114    if (!sStr.empty())
115    {
116        GetTextExtent( sStr
117                      ,&nRadioWidth
118                      ,&nRadioHeight
119                     );
120        nRadioWidth += snRadioSize;
121        if (nRadioHeight < snRadioSize)
122            nRadioHeight = snRadioSize;
123    }
124    else
125    {
126        nRadioWidth  = snRadioSize;
127        nRadioHeight = snRadioSize;
128    }
129    return wxSize( nRadioWidth
130                  ,nRadioHeight
131                 );
132} // end of wxRadioButton::DoGetBestSize
133
134//
135// Get single selection, for single choice list items
136//
137bool wxRadioButton::GetValue() const
138{
139    return((::WinSendMsg((HWND) GetHWND(), BM_QUERYCHECK, (MPARAM)0L, (MPARAM)0L) != 0));
140} // end of wxRadioButton::GetValue
141
142bool wxRadioButton::OS2Command( WXUINT wParam, WXWORD WXUNUSED(wId) )
143{
144    if (wParam != BN_CLICKED)
145        return false;
146
147    if (m_bFocusJustSet)
148    {
149        //
150        // See above: we want to ignore this event
151        //
152        m_bFocusJustSet = false;
153    }
154    else
155    {
156        bool bIsChecked = GetValue();
157
158        if (HasFlag(wxRB_SINGLE))
159        {
160            //
161            // When we use a "manual" radio button, we have to check the button
162            // ourselves -- but it's reset to unchecked state by the user code
163            // (presumably when another button is pressed)
164            //
165            if (!bIsChecked )
166                SetValue(true);
167        }
168        wxCommandEvent rEvent( wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_windowId );
169        rEvent.SetEventObject(this);
170        ProcessCommand(rEvent);
171    }
172    return true;
173} // end of wxRadioButton::OS2Command
174
175void wxRadioButton::SetFocus()
176{
177    // when the radio button receives a WM_SETFOCUS message it generates a
178    // BN_CLICKED which is totally unexpected and leads to catastrophic results
179    // if you pop up a dialog from the radio button event handler as, when the
180    // dialog is dismissed, the focus is returned to the radio button which
181    // generates BN_CLICKED which leads to showing another dialog and so on
182    // without end!
183    //
184    // to avoid this, we drop the pseudo BN_CLICKED events generated when the
185    // button gains focus
186    m_bFocusJustSet = true;
187
188    wxControl::SetFocus();
189}
190
191void wxRadioButton::SetLabel( const wxString& rsLabel )
192{
193    wxString                        sLabel = ::wxPMTextToLabel(rsLabel);
194    ::WinSetWindowText((HWND)GetHWND(), (const char *)sLabel.c_str());
195} // end of wxRadioButton::SetLabel
196
197void wxRadioButton::SetValue( bool bValue )
198{
199    ::WinSendMsg((HWND)GetHWND(), BM_SETCHECK, (MPARAM)bValue, (MPARAM)0);
200    if (bValue)
201    {
202        const wxWindowList&         rSiblings = GetParent()->GetChildren();
203        wxWindowList::compatibility_iterator nodeThis = rSiblings.Find(this);
204
205        wxCHECK_RET(nodeThis, _T("radio button not a child of its parent?"));
206
207        //
208        // If it's not the first item of the group ...
209        //
210        if ( !HasFlag(wxRB_GROUP) )
211        {
212            //
213            // ...turn off all radio buttons before this one
214            //
215            for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
216                  nodeBefore;
217                  nodeBefore = nodeBefore->GetPrevious() )
218            {
219                wxRadioButton*      pBtn = wxDynamicCast( nodeBefore->GetData()
220                                                         ,wxRadioButton
221                                                        );
222                if (!pBtn)
223                {
224                    //
225                    // The radio buttons in a group must be consecutive, so there
226                    // are no more of them
227                    //
228                    break;
229                }
230                pBtn->SetValue(false);
231                if (pBtn->HasFlag(wxRB_GROUP))
232                {
233                    //
234                    // Even if there are other radio buttons before this one,
235                    // they're not in the same group with us
236                    //
237                    break;
238                }
239            }
240        }
241
242        //
243        // ... and all after this one
244        //
245        for (wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
246             nodeAfter;
247             nodeAfter = nodeAfter->GetNext())
248        {
249            wxRadioButton*          pBtn = wxDynamicCast( nodeAfter->GetData()
250                                                         ,wxRadioButton
251                                                        );
252
253            if (!pBtn || pBtn->HasFlag(wxRB_GROUP) )
254            {
255                //
256                // No more buttons or the first button of the next group
257                //
258                break;
259            }
260            pBtn->SetValue(false);
261        }
262    }
263} // end of wxRadioButton::SetValue
264
265MRESULT wxRadioButton::OS2WindowProc(
266  WXUINT                            uMsg
267, WXWPARAM                          wParam
268, WXLPARAM                          lParam
269)
270{
271    if (uMsg == WM_SETFOCUS)
272    {
273        m_bFocusJustSet = true;
274
275        MRESULT                     mRc = wxControl::OS2WindowProc( uMsg
276                                                                   ,wParam
277                                                                   ,lParam
278                                                                  );
279
280        m_bFocusJustSet = false;
281        return mRc;
282    }
283    return wxControl::OS2WindowProc( uMsg
284                                    ,wParam
285                                    ,lParam
286                                   );
287} // end of wxRadioButton::OS2WindowProc
288