]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/combobox.cpp
Fixed post-expand/collapse rendering
[wxWidgets.git] / src / msw / combobox.cpp
index bb651346225a7cbe8d9aa2ff066f8db3700fbdda..84b1bca018f7d2a220f8d3f8732dce093cbf0b06 100644 (file)
 #endif
 
 #include "wx/clipbrd.h"
 #endif
 
 #include "wx/clipbrd.h"
+#include "wx/wupdlock.h"
 #include "wx/msw/private.h"
 
 #include "wx/msw/private.h"
 
+#if wxUSE_UXTHEME
+    #include "wx/msw/uxtheme.h"
+#endif
+
 #if wxUSE_TOOLTIPS
     #include "wx/tooltip.h"
 #endif // wxUSE_TOOLTIPS
 #if wxUSE_TOOLTIPS
     #include "wx/tooltip.h"
 #endif // wxUSE_TOOLTIPS
@@ -183,7 +188,7 @@ LRESULT APIENTRY _EXPORT wxComboEditWndProc(HWND hWnd,
                     // longer, check for it to avoid bogus assert failures
                     if ( !win->IsBeingDeleted() )
                     {
                     // longer, check for it to avoid bogus assert failures
                     if ( !win->IsBeingDeleted() )
                     {
-                        wxFAIL_MSG( _T("should have combo as parent") );
+                        wxFAIL_MSG( wxT("should have combo as parent") );
                     }
                 }
                 else if ( combo->MSWProcessEditMsg(message, wParam, lParam) )
                     }
                 }
                 else if ( combo->MSWProcessEditMsg(message, wParam, lParam) )
@@ -196,7 +201,7 @@ LRESULT APIENTRY _EXPORT wxComboEditWndProc(HWND hWnd,
 
         case WM_GETDLGCODE:
             {
 
         case WM_GETDLGCODE:
             {
-                wxCHECK_MSG( win, 0, _T("should have a parent") );
+                wxCHECK_MSG( win, 0, wxT("should have a parent") );
 
                 if ( win->GetWindowStyle() & wxTE_PROCESS_ENTER )
                 {
 
                 if ( win->GetWindowStyle() & wxTE_PROCESS_ENTER )
                 {
@@ -205,13 +210,6 @@ LRESULT APIENTRY _EXPORT wxComboEditWndProc(HWND hWnd,
                 }
             }
             break;
                 }
             }
             break;
-
-        case WM_CUT:
-        case WM_COPY:
-        case WM_PASTE:
-            if( win->HandleClipboardEvent( message ) )
-                return 0;
-            break;
     }
 
     return ::CallWindowProc(CASTWNDPROC gs_wndprocEdit, hWnd, message, wParam, lParam);
     }
 
     return ::CallWindowProc(CASTWNDPROC gs_wndprocEdit, hWnd, message, wParam, lParam);
@@ -240,8 +238,23 @@ WXLRESULT wxComboBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
 
                 long fromOld, toOld;
                 GetSelection(&fromOld, &toOld);
 
                 long fromOld, toOld;
                 GetSelection(&fromOld, &toOld);
+
+                // if an editable combobox has a not empty text not from the
+                // list, it tries to autocomplete it from the list when it is
+                // resized, but we don't want this to happen as it doesn't seem
+                // to make any sense, so we forcefully restore the old text
+                wxString textOld;
+                if ( !HasFlag(wxCB_READONLY) && GetCurrentSelection() == -1 )
+                    textOld = GetValue();
+
+                // eliminate flickering during following hacks
+                wxWindowUpdateLocker lock(this);
+
                 WXLRESULT result = wxChoice::MSWWindowProc(nMsg, wParam, lParam);
 
                 WXLRESULT result = wxChoice::MSWWindowProc(nMsg, wParam, lParam);
 
