X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3998c74b9b711bd47a4321ee6243b9621b144aad..d9106ec5b679d5c9a5eb61b9633e5f3b1437b6a8:/src/msw/radiobox.cpp diff --git a/src/msw/radiobox.cpp b/src/msw/radiobox.cpp index 800e82adf9..053da03797 100644 --- a/src/msw/radiobox.cpp +++ b/src/msw/radiobox.cpp @@ -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(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();