]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/combo.cpp
use facename in wxFontRefData::Init() in Unicode build (part of patch 1671684)
[wxWidgets.git] / src / msw / combo.cpp
index b006217757af281075a56200f4e43c8aeaecba8d..7c69f60c861b2c2b838f3b1d277752a62858fe1d 100644 (file)
@@ -1,6 +1,6 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        combo.cpp
-// Purpose:     wxMSW wxComboControl
+// Name:        src/msw/combo.cpp
+// Purpose:     wxMSW wxComboCtrl
 // Author:      Jaakko Salli
 // Modified by:
 // Created:     Apr-30-2006
@@ -23,7 +23,7 @@
     #pragma hdrstop
 #endif
 
-#if wxUSE_COMBOCONTROL
+#if wxUSE_COMBOCTRL
 
 #ifndef WX_PRECOMP
     #include "wx/log.h"
     #include "wx/dcclient.h"
     #include "wx/settings.h"
     #include "wx/dialog.h"
+    #include "wx/stopwatch.h"
 #endif
 
 #include "wx/dcbuffer.h"
-
 #include "wx/combo.h"
 
-
+#include "wx/msw/registry.h"
 #include "wx/msw/uxtheme.h"
 
 // Change to #if 1 to include tmschema.h for easier testing of theme
 #define TEXTCTRLXADJUST_CLASSIC     1
 #define TEXTCTRLYADJUST_CLASSIC     2
 
+#define COMBOBOX_ANIMATION_RESOLUTION   10
+
+#define COMBOBOX_ANIMATION_DURATION     200  // In milliseconds
+
+#define wxMSW_DESKTOP_USERPREFERENCESMASK_COMBOBOXANIM    (1<<2)
+
 
 // ============================================================================
 // implementation
 // ============================================================================
 
 
-BEGIN_EVENT_TABLE(wxComboControl, wxComboControlBase)
-    EVT_PAINT(wxComboControl::OnPaintEvent)
-    EVT_MOUSE_EVENTS(wxComboControl::OnMouseEvent)
+BEGIN_EVENT_TABLE(wxComboCtrl, wxComboCtrlBase)
+    EVT_PAINT(wxComboCtrl::OnPaintEvent)
+    EVT_MOUSE_EVENTS(wxComboCtrl::OnMouseEvent)
+#if wxUSE_COMBOCTRL_POPUP_ANIMATION
+    EVT_TIMER(wxID_ANY, wxComboCtrl::OnTimerEvent)
+#endif
 END_EVENT_TABLE()
 
 
-IMPLEMENT_DYNAMIC_CLASS(wxComboControl, wxComboControlBase)
+IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl, wxComboCtrlBase)
 
-void wxComboControl::Init()
+void wxComboCtrl::Init()
 {
 }
 
