]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/radiobut.cpp
submenu preparation in two methods encapsulated
[wxWidgets.git] / src / os2 / radiobut.cpp
index 83444cd1f0fa7f0f6cc09accff9eb0bb63269e32..540bb7deffc33561595ace19b5c6edc863e34880 100644 (file)
 #include "wx/setup.h"
 #include "wx/radiobut.h"
 #include "wx/brush.h"
 #include "wx/setup.h"
 #include "wx/radiobut.h"
 #include "wx/brush.h"
+#include "wx/dcscreen.h"
+#include "wx/settings.h"
 #endif
 
 #include "wx/os2/private.h"
 
 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
 
 #endif
 
 #include "wx/os2/private.h"
 
 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
 
+extern void  wxAssociateWinWithHandle( HWND         hWnd
+                                      ,wxWindowOS2* pWin
+                                     );
+
+void wxRadioButton::Init()
+{
+    m_bFocusJustSet = FALSE;
+} // end of wxRadioButton::Init
+
 void wxRadioButton::Command (
   wxCommandEvent&                   rEvent
 )
 void wxRadioButton::Command (
   wxCommandEvent&                   rEvent
 )
@@ -42,108 +53,97 @@ bool wxRadioButton::Create(
 , const wxPoint&                    rPos
 , const wxSize&                     rSize
 , long                              lStyle
 , const wxPoint&                    rPos
 , const wxSize&                     rSize
 , long                              lStyle
-#if wxUSE_VALIDATORS
 , const wxValidator&                rValidator
 , const wxValidator&                rValidator
-#endif
 , const wxString&                   rsName
 )
 {
 , const wxString&                   rsName
 )
 {
-    int                             nX          = rPos.x;
-    int                             nY          = rPos.y;
-    int                             nWidth      = rSize.x;
-    int                             nHeight     = rSize.y;
-    long                            lsStyle     = 0L;
-    long                            lGroupStyle = 0L;
-
-    SetName(rsName);
-#if wxUSE_VALIDATORS
-    SetValidator(rValidator);
-#endif
+    if ( !CreateControl( pParent
+                        ,vId
+                        ,rPos
+                        ,rSize
+                        ,lStyle
+                        ,rValidator
+                        ,rsName))
+        return FALSE;
 
 
-    if (pParent)
-        pParent->AddChild(this);
+    long                            lSstyle = WS_TABSTOP;
 
 
-    SetBackgroundColour(pParent->GetBackgroundColour());
-    SetForegroundColour(pParent->GetForegroundColour());
+    if (HasFlag(wxRB_GROUP))
+        lSstyle |= WS_GROUP;
 
 
-    if (vId == -1)
-        m_windowId = (int)NewControlId();
-    else
-        m_windowId = vId;
+    //
+    // wxRB_SINGLE is a temporary workaround for the following problem: if you
+    // have 2 radiobuttons in the same group but which are not consecutive in
+    // the dialog, Windows can enter an infinite loop! The simplest way to
+    // reproduce it is to create radio button, then a panel and then another
+    // radio button: then checking the last button hangs the app.
+    //
+    // Ideally, we'd detect (and avoid) such situation automatically but for
+    // now, as I don't know how to do it, just allow the user to create
+    // BS_RADIOBUTTON buttons for such situations.
+    //
+    lSstyle |= HasFlag(wxRB_SINGLE) ? BS_RADIOBUTTON : BS_AUTORADIOBUTTON;
 
 
+    if (HasFlag(wxCLIP_SIBLINGS))
+        lSstyle |= WS_CLIPSIBLINGS;
 
 
-    m_windowStyle = lStyle ;
+    if (!OS2CreateControl( _T("BUTTON")
+                          ,lSstyle
+                          ,rPos
+                          ,rSize
+                          ,rsLabel
+                          ,0
+                         ))
+        return FALSE;
 
 
-    if (m_windowStyle & wxRB_GROUP)
-        lGroupStyle = WS_GROUP;
+    wxAssociateWinWithHandle(m_hWnd, this);
+    if (HasFlag(wxRB_GROUP))
+        SetValue(TRUE);
 
 
-    lsStyle = lGroupStyle | BS_AUTORADIOBUTTON | WS_VISIBLE ;
+    SetFont(*wxSMALL_FONT);
+    SetSize( rPos.x
+            ,rPos.y
+            ,rSize.x
+            ,rSize.y
+           );
+    return TRUE;
+} // end of wxRadioButton::Create
 
 
-    if (m_windowStyle & wxCLIP_SIBLINGS )
-        lsStyle |= WS_CLIPSIBLINGS;
-    //
-    // If the parent is a scrolled window the controls must
-    // have this style or they will overlap the scrollbars
-    //
-    if (pParent)
-        if (pParent->IsKindOf(CLASSINFO(wxScrolledWindow)) ||
-            pParent->IsKindOf(CLASSINFO(wxGenericScrolledWindow)))
-            lsStyle |= WS_CLIPSIBLINGS;
-
-    m_hWnd = (WXHWND)::WinCreateWindow ( GetHwndOf(pParent)
-                                        ,WC_BUTTON
-                                        ,rsLabel.c_str()
-                                        ,lsStyle
-                                        ,0, 0, 0, 0
-                                        ,GetWinHwnd(pParent)
-                                        ,HWND_TOP
-                                        ,(HMENU)m_windowId
-                                        ,NULL
-                                        ,NULL
-                                       );
-    wxCHECK_MSG(m_hWnd, FALSE, wxT("Failed to create radiobutton"));
-
-    if (rsLabel != wxT(""))
+wxSize wxRadioButton::DoGetBestSize() const
+{
+    static int                      snRadioSize = 0;
+
+    if (!snRadioSize)
+    {
+        wxScreenDC                  vDC;
+
+        vDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
+        snRadioSize = vDC.GetCharHeight();
+    }
+
+    wxString                        sStr = GetLabel();
+    int                             nRadioWidth;
+    int                             nRadioHeight;
+
+    if (!sStr.empty())
     {
     {
-        int                         nLabelWidth;
-        int                         nLabelHeight;
-
-        GetTextExtent( rsLabel
-                      ,&nLabelWidth
-                      ,&nLabelHeight
-                      ,NULL
-                      ,NULL
-                      ,&this->GetFont()
+        GetTextExtent( sStr
+                      ,&nRadioWidth
+                      ,&nRadioHeight
                      );
                      );
-        if (nWidth < 0)
-            nWidth = (int)(nLabelWidth + RADIO_SIZE);
-        if (nHeight<0)
-        {
-            nHeight = (int)(nLabelHeight);
-            if (nHeight < RADIO_SIZE)
-                nHeight = RADIO_SIZE;
-        }
+        nRadioWidth += snRadioSize + GetCharWidth();
+        if (nRadioHeight < snRadioSize)
+            nRadioHeight = snRadioSize;
     }
     else
     {
     }
     else
     {
-        if (nWidth < 0)
-            nWidth = RADIO_SIZE;
-        if (nHeight < 0)
-            nHeight = RADIO_SIZE;
+        nRadioWidth  = snRadioSize;
+        nRadioHeight = snRadioSize;
     }
     }
-
-    //
-    // Subclass again for purposes of dialog editing mode
-    //
-    SubclassWin((WXHWND)m_hWnd);
-    SetFont(pParent->GetFont());
-    SetSize( nX
-            ,nY
-            ,nWidth
-            ,nHeight
-           );
-    return FALSE;
-} // end of wxRadioButton::Create
+    return wxSize( nRadioWidth
+                  ,nRadioHeight
+                 );
+} // end of wxRadioButton::DoGetBestSize
 
 //
 // Get single selection, for single choice list items
 
 //
 // Get single selection, for single choice list items
