/////////////////////////////////////////////////////////////////////////////
-// Name: choice.cpp
+// Name: src/msw/choice.cpp
// Purpose: wxChoice
// Author: Julian Smart
// Modified by: Vadim Zeitlin to derive from wxChoiceBase
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 )
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() )
{
// 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;
}
//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
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();
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)
}
#endif // wxUSE_CHOICE && !(__SMARTPHONE__ && __WXWINCE__)
-