X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f85f5ddf8855b67313f8d909d3544b84ca0980ec..51c72a7b56ea50fb3c9b082da1bbaddf6a218073:/src/common/combocmn.cpp diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 77c67f137e..65066b56c7 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -28,11 +28,13 @@ #include "wx/combobox.h" #ifndef WX_PRECOMP + #include "wx/app.h" #include "wx/log.h" #include "wx/dcclient.h" #include "wx/settings.h" #include "wx/dialog.h" #include "wx/timer.h" + #include "wx/textctrl.h" #endif #include "wx/tooltip.h" @@ -69,14 +71,20 @@ #elif defined(__WXGTK__) +#include "wx/gtk/private.h" + // NB: It is not recommended to use wxDialog as popup on wxGTK, because of // this bug: If wxDialog is hidden, its position becomes corrupt // between hide and next show, but without internal coordinates being // reflected (or something like that - atleast commenting out ->Hide() // seemed to eliminate the position change). +// NB: Let's not be afraid to use wxGTK's wxPopupTransientWindow as a +// 'perfect' popup, as it can succesfully host child controls even in +// popups that are shown in modal dialogs. + #define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common +#define TRANSIENT_POPUPWIN_IS_PERFECT 1 // wxPopupTransientWindow works, its child can have focus, and common // native controls work on it like normal. #define POPUPWIN_IS_PERFECT 1 // Same, but for non-transient popup window. #define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered @@ -84,10 +92,10 @@ #elif defined(__WXMAC__) -#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common +#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 1 // wxPopupTransientWindow works, its child can have focus, and common // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. +#define POPUPWIN_IS_PERFECT 1 // Same, but for non-transient popup window. #define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered #define FOCUS_RING 3 // Reserve room for the textctrl's focus ring to display @@ -111,7 +119,7 @@ // Popupwin is really only supported on wxMSW (not WINCE) and wxGTK, regardless // what the wxUSE_POPUPWIN says. // FIXME: Why isn't wxUSE_POPUPWIN reliable any longer? (it was in wxW2.6.2) -#if (!defined(__WXMSW__) && !defined(__WXGTK__)) || defined(__WXWINCE__) +#if (!defined(__WXMSW__) && !defined(__WXGTK__) && !defined(__WXMAC__)) || defined(__WXWINCE__) #undef wxUSE_POPUPWIN #define wxUSE_POPUPWIN 0 #endif @@ -355,6 +363,7 @@ public: #if USES_WXPOPUPTRANSIENTWINDOW virtual bool Show( bool show ); virtual bool ProcessLeftDown(wxMouseEvent& event); +protected: virtual void OnDismiss(); #endif @@ -375,12 +384,14 @@ bool wxComboPopupWindow::Show( bool show ) wxASSERT( IsKindOf(CLASSINFO(wxPopupTransientWindow)) ); wxPopupTransientWindow* ptw = (wxPopupTransientWindow*) this; - wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); if ( show != ptw->IsShown() ) { if ( show ) - ptw->Popup(combo->GetPopupControl()->GetControl()); + // We used to do wxPopupTransientWindow::Popup here, + // but this would hide normal Show, which we are + // also going to need. + ptw->Show(); else ptw->Dismiss(); } @@ -456,7 +467,7 @@ void wxComboPopupWindowEvtHandler::OnKeyEvent( wxKeyEvent& event ) wxWindowList children = m_combo->GetPopupWindow()->GetChildren(); wxWindowList::iterator node = children.begin(); wxWindow* child = (wxWindow*)*node; - child->AddPendingEvent(event); + child->GetEventHandler()->AddPendingEvent(event); } #if USES_WXDIALOG @@ -490,6 +501,11 @@ void wxComboPopup::OnDismiss() { } +wxComboCtrl* wxComboPopup::GetComboCtrl() const +{ + return wxStaticCast(m_combo, wxComboCtrl); +} + wxSize wxComboPopup::GetAdjustedSize( int minWidth, int prefHeight, int WXUNUSED(maxHeight) ) @@ -505,7 +521,7 @@ void wxComboPopup::DefaultPaintComboControl( wxComboCtrlBase* combo, combo->PrepareBackground(dc,rect,0); dc.DrawText( combo->GetValue(), - rect.x + combo->GetTextIndent(), + rect.x + combo->m_marginLeft, (rect.height-dc.GetCharHeight())/2 + rect.y ); } } @@ -568,7 +584,10 @@ private: BEGIN_EVENT_TABLE(wxComboBoxExtraInputHandler, wxEvtHandler) EVT_KEY_DOWN(wxComboBoxExtraInputHandler::OnKey) + EVT_KEY_UP(wxComboBoxExtraInputHandler::OnKey) + EVT_CHAR(wxComboBoxExtraInputHandler::OnKey) EVT_SET_FOCUS(wxComboBoxExtraInputHandler::OnFocus) + EVT_KILL_FOCUS(wxComboBoxExtraInputHandler::OnFocus) END_EVENT_TABLE() @@ -576,21 +595,25 @@ void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event) { // Let the wxComboCtrl event handler have a go first. wxComboCtrlBase* combo = m_combo; - wxObject* prevObj = event.GetEventObject(); - event.SetId(combo->GetId()); - event.SetEventObject(combo); - combo->GetEventHandler()->ProcessEvent(event); + wxKeyEvent redirectedEvent(event); + redirectedEvent.SetId(combo->GetId()); + redirectedEvent.SetEventObject(combo); - event.SetId(((wxWindow*)prevObj)->GetId()); - event.SetEventObject(prevObj); + if ( !combo->GetEventHandler()->ProcessEvent(redirectedEvent) ) + { + // Don't let TAB through to the text ctrl - looks ugly + if ( event.GetKeyCode() != WXK_TAB ) + event.Skip(); + } } void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) { // FIXME: This code does run when control is clicked, // yet on Windows it doesn't select all the text. - if ( !(m_combo->GetInternalFlags() & wxCC_NO_TEXT_AUTO_SELECT) ) + if ( event.GetEventType() == wxEVT_SET_FOCUS && + !(m_combo->GetInternalFlags() & wxCC_NO_TEXT_AUTO_SELECT) ) { if ( m_combo->GetTextCtrl() ) m_combo->GetTextCtrl()->SelectAll(); @@ -604,7 +627,7 @@ void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) // wxEVT_SET_FOCUSes (since m_text->SetFocus is called // from combo's focus event handler), they should be quite // harmless. - wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId()); + wxFocusEvent evt2(event.GetEventType(),m_combo->GetId()); evt2.SetEventObject(m_combo); m_combo->GetEventHandler()->ProcessEvent(evt2); @@ -657,6 +680,9 @@ void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) wxSize sz = m_combo->GetPopupControl()->GetControl()->GetClientSize(); int evtType = event.GetEventType(); bool isInside = pt.x >= 0 && pt.y >= 0 && pt.x < sz.x && pt.y < sz.y; + bool relayToButton = false; + + event.Skip(); if ( evtType == wxEVT_MOTION || evtType == wxEVT_LEFT_DOWN || @@ -666,7 +692,6 @@ void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) if ( !isInside || !m_combo->IsPopupShown() ) { event.Skip(false); - return; } } else if ( evtType == wxEVT_LEFT_UP ) @@ -674,10 +699,9 @@ void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) if ( !m_combo->IsPopupShown() ) { event.Skip(false); - return; + relayToButton = true; } - - if ( !m_beenInside ) + else if ( !m_beenInside ) { if ( isInside ) { @@ -685,27 +709,48 @@ void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) } else { - // - // Some mouse events to popup that happen outside it, before cursor - // has been inside the popu, need to be ignored by it but relayed to - // the dropbutton. - // - wxWindow* btn = m_combo->GetButton(); - if ( btn ) - btn->GetEventHandler()->AddPendingEvent(event); - else - m_combo->GetEventHandler()->AddPendingEvent(event); - - return; + relayToButton = true; } - - event.Skip(); } } - event.Skip(); + if ( relayToButton ) + { + // + // Some mouse events to popup that happen outside it, before cursor + // has been inside the popup, need to be ignored by it but relayed to + // the dropbutton. + // + wxWindow* eventSink = m_combo; + wxWindow* btn = m_combo->GetButton(); + if ( btn ) + eventSink = btn; + + eventSink->GetEventHandler()->ProcessEvent(event); + } } +// ---------------------------------------------------------------------------- +// wxComboCtrlTextCtrl +// ---------------------------------------------------------------------------- + +class wxComboCtrlTextCtrl : public wxTextCtrl +{ +public: + wxComboCtrlTextCtrl() : wxTextCtrl() { } + virtual ~wxComboCtrlTextCtrl() { } + + virtual wxWindow *GetMainWindowOfCompositeControl() + { + wxComboCtrl* combo = (wxComboCtrl*) GetParent(); + + // Returning this instead of just 'parent' lets FindFocus work + // correctly even when parent control is a child of a composite + // generic control (as is case with wxGenericDatePickerCtrl). + return combo->GetMainWindowOfCompositeControl(); + } +}; + // ---------------------------------------------------------------------------- // wxComboCtrlBase // ---------------------------------------------------------------------------- @@ -728,18 +773,18 @@ IMPLEMENT_ABSTRACT_CLASS(wxComboCtrlBase, wxControl) void wxComboCtrlBase::Init() { - m_winPopup = (wxWindow *)NULL; - m_popup = (wxWindow *)NULL; + m_winPopup = NULL; + m_popup = NULL; m_popupWinState = Hidden; - m_btn = (wxWindow*) NULL; - m_text = (wxTextCtrl*) NULL; - m_popupInterface = (wxComboPopup*) NULL; + m_btn = NULL; + m_text = NULL; + m_popupInterface = NULL; - m_popupExtraHandler = (wxEvtHandler*) NULL; - m_textEvtHandler = (wxEvtHandler*) NULL; + m_popupExtraHandler = NULL; + m_textEvtHandler = NULL; #if INSTALL_TOPLEV_HANDLER - m_toplevEvtHandler = (wxEvtHandler*) NULL; + m_toplevEvtHandler = NULL; #endif m_mainCtrlWnd = this; @@ -761,7 +806,7 @@ void wxComboCtrlBase::Init() m_extLeft = 0; m_extRight = 0; - m_absIndent = -1; + m_marginLeft = -1; m_iFlags = 0; m_timeCanAcceptClick = 0; @@ -790,7 +835,7 @@ bool wxComboCtrlBase::Create(wxWindow *parent, // Get colours OnThemeChange(); - m_absIndent = GetNativeTextIndent(); + m_marginLeft = GetNativeTextIndent(); m_iFlags |= wxCC_IFLAG_CREATED; @@ -839,9 +884,10 @@ wxComboCtrlBase::CreateTextCtrl(int style, const wxValidator& validator) else m_ignoreEvtText = 0; - m_text = new wxTextCtrl(this, wxID_ANY, m_valueString, - wxDefaultPosition, wxSize(10,-1), - style, validator); + m_text = new wxComboCtrlTextCtrl(); + m_text->Create(this, wxID_ANY, m_valueString, + wxDefaultPosition, wxSize(10,-1), + style, validator); } } @@ -862,7 +908,7 @@ wxComboCtrlBase::~wxComboCtrlBase() #if INSTALL_TOPLEV_HANDLER delete ((wxComboFrameEventHandler*)m_toplevEvtHandler); - m_toplevEvtHandler = (wxEvtHandler*) NULL; + m_toplevEvtHandler = NULL; #endif DestroyPopup(); @@ -896,6 +942,12 @@ void wxComboCtrlBase::CalculateAreas( int btnWidth ) m_iFlags |= wxCC_IFLAG_BUTTON_OUTSIDE; btnBorder = 0; } + else if ( (m_iFlags & wxCC_BUTTON_COVERS_BORDER) && + m_btnSpacingX == 0 && !m_bmpNormal.Ok() ) + { + m_iFlags &= ~(wxCC_IFLAG_BUTTON_OUTSIDE); + btnBorder = 0; + } else { m_iFlags &= ~(wxCC_IFLAG_BUTTON_OUTSIDE); @@ -903,8 +955,8 @@ void wxComboCtrlBase::CalculateAreas( int btnWidth ) } // Defaul indentation - if ( m_absIndent < 0 ) - m_absIndent = GetNativeTextIndent(); + if ( m_marginLeft < 0 ) + m_marginLeft = GetNativeTextIndent(); int butWidth = btnWidth; @@ -970,6 +1022,11 @@ void wxComboCtrlBase::CalculateAreas( int btnWidth ) { int newY = butHeight+(customBorder*2); SetClientSize(wxDefaultCoord,newY); + if ( m_bmpNormal.Ok() || m_btnArea.width != butWidth || m_btnArea.height != butHeight ) + m_iFlags |= wxCC_IFLAG_HAS_NONSTANDARD_BUTTON; + else + m_iFlags &= ~wxCC_IFLAG_HAS_NONSTANDARD_BUTTON; + sz.y = newY; } } @@ -1005,40 +1062,58 @@ void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust wxSize sz = GetClientSize(); -#if !TEXTCTRL_TEXT_CENTERED int customBorder = m_widthCustomBorder; if ( (m_text->GetWindowStyleFlag() & wxBORDER_MASK) == wxNO_BORDER ) { - // Centre textctrl + int x; + + if ( !m_widthCustomPaint ) + { + // No special custom paint area - we can use 0 left margin + // with wxTextCtrl. + if ( m_text->SetMargins(0) ) + textCtrlXAdjust = 0; + x = m_tcArea.x + m_marginLeft + textCtrlXAdjust; + } + else + { + // There is special custom paint area - it is better to + // use some margin with the wxTextCtrl. + m_text->SetMargins(m_marginLeft); + x = m_tcArea.x + m_widthCustomPaint + + m_marginLeft + textCtrlXAdjust; + } + + // Centre textctrl vertically, if needed +#if !TEXTCTRL_TEXT_CENTERED int tcSizeY = m_text->GetBestSize().y; - int diff = sz.y - tcSizeY; - int y = textCtrlYAdjust + (diff/2); + int diff0 = sz.y - tcSizeY; + int y = textCtrlYAdjust + (diff0/2); +#else + wxUnusedVar(textCtrlYAdjust); + int y = 0; +#endif if ( y < customBorder ) y = customBorder; - m_text->SetSize( m_tcArea.x + m_widthCustomPaint + m_absIndent + textCtrlXAdjust, - y, - m_tcArea.width - COMBO_MARGIN - - (textCtrlXAdjust + m_widthCustomPaint + m_absIndent), - -1 ); + m_text->SetSize(x, + y, + m_tcArea.width - m_tcArea.x - x, + -1 ); // Make sure textctrl doesn't exceed the bottom custom border wxSize tsz = m_text->GetSize(); - diff = (y + tsz.y) - (sz.y - customBorder); - if ( diff >= 0 ) + int diff1 = (y + tsz.y) - (sz.y - customBorder); + if ( diff1 >= 0 ) { - tsz.y = tsz.y - diff - 1; + tsz.y = tsz.y - diff1 - 1; m_text->SetSize(tsz); } } else -#else // TEXTCTRL_TEXT_CENTERED - wxUnusedVar(textCtrlXAdjust); - wxUnusedVar(textCtrlYAdjust); -#endif // !TEXTCTRL_TEXT_CENTERED/TEXTCTRL_TEXT_CENTERED { - // If it has border, have textctrl will the entire text field. + // If it has border, have textctrl fill the entire text field. m_text->SetSize( m_tcArea.x + m_widthCustomPaint, m_tcArea.y, m_tcArea.width - m_widthCustomPaint, @@ -1136,6 +1211,8 @@ bool wxComboCtrlBase::Enable(bool enable) if ( m_text ) m_text->Enable(enable); + Refresh(); + return true; } @@ -1158,8 +1235,15 @@ bool wxComboCtrlBase::SetFont ( const wxFont& font ) if ( !wxControl::SetFont(font) ) return false; - if (m_text) + if ( m_text ) + { + // Without hiding the wxTextCtrl there would be some + // visible 'flicker' (at least on Windows XP). + m_text->Hide(); m_text->SetFont(font); + OnResize(); + m_text->Show(); + } return true; } @@ -1178,8 +1262,8 @@ void wxComboCtrlBase::DoSetToolTip(wxToolTip *tooltip) } else { - if ( m_text ) m_text->SetToolTip( (wxToolTip*) NULL ); - if ( m_btn ) m_btn->SetToolTip( (wxToolTip*) NULL ); + if ( m_text ) m_text->SetToolTip( NULL ); + if ( m_btn ) m_btn->SetToolTip( NULL ); } } #endif // wxUSE_TOOLTIPS @@ -1191,16 +1275,15 @@ void wxComboCtrlBase::SetValidator(const wxValidator& validator) if ( textCtrl ) textCtrl->SetValidator( validator ); + else + wxControl::SetValidator( validator ); } wxValidator* wxComboCtrlBase::GetValidator() { wxTextCtrl* textCtrl = GetTextCtrl(); - if ( textCtrl ) - return textCtrl->GetValidator(); - - return wxControl::GetValidator(); + return textCtrl ? textCtrl->GetValidator() : wxControl::GetValidator(); } #endif // wxUSE_VALIDATORS @@ -1214,7 +1297,7 @@ void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags { wxSize sz = GetClientSize(); bool isEnabled; - bool isFocused; // also selected + bool doDrawFocusRect; // also selected // For smaller size control (and for disabled background) use less spacing int focusSpacingX; @@ -1224,7 +1307,7 @@ void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags { // Drawing control isEnabled = IsEnabled(); - isFocused = ShouldDrawFocus(); + doDrawFocusRect = ShouldDrawFocus() && !(m_iFlags & wxCC_FULL_BUTTON); // Windows-style: for smaller size control (and for disabled background) use less spacing focusSpacingX = isEnabled ? 2 : 1; @@ -1234,7 +1317,7 @@ void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags { // Drawing a list item isEnabled = true; // they are never disabled - isFocused = flags & wxCONTROL_SELECTED ? true : false; + doDrawFocusRect = (flags & wxCONTROL_SELECTED) != 0; focusSpacingX = 0; focusSpacingY = 0; @@ -1254,12 +1337,13 @@ void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags selRect.width -= wcp + (focusSpacingX*2); wxColour bgCol; + bool doDrawSelRect = true; if ( isEnabled ) { // If popup is hidden and this control is focused, // then draw the focus-indicator (selbgcolor background etc.). - if ( isFocused ) + if ( doDrawFocusRect ) { dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) ); bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); @@ -1268,6 +1352,7 @@ void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags { dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) ); #ifndef __WXMAC__ // see note in OnThemeChange + doDrawSelRect = false; bgCol = GetBackgroundColour(); #else bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); @@ -1285,8 +1370,11 @@ void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags } dc.SetBrush( bgCol ); - dc.SetPen( bgCol ); - dc.DrawRectangle( selRect ); + if ( doDrawSelRect ) + { + dc.SetPen( bgCol ); + dc.DrawRectangle( selRect ); + } // Don't clip exactly to the selection rectangle so we can draw // to the non-selected area in front of it. @@ -1301,14 +1389,13 @@ void wxComboCtrlBase::PrepareBackground( wxDC&, const wxRect&, int ) const } #endif -void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int paintBg ) +void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int flags ) { int drawState = m_btnState; -#ifdef __WXGTK__ - if ( GetPopupWindowState() >= Animating ) + if ( (m_iFlags & wxCC_BUTTON_STAYS_DOWN) && + GetPopupWindowState() >= Animating ) drawState |= wxCONTROL_PRESSED; -#endif wxRect drawRect(rect.x+m_btnSpacingX, rect.y+((rect.height-m_btnSize.y)/2), @@ -1328,8 +1415,11 @@ void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int paintBg ) if ( !m_bmpNormal.Ok() ) { + if ( flags & Button_BitmapOnly ) + return; + // Need to clear button background even if m_btn is present - if ( paintBg ) + if ( flags & Button_PaintBackground ) { wxColour bgCol; @@ -1368,7 +1458,7 @@ void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int paintBg ) { // If using blank button background, we need to clear its background // with button face colour instead of colour for rest of the control. - if ( paintBg ) + if ( flags & Button_PaintBackground ) { wxColour bgCol = GetParent()->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); //wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); @@ -1377,18 +1467,20 @@ void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int paintBg ) dc.DrawRectangle(rect); } - wxRendererNative::Get().DrawPushButton(this, - dc, - drawRect, - drawState); - + if ( !(flags & Button_BitmapOnly) ) + { + wxRendererNative::Get().DrawPushButton(this, + dc, + drawRect, + drawState); + } } else { // Need to clear button background even if m_btn is present // (assume non-button background was cleared just before this call so brushes are good) - if ( paintBg ) + if ( flags & Button_PaintBackground ) dc.DrawRectangle(rect); } @@ -1435,13 +1527,14 @@ void wxComboCtrlBase::OnTextCtrlEvent(wxCommandEvent& event) // call if cursor is on button area or mouse is captured for the button bool wxComboCtrlBase::HandleButtonMouseEvent( wxMouseEvent& event, - int flags ) + int flags ) { int type = event.GetEventType(); if ( type == wxEVT_MOTION ) { - if ( flags & wxCC_MF_ON_BUTTON ) + if ( (flags & wxCC_MF_ON_BUTTON) && + IsPopupWindowState(Hidden) ) { if ( !(m_btnState & wxCONTROL_CURRENT) ) { @@ -1510,6 +1603,11 @@ bool wxComboCtrlBase::HandleButtonMouseEvent( wxMouseEvent& event, else return false; + // Never have 'hot' state when popup is being shown + // (this is mostly needed because of the animation). + if ( !IsPopupWindowState(Hidden) ) + m_btnState &= ~wxCONTROL_CURRENT; + return true; } @@ -1532,7 +1630,7 @@ bool wxComboCtrlBase::PreprocessMouseEvent( wxMouseEvent& event, } #endif - // Filter out clicks on button immediately after popup dismiss (Windows like behaviour) + // Filter out clicks on button immediately after popup dismiss if ( evtType == wxEVT_LEFT_DOWN && t < m_timeCanAcceptClick ) { event.SetEventType(0); @@ -1579,7 +1677,7 @@ void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event ) { // relay (some) mouse events to the popup if ( evtType == wxEVT_MOUSEWHEEL ) - m_popup->AddPendingEvent(event); + m_popup->GetEventHandler()->AddPendingEvent(event); } else if ( evtType ) event.Skip(); @@ -1590,26 +1688,13 @@ void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event) if ( IsPopupShown() ) { // pass it to the popped up control - GetPopupControl()->GetControl()->AddPendingEvent(event); + GetPopupControl()->GetControl()->GetEventHandler()->AddPendingEvent(event); } else // no popup { - int keycode = event.GetKeyCode(); - - if ( keycode == WXK_TAB ) - { - wxNavigationKeyEvent evt; - - wxWindow* mainCtrl = GetMainWindowOfCompositeControl(); - - evt.SetFlags(wxNavigationKeyEvent::FromTab| - (!event.ShiftDown() ? wxNavigationKeyEvent::IsForward - : wxNavigationKeyEvent::IsBackward)); - evt.SetEventObject(mainCtrl); - evt.SetCurrentFocus(mainCtrl); - mainCtrl->GetParent()->GetEventHandler()->AddPendingEvent(evt); + if ( GetParent()->HasFlag(wxTAB_TRAVERSAL) && + HandleAsNavigationKey(event) ) return; - } if ( IsKeyPopupToggle(event) ) { @@ -1626,6 +1711,8 @@ void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event) return; } + int keycode = event.GetKeyCode(); + if ( (comboStyle & wxCB_READONLY) || (keycode != WXK_RIGHT && keycode != WXK_LEFT) ) { @@ -1642,11 +1729,9 @@ void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event ) { wxWindow* tc = GetTextCtrl(); if ( tc && tc != DoFindFocus() ) -#ifdef __WXMAC__ - m_resetFocus = true; -#else + { tc->SetFocus(); -#endif + } } Refresh(); @@ -1666,9 +1751,9 @@ void wxComboCtrlBase::OnIdleEvent( wxIdleEvent& WXUNUSED(event) ) void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) { OnThemeChange(); - // indentation may also have changed - if ( !(m_iFlags & wxCC_IFLAG_INDENT_SET) ) - m_absIndent = GetNativeTextIndent(); + // left margin may also have changed + if ( !(m_iFlags & wxCC_IFLAG_LEFT_MARGIN_SET) ) + m_marginLeft = GetNativeTextIndent(); RecalcAndRefresh(); } @@ -1697,7 +1782,7 @@ void wxComboCtrlBase::CreatePopup() m_popupWinType = SECONDARY_POPUP_TYPE; } else -#endif +#endif // wxComboPopupWindowBase2 { m_winPopup = new wxComboPopupWindow( this, wxNO_BORDER ); m_popupWinType = PRIMARY_POPUP_TYPE; @@ -1740,10 +1825,10 @@ void wxComboCtrlBase::DestroyPopup() m_winPopup->Destroy(); } - m_popupExtraHandler = (wxEvtHandler*) NULL; - m_popupInterface = (wxComboPopup*) NULL; - m_winPopup = (wxWindow*) NULL; - m_popup = (wxWindow*) NULL; + m_popupExtraHandler = NULL; + m_popupInterface = NULL; + m_winPopup = NULL; + m_popup = NULL; } void wxComboCtrlBase::DoSetPopupControl(wxComboPopup* iface) @@ -1763,7 +1848,7 @@ void wxComboCtrlBase::DoSetPopupControl(wxComboPopup* iface) } else { - m_popup = (wxWindow*) NULL; + m_popup = NULL; } // This must be done after creation @@ -1785,7 +1870,10 @@ void wxComboCtrlBase::OnButtonClick() { // Derived classes can override this method for totally custom // popup action - ShowPopup(); + if ( !IsPopupWindowState(Visible) ) + ShowPopup(); + else + HidePopup(); } void wxComboCtrlBase::ShowPopup() @@ -1852,7 +1940,7 @@ void wxComboCtrlBase::ShowPopup() } winPopup->Enable(); - + wxASSERT( !m_popup || m_popup == popup ); // Consistency check. wxSize adjustedSize = m_popupInterface->GetAdjustedSize(widthPopup, @@ -1879,6 +1967,10 @@ void wxComboCtrlBase::ShowPopup() int rightX = scrPos.x + ctrlSz.x + m_extRight - szp.x; int leftX = scrPos.x - m_extLeft; + + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + leftX -= ctrlSz.x; + int screenWidth = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ); // If there is not enough horizontal space, anchor on the other side. @@ -1979,7 +2071,12 @@ void wxComboCtrlBase::DoShowPopup( const wxRect& rect, int WXUNUSED(flags) ) // (though the bug was probably fixed). winPopup->SetSize( rect ); - winPopup->Show(); +#if USES_WXPOPUPTRANSIENTWINDOW + if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW ) + ((wxPopupTransientWindow*)winPopup)->Popup(m_popup); + else +#endif + winPopup->Show(); m_popupWinState = Visible; } @@ -1991,6 +2088,8 @@ void wxComboCtrlBase::DoShowPopup( const wxRect& rect, int WXUNUSED(flags) ) m_popupWinState = Hidden; } + + Refresh(); } void wxComboCtrlBase::OnPopupDismiss() @@ -2140,22 +2239,61 @@ void wxComboCtrlBase::SetCustomPaintWidth( int width ) RecalcAndRefresh(); } +bool wxComboCtrlBase::DoSetMargins(const wxPoint& margins) +{ + // For general sanity's sake, we ignore top margin. Instead + // we will always try to center the text vertically. + bool res = true; + + if ( margins.x != -1 ) + { + m_marginLeft = margins.x; + m_iFlags |= wxCC_IFLAG_LEFT_MARGIN_SET; + } + else + { + m_marginLeft = GetNativeTextIndent(); + m_iFlags &= ~(wxCC_IFLAG_LEFT_MARGIN_SET); + } + + if ( margins.y != -1 ) + { + res = false; + } + + RecalcAndRefresh(); + + return res; +} + +wxPoint wxComboCtrlBase::DoGetMargins() const +{ + return wxPoint(m_marginLeft, -1); +} + +#if WXWIN_COMPATIBILITY_2_6 void wxComboCtrlBase::SetTextIndent( int indent ) { if ( indent < 0 ) { - m_absIndent = GetNativeTextIndent(); - m_iFlags &= ~(wxCC_IFLAG_INDENT_SET); + m_marginLeft = GetNativeTextIndent(); + m_iFlags &= ~(wxCC_IFLAG_LEFT_MARGIN_SET); } else { - m_absIndent = indent; - m_iFlags |= wxCC_IFLAG_INDENT_SET; + m_marginLeft = indent; + m_iFlags |= wxCC_IFLAG_LEFT_MARGIN_SET; } RecalcAndRefresh(); } +wxCoord wxComboCtrlBase::GetTextIndent() const +{ + return m_marginLeft; +} +#endif + wxCoord wxComboCtrlBase::GetNativeTextIndent() const { return DEFAULT_TEXT_INDENT; @@ -2180,20 +2318,24 @@ void wxComboCtrlBase::SetValueWithEvent(const wxString& value, bool withEvent) m_ignoreEvtText++; m_text->SetValue(value); + if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) m_text->SelectAll(); } - m_valueString = value; - - Refresh(); - // Since wxComboPopup may want to paint the combo as well, we need // to set the string value here (as well as sometimes in ShowPopup). - if ( m_valueString != value && m_popupInterface ) + if ( m_valueString != value ) { - m_popupInterface->SetStringValue(value); + m_valueString = value; + + EnsurePopupControl(); + + if (m_popupInterface) + m_popupInterface->SetStringValue(value); } + + Refresh(); } void wxComboCtrlBase::SetValue(const wxString& value)