+                if ( !textOld.empty() && GetValue() != textOld )
+                    SetLabel(textOld);
+
                 long fromNew, toNew;
                 GetSelection(&fromNew, &toNew);
 
                 long fromNew, toNew;
                 GetSelection(&fromNew, &toNew);
 
@@ -302,6 +315,11 @@ bool wxComboBox::MSWProcessEditMsg(WXUINT msg, WXWPARAM wParam, WXLPARAM lParam)
 
         case WM_KILLFOCUS:
             return HandleKillFocus((WXHWND)wParam);
 
         case WM_KILLFOCUS:
             return HandleKillFocus((WXHWND)wParam);
+
+        case WM_CUT:
+        case WM_COPY:
+        case WM_PASTE:
+            return HandleClipboardEvent(msg);
     }
 
     return false;
     }
 
     return false;
@@ -314,6 +332,29 @@ bool wxComboBox::MSWCommand(WXUINT param, WXWORD id)
 
     switch ( param )
     {
 
     switch ( param )
     {
+        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:
+            {
+                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
         case CBN_SELENDOK:
 #ifndef __SMARTPHONE__
             // we need to reset this to prevent the selection from being undone
@@ -345,6 +386,7 @@ bool wxComboBox::MSWCommand(WXUINT param, WXWORD id)
             // logical as the text does change)
 
         case CBN_EDITCHANGE:
             // logical as the text does change)
 
         case CBN_EDITCHANGE:
+            if ( m_allowTextEvents )
             {
                 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
 
             {
                 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
 
@@ -366,7 +408,7 @@ bool wxComboBox::MSWCommand(WXUINT param, WXWORD id)
     }
 
     // skip wxChoice version as it would generate its own events for
     }
 
     // skip wxChoice version as it would generate its own events for
-    // CBN_SELENDOK
+    // CBN_SELENDOK and also interfere with our handling of CBN_DROPDOWN
     return true;
 }
 
     return true;
 }
 
@@ -396,9 +438,39 @@ bool wxComboBox::MSWShouldPreProcessMessage(WXMSG *pMsg)
 
 WXHWND wxComboBox::GetEditHWNDIfAvailable() const
 {
 
 WXHWND wxComboBox::GetEditHWNDIfAvailable() const
 {
-    // we assume that the only child of the combobox is the edit window so it's
-    // unnecessary to pass "EDIT" as class name parameter
-    return (WXHWND)::FindWindowEx(GetHwnd(), NULL, NULL, NULL);
+#if defined(WINVER) && WINVER >= 0x0500
+    typedef BOOL (WINAPI *GetComboBoxInfo_t)(HWND, COMBOBOXINFO*);
+    static GetComboBoxInfo_t s_pfnGetComboBoxInfo = NULL;
+    static bool s_triedToLoad = false;
+    if ( !s_triedToLoad )
+    {
+        s_triedToLoad = true;
+        wxLoadedDLL dllUser32("user32.dll");
+        wxDL_INIT_FUNC(s_pfn, GetComboBoxInfo, dllUser32);
+    }
+
+    if ( s_pfnGetComboBoxInfo )
+    {
+        WinStruct<COMBOBOXINFO> info;
+        (*s_pfnGetComboBoxInfo)(GetHwnd(), &info);
+        return info.hwndItem;
+    }
+#endif
+
+    if (HasFlag(wxCB_SIMPLE))
+    {
+        POINT pt;
+        pt.x = pt.y = 4;
+        return (WXHWND) ::ChildWindowFromPoint(GetHwnd(), pt);
+    }
+
+    // notice that a slightly safer alternative could be to use FindWindowEx()
+    // but it's not available under WinCE so just take the first child for now
+    // to keep one version of the code for all platforms and fix it later if
+    // problems are discovered
+
+    // we assume that the only child of the combobox is the edit window
+    return (WXHWND)::GetWindow(GetHwnd(), GW_CHILD);
 }
 
 WXHWND wxComboBox::GetEditHWND() const
 }
 
 WXHWND wxComboBox::GetEditHWND() const
@@ -406,14 +478,22 @@ WXHWND wxComboBox::GetEditHWND() const
     // this function should not be called for wxCB_READONLY controls, it is
     // the callers responsibility to check this
     wxASSERT_MSG( !HasFlag(wxCB_READONLY),
     // this function should not be called for wxCB_READONLY controls, it is
     // the callers responsibility to check this
     wxASSERT_MSG( !HasFlag(wxCB_READONLY),
-                  _T("read-only combobox doesn't have any edit control") );
+                  wxT("read-only combobox doesn't have any edit control") );
 
     WXHWND hWndEdit = GetEditHWNDIfAvailable();
 
     WXHWND hWndEdit = GetEditHWNDIfAvailable();
-    wxASSERT_MSG( hWndEdit, _T("combobox without edit control?") );
+    wxASSERT_MSG( hWndEdit, wxT("combobox without edit control?") );
 
     return hWndEdit;
 }
 
 
     return hWndEdit;
 }
 