-bool wxComboControl::Create(wxWindow *parent,
+bool wxComboCtrl::Create(wxWindow *parent,
                             wxWindowID id,
                             const wxString& value,
                             const wxPoint& pos,
@@ -118,14 +127,14 @@ bool wxComboControl::Create(wxWindow *parent,
     }
 
     // create main window
-    if ( !wxComboControlBase::Create(parent,
-                            id,
-                            value,
-                            wxDefaultPosition,
-                            wxDefaultSize,
-                            style | wxFULL_REPAINT_ON_RESIZE,
-                            wxDefaultValidator,
-                            name) )
+    if ( !wxComboCtrlBase::Create(parent,
+                           id,
+                           value,
+                           pos,
+                           size,
+                           style | wxFULL_REPAINT_ON_RESIZE,
+                           wxDefaultValidator,
+                           name) )
         return false;
 
     if ( style & wxCC_STD_BUTTON )
@@ -135,22 +144,22 @@ bool wxComboControl::Create(wxWindow *parent,
     CreateTextCtrl( wxNO_BORDER, validator );
 
     // Add keyboard input handlers for main control and textctrl
-    InstallInputHandlers( true );
+    InstallInputHandlers();
 
     // Prepare background for double-buffering
     SetBackgroundStyle( wxBG_STYLE_CUSTOM );
 
-    // SetSize should be called last
-    SetSize(pos.x,pos.y,size.x,size.y);
+    // SetInitialSize should be called last
+    SetInitialSize(size);
 
     return true;
 }
 
-wxComboControl::~wxComboControl()
+wxComboCtrl::~wxComboCtrl()
 {
 }
 
-void wxComboControl::OnThemeChange()
+void wxComboCtrl::OnThemeChange()
 {
     wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
     if ( theme )
@@ -170,7 +179,7 @@ void wxComboControl::OnThemeChange()
     }
 }
 
-void wxComboControl::OnResize()
+void wxComboCtrl::OnResize()
 {
     //
     // Recalculates button and textctrl areas
@@ -239,9 +248,9 @@ static void wxMSWDrawFocusRect( wxDC& dc, const wxRect& rect )
 }
 
 // draw focus background on area in a way typical on platform
-void wxComboControl::DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags )
+void
+wxComboCtrl::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const
 {
-    wxUxThemeEngine* theme = (wxUxThemeEngine*) NULL;
     wxUxThemeHandle hTheme(this, L"COMBOBOX");
     //COLORREF cref;
 
@@ -295,11 +304,18 @@ void wxComboControl::DrawFocusBackground( wxDC& dc, const wxRect& rect, int flag
     wxRect selRect(rect);
     selRect.y += focusSpacingY;
     selRect.height -= (focusSpacingY*2);
-    selRect.x += m_widthCustomPaint + focusSpacingX;
-    selRect.width -= m_widthCustomPaint + (focusSpacingX*2);
 
-    if ( hTheme )
-        theme = wxUxThemeEngine::GetIfActive();
+    int wcp = 0;
+
+    if ( !(flags & wxCONTROL_ISSUBMENU) )
+        wcp += m_widthCustomPaint;
+
+    selRect.x += wcp + focusSpacingX;
+    selRect.width -= wcp + (focusSpacingX*2);
+
+    //wxUxThemeEngine* theme = (wxUxThemeEngine*) NULL;
+    //if ( hTheme )
+    //    theme = wxUxThemeEngine::GetIfActive();
 
     wxColour bgCol;
     bool drawDottedEdge = false;
@@ -367,14 +383,19 @@ void wxComboControl::DrawFocusBackground( wxDC& dc, const wxRect& rect, int flag
     if ( drawDottedEdge )
         wxMSWDrawFocusRect(dc,selRect);
 
+    // Don't clip exactly to the selection rectangle so we can draw
+    // to the non-selected area in front of it.
+    wxRect clipRect(rect.x,rect.y,
+                    (selRect.x+selRect.width)-rect.x-1,rect.height);
+    dc.SetClippingRegion(clipRect);
 }
 
-void wxComboControl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
+void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
 {
     // TODO: Convert drawing in this function to Windows API Code
 
     wxSize sz = GetClientSize();
-    wxBufferedPaintDC dc(this,GetBufferBitmap(sz));
+    wxAutoBufferedPaintDC dc(this);
 
     const wxRect& rectb = m_btnArea;
     wxRect rect = m_tcArea;
@@ -435,7 +456,7 @@ void wxComboControl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
     dc.DrawRectangle(rect);
 
     // Button background with theme?
-    bool drawButBg = true;
+    int drawButFlags = Draw_PaintBg;
     if ( hTheme && m_blankButtonBg )
     {
         RECT r;
@@ -447,14 +468,14 @@ void wxComboControl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
                                          GetHdcOf(dc),
                                          &r);
 
-        drawButBg = false;
-    } 
+        drawButFlags = 0;
+    }
 
     // Standard button rendering
-    DrawButton(dc,rectb,drawButBg);
+    DrawButton(dc,rectb,drawButFlags);
 
     // paint required portion on the control
-    if ( !m_text || m_widthCustomPaint )
+    if ( (!m_text || m_widthCustomPaint) )
     {
         wxASSERT( m_widthCustomPaint >= 0 );
 
@@ -466,17 +487,19 @@ void wxComboControl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
         dc.SetFont( GetFont() );
 
         dc.SetClippingRegion(rect);
-        m_popupInterface->PaintComboControl(dc,rect);
+        if ( m_popupInterface )
+            m_popupInterface->PaintComboControl(dc,rect);
+        else
+            wxComboPopup::DefaultPaintComboControl(this,dc,rect);
     }
 }
 
-void wxComboControl::OnMouseEvent( wxMouseEvent& event )
+void wxComboCtrl::OnMouseEvent( wxMouseEvent& event )
 {
-    bool isOnButtonArea = m_btnArea.Inside(event.m_x,event.m_y);
+    int mx = event.m_x;
+    bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y);
     int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
 
-    // Preprocessing fabricates double-clicks and prevents
-    // (it may also do other common things in future)
     if ( PreprocessMouseEvent(event,isOnButtonArea) )
         return;
 
@@ -490,8 +513,11 @@ void wxComboControl::OnMouseEvent( wxMouseEvent& event )
     }
     else
     {
-        if ( isOnButtonArea || HasCapture() )
+        if ( isOnButtonArea || HasCapture() ||
+             (m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) )
         {
+            handlerFlags |= wxCC_MF_ON_CLICK_AREA;
+
             if ( HandleButtonMouseEvent(event,handlerFlags) )
                 return;
         }
@@ -510,12 +536,165 @@ void wxComboControl::OnMouseEvent( wxMouseEvent& event )
 
 }
 
