]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/radiobut.cpp
send more page change events (patch 750521); document this behaviour
[wxWidgets.git] / src / os2 / radiobut.cpp
index 1905f909e26e1a8cb13a1a25bf180e87fa4a2ff9..8d1b543ad8f108ad4aec8d4cc4cedc22cfc55434 100644 (file)
 #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"
 
-#if !USE_SHARED_LIBRARY
 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
-IMPLEMENT_DYNAMIC_CLASS(wxBitmapRadioButton, wxRadioButton)
-#endif
 
-bool wxRadioButton::OS2Command(WXUINT param, WXWORD id)
-{
-  if (param == BN_CLICKED)
-  {
-    wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_windowId);
-    event.SetEventObject( this );
-    ProcessCommand(event);
-    return TRUE;
-  }
-  else return FALSE;
-}
+extern void  wxAssociateWinWithHandle( HWND         hWnd
+                                      ,wxWindowOS2* pWin
+                                     );
 
-bool wxRadioButton::Create(wxWindow *parent, wxWindowID id,
-           const wxString& label,
-           const wxPoint& pos,
-           const wxSize& size, long style,
-#if wxUSE_VALIDATORS
-           const wxValidator& validator,
-#endif
-           const wxString& name)
+void wxRadioButton::Init()
 {
-    SetName(name);
-#if wxUSE_VALIDATORS
-    SetValidator(validator);
-#endif
-
-    if (parent) parent->AddChild(this);
-
-    SetBackgroundColour(parent->GetBackgroundColour());
-    SetForegroundColour(parent->GetForegroundColour());
-
-    if ( id == -1 )
-        m_windowId = (int)NewControlId();
-    else
-        m_windowId = id;
-
-    int x = pos.x;
-    int y = pos.y;
-    int width = size.x;
-    int height = size.y;
-
-    m_windowStyle = style ;
-
-// TODO create radiobutton
-/*
-  long groupStyle = 0;
-  if (m_windowStyle & wxRB_GROUP)
-    groupStyle = WS_GROUP;
-
-//  long msStyle = groupStyle | RADIO_FLAGS;
-  long msStyle = groupStyle | BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE ;
-
-  bool want3D;
-  WXDWORD exStyle = Determine3DEffects(0, &want3D) ;
-
-  m_hWnd = (WXHWND) CreateWindowEx(exStyle, RADIO_CLASS, (const wxChar *)label,
-                          msStyle,0,0,0,0,
-                          (HWND) parent->GetHWND(), (HMENU)m_windowId, wxGetInstance(), NULL);
+    m_bFocusJustSet = FALSE;
+} // end of wxRadioButton::Init
 
-  wxCHECK_MSG( m_hWnd, FALSE, wxT("Failed to create radiobutton") );
+void wxRadioButton::Command (
+  wxCommandEvent&                   rEvent
+)
+{
+    SetValue ((rEvent.GetInt() != 0) );
+    ProcessCommand (rEvent);
+} // end of wxRadioButton::Command
+
+bool wxRadioButton::Create(
+  wxWindow*                         pParent
+, wxWindowID                        vId
+, const wxString&                   rsLabel
+, const wxPoint&                    rPos
+, const wxSize&                     rSize
+, long                              lStyle
+, const wxValidator&                rValidator
+, const wxString&                   rsName
+)
+{
+    if ( !CreateControl( pParent
+                        ,vId
+                        ,rPos
+                        ,rSize
+                        ,lStyle
+                        ,rValidator
+                        ,rsName))
+        return FALSE;
+
+    long                            lSstyle = WS_TABSTOP;
+
+    if (HasFlag(wxRB_GROUP))
+        lSstyle |= WS_GROUP;
+
+    //
+    // 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;
+
+    if (!OS2CreateControl( _T("BUTTON")
+                          ,lSstyle
+                          ,rPos
+                          ,rSize
+                          ,rsLabel
+                          ,0
+                         ))
+        return FALSE;
+
+    wxAssociateWinWithHandle(m_hWnd, this);
+    if (HasFlag(wxRB_GROUP))
+        SetValue(TRUE);
+
+    SetFont(*wxSMALL_FONT);
+    SetSize( rPos.x
+            ,rPos.y
+            ,rSize.x
+            ,rSize.y
+           );
+    return TRUE;
+} // end of wxRadioButton::Create
 
+wxSize wxRadioButton::DoGetBestSize() const
+{
+    static int                      snRadioSize = 0;
 
-  SetFont(parent->GetFont());
+    if (!snRadioSize)
+    {
+        wxScreenDC                  vDC;
 
-  // Subclass again for purposes of dialog editing mode
-  SubclassWin((WXHWND)m_hWnd);
+        vDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
+        snRadioSize = vDC.GetCharHeight();
+    }
 
-//  SetValue(value);
-*/
+    wxString                        sStr = GetLabel();
+    int                             nRadioWidth;
+    int                             nRadioHeight;
 
-  // start GRW fix
-  if (label != wxT(""))
-  {
-    int label_width, label_height;
-    GetTextExtent(label, &label_width, &label_height, NULL, NULL, & this->GetFont());
-    if (width < 0)
-      width = (int)(label_width + RADIO_SIZE);
-    if (height<0)
+    if (!sStr.empty())
     {
-      height = (int)(label_height);
-      if (height < RADIO_SIZE)
-        height = RADIO_SIZE;
+        GetTextExtent( sStr
+                      ,&nRadioWidth
+                      ,&nRadioHeight
+                     );
+        nRadioWidth += snRadioSize + GetCharWidth();
+        if (nRadioHeight < snRadioSize)
+            nRadioHeight = snRadioSize;
     }
-  }
-  else
-  {
-    if (width < 0)
-      width = RADIO_SIZE;
-    if (height < 0)
-      height = RADIO_SIZE;
-  }
-  // end GRW fix
-
-  SetSize(x, y, width, height);
-  return FALSE;
-}
-
-void wxRadioButton::SetLabel(const wxString& label)
-{
-    // TODO
-}
-
-void wxRadioButton::SetValue(bool value)
-{
-    // TODO
-}
+    else
+    {
+        nRadioWidth  = snRadioSize;
+        nRadioHeight = snRadioSize;
+    }
+    return wxSize( nRadioWidth
+                  ,nRadioHeight
+                 );
+} // end of wxRadioButton::DoGetBestSize
 