+wxWindow *wxComboBox::GetEditableWindow()
+{
+    wxASSERT_MSG( !HasFlag(wxCB_READONLY),
+                  wxT("read-only combobox doesn't have any edit control") );
+
+    return this;
+}
+
 // ----------------------------------------------------------------------------
 // wxComboBox creation
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // wxComboBox creation
 // ----------------------------------------------------------------------------
@@ -579,15 +659,12 @@ void wxComboBox::OnRedo(wxCommandEvent& WXUNUSED(event))
 
 void wxComboBox::OnDelete(wxCommandEvent& WXUNUSED(event))
 {
 
 void wxComboBox::OnDelete(wxCommandEvent& WXUNUSED(event))
 {
-    long from, to;
-    GetSelection(& from, & to);
-    if (from != -1 && to != -1)
-        Remove(from, to);
+    RemoveSelection();
 }
 
 void wxComboBox::OnSelectAll(wxCommandEvent& WXUNUSED(event))
 {
 }
 
 void wxComboBox::OnSelectAll(wxCommandEvent& WXUNUSED(event))
 {
-    SetSelection(-1, -1);
+    SelectAll();
 }
 
 void wxComboBox::OnUpdateCut(wxUpdateUIEvent& event)
 }
 
 void wxComboBox::OnUpdateCut(wxUpdateUIEvent& event)
@@ -622,7 +699,7 @@ void wxComboBox::OnUpdateDelete(wxUpdateUIEvent& event)
 
 void wxComboBox::OnUpdateSelectAll(wxUpdateUIEvent& event)
 {
 
 void wxComboBox::OnUpdateSelectAll(wxUpdateUIEvent& event)
 {
-    event.Enable(IsEditable() && GetLastPosition() > 0);
+    event.Enable(IsEditable() && !wxTextEntry::IsEmpty());
 }
 
 #if wxUSE_TOOLTIPS
 }
 
 #if wxUSE_TOOLTIPS
@@ -637,4 +714,22 @@ void wxComboBox::DoSetToolTip(wxToolTip *tip)
 
 #endif // wxUSE_TOOLTIPS
 
 
 #endif // wxUSE_TOOLTIPS
 
+#if wxUSE_UXTHEME
+
+bool wxComboBox::SetHint(const wxString& hintOrig)
+{
+    wxString hint(hintOrig);
+    if ( wxUxThemeEngine::GetIfActive() )
+    {
+        // under XP (but not Vista) there is a bug in cue banners
+        // implementation for combobox edit control: the first character is
+        // partially chopped off, so prepend a space to make it fully visible
+        hint.insert(0, " ");
+    }
+
+    return wxTextEntry::SetHint(hint);
+}
+
+#endif // wxUSE_UXTHEME
+
 #endif // wxUSE_COMBOBOX
 #endif // wxUSE_COMBOBOX