]> git.saurik.com Git - wxWidgets.git/commitdiff
Make wxChoice and wxComboBox behaviour same as in native controls in wxMSW.
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 2 Dec 2012 23:49:25 +0000 (23:49 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 2 Dec 2012 23:49:25 +0000 (23:49 +0000)
Keep the item selected from the drop down using keyboard when switching away
from the control by pressing TAB: although this generates CBN_SELENDCANCEL
notification, the selection is actually kept by the native controls in this
case, so don't reset it ourselves -- even though it makes sense, it makes wx
applications behave differently from the native ones.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@73103 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/msw/choice.h
src/msw/choice.cpp
src/msw/combobox.cpp

index 496c20f9f6b6bb4430a48fe4b837550f8a598a12..294605d5277c95c8fa1fe2c98b0b023ac30b8215 100644 (file)
@@ -106,7 +106,8 @@ protected:
     // common part of all ctors
     void Init()
     {
-        m_lastAcceptedSelection = wxID_NONE;
+        m_lastAcceptedSelection =
+        m_pendingSelection = wxID_NONE;
         m_heightOwn = wxDefaultCoord;
     }
 
@@ -162,10 +163,13 @@ protected:
     virtual void MSWEndDeferWindowPos();
 #endif // wxUSE_DEFERRED_SIZING
 
-    // last "completed" selection, i.e. not the transient one while the user is
-    // browsing the popup list: this is only used when != wxID_NONE which is
-    // the case while the drop down is opened
-    int m_lastAcceptedSelection;
+    // These variables are only used while the drop down is opened.
+    //
+    // The first one contains the item that had been originally selected before
+    // the drop down was opened and the second one the item we should select
+    // when the drop down is closed again.
+    int m_lastAcceptedSelection,
+        m_pendingSelection;
 
     // the height of the control itself if it was set explicitly or
     // wxDefaultCoord if it hadn't
index b6670350f32a08fec9f141dbb45ca56669ef305d..30dad609d01e46fe6f04b30b8b75e892e1af7c69 100644 (file)
@@ -740,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
@@ -764,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 )
     {
@@ -776,31 +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;
+            // 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;
 
             SendSelectionChangedEvent(wxEVT_COMMAND_CHOICE_SELECTED);
             break;
 
+        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_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
+        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;
index d0b9836bafcb077eb970211ac46a20233ff7fce4..b823cc589942d478e1a1ca3ec6d166b0d15e4b69 100644 (file)
@@ -274,26 +274,27 @@ bool wxComboBox::MSWCommand(WXUINT param, WXWORD id)
         case CBN_DROPDOWN:
             // remember the last selection, just as wxChoice does
             m_lastAcceptedSelection = GetCurrentSelection();
-            if ( m_lastAcceptedSelection == -1 )
-            {
-                // but unlike with wxChoice we may have no selection but still
-                // have some text and we should avoid erasing it if the drop
-                // down is cancelled (see #8474)
-                m_lastAcceptedSelection = wxID_NONE;
-            }
             {
                 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_DROPDOWN, GetId());
                 event.SetEventObject(this);
                 ProcessCommand(event);
             }
             break;
+
         case CBN_CLOSEUP:
+            // Do the same thing as in wxChoice but using different event type.
+            if ( m_pendingSelection != wxID_NONE )
+            {
+                SendSelectionChangedEvent(wxEVT_COMMAND_COMBOBOX_SELECTED);
+                m_pendingSelection = wxID_NONE;
+            }
             {
                 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_CLOSEUP, GetId());
                 event.SetEventObject(this);
                 ProcessCommand(event);
             }
             break;
+
         case CBN_SELENDOK:
 #ifndef __SMARTPHONE__
             // we need to reset this to prevent the selection from being undone