+//
 // Get single selection, for single choice list items
+//
 bool wxRadioButton::GetValue() const
 {
-    // TODO
-    return FALSE;
-}
-
-void wxRadioButton::Command (wxCommandEvent & event)
-{
-  SetValue ( (event.m_commandInt != 0) );
-  ProcessCommand (event);
-}
+    return((::WinSendMsg((HWND) GetHWND(), BM_QUERYCHECK, (MPARAM)0L, (MPARAM)0L) != 0));
+} // end of wxRadioButton::GetValue
 
-bool wxBitmapRadioButton::Create(wxWindow *parent, wxWindowID id,
-       const wxBitmap *bitmap,
-           const wxPoint& pos,
-           const wxSize& size, long style,
-#if wxUSE_VALIDATORS
-           const wxValidator& validator,
-#endif
-           const wxString& name)
+bool wxRadioButton::OS2Command(
+  WXUINT                            wParam
+, WXWORD                            wId
+)
 {
-  SetName(name);
-#if wxUSE_VALIDATORS
-  SetValidator(validator);
-#endif
-
-  if (parent) parent->AddChild(this);
-  SetBackgroundColour(parent->GetBackgroundColour());
-  SetForegroundColour(parent->GetForegroundColour());
+    if (wParam != BN_CLICKED)
+        return FALSE;
 
-  if ( id == -1 )
-    m_windowId = (int)NewControlId();
-  else
-  m_windowId = id;
-
-  int x = pos.x;
-  int y = pos.y;
-  int width = size.x;
-  int height = size.y;
-  m_windowStyle = style ;
-
-  long groupStyle = 0;
-  if (m_windowStyle & wxRB_GROUP)
-    groupStyle = WS_GROUP;
-
-// TODO:
-/*
-//  long msStyle = groupStyle | RADIO_FLAGS;
-//  long msStyle = groupStyle | BS_RADIOBUTTON | WS_CHILD | WS_VISIBLE ;
-
-  m_hWnd = (WXHWND) CreateWindowEx(MakeExtendedStyle(m_windowStyle), RADIO_CLASS, "toggle",
-                          msStyle,0,0,0,0,
-                          (HWND) parent->GetHWND(), (HMENU)m_windowId, wxGetInstance(), NULL);
-
-  wxCHECK_MSG( m_hWnd, "Failed to create radio button", FALSE );
-
-*/
-  // Subclass again for purposes of dialog editing mode
-  SubclassWin(GetHWND());
-
-  SetSize(x, y, width, height);
+    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);
+    }
+    return TRUE;
+} // end of wxRadioButton::OS2Command
 
-  return TRUE;
+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 wxBitmapRadioButton::SetLabel(const wxBitmap *bitmap)
+void wxRadioButton::SetLabel(
+  const wxString&                   rsLabel
+)
 {
-}
+    ::WinSetWindowText((HWND)GetHWND(), (const char *)rsLabel.c_str());
+} // end of wxRadioButton::SetLabel
 
-void wxBitmapRadioButton::SetValue(bool value)
+void wxRadioButton::SetValue(
+  bool                              bValue
+)
 {
-// Following necessary for Win32s, because Win32s translate BM_SETCHECK
-//  SendMessage((HWND) GetHWND(), BM_SETCHECK, (WPARAM)value, 0L);
-}
+    ::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?"));
+
+        //
+        // If it's not the first item of the group ...
+        //
+        if ( !HasFlag(wxRB_GROUP) )
+        {
+            //
+            // ...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
 
-// Get single selection, for single choice list items
-bool wxBitmapRadioButton::GetValue(void) const
+MRESULT wxRadioButton::OS2WindowProc(
+  WXUINT                            uMsg
+, WXWPARAM                          wParam
+, WXLPARAM                          lParam
+)
 {
-//  return (bool)SendMessage((HWND) GetHWND(), BM_GETCHECK, 0, 0L);
-    return FALSE;
-}
+    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