X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/df74e2d2510d0bf2e2ae6b888c5948a302a6e0eb..07aaf32633ecf18ec3edfbb41793a112914792d0:/src/msw/choice.cpp diff --git a/src/msw/choice.cpp b/src/msw/choice.cpp index e408eb89ad..30dad609d0 100644 --- a/src/msw/choice.cpp +++ b/src/msw/choice.cpp @@ -200,12 +200,12 @@ wxChoice::~wxChoice() Clear(); } -bool wxChoice::MSWGetComboBoxInfo(COMBOBOXINFO* info) const +bool wxChoice::MSWGetComboBoxInfo(tagCOMBOBOXINFO* info) const { // TODO-Win9x: Get rid of this once we officially drop support for Win9x // and just call the function directly. #if wxUSE_DYNLIB_CLASS - typedef BOOL (WINAPI *GetComboBoxInfo_t)(HWND, COMBOBOXINFO*); + typedef BOOL (WINAPI *GetComboBoxInfo_t)(HWND, tagCOMBOBOXINFO*); static GetComboBoxInfo_t s_pfnGetComboBoxInfo = NULL; static bool s_triedToLoad = false; if ( !s_triedToLoad ) @@ -612,18 +612,7 @@ void wxChoice::DoSetSize(int x, int y, wxSize wxChoice::DoGetBestSize() const { // The base version returns the size of the largest string - wxSize best( wxChoiceBase::DoGetBestSize() ); - - // We just need to adjust it to account for the arrow width. - best.x += 5*GetCharWidth(); - - // set height on our own - if( HasFlag( wxCB_SIMPLE ) ) - best.y = SetHeightSimpleComboBox(GetCount()); - else - best.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(GetCharHeight()); - - return best; + return GetSizeFromTextSize(wxChoiceBase::DoGetBestSize().x); } int wxChoice::SetHeightSimpleComboBox(int nItems) const @@ -634,6 +623,42 @@ int wxChoice::SetHeightSimpleComboBox(int nItems) const return EDIT_HEIGHT_FROM_CHAR_HEIGHT( cy ) * wxMin( wxMax( nItems, 3 ), 6 ) + hItem - 1; } +wxSize wxChoice::DoGetSizeFromTextSize(int xlen, int ylen) const +{ + int cHeight = GetCharHeight(); + + // We are interested in the difference of sizes between the whole control + // and its child part. I.e. arrow, separators, etc. + wxSize tsize(xlen, 0); + + // FIXME-VC6: Only VC6 needs this guard, see WINVER definition in + // include/wx/msw/wrapwin.h +#if defined(WINVER) && WINVER >= 0x0500 + WinStruct info; + if ( MSWGetComboBoxInfo(&info) ) + { + tsize.x += info.rcItem.left + info.rcButton.right - info.rcItem.right + + info.rcItem.left + 3; // right and extra margins + } + else // Just use some rough approximation. +#endif // WINVER >= 0x0500 + { + tsize.x += 4*cHeight; + } + + // set height on our own + if( HasFlag( wxCB_SIMPLE ) ) + tsize.y = SetHeightSimpleComboBox(GetCount()); + else + tsize.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cHeight); + + // Perhaps the user wants something different from CharHeight + if ( ylen > 0 ) + tsize.IncBy(0, ylen - cHeight); + + return tsize; +} + // ---------------------------------------------------------------------------- // Popup operations // ---------------------------------------------------------------------------- @@ -715,9 +740,7 @@ bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) /* The native control provides a great variety in the events it sends in the different selection scenarios (undoubtedly for greater amusement of - the programmers using it). For the reference, here are the cases when - the final selection is accepted (things are quite interesting when it - is cancelled too): + the programmers using it). Here are the different cases: A. Selecting with just the arrows without opening the dropdown: 1. CBN_SELENDOK @@ -739,6 +762,12 @@ bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) Admire the different order of messages in all of those cases, it must surely have taken a lot of effort to Microsoft developers to achieve such originality. + + Additionally, notice that CBN_SELENDCANCEL doesn't seem to actually + cancel anything, if we get CBN_SELCHANGE before it, as it happens in + the case (B), the selection is still accepted. This doesn't make much + sense and directly contradicts MSDN documentation but is how the native + comboboxes behave and so we do the same thing. */ switch ( param ) { @@ -751,44 +780,40 @@ bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) break; case CBN_CLOSEUP: - // if the selection was accepted by the user, it should have been - // reset to wxID_NONE by CBN_SELENDOK, otherwise the selection was - // cancelled and we must restore the old one - if ( m_lastAcceptedSelection != wxID_NONE ) + if ( m_pendingSelection != wxID_NONE ) { - SetSelection(m_lastAcceptedSelection); - m_lastAcceptedSelection = wxID_NONE; + // This can only happen in the case (B), so set the item + // selected in the drop down as our real selection. + SendSelectionChangedEvent(wxEVT_COMMAND_CHOICE_SELECTED); + m_pendingSelection = wxID_NONE; } break; case CBN_SELENDOK: - // reset it to prevent CBN_CLOSEUP from undoing the selection (it's - // ok to reset it now as GetCurrentSelection() will now return the - // same thing anyhow) - m_lastAcceptedSelection = wxID_NONE; - - { - const int n = GetSelection(); - - wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_windowId); - event.SetInt(n); - event.SetEventObject(this); + // Reset the variables to prevent CBN_CLOSEUP from doing anything, + // it's not needed if we do get CBN_SELENDOK. + m_lastAcceptedSelection = + m_pendingSelection = wxID_NONE; - if ( n > -1 ) - { - event.SetString(GetStringSelection()); - InitCommandEventWithItems(event, n); - } - - ProcessCommand(event); - } + SendSelectionChangedEvent(wxEVT_COMMAND_CHOICE_SELECTED); break; - // don't handle CBN_SELENDCANCEL: just leave m_lastAcceptedSelection - // valid and the selection will be undone in CBN_CLOSEUP above + case CBN_SELCHANGE: + // If we get this event after CBN_SELENDOK, i.e. cases (A) or (C) + // above, we don't have anything to do. But in the case (B) we need + // to remember that the selection should really change once the + // drop down is closed. + if ( m_lastAcceptedSelection != wxID_NONE ) + m_pendingSelection = GetCurrentSelection(); + break; - // don't handle CBN_SELCHANGE neither, we don't want to generate events - // while the dropdown is opened -- but do add it if we ever need this + case CBN_SELENDCANCEL: + // Do not reset m_pendingSelection here -- it would make sense but, + // as described above, native controls keep the selection even when + // closing the drop down by pressing Escape or TAB, so conform to + // their behaviour. + m_lastAcceptedSelection = wxID_NONE; + break; default: return false;