X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/06077aaf2c11135bb9ca18ef33181ab18ac7480e..e3ff35918924c912d7addb50f1ab9d7dea78216d:/src/common/combocmn.cpp diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 0b53234ca9..7e53044b3e 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -44,10 +44,6 @@ // 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 @@ -344,20 +340,50 @@ public: 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 ) +{ + // 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 wxComboPopupWindowBase::ProcessLeftDown(event); + return wxPopupTransientWindow::ProcessLeftDown(event); } // First thing that happens when a transient popup closes is that this method gets called. @@ -387,6 +413,7 @@ public: m_combo = parent; } + void OnSizeEvent( wxSizeEvent& event ); void OnKeyEvent(wxKeyEvent& event); #if USES_WXDIALOG void OnActivate( wxActivateEvent& event ); @@ -405,9 +432,15 @@ BEGIN_EVENT_TABLE(wxComboPopupWindowEvtHandler, wxEvtHandler) #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 @@ -621,7 +654,7 @@ void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) evtType == wxEVT_RIGHT_DOWN ) { // Block motion and click events outside the popup - if ( !isInside ) + if ( !isInside || !m_combo->IsPopupShown() ) { event.Skip(false); return; @@ -629,11 +662,10 @@ void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) } 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 ) @@ -688,7 +720,7 @@ void wxComboCtrlBase::Init() { 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; @@ -700,6 +732,8 @@ void wxComboCtrlBase::Init() m_toplevEvtHandler = (wxEvtHandler*) NULL; #endif + m_mainCtrlWnd = this; + m_heightPopup = -1; m_widthMinPopup = -1; m_anchorSide = 0; @@ -1212,7 +1246,7 @@ void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, bool paintBg ) int drawState = m_btnState; #ifdef __WXGTK__ - if ( m_isPopupShown ) + if ( GetPopupWindowState() >= Animating ) drawState |= wxCONTROL_PRESSED; #endif @@ -1365,7 +1399,7 @@ bool wxComboCtrlBase::HandleButtonMouseEvent( wxMouseEvent& event, 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) ) { @@ -1406,7 +1440,7 @@ bool wxComboCtrlBase::HandleButtonMouseEvent( wxMouseEvent& event, m_btnState &= ~(wxCONTROL_CURRENT); // Mouse hover ends - if ( !m_isPopupShown ) + if ( IsPopupWindowState(Hidden) ) { m_btnState &= ~(wxCONTROL_PRESSED); Refresh(); @@ -1429,7 +1463,7 @@ bool wxComboCtrlBase::PreprocessMouseEvent( wxMouseEvent& event, #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(); @@ -1455,7 +1489,7 @@ void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event ) 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. @@ -1481,7 +1515,7 @@ void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event ) } } else - if ( m_isPopupShown ) + if ( IsPopupShown() ) { // relay (some) mouse events to the popup if ( evtType == wxEVT_MOUSEWHEEL ) @@ -1505,11 +1539,15 @@ void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event) if ( keycode == WXK_TAB ) { wxNavigationKeyEvent evt; + + wxWindow* mainCtrl = GetMainWindowOfCompositeControl(); + evt.SetFlags(wxNavigationKeyEvent::FromTab| (!event.ShiftDown() ? wxNavigationKeyEvent::IsForward : wxNavigationKeyEvent::IsBackward)); - evt.SetEventObject(this); - GetParent()->GetEventHandler()->AddPendingEvent(evt); + evt.SetEventObject(mainCtrl); + evt.SetCurrentFocus(mainCtrl); + mainCtrl->GetParent()->GetEventHandler()->AddPendingEvent(evt); return; } @@ -1542,8 +1580,10 @@ void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event ) { if ( event.GetEventType() == wxEVT_SET_FOCUS ) { +#ifndef __WXMAC__ if ( m_text && m_text != ::wxWindow::FindFocus() ) m_text->SetFocus(); +#endif } Refresh(); @@ -1677,7 +1717,10 @@ void wxComboCtrlBase::OnButtonClick() 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(); @@ -1793,22 +1836,27 @@ void wxComboCtrlBase::ShowPopup() 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 ) @@ -1825,51 +1873,69 @@ void wxComboCtrlBase::ShowPopup() } // 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 ( (m_iFlags & wxCC_IFLAG_DISABLE_POPUP_ANIM) || + 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(); @@ -1887,7 +1953,10 @@ void wxComboCtrlBase::OnPopupDismiss() } #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) @@ -1912,19 +1981,14 @@ void wxComboCtrlBase::OnPopupDismiss() 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(); }