]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/radiobox.cpp
Correct erasing of background behind controls in a toolbar in wxMSW.
[wxWidgets.git] / src / msw / radiobox.cpp
index 800e82adf9779c16e616f0700d43bc77f27d1718..053da037976d97354d11cd864b6251f426870176 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Julian Smart
 // Modified by:
 // Created:     04/01/98
-// RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -29,6 +28,7 @@
 #include "wx/radiobox.h"
 
 #ifndef WX_PRECOMP
+    #include "wx/hashmap.h"
     #include "wx/bitmap.h"
     #include "wx/brush.h"
     #include "wx/settings.h"
@@ -80,7 +80,7 @@ wxEND_FLAGS( wxRadioBoxStyle )
 IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioBox, wxControl,"wx/radiobox.h")
 
 wxBEGIN_PROPERTIES_TABLE(wxRadioBox)
-    wxEVENT_PROPERTY( Select , wxEVT_COMMAND_RADIOBOX_SELECTED , wxCommandEvent )
+    wxEVENT_PROPERTY( Select , wxEVT_RADIOBOX , wxCommandEvent )
     wxPROPERTY_FLAGS( WindowStyle , wxRadioBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
 wxEND_PROPERTIES_TABLE()
 
@@ -110,13 +110,34 @@ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hWnd,
 // global vars
 // ---------------------------------------------------------------------------
 
+namespace
+{
+
 // the pointer to standard radio button wnd proc
-static WXFARPROC s_wndprocRadioBtn = (WXFARPROC)NULL;
+WXFARPROC s_wndprocRadioBtn = (WXFARPROC)NULL;
+
+// Hash allowing to find wxRadioBox containing the given radio button by its
+// HWND. This is used by (subclassed) radio button window proc to find the
+// radio box it belongs to.
+WX_DECLARE_HASH_MAP(HWND, wxRadioBox *,
+                    wxPointerHash, wxPointerEqual,
+                    RadioBoxFromButton);
+
+RadioBoxFromButton gs_boxFromButton;
+
+} // anonymous namespace
 
 // ===========================================================================
 // implementation
 // ===========================================================================
 
+/* static */
+wxRadioBox* wxRadioBox::GetFromRadioButtonHWND(WXHWND hwnd)
+{
+    const RadioBoxFromButton::const_iterator it = gs_boxFromButton.find(hwnd);
+    return it == gs_boxFromButton.end() ? NULL : it->second;
+}
+
 // ---------------------------------------------------------------------------
 // wxRadioBox creation
 // ---------------------------------------------------------------------------
@@ -180,8 +201,8 @@ bool wxRadioBox::Create(wxWindow *parent,
 
         wxWindowIDRef subid = NewControlId();
 
-        HWND hwndBtn = ::CreateWindow(_T("BUTTON"),
-                                      choices[i].wx_str(),
+        HWND hwndBtn = ::CreateWindow(wxT("BUTTON"),
+                                      choices[i].t_str(),
                                       styleBtn,
                                       0, 0, 0, 0,   // will be set in SetSize()
                                       GetHwndOf(parent),
@@ -208,7 +229,7 @@ bool wxRadioBox::Create(wxWindow *parent,
     // Create a dummy radio control to end the group.
     m_dummyId = NewControlId();
 
-    m_dummyHwnd = (WXHWND)::CreateWindow(_T("BUTTON"),
+    m_dummyHwnd = (WXHWND)::CreateWindow(wxT("BUTTON"),
                          wxEmptyString,
                          WS_GROUP | BS_AUTORADIOBUTTON | WS_CHILD,
                          0, 0, 0, 0, GetHwndOf(parent),
@@ -230,6 +251,16 @@ bool wxRadioBox::Create(wxWindow *parent,
     // Now that we have items determine what is the best size and set it.
     SetInitialSize(size);
 
+    // And update all the buttons positions to match it.
+    const wxSize actualSize = GetSize();
+    PositionAllButtons(pos.x, pos.y, actualSize.x, actualSize.y);
+
+    // The base wxStaticBox class never accepts focus, but we do because giving
+    // focus to a wxRadioBox actually gives it to one of its buttons, which are
+    // not visible at wx level and hence are not taken into account by the
+    // logic in wxControlContainer code.
+    m_container.EnableSelfFocus();
+
     return true;
 }
 
@@ -253,9 +284,23 @@ wxRadioBox::~wxRadioBox()
 {
     SendDestroyEvent();
 
+    // Unsubclass all the radio buttons and remove their soon-to-be-invalid
+    // HWNDs from the global map. Notice that we need to unsubclass because
+    // otherwise we'd need the entries in gs_boxFromButton for the buttons
+    // being deleted to handle the messages generated during their destruction.
+    for ( size_t item = 0; item < m_radioButtons->GetCount(); item++ )
+    {
+        HWND hwnd = m_radioButtons->Get(item);
+
+        wxSetWindowProc(hwnd, reinterpret_cast<WNDPROC>(s_wndprocRadioBtn));
+        gs_boxFromButton.erase(hwnd);
+    }
+
     delete m_radioButtons;
+
     if ( m_dummyHwnd )
         DestroyWindow((HWND)m_dummyHwnd);
+
     delete[] m_radioWidth;
     delete[] m_radioHeight;
 }
@@ -270,7 +315,8 @@ void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn)
         s_wndprocRadioBtn = (WXFARPROC)wxGetWindowProc(hwndBtn);
 
     wxSetWindowProc(hwndBtn, wxRadioBtnWndProc);
-    wxSetWindowUserData(hwndBtn, this);
+
+    gs_boxFromButton[hwndBtn] = this;
 }
 
 // ----------------------------------------------------------------------------
@@ -336,7 +382,7 @@ void wxRadioBox::Command(wxCommandEvent & event)
 
 void wxRadioBox::SendNotificationEvent()
 {
-    wxCommandEvent event(wxEVT_COMMAND_RADIOBOX_SELECTED, m_windowId);
+    wxCommandEvent event(wxEVT_RADIOBOX, m_windowId);
     event.SetInt( m_selectedButton );
     event.SetString(GetString(m_selectedButton));
     event.SetEventObject( this );
@@ -397,13 +443,32 @@ void wxRadioBox::SetFocus()
     }
 }
 
+bool wxRadioBox::CanBeFocused() const
+{
+    // If the control itself is hidden or disabled, no need to check anything
+    // else.
+    if ( !wxStaticBox::CanBeFocused() )
+        return false;
+
+    // Otherwise, check if we have any buttons that can be focused.
+    for ( size_t item = 0; item < m_radioButtons->GetCount(); item++ )
+    {
+        if ( IsItemEnabled(item) && IsItemShown(item) )
+            return true;
+    }
+
+    // We didn't find any items that can accept focus, so neither can we as a
+    // whole accept it.
+    return false;
+}
+
 // Enable a specific button
 bool wxRadioBox::Enable(unsigned int item, bool enable)
 {
     wxCHECK_MSG( IsValid(item), false,
                  wxT("invalid item in wxRadioBox::Enable()") );
 
-    BOOL ret = ::EnableWindow((*m_radioButtons)[item], enable);
+    BOOL ret = MSWEnableHWND((*m_radioButtons)[item], enable);
 
     return (ret == 0) != enable;
 }
@@ -457,7 +522,7 @@ void wxRadioBox::DoSetItemToolTip(unsigned int item, wxToolTip *tooltip)
     // we have already checked for the item to be valid in wxRadioBoxBase
     const HWND hwndRbtn = (*m_radioButtons)[item];
     if ( tooltip != NULL )
-        tooltip->Add(hwndRbtn);
+        tooltip->AddOtherWindow(hwndRbtn);
     else // unset the tooltip
         wxToolTip::Remove(hwndRbtn, 0, wxRect(0,0,0,0));
         // the second parameter can be zero since it's ignored by Remove()
@@ -588,6 +653,12 @@ void wxRadioBox::DoMoveWindow(int x, int y, int width, int height)
 {
     wxStaticBox::DoMoveWindow(x, y, width, height);
 
+    PositionAllButtons(x, y, width, height);
+}
+
+void
+wxRadioBox::PositionAllButtons(int x, int y, int width, int WXUNUSED(height))
+{
     wxSize maxSize = GetMaxButtonSize();
     int maxWidth = maxSize.x,
         maxHeight = maxSize.y;
@@ -745,6 +816,10 @@ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd,
                                            WPARAM wParam,
                                            LPARAM lParam)
 {
+
+    wxRadioBox * const radiobox = wxRadioBox::GetFromRadioButtonHWND(hwnd);
+    wxCHECK_MSG( radiobox, 0, wxT("Should have the associated radio box") );
+
     switch ( message )
     {
         case WM_GETDLGCODE:
@@ -760,10 +835,6 @@ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd,
 
         case WM_KEYDOWN:
             {
-                wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);
-
-                wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );
-
                 bool processed = true;
 
                 wxDirection dir;
@@ -819,10 +890,6 @@ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd,
         case WM_SETFOCUS:
         case WM_KILLFOCUS:
             {
-                wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);
-
-                wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );
-
                 // if we don't do this, no focus events are generated for the
                 // radiobox and, besides, we need to notify the parent about
                 // the focus change, otherwise the focus handling logic in
@@ -837,10 +904,6 @@ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd,
 #ifndef __WXWINCE__
         case WM_HELP:
             {
-                wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);
-
-                wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );
-
                 bool processed = false;
 
                 wxEvtHandler * const handler = radiobox->GetEventHandler();