-wxCoord wxComboControl::GetNativeTextIndent() const
+#if wxUSE_COMBOCTRL_POPUP_ANIMATION
+static wxUint32 GetUserPreferencesMask()
+{
+    static wxUint32 userPreferencesMask = 0;
+    static bool valueSet = false;
+
+    if ( valueSet )
+        return userPreferencesMask;
+
+    wxRegKey* pKey = NULL;
+    wxRegKey key1(wxRegKey::HKCU, wxT("Software\\Policies\\Microsoft\\Control Panel"));
+    wxRegKey key2(wxRegKey::HKCU, wxT("Software\\Policies\\Microsoft\\Windows\\Control Panel"));
+    wxRegKey key3(wxRegKey::HKCU, wxT("Control Panel\\Desktop"));
+
+    if ( key1.Exists() )
+        pKey = &key1;
+    else if ( key2.Exists() )
+        pKey = &key2;
+    else if ( key3.Exists() )
+        pKey = &key3;
+
+    if ( pKey && pKey->Open(wxRegKey::Read) )
+    {
+        wxMemoryBuffer buf;
+        if ( pKey->HasValue(wxT("UserPreferencesMask")) &&
+             pKey->QueryValue(wxT("UserPreferencesMask"), buf) )
+        {
+            if ( buf.GetDataLen() >= 4 )
+            {
+                wxUint32* p = (wxUint32*) buf.GetData();
+                userPreferencesMask = *p;
+            }
+        }
+    }
+
+    valueSet = true;
+
+    return userPreferencesMask;
+}
+#endif
+
+#if wxUSE_COMBOCTRL_POPUP_ANIMATION
+void wxComboCtrl::OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
+{
+    bool stopTimer = false;
+
+    wxWindow* popup = GetPopupControl()->GetControl();
+
+    // Popup was hidden before it was fully shown?
+    if ( IsPopupWindowState(Hidden) )
+    {
+        stopTimer = true;
+    }
+    else
+    {
+        wxLongLong t = ::wxGetLocalTimeMillis();
+        const wxRect& rect = m_animRect;
+        wxWindow* win = GetPopupWindow();
+
+        int pos = (int) (t-m_animStart).GetLo();
+        if ( pos < COMBOBOX_ANIMATION_DURATION )
+        {
+            int height = rect.height;
+            //int h0 = rect.height;
+            int h = (((pos*256)/COMBOBOX_ANIMATION_DURATION)*height)/256;
+            int y = (height - h);
+            if ( y < 0 )
+                y = 0;
+
+            if ( m_animFlags & ShowAbove )
+            {
+                win->SetSize( rect.x, rect.y + height - h, rect.width, h );
+            }
+            else
+            {
+                popup->Move( 0, -y );
+                win->SetSize( rect.x, rect.y, rect.width, h );
+            }
+        }
+        else
+        {
+            stopTimer = true;
+        }
+    }
+
+    if ( stopTimer )
+    {
+        popup->Move( 0, 0 );
+        m_animTimer.Stop();
+        DoShowPopup( m_animRect, m_animFlags );
+    }
+}
+#endif
+
+#if wxUSE_COMBOCTRL_POPUP_ANIMATION
+bool wxComboCtrl::AnimateShow( const wxRect& rect, int flags )
+{
+    if ( GetUserPreferencesMask() & wxMSW_DESKTOP_USERPREFERENCESMASK_COMBOBOXANIM )
+    {
+        m_animStart = ::wxGetLocalTimeMillis();
+        m_animRect = rect;
+        m_animFlags = flags;
+
+        wxWindow* win = GetPopupWindow();
+        win->SetSize( rect.x, rect.y, rect.width, 0 );
+        win->Show();
+
+        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
+
+        return false;
+    }
+
+    return true;
+}
+#endif
+
+wxCoord wxComboCtrl::GetNativeTextIndent() const
 {
     if ( wxUxThemeEngine::GetIfActive() )
         return NATIVE_TEXT_INDENT_XP;
     return NATIVE_TEXT_INDENT_CLASSIC;
 }
 
+bool wxComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
+{
+    const bool isPopupShown = IsPopupShown();
+
+    switch ( event.GetKeyCode() )
+    {
+        case WXK_F4:
+            // F4 toggles the popup in the native comboboxes, so emulate them
+            if ( !event.AltDown() )
+                return true;
+            break;
+
+        case WXK_ESCAPE:
+            if ( isPopupShown )
+                return true;
+            break;
+
+        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()
+                    ) )
+            {
+                return true;
+            }
+            break;
+    }
+
+    return false;
+}
 
-#endif // wxUSE_COMBOCONTROL
+#endif // wxUSE_COMBOCTRL