]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/combocmn.cpp
add a note about changing selection background colour
[wxWidgets.git] / src / common / combocmn.cpp
index 6139dfc17908e8f96e6994adf00dd156a7c3b14f..2595b6ad92ace1787abfa67ff16d40f82bb3fa68 100644 (file)
@@ -28,6 +28,7 @@
 #include "wx/combobox.h"
 
 #ifndef WX_PRECOMP
+    #include "wx/app.h"
     #include "wx/log.h"
     #include "wx/dcclient.h"
     #include "wx/settings.h"
@@ -62,6 +63,7 @@
                                         // native controls work on it like normal.
 #define POPUPWIN_IS_PERFECT           0 // Same, but for non-transient popup window.
 #define TEXTCTRL_TEXT_CENTERED        0 // 1 if text in textctrl is vertically centered
+#define FOCUS_RING                    0 // No focus ring on wxMSW
 
 //#undef wxUSE_POPUPWIN
 //#define wxUSE_POPUPWIN 0
@@ -79,6 +81,7 @@
                                         // 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
+#define FOCUS_RING                    0 // No focus ring on wxGTK
 
 #elif defined(__WXMAC__)
 
                                         // native controls work on it like normal.
 #define POPUPWIN_IS_PERFECT           0 // 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
+
+#undef DEFAULT_DROPBUTTON_WIDTH
+#define DEFAULT_DROPBUTTON_WIDTH      22
+#undef COMBO_MARGIN
+#define COMBO_MARGIN                  FOCUS_RING
 
 #else
 
                                         // native controls work on it like normal.
 #define POPUPWIN_IS_PERFECT           0 // Same, but for non-transient popup window.
 #define TEXTCTRL_TEXT_CENTERED        1 // 1 if text in textctrl is vertically centered
+#define FOCUS_RING                    0
 
 #endif
 
@@ -346,6 +356,7 @@ public:
 #if USES_WXPOPUPTRANSIENTWINDOW
     virtual bool Show( bool show );
     virtual bool ProcessLeftDown(wxMouseEvent& event);
+protected:
     virtual void OnDismiss();
 #endif
 
@@ -707,6 +718,7 @@ BEGIN_EVENT_TABLE(wxComboCtrlBase, wxControl)
     EVT_SIZE(wxComboCtrlBase::OnSizeEvent)
     EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent)
     EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent)
+    EVT_IDLE(wxComboCtrlBase::OnIdleEvent)
     //EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent)
     EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent)
     EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent)
@@ -732,6 +744,8 @@ void wxComboCtrlBase::Init()
     m_toplevEvtHandler = (wxEvtHandler*) NULL;
 #endif
 
+    m_mainCtrlWnd = this;
+
     m_heightPopup = -1;
     m_widthMinPopup = -1;
     m_anchorSide = 0;
@@ -752,6 +766,8 @@ void wxComboCtrlBase::Init()
     m_absIndent = -1;
     m_iFlags = 0;
     m_timeCanAcceptClick = 0;
+
+    m_resetFocus = false;
 }
 
 bool wxComboCtrlBase::Create(wxWindow *parent,
@@ -826,17 +842,19 @@ wxComboCtrlBase::CreateTextCtrl(int style, const wxValidator& validator)
             m_ignoreEvtText = 0;
 
         m_text = new wxTextCtrl(this, wxID_ANY, m_valueString,
-                                wxDefaultPosition, wxDefaultSize,
+                                wxDefaultPosition, wxSize(10,-1),
                                 style, validator);
-
-        // This is required for some platforms (GTK+ atleast)
-        m_text->SetSizeHints(2,4);
     }
 }
 
 void wxComboCtrlBase::OnThemeChange()
 {
-    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+    // Leave the default bg on the Mac so the area used by the focus ring will
+    // be the correct colour and themed brush.  Instead we'll use
+    // wxSYS_COLOUR_WINDOW in the EVT_PAINT handler as needed.
+#ifndef __WXMAC__
+    SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+#endif
 }
 
 wxComboCtrlBase::~wxComboCtrlBase()
@@ -964,14 +982,14 @@ void wxComboCtrlBase::CalculateAreas( int btnWidth )
     m_btnSize.y = butHeight;
 
     m_btnArea.x = ( m_btnSide==wxRIGHT ? sz.x - butAreaWid - btnBorder : btnBorder );
-    m_btnArea.y = btnBorder;
+    m_btnArea.y = btnBorder + FOCUS_RING;
     m_btnArea.width = butAreaWid;
-    m_btnArea.height = sz.y - (btnBorder*2);
+    m_btnArea.height = sz.y - ((btnBorder+FOCUS_RING)*2);
 
