X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8907154c1a8a6882c6797d1f16393ddfb23e7f3a..40cc34ec564f7c036724573caba0b4e5643018d8:/src/msw/choice.cpp diff --git a/src/msw/choice.cpp b/src/msw/choice.cpp index a21d63a688..7c15b52d83 100644 --- a/src/msw/choice.cpp +++ b/src/msw/choice.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: choice.cpp +// Name: src/msw/choice.cpp // Purpose: wxChoice // Author: Julian Smart // Modified by: Vadim Zeitlin to derive from wxChoiceBase @@ -239,7 +239,7 @@ int wxChoice::DoAppend(const wxString& item) int wxChoice::DoInsert(const wxString& item, int pos) { wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list")); - wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index")); + wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index")); int n = (int)SendMessage(GetHwnd(), CB_INSERTSTRING, pos, (LPARAM)item.c_str()); if ( n == CB_ERR ) @@ -258,7 +258,7 @@ int wxChoice::DoInsert(const wxString& item, int pos) void wxChoice::Delete(int n) { - wxCHECK_RET( n < GetCount(), wxT("invalid item index in wxChoice::Delete") ); + wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") ); if ( HasClientObjectData() ) { @@ -326,21 +326,21 @@ void wxChoice::SetSelection(int n) // string list functions // ---------------------------------------------------------------------------- -int wxChoice::GetCount() const +size_t wxChoice::GetCount() const { - return (int)SendMessage(GetHwnd(), CB_GETCOUNT, 0, 0); + return (size_t)SendMessage(GetHwnd(), CB_GETCOUNT, 0, 0); } -int wxChoice::FindString(const wxString& s) const +int wxChoice::FindString(const wxString& s, bool bCase) const { #if defined(__WATCOMC__) && defined(__WIN386__) // For some reason, Watcom in WIN386 mode crashes in the CB_FINDSTRINGEXACT message. // wxChoice::Do it the long way instead. - int count = GetCount(); - for ( int i = 0; i < count; i++ ) + size_t count = GetCount(); + for ( size_t i = 0; i < count; i++ ) { // as CB_FINDSTRINGEXACT is case insensitive, be case insensitive too - if ( GetString(i).IsSameAs(s, false) ) + if ( GetString(i).IsSameAs(s, bCase) ) return i; } @@ -350,29 +350,33 @@ int wxChoice::FindString(const wxString& s) const //passed to SendMessage, so we have to do it ourselves in that case if ( s.empty() ) { - int count = GetCount(); - for ( int i = 0; i < count; i++ ) - { - if ( GetString(i).empty() ) - return i; - } - - return wxNOT_FOUND; + size_t count = GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + if ( GetString(i).empty() ) + return i; + } + + return wxNOT_FOUND; + } + else if (bCase) + { + // back to base class search for not native search type + return wxItemContainerImmutable::FindString( s, bCase ); } else { - int pos = (int)SendMessage(GetHwnd(), CB_FINDSTRINGEXACT, - (WPARAM)-1, (LPARAM)s.c_str()); + int pos = (int)SendMessage(GetHwnd(), CB_FINDSTRINGEXACT, + (WPARAM)-1, (LPARAM)s.c_str()); - return pos == LB_ERR ? wxNOT_FOUND : pos; + return pos == LB_ERR ? wxNOT_FOUND : pos; } #endif // Watcom/!Watcom } void wxChoice::SetString(int n, const wxString& s) { - wxCHECK_RET( n >= 0 && n < GetCount(), - wxT("invalid item index in wxChoice::SetString") ); + wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::SetString") ); // we have to delete and add back the string as there is no way to change a // string in place @@ -628,20 +632,61 @@ WXLRESULT wxChoice::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) 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): + + A. Selecting with just the arrows without opening the dropdown: + 1. CBN_SELENDOK + 2. CBN_SELCHANGE + + B. Opening dropdown with F4 and selecting with arrows: + 1. CBN_DROPDOWN + 2. many CBN_SELCHANGE while changing selection in the list + 3. CBN_SELENDOK + 4. CBN_CLOSEUP + + C. Selecting with the mouse: + 1. CBN_DROPDOWN + -- no intermediate CBN_SELCHANGEs -- + 2. CBN_SELENDOK + 3. CBN_CLOSEUP + 4. CBN_SELCHANGE + + 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. + */ switch ( param ) { case CBN_DROPDOWN: - // we don't want to track selection using CB_GETCURSEL while the - // dropdown is opened + // we use this value both because we don't want to track selection + // using CB_GETCURSEL while the dropdown is opened and because we + // need to reset the selection back to it if it's eventually + // cancelled by user m_lastAcceptedSelection = GetCurrentSelection(); break; case CBN_CLOSEUP: - // it should be safe to use CB_GETCURSEL again - m_lastAcceptedSelection = wxID_NONE; + // 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 ) + { + SetSelection(m_lastAcceptedSelection); + m_lastAcceptedSelection = wxID_NONE; + } break; - case CBN_SELCHANGE: + 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(); @@ -660,10 +705,19 @@ bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) ProcessCommand(event); } - return true; + break; + + // don't handle CBN_SELENDCANCEL: just leave m_lastAcceptedSelection + // valid and the selection will be undone in CBN_CLOSEUP above + + // 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 + + default: + return false; } - return false; + return true; } WXHBRUSH wxChoice::MSWControlColor(WXHDC hDC, WXHWND hWnd) @@ -675,4 +729,3 @@ WXHBRUSH wxChoice::MSWControlColor(WXHDC hDC, WXHWND hWnd) } #endif // wxUSE_CHOICE && !(__SMARTPHONE__ && __WXWINCE__) -