From 30be036c6d4990f8aa21af5b86abdc0852e686a0 Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Thu, 26 Oct 2006 20:35:57 +0000 Subject: [PATCH] Make animation of combo-popdown optional. Replace wxMiniSleep() + wxYield() implemenation by wxTimer based one. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42470 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/comboctrl.tex | 8 +++ include/wx/combo.h | 13 +++- include/wx/msw/combo.h | 22 ++++++- samples/combo/combo.cpp | 117 +++++++++++++++++++++++++++--------- src/common/combocmn.cpp | 3 +- src/msw/combo.cpp | 95 ++++++++++++++++++----------- 6 files changed, 192 insertions(+), 66 deletions(-) diff --git a/docs/latex/wx/comboctrl.tex b/docs/latex/wx/comboctrl.tex index aa8d440a6d..07d9608518 100644 --- a/docs/latex/wx/comboctrl.tex +++ b/docs/latex/wx/comboctrl.tex @@ -295,6 +295,14 @@ In this case, \helpref{AnimateShow}{wxcomboctrlanimateshow} must return \false.} \end{twocollist} +\membersection{wxComboCtrl::EnablePopupAnimation}\label{wxcomboctrlenablepopupanimation} + +\func{void}{EnablePopupAnimation}{\param{bool }{enable = true}} + +Enables or disables popup animation, if any, depending on the value of +the argument. + + \membersection{wxComboCtrl::GetBitmapDisabled}\label{wxcomboctrlgetbitmapdisabled} \constfunc{const wxBitmap\&}{GetBitmapDisabled}{\void} diff --git a/include/wx/combo.h b/include/wx/combo.h index 8aa155ed71..e8704a4f66 100644 --- a/include/wx/combo.h +++ b/include/wx/combo.h @@ -85,7 +85,9 @@ enum // Internal use: Set wxTAB_TRAVERSAL to parent when popup is dismissed wxCC_IFLAG_PARENT_TAB_TRAVERSAL = 0x0800, // Internal use: Secondary popup window type should be used (if available). - wxCC_IFLAG_USE_ALT_POPUP = 0x1000 + wxCC_IFLAG_USE_ALT_POPUP = 0x1000, + // Internal use: Skip popup animation. + wxCC_IFLAG_DISABLE_POPUP_ANIM = 0x2000 }; @@ -322,6 +324,15 @@ public: m_iFlags &= ~wxCC_IFLAG_USE_ALT_POPUP; } + // Call with false to disable popup animation, if any. + void EnablePopupAnimation( bool enable = true ) + { + if ( enable ) + m_iFlags &= ~wxCC_IFLAG_DISABLE_POPUP_ANIM; + else + m_iFlags |= wxCC_IFLAG_DISABLE_POPUP_ANIM; + } + // // Utilies needed by the popups or native implementations // diff --git a/include/wx/msw/combo.h b/include/wx/msw/combo.h index 096d0798e2..4f350d8f30 100644 --- a/include/wx/msw/combo.h +++ b/include/wx/msw/combo.h @@ -18,6 +18,14 @@ #if wxUSE_COMBOCTRL +#if !defined(__WXWINCE__) && wxUSE_TIMER + #include "wx/timer.h" + #define wxUSE_COMBOCTRL_POPUP_ANIMATION 1 +#else + #define wxUSE_COMBOCTRL_POPUP_ANIMATION 0 +#endif + + // ---------------------------------------------------------------------------- // Native wxComboCtrl // ---------------------------------------------------------------------------- @@ -60,11 +68,15 @@ public: virtual ~wxComboCtrl(); virtual void PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const; - virtual bool AnimateShow( const wxRect& rect, int flags ); virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const; static int GetFeatures() { return wxComboCtrlFeatures::All; } +#if wxUSE_COMBOCTRL_POPUP_ANIMATION + virtual bool AnimateShow( const wxRect& rect, int flags ); + void OnTimerEvent( wxTimerEvent& event ); +#endif + protected: // customization @@ -79,6 +91,14 @@ protected: private: void Init(); +#if wxUSE_COMBOCTRL_POPUP_ANIMATION + // Popup animation related + wxLongLong m_animStart; + wxTimer m_animTimer; + wxRect m_animRect; + int m_animFlags; +#endif + DECLARE_EVENT_TABLE() DECLARE_DYNAMIC_CLASS(wxComboCtrl) diff --git a/samples/combo/combo.cpp b/samples/combo/combo.cpp index 785a104038..e4cde90f95 100644 --- a/samples/combo/combo.cpp +++ b/samples/combo/combo.cpp @@ -494,65 +494,126 @@ BEGIN_EVENT_TABLE(TreeCtrlComboPopup, wxTreeCtrl) END_EVENT_TABLE() // ---------------------------------------------------------------------------- -// wxComboCtrl with custom popup animation +// wxComboCtrl with custom popup animation. We use EVT_TIMER, which is quite +// safe, but requires much more can than doing it in a single function (ie. +// AnimateShow) and using combination of wxSleep and wxSafeYield. // ---------------------------------------------------------------------------- +#if wxUSE_TIMER + +#define CUSTOM_COMBOBOX_ANIMATION_DURATION 200 // In milliseconds + +#include "wx/timer.h" + class wxComboCtrlWithCustomPopupAnim : public wxComboCtrl { public: - virtual bool AnimateShow( const wxRect& rect, int WXUNUSED(flags) ) + virtual bool AnimateShow( const wxRect& rect, int flags ) { MyFrame* myFrame = (MyFrame*) ::wxGetTopLevelParent(this); if ( !myFrame->m_cbUseAnim->GetValue() ) return true; - int width = rect.width; - int height = rect.height; - wxBitmap bitmap( width, height, -1 ); + m_animStart = ::wxGetLocalTimeMillis(); + m_animRect = rect; + m_animFlags = flags; + wxScreenDC dc; + + wxBitmap bitmap( rect.width, rect.height, -1 ); wxMemoryDC memdc( bitmap ); - memdc.Blit( 0, 0, width, height, &dc, rect.x, rect.y ); + memdc.Blit( 0, 0, rect.width, rect.height, &dc, rect.x, rect.y ); memdc.SelectObject(wxNullBitmap); + m_animBackBitmap = bitmap; + + m_animTimer.SetOwner( this, wxID_ANY ); + m_animTimer.Start( 10, wxTIMER_CONTINUOUS ); - wxLongLong tStart = ::wxGetLocalTimeMillis(); - const int delay = 300; - const int resolution = 10; + OnTimerEvent(*((wxTimerEvent*)NULL)); // Event is never used, so we can give NULL + return false; + } - int center_x = rect.x + (width/2); - int center_y = rect.y + (height/2); + void OnTimerEvent( wxTimerEvent& WXUNUSED(event) ) + { + bool stopTimer = false; - double d_height = (double) height; + wxWindow* popup = GetPopupControl()->GetControl(); + wxScreenDC dc; + const wxRect& rect = m_animRect; - dc.SetPen( *wxBLACK_PEN ); - dc.SetBrush( *wxTRANSPARENT_BRUSH ); - for (;;) + // Popup was hidden before it was fully shown? + if ( IsPopupWindowState(Hidden) ) + { + stopTimer = true; + } + else { wxLongLong t = ::wxGetLocalTimeMillis(); - int pos = (int) (t-tStart).GetLo(); - if ( pos > delay ) - break; - int w = (((pos*256)/delay)*width)/256; + int pos = (int) (t-m_animStart).GetLo(); + if ( pos < CUSTOM_COMBOBOX_ANIMATION_DURATION ) + { + // + // Actual animation happens here + // + int width = rect.width; + int height = rect.height; + + int center_x = rect.x + (width/2); + int center_y = rect.y + (height/2); + + double d_height = (double) height; + + dc.SetPen( *wxBLACK_PEN ); + dc.SetBrush( *wxTRANSPARENT_BRUSH ); - double ratio = ((double)w / (double)width); - int h = (int)(d_height * ratio); - dc.DrawRectangle( center_x - w/2, center_y - h/2, w, h ); - wxMilliSleep( resolution ); - wxYield(); - dc.DrawBitmap( bitmap, rect.x, rect.y ); + int w = (((pos*256)/CUSTOM_COMBOBOX_ANIMATION_DURATION)*width)/256; - if ( IsPopupWindowState(Hidden) ) - return true; + double ratio = ((double)w / (double)width); + int h = (int)(d_height * ratio); + dc.DrawBitmap( m_animBackBitmap, rect.x, rect.y ); + dc.DrawRectangle( center_x - w/2, center_y - h/2, w, h ); + } + else + { + stopTimer = true; + } } - return true; + if ( stopTimer ) + { + dc.DrawBitmap( m_animBackBitmap, rect.x, rect.y ); + popup->Move( 0, 0 ); + m_animTimer.Stop(); + DoShowPopup( m_animRect, m_animFlags ); + } } protected: + + // Popup animation related + wxLongLong m_animStart; + wxTimer m_animTimer; + wxRect m_animRect; + wxBitmap m_animBackBitmap; + int m_animFlags; + +private: + DECLARE_EVENT_TABLE() }; +BEGIN_EVENT_TABLE(wxComboCtrlWithCustomPopupAnim, wxComboCtrl) + EVT_TIMER(wxID_ANY, wxComboCtrlWithCustomPopupAnim::OnTimerEvent) +END_EVENT_TABLE() + +#else + +#define wxComboCtrlWithCustomPopupAnim wxComboCtrl + +#endif + // ---------------------------------------------------------------------------- // wxComboCtrl with entirely custom button action (opens file dialog) // ---------------------------------------------------------------------------- diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 6139dfc179..bcfbb96bfd 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -1870,7 +1870,8 @@ void wxComboCtrlBase::ShowPopup() wxRect popupWinRect( popupX, popupY, szp.x, szp.y ); m_popup = popup; - if ( AnimateShow( popupWinRect, showFlags ) ) + if ( (m_iFlags & wxCC_IFLAG_DISABLE_POPUP_ANIM) || + AnimateShow( popupWinRect, showFlags ) ) { DoShowPopup( popupWinRect, showFlags ); } diff --git a/src/msw/combo.cpp b/src/msw/combo.cpp index 822eaf453c..e784c4a1cd 100644 --- a/src/msw/combo.cpp +++ b/src/msw/combo.cpp @@ -70,8 +70,13 @@ #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<<26) + + // ============================================================================ // implementation // ============================================================================ @@ -80,6 +85,7 @@ BEGIN_EVENT_TABLE(wxComboCtrl, wxComboCtrlBase) EVT_PAINT(wxComboCtrl::OnPaintEvent) EVT_MOUSE_EVENTS(wxComboCtrl::OnMouseEvent) + EVT_TIMER(wxID_ANY, wxComboCtrl::OnTimerEvent) END_EVENT_TABLE() @@ -530,7 +536,7 @@ void wxComboCtrl::OnMouseEvent( wxMouseEvent& event ) } -#if !defined(__WXWINCE__) +#if wxUSE_COMBOCTRL_POPUP_ANIMATION static wxUint32 GetUserPreferencesMask() { static wxUint32 userPreferencesMask = 0; @@ -559,64 +565,83 @@ static wxUint32 GetUserPreferencesMask() } #endif -bool wxComboCtrl::AnimateShow( const wxRect& rect, int flags ) +#if wxUSE_COMBOCTRL_POPUP_ANIMATION +void wxComboCtrl::OnTimerEvent( wxTimerEvent& WXUNUSED(event) ) { -#if !defined(__WXWINCE__) - if ( GetUserPreferencesMask() & (1<<26) ) - { - wxLongLong tStart = ::wxGetLocalTimeMillis(); + bool stopTimer = false; - int height = rect.height; + 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(); - wxWindow* popup = GetPopupControl()->GetControl(); - - const int delay = COMBOBOX_ANIMATION_DURATION; - const int resolution = 10; - int h0 = popup->GetSize().y; - - win->SetSize( rect.x, rect.y, rect.width, 0 ); - win->Show(); - for (;;) + int pos = (int) (t-m_animStart).GetLo(); + if ( pos < COMBOBOX_ANIMATION_DURATION ) { - wxLongLong t = ::wxGetLocalTimeMillis(); - int pos = (int) (t-tStart).GetLo(); - if ( pos > delay ) - break; - - int h = (((pos*256)/delay)*height)/256; - int y = (h0 - h); + 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 ( flags & ShowAbove ) + if ( m_animFlags & ShowAbove ) { - win->SetSize( rect.x, rect.y + h0 - h, rect.width, h ); + 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 ); } - - wxMilliSleep( resolution ); - wxYield(); - - // Popup was hidden before it was fully shown? - if ( IsPopupWindowState(Hidden) ) - return true; } + else + { + stopTimer = true; + } + } + if ( stopTimer ) + { popup->Move( 0, 0 ); + m_animTimer.Stop(); + DoShowPopup( m_animRect, m_animFlags ); } -#else - wxUnusedVar(rect); - wxUnusedVar(flags); +} #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 { -- 2.45.2