-    m_tcArea.x = ( m_btnSide==wxRIGHT ? 0 : butAreaWid ) + customBorder;
-    m_tcArea.y = customBorder;
-    m_tcArea.width = sz.x - butAreaWid - (customBorder*2);
-    m_tcArea.height = sz.y - (customBorder*2);
+    m_tcArea.x = ( m_btnSide==wxRIGHT ? 0 : butAreaWid ) + customBorder + FOCUS_RING;
+    m_tcArea.y = customBorder + FOCUS_RING;
+    m_tcArea.width = sz.x - butAreaWid - (customBorder*2) - (FOCUS_RING*2);
+    m_tcArea.height = sz.y - ((customBorder+FOCUS_RING)*2);
 
 /*
     if ( m_text )
@@ -987,10 +1005,11 @@ void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust
     if ( !m_text )
         return;
 
+#if !TEXTCTRL_TEXT_CENTERED
+
     wxSize sz = GetClientSize();
-    int customBorder = m_widthCustomBorder;
 
-#if !TEXTCTRL_TEXT_CENTERED
+    int customBorder = m_widthCustomBorder;
     if ( (m_text->GetWindowStyleFlag() & wxBORDER_MASK) == wxNO_BORDER )
     {
         // Centre textctrl
@@ -1017,16 +1036,16 @@ void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust
         }
     }
     else
-#else
+#else // TEXTCTRL_TEXT_CENTERED
     wxUnusedVar(textCtrlXAdjust);
     wxUnusedVar(textCtrlYAdjust);
-#endif
+#endif // !TEXTCTRL_TEXT_CENTERED/TEXTCTRL_TEXT_CENTERED
     {
         // If it has border, have textctrl will the entire text field.
         m_text->SetSize( m_tcArea.x + m_widthCustomPaint,
-                         customBorder,
-                         sz.x - m_btnArea.width - m_widthCustomPaint - customBorder,
-                         sz.y-(customBorder*2) );
+                         m_tcArea.y,
+                         m_tcArea.width - m_widthCustomPaint,
+                         m_tcArea.height );
     }
 }
 
@@ -1070,9 +1089,27 @@ wxSize wxComboCtrlBase::DoGetBestSize() const
     fhei += 1;
 #endif
 
-    wxSize ret(sizeText.x + COMBO_MARGIN + DEFAULT_DROPBUTTON_WIDTH,
-               fhei);
+#ifdef __WXMAC__
+    // these are the numbers from the HIG:
+    switch ( m_windowVariant )
+    {
+        case wxWINDOW_VARIANT_NORMAL:
+        default :
+            fhei = 22;
+            break;
+        case wxWINDOW_VARIANT_SMALL:
+            fhei = 19;
+            break;
+        case wxWINDOW_VARIANT_MINI:
+            fhei = 15;
+            break;
+    }
+#endif
+
+    fhei += 2 * FOCUS_RING;
+    int width = sizeText.x + FOCUS_RING + COMBO_MARGIN + DEFAULT_DROPBUTTON_WIDTH;
 
+    wxSize ret(width, fhei);
     CacheBestSize(ret);
     return ret;
 }
@@ -1150,6 +1187,26 @@ void wxComboCtrlBase::DoSetToolTip(wxToolTip *tooltip)
 }
 #endif // wxUSE_TOOLTIPS
 
+#if wxUSE_VALIDATORS
+void wxComboCtrlBase::SetValidator(const wxValidator& validator)
+{
+    wxTextCtrl* textCtrl = GetTextCtrl();
+
+    if ( textCtrl )
+        textCtrl->SetValidator( validator );
+}
+
+wxValidator* wxComboCtrlBase::GetValidator()
+{
+    wxTextCtrl* textCtrl = GetTextCtrl();
+
+    if ( textCtrl )
+        return textCtrl->GetValidator();
+
+    return wxControl::GetValidator();
+}
+#endif // wxUSE_VALIDATORS
+
 // ----------------------------------------------------------------------------
 // painting
 // ----------------------------------------------------------------------------
@@ -1213,13 +1270,21 @@ void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags
         else
         {
             dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
+#ifndef __WXMAC__  // see note in OnThemeChange
             bgCol = GetBackgroundColour();
+#else
+            bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+#endif
         }
     }
     else
     {
         dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT) );
+#ifndef __WXMAC__  // see note in OnThemeChange
         bgCol = GetBackgroundColour();
+#else
+        bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+#endif
     }
 
     dc.SetBrush( bgCol );
@@ -1239,7 +1304,7 @@ void wxComboCtrlBase::PrepareBackground( wxDC&, const wxRect&, int ) const
 }
 #endif
 
-void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, bool paintBg )
+void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int paintBg )
 {
     int drawState = m_btnState;
 
@@ -1537,11 +1602,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;
         }
 
@@ -1574,13 +1643,29 @@ void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event )
 {
     if ( event.GetEventType() == wxEVT_SET_FOCUS )
     {
-        if ( m_text && m_text != ::wxWindow::FindFocus() )
-            m_text->SetFocus();
+        wxWindow* tc = GetTextCtrl();
+        if ( tc && tc != DoFindFocus() )
+#ifdef __WXMAC__
+            m_resetFocus = true;
+#else
+            tc->SetFocus();
+#endif
     }
 
     Refresh();
 }
 
+void wxComboCtrlBase::OnIdleEvent( wxIdleEvent& WXUNUSED(event) )
+{
+    if ( m_resetFocus )
+    {
+        m_resetFocus = false;
+        wxWindow* tc = GetTextCtrl();
+        if ( tc )
+            tc->SetFocus();
+    }
+}
+
 void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
 {
     OnThemeChange();
@@ -1769,6 +1854,8 @@ void wxComboCtrlBase::ShowPopup()
         popup = m_popup;
     }
 
+    winPopup->Enable();
+
     wxASSERT( !m_popup || m_popup == popup ); // Consistency check.
 
     wxSize adjustedSize = m_popupInterface->GetAdjustedSize(widthPopup,
@@ -1795,6 +1882,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.
@@ -1870,7 +1961,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 );
     }
@@ -1914,20 +2006,13 @@ void wxComboCtrlBase::OnPopupDismiss()
     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_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_popupWinState).
-
-    SetFocus();
-
-    // This should preferably be set before focus.
+    // This must be set before focus - otherwise there will be recursive
+    // OnPopupDismisses.
     m_popupWinState = Hidden;
 
+    //SetFocus();
+    m_winPopup->Disable();
+
     // Inform popup control itself
     m_popupInterface->OnDismiss();