]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/combo.cpp
Preserve client data pointers when setting bitmaps in wxBitmapComboBox.
[wxWidgets.git] / src / msw / combo.cpp
index 6ffbb31861b19771f222bdfec4522969bcc0696d..2ef7d8925a4df77ecac03c0d629f194a933c0ca4 100644 (file)
 #include "wx/combo.h"
 
 #include "wx/msw/registry.h"
+#if wxUSE_UXTHEME
 #include "wx/msw/uxtheme.h"
+#endif
+#include "wx/msw/dc.h"
 
 // Change to #if 1 to include tmschema.h for easier testing of theme
 // parameters.
 #define NATIVE_TEXT_INDENT_XP       4
 #define NATIVE_TEXT_INDENT_CLASSIC  2
 
-#define TEXTCTRLXADJUST_XP          1
-#define TEXTCTRLYADJUST_XP          3
-#define TEXTCTRLXADJUST_CLASSIC     1
-#define TEXTCTRLYADJUST_CLASSIC     3
-
 #define COMBOBOX_ANIMATION_RESOLUTION   10
 
 #define COMBOBOX_ANIMATION_DURATION     200  // In milliseconds
@@ -159,10 +157,13 @@ bool wxComboCtrl::Create(wxWindow *parent,
     // Set border
     long border = style & wxBORDER_MASK;
 
+#if wxUSE_UXTHEME
     wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+#endif
 
     if ( !border )
     {
+#if wxUSE_UXTHEME
         if ( theme )
         {
             // For XP, have 1-width custom border, for older version use sunken
@@ -170,6 +171,7 @@ bool wxComboCtrl::Create(wxWindow *parent,
             m_widthCustomBorder = 1;
         }
         else
+#endif
             border = wxBORDER_SUNKEN;
 
         style = (style & ~(wxBORDER_MASK)) | border;
@@ -182,28 +184,33 @@ bool wxComboCtrl::Create(wxWindow *parent,
                            pos,
                            size,
                            style | wxFULL_REPAINT_ON_RESIZE,
-                           wxDefaultValidator,
+                           validator,
                            name) )
         return false;
 
+#if wxUSE_UXTHEME
     if ( theme )
     {
         if ( ::wxGetWinVersion() >= wxWinVersion_Vista )
             m_iFlags |= wxCC_BUTTON_STAYS_DOWN |wxCC_BUTTON_COVERS_BORDER;
     }
+#endif
 
     if ( style & wxCC_STD_BUTTON )
         m_iFlags |= wxCC_POPUP_ON_MOUSE_UP;
 
+    // Prepare background for double-buffering or better background theme
+    // support, whichever is possible.
+    SetDoubleBuffered(true);
+    if ( !IsDoubleBuffered() )
+        SetBackgroundStyle( wxBG_STYLE_PAINT );
+
     // Create textctrl, if necessary
-    CreateTextCtrl( wxNO_BORDER, validator );
+    CreateTextCtrl( wxNO_BORDER );
 
     // Add keyboard input handlers for main control and textctrl
     InstallInputHandlers();
 
-    // Prepare background for double-buffering
-    SetBackgroundStyle( wxBG_STYLE_CUSTOM );
-
     // SetInitialSize should be called last
     SetInitialSize(size);
 
@@ -214,59 +221,18 @@ wxComboCtrl::~wxComboCtrl()
 {
 }
 
-void wxComboCtrl::OnThemeChange()
-{
-    wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
-    if ( theme )
-    {
-        wxUxThemeHandle hTheme(this, L"EDIT");
-
-        COLORREF col;
-        HRESULT hr = theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_NORMAL,TMT_FILLCOLOR,&col);
-        if ( FAILED(hr) )
-            wxLogApiError(_T("GetThemeColor(EDIT, EP_EDITTEXT, ETS_NORMAL, TMT_FILLCOLOR)"), hr);
-        else
-            SetBackgroundColour(wxRGBToColour(col));
-
-        hr = theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_NORMAL,TMT_TEXTCOLOR,&col);
-        if ( FAILED(hr) )
-            wxLogApiError(_T("GetThemeColor(EDIT, EP_EDITTEXT, ETS_NORMAL, TMT_TEXTCOLOR)"), hr);
-        else
-            SetForegroundColour(wxRGBToColour(col));
-    }
-    else
-    {
-        SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
-        SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
-    }
-}
-
 void wxComboCtrl::OnResize()
 {
     //
     // Recalculates button and textctrl areas
 
-    int textCtrlXAdjust;
-    int textCtrlYAdjust;
-
-    if ( wxUxThemeEngine::GetIfActive() )
-    {
-        textCtrlXAdjust = TEXTCTRLXADJUST_XP;
-        textCtrlYAdjust = TEXTCTRLYADJUST_XP;
-    }
-    else
-    {
-        textCtrlXAdjust = TEXTCTRLXADJUST_CLASSIC;
-        textCtrlYAdjust = TEXTCTRLYADJUST_CLASSIC;
-    }
-
     // Technically Classic Windows style combo has more narrow button,
     // but the native renderer doesn't paint it well like that.
     int btnWidth = 17;
     CalculateAreas(btnWidth);
 
     // Position textctrl using standard routine
-    PositionTextCtrl(textCtrlXAdjust,textCtrlYAdjust);
+    PositionTextCtrl();
 }
 
 // Draws non-XP GUI dotted line around the focus area
