X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a57d600f1aa4bae88f4c9b8d89a35332c412939e..f89919f5e9c80195007ebc3480f3fe4c133d5505:/src/msw/combo.cpp diff --git a/src/msw/combo.cpp b/src/msw/combo.cpp index 92711ac9d6..7c69f60c86 100644 --- a/src/msw/combo.cpp +++ b/src/msw/combo.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: combo.cpp +// Name: src/msw/combo.cpp // Purpose: wxMSW wxComboCtrl // Author: Jaakko Salli // Modified by: @@ -31,13 +31,13 @@ #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 @@ -70,6 +70,12 @@ #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 @@ -79,6 +85,9 @@ 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() @@ -119,13 +128,13 @@ bool wxComboCtrl::Create(wxWindow *parent, // create main window if ( !wxComboCtrlBase::Create(parent, - id, - value, - wxDefaultPosition, - wxDefaultSize, - style | wxFULL_REPAINT_ON_RESIZE, - wxDefaultValidator, - name) ) + id, + value, + pos, + size, + style | wxFULL_REPAINT_ON_RESIZE, + wxDefaultValidator, + name) ) return false; if ( style & wxCC_STD_BUTTON ) @@ -135,13 +144,13 @@ bool wxComboCtrl::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; } @@ -239,9 +248,9 @@ static void wxMSWDrawFocusRect( wxDC& dc, const wxRect& rect ) } // draw focus background on area in a way typical on platform -void wxComboCtrl::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 wxComboCtrl::DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags ) 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,6 +383,11 @@ void wxComboCtrl::DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags ) 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 wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) ) @@ -374,7 +395,7 @@ 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 wxComboCtrl::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,11 +468,11 @@ void wxComboCtrl::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) ) @@ -475,11 +496,10 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(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; @@ -493,8 +513,11 @@ void wxComboCtrl::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; } @@ -513,6 +536,125 @@ void wxComboCtrl::OnMouseEvent( wxMouseEvent& event ) } +#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() ) @@ -520,5 +662,39 @@ wxCoord wxComboCtrl::GetNativeTextIndent() const 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_COMBOCTRL