@@ -158,20 +158,56 @@ bool wxRadioButton::OS2Command(
 , WXWORD                            wId
 )
 {
 , WXWORD                            wId
 )
 {
-    if (wParam == BN_CLICKED)
+    if (wParam != BN_CLICKED)
+        return FALSE;
+
+    if (m_bFocusJustSet)
+    {
+        //
+        // See above: we want to ignore this event
+        //
+        m_bFocusJustSet = FALSE;
+    }
+    else
     {
     {
+        bool                        bIsChecked = GetValue();
+
+        if (HasFlag(wxRB_SINGLE))
+        {
+            //
+            // When we use a "manual" radio button, we have to check the button
+            // ourselves -- but it's reset to unchecked state by the user code
+            // (presumably when another button is pressed)
+            //
+            if (!bIsChecked )
+                SetValue(TRUE);
+        }
         wxCommandEvent              rEvent( wxEVT_COMMAND_RADIOBUTTON_SELECTED
                                            ,m_windowId
                                           );
 
         rEvent.SetEventObject(this);
         ProcessCommand(rEvent);
         wxCommandEvent              rEvent( wxEVT_COMMAND_RADIOBUTTON_SELECTED
                                            ,m_windowId
                                           );
 
         rEvent.SetEventObject(this);
         ProcessCommand(rEvent);
-        return TRUE;
     }
     }
-    else
-        return FALSE;
+    return TRUE;
 } // end of wxRadioButton::OS2Command
 
 } // end of wxRadioButton::OS2Command
 