@@ -289,7 +255,7 @@ static void wxMSWDrawFocusRect( wxDC& dc, const wxRect& rect )
     //   it employs wxCAP_BUTT hack to have line of width 1.
     dc.SetLogicalFunction(wxINVERT);
 
-    wxPen pen(*wxBLACK,1,wxDOT);
+    wxPen pen(*wxBLACK, 1, wxPENSTYLE_DOT);
     pen.SetCap(wxCAP_BUTT);
     dc.SetPen(pen);
     dc.SetBrush(*wxTRANSPARENT_BRUSH);
@@ -313,7 +279,9 @@ static void wxMSWDrawFocusRect( wxDC& dc, const wxRect& rect )
 void
 wxComboCtrl::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const
 {
+#if wxUSE_UXTHEME
     wxUxThemeHandle hTheme(this, L"COMBOBOX");
+#endif
 
     wxSize sz = GetClientSize();
     bool isEnabled;
@@ -326,9 +294,10 @@ wxComboCtrl::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const
     if ( !(flags & wxCONTROL_ISSUBMENU) )
     {
         // Drawing control
-        isEnabled = IsEnabled();
+        isEnabled = IsThisEnabled();
         doDrawFocusRect = ShouldDrawFocus();
 
+#if wxUSE_UXTHEME
         // Windows-style: for smaller size control (and for disabled background) use less spacing
         if ( hTheme )
         {
@@ -337,6 +306,7 @@ wxComboCtrl::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const
             focusSpacingY = sz.y > (GetCharHeight()+2) && isEnabled ? 2 : 1;
         }
         else
+#endif
         {
             // Classic Theme
             if ( isEnabled )
@@ -374,10 +344,11 @@ wxComboCtrl::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const
     selRect.x += wcp + focusSpacingX;
     selRect.width -= wcp + (focusSpacingX*2);
 
-    //wxUxThemeEngine* theme = (wxUxThemeEngine*) NULL;
+    //wxUxThemeEngine* theme = NULL;
     //if ( hTheme )
     //    theme = wxUxThemeEngine::GetIfActive();
 
+    wxColour fgCol;
     wxColour bgCol;
     bool doDrawDottedEdge = false;
     bool doDrawSelRect = true;
@@ -403,28 +374,31 @@ wxComboCtrl::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const
             if ( (m_iFlags & wxCC_FULL_BUTTON) && !(flags & wxCONTROL_ISSUBMENU) )
             {
                 // Vista style read-only combo
+                fgCol = GetForegroundColour();
+                bgCol = GetBackgroundColour();
                 doDrawSelRect = false;
                 doDrawDottedEdge = true;
             }
             else
             {
-                dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
+                fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
                 bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
             }
         }
         else
         {
-            dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
+            fgCol = GetForegroundColour();
             bgCol = GetBackgroundColour();
             doDrawSelRect = false;
         }
     }
     else
     {
-        dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT) );
+        fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
         bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
     }
 
