Destructor, destroying the combo control.
+\membersection{wxComboCtrl::AnimateShow}\label{wxcomboctrlanimateshow}
+
+\func{virtual bool}{AnimateShow}{\param{const wxRect\& }{rect}, \param{int }{flags}}
+
+This member function is not normally called in application code.
+Instead, it can be implemented in a derived class to create a
+custom popup animation.
+
+\wxheading{Parameters}
+
+Same as in \helpref{DoShowPopup}{wxcomboctrldoshowpopup}.
+
+\wxheading{Return value}
+
+\true if animation finishes before the function returns.
+\false otherwise. In the latter case you need to manually call DoShowPopup
+after the animation ends.
+
+
\membersection{wxComboCtrl::Create}\label{wxcomboctrlcreate}
\func{bool}{Create}{\param{wxWindow*}{ parent}, \param{wxWindowID}{ id},\rtfsp
must always return NULL.
+\membersection{wxComboCtrl::DoShowPopup}\label{wxcomboctrldoshowpopup}
+
+\func{virtual void}{DoShowPopup}{\param{const wxRect\& }{rect}, \param{int }{flags}}
+
+This member function is not normally called in application code.
+Instead, it must be called in a derived class to make sure popup
+is properly shown after a popup animation has finished (but only
+if \helpref{AnimateShow}{wxcomboctrlanimateshow} did not finish
+the animation within it's function scope).
+
+\wxheading{Parameters}
+
+\docparam{rect}{Position to show the popup window at, in screen coordinates.}
+
+\docparam{flags}{Combination of any of the following:}
+\twocolwidtha{8cm}%
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\tt wxComboCtrl::ShowAbove}}{Popup is shown above the control instead
+of below.}
+\twocolitem{{\tt wxComboCtrl::CanDeferShow}}{Showing the popup can be deferred
+to happen sometime after \helpref{ShowPopup}{wxcomboctrlshowpopup} has finished.
+In this case, \helpref{AnimateShow}{wxcomboctrlanimateshow} must return \false.}
+\end{twocollist}
+
+
\membersection{wxComboCtrl::GetBitmapDisabled}\label{wxcomboctrlgetbitmapdisabled}
\constfunc{const wxBitmap\&}{GetBitmapDisabled}{\void}
doesn't have the focus.
+\membersection{wxComboCtrl::IsPopupWindowState}\label{wxcomboctrlispopupwindowstate}
+
+\constfunc{bool}{IsPopupWindowState}{\param{int }{state}}
+
+Returns \true if the popup window is in the given state.
+Possible values are:
+\twocolwidtha{8cm}%
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\tt wxComboCtrl::Hidden}}{Popup window is hidden.}
+\twocolitem{{\tt wxComboCtrl::Animating}}{Popup window is being shown, but the
+popup animation has not yet finished.}
+\twocolitem{{\tt wxComboCtrl::Visible}}{Popup window is fully visible.}
+\end{twocollist}
+
+
+
\membersection{wxComboCtrl::GetLastPosition}\label{wxcomboctrlgetlastposition}
\constfunc{long}{GetLastPosition}{\void}
virtual void OnButtonClick();
// return true if the popup is currently shown
- bool IsPopupShown() const { return m_isPopupShown; }
+ bool IsPopupShown() const { return m_popupWinState == Visible; }
// set interface class instance derived from wxComboPopup
// NULL popup can be used to indicate default in a derived class
bool ShouldDrawFocus() const
{
const wxWindow* curFocus = FindFocus();
- return ( !m_isPopupShown &&
+ return ( !IsPopupShown() &&
(curFocus == this || (m_btn && curFocus == m_btn)) &&
(m_windowStyle & wxCB_READONLY) );
}
// common code to be called on popup hide/dismiss
void OnPopupDismiss();
+ // PopupShown states
+ enum
+ {
+ Hidden = 0,
+ //Closing = 1,
+ Animating = 2,
+ Visible = 3
+ };
+
+ bool IsPopupWindowState( int state ) const { return (state == m_popupWinState) ? true : false; }
+
+ wxByte GetPopupWindowState() const { return m_popupWinState; }
+
protected:
//
// Dispatches size event and refreshes
void RecalcAndRefresh();
+ // Flags for DoShowPopup and AnimateShow
+ enum
+ {
+ ShowBelow = 0x0000, // Showing popup below the control
+ ShowAbove = 0x0001, // Showing popup above the control
+ CanDeferShow = 0x0002 // Can only return true from AnimateShow if this is set
+ };
+
+ // Shows and positions the popup.
+ virtual void DoShowPopup( const wxRect& rect, int flags );
+
+ // Implement in derived class to create a drop-down animation.
+ // Return true if finished immediately. Otherwise popup is only
+ // shown when the derived class call DoShowPopup.
+ // Flags are same as for DoShowPopup.
+ virtual bool AnimateShow( const wxRect& rect, int flags );
+
#if wxUSE_TOOLTIPS
virtual void DoSetToolTip( wxToolTip *tip );
#endif
bool m_blankButtonBg;
// is the popup window currenty shown?
- bool m_isPopupShown;
+ wxByte m_popupWinState;
private:
void Init();
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; }
void OnIdle( wxIdleEvent& event );
+
+ wxCheckBox* m_cbUseAnim;
+
protected:
wxTextCtrl* m_logWin;
wxLog* m_logOld;
EVT_LEFT_DOWN(TreeCtrlComboPopup::OnMouseClick)
END_EVENT_TABLE()
+// ----------------------------------------------------------------------------
+// wxComboCtrl with custom popup animation
+// ----------------------------------------------------------------------------
+
+class wxComboCtrlWithCustomPopupAnim : public wxComboCtrl
+{
+public:
+
+ virtual bool AnimateShow( const wxRect& rect, int WXUNUSED(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 );
+ wxScreenDC dc;
+ wxMemoryDC memdc( bitmap );
+ memdc.Blit( 0, 0, width, height, &dc, rect.x, rect.y );
+ memdc.SelectObject(wxNullBitmap);
+
+ wxLongLong tStart = ::wxGetLocalTimeMillis();
+ const int delay = 300;
+ const int resolution = 10;
+
+ 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 );
+ for (;;)
+ {
+ wxLongLong t = ::wxGetLocalTimeMillis();
+ int pos = (int) (t-tStart).GetLo();
+ if ( pos > delay )
+ break;
+
+ int w = (((pos*256)/delay)*width)/256;
+
+ 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 );
+
+ if ( IsPopupWindowState(Hidden) )
+ return true;
+ }
+
+ return true;
+ }
+
+protected:
+};
+
// ----------------------------------------------------------------------------
// wxComboCtrl with entirely custom button action (opens file dialog)
// ----------------------------------------------------------------------------
colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
rowSizer = new wxBoxSizer( wxHORIZONTAL );
- cc = new wxComboCtrl(panel,2,wxEmptyString,
- wxDefaultPosition, wxDefaultSize);
+ cc = new wxComboCtrlWithCustomPopupAnim();
+ cc->Create(panel, wxID_ANY, wxEmptyString);
// Make sure we use popup that allows focusing the listview.
cc->UseAltPopupWindow();
topRowSizer->Add( colSizer, 1, wxALL, 2 );
- topRowSizer->Add( m_logWin, 1, wxEXPAND|wxALL, 5 );
+ colSizer = new wxBoxSizer( wxVERTICAL );
+
+ wxStaticBoxSizer* sbSizer = new wxStaticBoxSizer( new wxStaticBox(panel,
+ wxID_ANY,
+ wxT("Options")),
+ wxVERTICAL );
+
+ m_cbUseAnim = new wxCheckBox(panel, wxID_ANY, wxT("Custom popup animation for ListView wxComboCtrl"));
+ m_cbUseAnim->SetValue(true);
+ sbSizer->Add( m_cbUseAnim, 0, wxALL, 3 );
+
+ colSizer->Add( sbSizer, 0, wxEXPAND|wxALL, 3 );
+ colSizer->AddSpacer(8);
+ colSizer->Add( new wxStaticText(panel, wxID_ANY, wxT("Log Messages:")), 0, wxTOP|wxLEFT, 3 );
+ colSizer->Add( m_logWin, 1, wxEXPAND|wxALL, 3 );
+
+ topRowSizer->Add( colSizer, 1, wxEXPAND|wxALL, 2 );
topSizer->Add( topRowSizer, 1, wxEXPAND );
panel->SetSizer( topSizer );
// constants
// ----------------------------------------------------------------------------
-// Milliseconds to wait for two mouse-ups after focus inorder
-// to trigger a double-click.
-#define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
-
#define DEFAULT_DROPBUTTON_WIDTH 19
#define BMP_BUTTON_MARGIN 4
style)
#endif
{
+ m_inShow = 0;
}
#if USES_WXPOPUPTRANSIENTWINDOW
+ virtual bool Show( bool show );
virtual bool ProcessLeftDown(wxMouseEvent& event);
virtual void OnDismiss();
#endif
+private:
+ wxByte m_inShow;
};
#if USES_WXPOPUPTRANSIENTWINDOW
-bool wxComboPopupWindow::ProcessLeftDown(wxMouseEvent& event )
+bool wxComboPopupWindow::Show( bool show )
{
- return wxComboPopupWindowBase::ProcessLeftDown(event);
+ // Guard against recursion
+ if ( m_inShow )
+ return wxComboPopupWindowBase::Show(show);
+
+ m_inShow++;
+
+ wxASSERT( IsKindOf(CLASSINFO(wxPopupTransientWindow)) );
+
+ wxPopupTransientWindow* ptw = (wxPopupTransientWindow*) this;
+ wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent();
+
+ if ( show != ptw->IsShown() )
+ {
+ if ( show )
+ ptw->Popup(combo->GetPopupControl()->GetControl());
+ else
+ ptw->Dismiss();
+ }
+
+ m_inShow--;
+
+ return true;
+}
+
+bool wxComboPopupWindow::ProcessLeftDown(wxMouseEvent& event)
+{
+ return wxPopupTransientWindow::ProcessLeftDown(event);
}
// First thing that happens when a transient popup closes is that this method gets called.
m_combo = parent;
}
+ void OnSizeEvent( wxSizeEvent& event );
void OnKeyEvent(wxKeyEvent& event);
#if USES_WXDIALOG
void OnActivate( wxActivateEvent& event );
#if USES_WXDIALOG
EVT_ACTIVATE(wxComboPopupWindowEvtHandler::OnActivate)
#endif
+ EVT_SIZE(wxComboPopupWindowEvtHandler::OnSizeEvent)
END_EVENT_TABLE()
+void wxComboPopupWindowEvtHandler::OnSizeEvent( wxSizeEvent& WXUNUSED(event) )
+{
+ // Block the event so that the popup control does not get auto-resized.
+}
+
void wxComboPopupWindowEvtHandler::OnKeyEvent( wxKeyEvent& event )
{
// Relay keyboard event to the main child controls
evtType == wxEVT_RIGHT_DOWN )
{
// Block motion and click events outside the popup
- if ( !isInside )
+ if ( !isInside || !m_combo->IsPopupShown() )
{
event.Skip(false);
return;
}
else if ( evtType == wxEVT_LEFT_UP )
{
- // Don't let left-down events in if outside
- if ( evtType == wxEVT_LEFT_DOWN )
+ if ( !m_combo->IsPopupShown() )
{
- if ( !isInside )
- return;
+ event.Skip(false);
+ return;
}
if ( !m_beenInside )
{
m_winPopup = (wxWindow *)NULL;
m_popup = (wxWindow *)NULL;
- m_isPopupShown = false;
+ m_popupWinState = Hidden;
m_btn = (wxWindow*) NULL;
m_text = (wxTextCtrl*) NULL;
m_popupInterface = (wxComboPopup*) NULL;
int drawState = m_btnState;
#ifdef __WXGTK__
- if ( m_isPopupShown )
+ if ( GetPopupWindowState() >= Animating )
drawState |= wxCONTROL_PRESSED;
#endif
Refresh();
}
}
- else if ( type == wxEVT_LEFT_DOWN )
+ else if ( type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_DCLICK )
{
if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) )
{
m_btnState &= ~(wxCONTROL_CURRENT);
// Mouse hover ends
- if ( !m_isPopupShown )
+ if ( IsPopupWindowState(Hidden) )
{
m_btnState &= ~(wxCONTROL_PRESSED);
Refresh();
#if USES_WXPOPUPWINDOW || USES_WXDIALOG
if ( m_popupWinType != POPUPWIN_WXPOPUPTRANSIENTWINDOW )
{
- if ( m_isPopupShown &&
+ if ( IsPopupWindowState(Visible) &&
( evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_RIGHT_DOWN ) )
{
HidePopup();
if ( (evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_LEFT_DCLICK) &&
(m_windowStyle & wxCB_READONLY) )
{
- if ( m_isPopupShown )
+ if ( GetPopupWindowState() >= Animating )
{
#if USES_WXPOPUPWINDOW
// Click here always hides the popup.
}
}
else
- if ( m_isPopupShown )
+ if ( IsPopupShown() )
{
// relay (some) mouse events to the popup
if ( evtType == wxEVT_MOUSEWHEEL )
void wxComboCtrlBase::ShowPopup()
{
EnsurePopupControl();
- wxCHECK_RET( !IsPopupShown(), wxT("popup window already shown") );
+ wxCHECK_RET( !IsPopupWindowState(Visible), wxT("popup window already shown") );
+
+ if ( IsPopupWindowState(Animating) )
+ return;
SetFocus();
else
popupX = 0;
+ int showFlags = CanDeferShow;
+
if ( spaceBelow < szp.y )
{
popupY = scrPos.y - szp.y;
+ showFlags |= ShowAbove;
}
- // Move to position
- //wxLogDebug(wxT("popup scheduled position1: %i,%i"),ptp.x,ptp.y);
- //wxLogDebug(wxT("popup position1: %i,%i"),winPopup->GetPosition().x,winPopup->GetPosition().y);
-
- // Some platforms (GTK) may need these two to be separate
- winPopup->SetSize( szp.x, szp.y );
- winPopup->Move( popupX, popupY );
-
- //wxLogDebug(wxT("popup position2: %i,%i"),winPopup->GetPosition().x,winPopup->GetPosition().y);
+#if INSTALL_TOPLEV_HANDLER
+ // Put top level window event handler into place
+ if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW )
+ {
+ if ( !m_toplevEvtHandler )
+ m_toplevEvtHandler = new wxComboFrameEventHandler(this);
- m_popup = popup;
+ wxWindow* toplev = ::wxGetTopLevelParent( this );
+ wxASSERT( toplev );
+ ((wxComboFrameEventHandler*)m_toplevEvtHandler)->OnPopup();
+ toplev->PushEventHandler( m_toplevEvtHandler );
+ }
+#endif
// Set string selection (must be this way instead of SetStringSelection)
if ( m_text )
}
// This must be after SetStringValue
- m_isPopupShown = true;
+ m_popupWinState = Animating;
- // Show it
-#if USES_WXPOPUPTRANSIENTWINDOW
- if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW )
- ((wxPopupTransientWindow*)winPopup)->Popup(popup);
- else
-#endif
- winPopup->Show();
+ wxRect popupWinRect( popupX, popupY, szp.x, szp.y );
-#if INSTALL_TOPLEV_HANDLER
- // Put top level window event handler into place
- if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW )
+ m_popup = popup;
+ if ( AnimateShow( popupWinRect, showFlags ) )
{
- if ( !m_toplevEvtHandler )
- m_toplevEvtHandler = new wxComboFrameEventHandler(this);
+ DoShowPopup( popupWinRect, showFlags );
+ }
+}
- wxWindow* toplev = ::wxGetTopLevelParent( this );
- wxASSERT( toplev );
- ((wxComboFrameEventHandler*)m_toplevEvtHandler)->OnPopup();
- toplev->PushEventHandler( m_toplevEvtHandler );
+bool wxComboCtrlBase::AnimateShow( const wxRect& WXUNUSED(rect), int WXUNUSED(flags) )
+{
+ return true;
+}
+
+void wxComboCtrlBase::DoShowPopup( const wxRect& rect, int WXUNUSED(flags) )
+{
+ wxWindow* winPopup = m_winPopup;
+
+ if ( IsPopupWindowState(Animating) )
+ {
+ // Make sure the popup window is shown in the right position.
+ // Should not matter even if animation already did this.
+
+ // Some platforms (GTK) may like SetSize and Move to be separate
+ // (though the bug was probably fixed).
+ winPopup->SetSize( rect );
+
+ winPopup->Show();
+
+ m_popupWinState = Visible;
}
-#endif
+ else if ( IsPopupWindowState(Hidden) )
+ {
+ // Animation was aborted
+ wxASSERT( !winPopup->IsShown() );
+
+ m_popupWinState = Hidden;
+ }
}
void wxComboCtrlBase::OnPopupDismiss()
-{
+{
// Just in case, avoid double dismiss
- if ( !m_isPopupShown )
+ if ( IsPopupWindowState(Hidden) )
return;
// NB: Focus setting is really funny, atleast on wxMSW. First of all,
// we need to have SetFocus at the end. Otherwise wxTextCtrl may
// freeze until focus goes somewhere else. Second, wxTreeCtrl as
// popup, when dismissing, "steals" focus back to itself unless
- // SetFocus is called also here, exactly before m_isPopupShown
+ // SetFocus is called also here, exactly before m_popupWinState
// is set to false. Which is truly weird since SetFocus is just
// wxWindowMSW method and does not call event handler or anything like
- // that (ie. does not care about m_isPopupShown).
+ // that (ie. does not care about m_popupWinState).
SetFocus();
// This should preferably be set before focus.
- m_isPopupShown = false;
+ m_popupWinState = Hidden;
// Inform popup control itself
m_popupInterface->OnDismiss();
}
#endif
- m_timeCanAcceptClick = ::wxGetLocalTimeMillis() + 150;
+ m_timeCanAcceptClick = ::wxGetLocalTimeMillis();
+
+ if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW )
+ m_timeCanAcceptClick += 150;
// If cursor not on dropdown button, then clear its state
// (technically not required by all ports, but do it for all just in case)
void wxComboCtrlBase::HidePopup()
{
// Should be able to call this without popup interface
- //wxCHECK_RET( m_popupInterface, _T("no popup interface") );
- if ( !m_isPopupShown )
+ if ( IsPopupWindowState(Hidden) )
return;
// transfer value and show it in textctrl, if any
- SetValue( m_popupInterface->GetStringValue() );
+ if ( !IsPopupWindowState(Animating) )
+ SetValue( m_popupInterface->GetStringValue() );
-#if USES_WXPOPUPTRANSIENTWINDOW
- if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW )
- ((wxPopupTransientWindow*)m_winPopup)->Dismiss();
- else
-#endif
- m_winPopup->Hide();
+ m_winPopup->Hide();
OnPopupDismiss();
}
#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_DURATION 200 // In milliseconds
// ============================================================================
// implementation
}
+#if !defined(__WXWINCE__)
+static wxUint32 GetUserPreferencesMask()
+{
+ static wxUint32 userPreferencesMask = 0;
+ static bool valueSet = false;
+
+ if ( valueSet )
+ return userPreferencesMask;
+
+ wxRegKey key(wxRegKey::HKCU, wxT("Control Panel\\Desktop"));
+ if( key.Open(wxRegKey::Read) )
+ {
+ wxMemoryBuffer buf;
+ if ( key.QueryValue(wxT("UserPreferencesMask"), buf) )
+ {
+ if ( buf.GetDataLen() >= 4 )
+ {
+ wxByte* p = (wxByte*) buf.GetData();
+ userPreferencesMask = p[3] + (p[2]<<8) + (p[1]<<16) + (p[0]<<24);
+ }
+ }
+ }
+
+ valueSet = true;
+
+ return userPreferencesMask;
+}
+#endif
+
+bool wxComboCtrl::AnimateShow( const wxRect& rect, int flags )
+{
+#if !defined(__WXWINCE__)
+ if ( GetUserPreferencesMask() & (1<<26) )
+ {
+ wxLongLong tStart = ::wxGetLocalTimeMillis();
+
+ int height = rect.height;
+
+ 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 (;;)
+ {
+ wxLongLong t = ::wxGetLocalTimeMillis();
+ int pos = (int) (t-tStart).GetLo();
+ if ( pos > delay )
+ break;
+
+ int h = (((pos*256)/delay)*height)/256;
+ int y = (h0 - h);
+ if ( y < 0 )
+ y = 0;
+
+ if ( flags & ShowAbove )
+ {
+ win->SetSize( rect.x, rect.y + h0 - 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;
+ }
+
+ popup->Move( 0, 0 );
+ }
+#else
+ wxUnusedVar(rect);
+ wxUnusedVar(flags);
+#endif
+
+ return true;
+}
+
wxCoord wxComboCtrl::GetNativeTextIndent() const
{
if ( wxUxThemeEngine::GetIfActive() )