+void wxRadioButton::SetFocus()
+{
+    // when the radio button receives a WM_SETFOCUS message it generates a
+    // BN_CLICKED which is totally unexpected and leads to catastrophic results
+    // if you pop up a dialog from the radio button event handler as, when the
+    // dialog is dismissed, the focus is returned to the radio button which
+    // generates BN_CLICKED which leads to showing another dialog and so on
+    // without end!
+    //
+    // to aviod this, we drop the pseudo BN_CLICKED events generated when the
+    // button gains focus
+    m_bFocusJustSet = TRUE;
+
+    wxControl::SetFocus();
+}
+
 void wxRadioButton::SetLabel(
   const wxString&                   rsLabel
 )
 void wxRadioButton::SetLabel(
   const wxString&                   rsLabel
 )
@@ -184,5 +220,85 @@ void wxRadioButton::SetValue(
 )
 {
     ::WinSendMsg((HWND)GetHWND(), BM_SETCHECK, (MPARAM)bValue, (MPARAM)0);
 )
 {
     ::WinSendMsg((HWND)GetHWND(), BM_SETCHECK, (MPARAM)bValue, (MPARAM)0);
+    if (bValue)
+    {
+        const wxWindowList&         rSiblings = GetParent()->GetChildren();
+        wxWindowList::Node*         pNodeThis = rSiblings.Find(this);
+
+        wxCHECK_RET(pNodeThis, _T("radio button not a child of its parent?"));
+
+        // 
+        // Turn off all radio buttons before this one
+        //
+        for ( wxWindowList::Node* pNodeBefore = pNodeThis->GetPrevious();
+              pNodeBefore;
+              pNodeBefore = pNodeBefore->GetPrevious() )
+        {
+            wxRadioButton*          pBtn = wxDynamicCast( pNodeBefore->GetData()
+                                                         ,wxRadioButton
+                                                        );
+            if (!pBtn)
+            {
+                // 
+                // The radio buttons in a group must be consecutive, so there
+                // are no more of them
+                //
+                break;
+            }
+            pBtn->SetValue(FALSE);
+            if (pBtn->HasFlag(wxRB_GROUP))
+            {
+                // 
+                // Even if there are other radio buttons before this one,
+                // they're not in the same group with us
+                //
+                break;
+            }
+        }
+
+        // 
+        // ... and all after this one
+        //
+        for (wxWindowList::Node* pNodeAfter = pNodeThis->GetNext();
+             pNodeAfter;
+             pNodeAfter = pNodeAfter->GetNext())
+        {
+            wxRadioButton*          pBtn = wxDynamicCast( pNodeAfter->GetData()
+                                                         ,wxRadioButton
+                                                        );
+
+            if (!pBtn || pBtn->HasFlag(wxRB_GROUP) )
+            {
+                // 
+                // No more buttons or the first button of the next group
+                //
+                break;
+            }
+            pBtn->SetValue(FALSE);
+        }
+    }
 } // end of wxRadioButton::SetValue
 
 } // end of wxRadioButton::SetValue
 
+MRESULT wxRadioButton::OS2WindowProc(
+  WXUINT                            uMsg
+, WXWPARAM                          wParam
+, WXLPARAM                          lParam
+)
+{
+    if (uMsg == WM_SETFOCUS)
+    {
+        m_bFocusJustSet = TRUE;
+
+        MRESULT                     mRc = wxControl::OS2WindowProc( uMsg
+                                                                   ,wParam
+                                                                   ,lParam
+                                                                  );
+
+        m_bFocusJustSet = FALSE;
+        return mRc;
+    }
+    return wxControl::OS2WindowProc( uMsg
+                                    ,wParam
+                                    ,lParam
+                                   );
+} // end of wxRadioButton::OS2WindowProc