+    dc.SetTextForeground(fgCol);
     dc.SetBrush(bgCol);
     if ( doDrawSelRect )
     {
@@ -447,14 +421,25 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
     // TODO: Convert drawing in this function to Windows API Code
 
     wxSize sz = GetClientSize();
-    wxAutoBufferedPaintDC dc(this);
+    wxDC* dcPtr = wxAutoBufferedPaintDCFactory(this);
+    wxDC& dc = *dcPtr;
 
     const wxRect& rectButton = m_btnArea;
     wxRect rectTextField = m_tcArea;
-    const bool isEnabled = IsEnabled();
-    wxColour bgCol = GetBackgroundColour();
 
-    HDC hDc = GetHdcOf(dc);
+    // FIXME: Either SetBackgroundColour or GetBackgroundColour
+    //        doesn't work under Vista, so here's a temporary
+    //        workaround.
+    //        In the theme-less rendering code below, this fixes incorrect
+    //        background on read-only comboboxes (they are gray, but should be
+    //        white).
+    wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+
+#if wxUSE_UXTHEME
+    const bool isEnabled = IsThisEnabled();
+
+    wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+    HDC hDc = GetHdcOf(*impl);
     HWND hWnd = GetHwndOf(this);
 
     wxUxThemeEngine* theme = NULL;
@@ -462,6 +447,7 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
 
     if ( hTheme )
         theme = wxUxThemeEngine::GetIfActive();
+#endif // wxUSE_UXTHEME
 
     wxRect borderRect(0,0,sz.x,sz.y);
 
@@ -473,6 +459,7 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
 
     int drawButFlags = 0;
 
+#if wxUSE_UXTHEME
     if ( hTheme )
     {
         const bool useVistaComboBox = ::wxGetWinVersion() >= wxWinVersion_Vista;
@@ -522,11 +509,6 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
 
         if ( useVistaComboBox )
         {
-            // FIXME: Either SetBackgroundColour or GetBackgroundColour
-            //        doesn't work under Vista, so here's a temporary
-            //        workaround.
-            bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
-
             // Draw the entire control as a single button?
             if ( !isNonStdButton )
             {
@@ -617,6 +599,7 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
         }
     }
     else
+#endif
     {
         // Windows 2000 and earlier
         drawButFlags = Button_PaintBackground;
@@ -647,6 +630,8 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
         else
             wxComboPopup::DefaultPaintComboControl(this,dc,rectTextField);
     }
+
+    delete dcPtr;
 }
 
 void wxComboCtrl::OnMouseEvent( wxMouseEvent& event )
@@ -733,10 +718,11 @@ static wxUint32 GetUserPreferencesMask()
 #endif
 
 #if wxUSE_COMBOCTRL_POPUP_ANIMATION
-void wxComboCtrl::OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
+void wxComboCtrl::DoTimerEvent()
 {
     bool stopTimer = false;
 
+    wxWindow* win = GetPopupWindow();
     wxWindow* popup = GetPopupControl()->GetControl();
 
     // Popup was hidden before it was fully shown?
@@ -748,7 +734,6 @@ void wxComboCtrl::OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
     {
         wxLongLong t = ::wxGetLocalTimeMillis();
         const wxRect& rect = m_animRect;
-        wxWindow* win = GetPopupWindow();
 
         int pos = (int) (t-m_animStart).GetLo();
         if ( pos < COMBOBOX_ANIMATION_DURATION )
@@ -766,8 +751,10 @@ void wxComboCtrl::OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
             }
             else
             {
-                popup->Move( 0, -y );
+                // Note that apparently Move() should be called after
+                // SetSize() to reduce (or even eliminate) animation garbage
                 win->SetSize( rect.x, rect.y, rect.width, h );
+                popup->Move( 0, -y );
             }
         }
         else
@@ -778,9 +765,13 @@ void wxComboCtrl::OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
 
     if ( stopTimer )
     {
-        popup->Move( 0, 0 );
         m_animTimer.Stop();
         DoShowPopup( m_animRect, m_animFlags );
+        popup->Move( 0, 0 );
+
+        // Do a one final refresh to clean up the rare cases of animation
+        // garbage
+        win->Refresh();
     }
 }
 #endif
@@ -801,7 +792,7 @@ bool wxComboCtrl::AnimateShow( const wxRect& rect, int flags )
         m_animTimer.SetOwner( this, wxID_ANY );
         m_animTimer.Start( COMBOBOX_ANIMATION_RESOLUTION, wxTIMER_CONTINUOUS );
 
-        OnTimerEvent(*((wxTimerEvent*)NULL));  // Event is never used, so we can give NULL
+        DoTimerEvent();
 
         return false;
     }
@@ -812,8 +803,10 @@ bool wxComboCtrl::AnimateShow( const wxRect& rect, int flags )
 
 wxCoord wxComboCtrl::GetNativeTextIndent() const
 {
+#if wxUSE_UXTHEME
     if ( wxUxThemeEngine::GetIfActive() )
         return NATIVE_TEXT_INDENT_XP;
+#endif
     return NATIVE_TEXT_INDENT_CLASSIC;
 }
 
@@ -836,16 +829,12 @@ bool wxComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
 
         case WXK_DOWN:
         case WXK_UP:
-            // On XP or with writable combo in Classic, arrows don't open the
-            // popup but Alt-arrow does
-            if ( event.AltDown() ||
-                    ( !isPopupShown &&
-                      HasFlag(wxCB_READONLY) &&
-                      !wxUxThemeEngine::GetIfActive()
-                    ) )
-            {
+        case WXK_NUMPAD_DOWN:
+        case WXK_NUMPAD_UP:
+            // Arrow keys (and mouse wheel) toggle the popup in the native
+            // combo boxes
+            if ( event.AltDown() )
                 return true;
-            }
             break;
     }