X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/345264343a2fa3ee7362a4afb91b669216ee51fe..96c9640205933ad0673d5af2c96af0816c50160c:/src/msw/radiobox.cpp diff --git a/src/msw/radiobox.cpp b/src/msw/radiobox.cpp index e9f53d0f46..1414e04edd 100644 --- a/src/msw/radiobox.cpp +++ b/src/msw/radiobox.cpp @@ -29,6 +29,7 @@ #include "wx/radiobox.h" #ifndef WX_PRECOMP + #include "wx/hashmap.h" #include "wx/bitmap.h" #include "wx/brush.h" #include "wx/settings.h" @@ -74,10 +75,7 @@ wxBEGIN_FLAGS( wxRadioBoxStyle ) wxFLAGS_MEMBER(wxHSCROLL) wxFLAGS_MEMBER(wxRA_SPECIFY_COLS) - wxFLAGS_MEMBER(wxRA_HORIZONTAL) wxFLAGS_MEMBER(wxRA_SPECIFY_ROWS) - wxFLAGS_MEMBER(wxRA_VERTICAL) - wxEND_FLAGS( wxRadioBoxStyle ) IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioBox, wxControl,"wx/radiobox.h") @@ -113,13 +111,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 // --------------------------------------------------------------------------- @@ -150,6 +169,11 @@ bool wxRadioBox::Create(wxWindow *parent, if ( !wxStaticBox::Create(parent, id, title, pos, size, style, name) ) return false; + // the code elsewhere in this file supposes that either wxRA_SPECIFY_COLS + // or wxRA_SPECIFY_ROWS is set, ensure that this is indeed the case + if ( !(style & (wxRA_SPECIFY_ROWS | wxRA_SPECIFY_COLS)) ) + style |= wxRA_SPECIFY_COLS; + #if wxUSE_VALIDATORS SetValidator(val); #else @@ -178,12 +202,12 @@ bool wxRadioBox::Create(wxWindow *parent, wxWindowIDRef subid = NewControlId(); - HWND hwndBtn = ::CreateWindow(_T("BUTTON"), + HWND hwndBtn = ::CreateWindow(wxT("BUTTON"), choices[i].wx_str(), styleBtn, 0, 0, 0, 0, // will be set in SetSize() GetHwndOf(parent), - (HMENU)subid.GetValue(), + (HMENU)wxUIntToPtr(subid.GetValue()), wxGetInstance(), NULL); @@ -206,11 +230,12 @@ 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), - (HMENU)m_dummyId.GetValue(), wxGetInstance(), NULL); + (HMENU)wxUIntToPtr(m_dummyId.GetValue()), + wxGetInstance(), NULL); m_radioButtons->SetFont(GetFont()); @@ -227,6 +252,10 @@ 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); + return true; } @@ -248,11 +277,25 @@ bool wxRadioBox::Create(wxWindow *parent, wxRadioBox::~wxRadioBox() { - m_isBeingDeleted = true; + 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; } @@ -267,7 +310,8 @@ void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn) s_wndprocRadioBtn = (WXFARPROC)wxGetWindowProc(hwndBtn); wxSetWindowProc(hwndBtn, wxRadioBtnWndProc); - wxSetWindowUserData(hwndBtn, this); + + gs_boxFromButton[hwndBtn] = this; } // ---------------------------------------------------------------------------- @@ -400,7 +444,7 @@ 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; } @@ -454,9 +498,11 @@ 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); + wxToolTip::Remove(hwndRbtn, 0, wxRect(0,0,0,0)); + // the second parameter can be zero since it's ignored by Remove() + // as we pass a rect for which wxRect::IsEmpty()==true... } #endif // wxUSE_TOOLTIPS @@ -559,57 +605,40 @@ wxSize wxRadioBox::DoGetBestSize() const return best; } -// Restored old code. void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags) { - int currentX, currentY; - GetPosition(¤tX, ¤tY); - int widthOld, heightOld; - GetSize(&widthOld, &heightOld); + if ( (width == wxDefaultCoord && (sizeFlags & wxSIZE_AUTO_WIDTH)) || + (height == wxDefaultCoord && (sizeFlags & wxSIZE_AUTO_HEIGHT)) ) + { + // Attempt to have a look coherent with other platforms: We compute the + // biggest toggle dim, then we align all items according this value. + const wxSize totSize = GetTotalButtonSize(GetMaxButtonSize()); - int xx = x; - int yy = y; + // only change our width/height if asked for + if ( width == wxDefaultCoord && (sizeFlags & wxSIZE_AUTO_WIDTH) ) + width = totSize.x; - if (x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) - xx = currentX; - if (y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) - yy = currentY; + if ( height == wxDefaultCoord && (sizeFlags & wxSIZE_AUTO_HEIGHT) ) + height = totSize.y; + } - int y_offset = yy; - int x_offset = xx; + wxStaticBox::DoSetSize(x, y, width, height); +} - int cx1, cy1; - wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont()); +void wxRadioBox::DoMoveWindow(int x, int y, int width, int height) +{ + wxStaticBox::DoMoveWindow(x, y, width, height); - // Attempt to have a look coherent with other platforms: We compute the - // biggest toggle dim, then we align all items according this value. + 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; - wxSize totSize = GetTotalButtonSize(maxSize); - int totWidth = totSize.x, - totHeight = totSize.y; - - // only change our width/height if asked for - if ( width == wxDefaultCoord ) - { - if ( sizeFlags & wxSIZE_AUTO_WIDTH ) - width = totWidth; - else - width = widthOld; - } - - if ( height == wxDefaultCoord ) - { - if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) - height = totHeight; - else - height = heightOld; - } - - DoMoveWindow(xx, yy, width, height); - // Now position all the buttons: the current button will be put at // wxPoint(x_offset, y_offset) and the new row/column will start at // startX/startY. The size of all buttons will be the same wxSize(maxWidth, @@ -621,8 +650,11 @@ void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags) // wxRA_SPECIFY_ROWS means that the buttons are arranged top to bottom and // GetMajorDim() is the number of rows. - x_offset += cx1; - y_offset += cy1; + int cx1, cy1; + wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont()); + + int x_offset = x + cx1; + int y_offset = y + cy1; // Add extra space under the label, if it exists. if (!wxControl::GetLabel().empty()) @@ -760,6 +792,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: @@ -775,10 +811,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; @@ -834,10 +866,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 @@ -852,10 +880,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();