]> git.saurik.com Git - wxWidgets.git/commitdiff
better key handling for MSW and GTK (patch 1526666)
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 13 Aug 2006 00:35:02 +0000 (00:35 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 13 Aug 2006 00:35:02 +0000 (00:35 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@40579 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/combo.h
include/wx/generic/combo.h
include/wx/msw/combo.h
src/common/combocmn.cpp
src/generic/combog.cpp
src/generic/odcombo.cpp
src/msw/combo.cpp

index 36d9a720e2c4ad403bc8d9bc8923e7da5ad6318d..ec19e490d1d84366932e41f46e31df96995b90ee 100644 (file)
@@ -297,6 +297,14 @@ public:
     // Utilies needed by the popups or native implementations
     //
 
+    // Returns true if given key combination should toggle the popup.
+    // NB: This is a separate from other keyboard handling because:
+    //     1) Replaceability.
+    //     2) Centralized code (otherwise it'd be split up between
+    //        wxComboCtrl key handler and wxVListBoxComboPopup's
+    //        key handler).
+    virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const = 0;
+
     // Draws focus background (on combo control) in a way typical on platform.
     // Unless you plan to paint your own focus indicator, you should always call this
     // in your wxComboPopup::PaintComboControl implementation.
@@ -351,7 +359,7 @@ protected:
     void CreateTextCtrl( int extraStyle, const wxValidator& validator );
 
     // Installs standard input handler to combo (and optionally to the textctrl)
-    void InstallInputHandlers( bool alsoTextCtrl = true );
+    void InstallInputHandlers();
 
     // Draws dropbutton. Using wxRenderer or bitmaps, as appropriate.
     void DrawButton( wxDC& dc, const wxRect& rect, bool paintBg = true );
@@ -402,6 +410,7 @@ protected:
     void OnFocusEvent(wxFocusEvent& event);
     void OnTextCtrlEvent(wxCommandEvent& event);
     void OnSysColourChanged(wxSysColourChangedEvent& event);
+    void OnKeyEvent(wxKeyEvent& event);
 
     // Set customization flags (directs how wxComboCtrlBase helpers behave)
     void Customize( wxUint32 flags ) { m_iFlags |= flags; }
@@ -432,10 +441,7 @@ protected:
     // popup interface
     wxComboPopup*           m_popupInterface;
 
-    // this is for this control itself
-    wxEvtHandler*           m_extraEvtHandler;
-
-    // this is for text
+    // this is input etc. handler for the text control
     wxEvtHandler*           m_textEvtHandler;
 
     // this is for the top level window
index feca13db3c20b19c5245f8549f5bb540e8bd0a5d..e6df1706e05841a74315d5f509966971c25d9c7d 100644 (file)
@@ -65,6 +65,8 @@ public:
 
     virtual ~wxGenericComboControl();
 
+    virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const;
+
     static int GetFeatures() { return wxComboCtrlFeatures::All; }
 
 #if defined(__WXUNIVERSAL__)
index 7204e649d8517f1794f5e0156d9e74b2816c2d33..5c02285db64e894c1ef25d21f5bacc81e8b52726 100644 (file)
@@ -60,6 +60,7 @@ public:
     virtual ~wxComboCtrl();
 
     virtual void DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags ) const;
+    virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const;
 
     static int GetFeatures() { return wxComboCtrlFeatures::All; }
 
index b9792d8df82ce6f08038eb2aac335ff184e0af75..b5cd42e4248aca621f33274daa25af269b49320e 100644 (file)
@@ -427,8 +427,7 @@ void wxComboPopup::Dismiss()
 // ----------------------------------------------------------------------------
 
 //
-// This is pushed to the event handler queue of either combo box
-// or its textctrl (latter if not readonly combo).
+// This is pushed to the event handler queue of the child textctrl.
 //
 class wxComboBoxExtraInputHandler : public wxEvtHandler
 {
@@ -459,44 +458,16 @@ END_EVENT_TABLE()
 
 void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event)
 {
-    int keycode = event.GetKeyCode();
+    // Let the wxComboCtrl event handler have a go first.
+    wxComboCtrlBase* combo = m_combo;
+    wxObject* prevObj = event.GetEventObject();
 
-    if ( keycode == WXK_TAB && !m_combo->IsPopupShown() )
-    {
-        wxNavigationKeyEvent evt;
-        evt.SetFlags(wxNavigationKeyEvent::FromTab|
-                     (!event.ShiftDown()?wxNavigationKeyEvent::IsForward:
-                                         wxNavigationKeyEvent::IsBackward));
-        evt.SetEventObject(m_combo);
-        m_combo->GetParent()->GetEventHandler()->AddPendingEvent(evt);
-        return;
-    }
-
-    if ( m_combo->IsPopupShown() )
-    {
-        // pass it to the popped up control
-        m_combo->GetPopupControl()->GetControl()->AddPendingEvent(event);
-    }
-    else // no popup
-    {
-        int comboStyle = m_combo->GetWindowStyle();
-        wxComboPopup* popupInterface = m_combo->GetPopupControl();
-
-        if ( !popupInterface )
-        {
-            event.Skip();
-            return;
-        }
+    event.SetId(combo->GetId());
+    event.SetEventObject(combo);
+    combo->GetEventHandler()->ProcessEvent(event);
 
-        if ( (comboStyle & wxCB_READONLY) ||
-             ( keycode != WXK_RIGHT && keycode != WXK_LEFT )
-            )
-        {
-            popupInterface->OnComboKeyEvent(event);
-        }
-        else
-            event.Skip();
-    }
+    event.SetId(((wxWindow*)prevObj)->GetId());
+    event.SetEventObject(prevObj);
 }
 
 void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event)
@@ -511,17 +482,15 @@ void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event)
             m_combo->SetSelection(-1,-1);
     }
 
-    if ( event.GetId() != m_combo->GetId() )
-    {
-        // Add textctrl set focus events as combo set focus events
-        // NOTE: Simply changing the event and skipping didn't seem
-        // to do the trick.
-        wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId());
-        evt2.SetEventObject(m_combo);
-        m_combo->GetEventHandler()->ProcessEvent(evt2);
-    }
-    else
-        event.Skip();
+    // Send focus indication to parent.
+    // NB: This is needed for cases where the textctrl gets focus
+    //     instead of its parent. While this may trigger multiple
+    //     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());
+    evt2.SetEventObject(m_combo);
+    m_combo->GetEventHandler()->ProcessEvent(evt2);
 
     event.Skip();
 }
@@ -633,6 +602,7 @@ BEGIN_EVENT_TABLE(wxComboCtrlBase, wxControl)
     EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent)
     EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent)
     //EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent)
+    EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent)
     EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent)
     EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged)
 END_EVENT_TABLE()
@@ -652,7 +622,6 @@ void wxComboCtrlBase::Init()
     m_text = (wxTextCtrl*) NULL;
     m_popupInterface = (wxComboPopup*) NULL;
 
-    m_extraEvtHandler = (wxEvtHandler*) NULL;
     m_popupExtraHandler = (wxEvtHandler*) NULL;
     m_textEvtHandler = (wxEvtHandler*) NULL;
 
@@ -718,17 +687,13 @@ bool wxComboCtrlBase::Create(wxWindow *parent,
     return true;
 }
 
-void wxComboCtrlBase::InstallInputHandlers( bool alsoTextCtrl )
+void wxComboCtrlBase::InstallInputHandlers()
 {
-    if ( m_text && alsoTextCtrl )
+    if ( m_text )
     {
         m_textEvtHandler = new wxComboBoxExtraInputHandler(this);
         m_text->PushEventHandler(m_textEvtHandler);
     }
-
-    wxComboBoxExtraInputHandler* inputHandler = new wxComboBoxExtraInputHandler(this);
-    PushEventHandler(inputHandler);
-    m_extraEvtHandler = inputHandler;
 }
 
 void
@@ -774,13 +739,10 @@ wxComboCtrlBase::~wxComboCtrlBase()
 
     DestroyPopup();
 
-    RemoveEventHandler(m_extraEvtHandler);
-
     if ( m_text )
         m_text->RemoveEventHandler(m_textEvtHandler);
 
     delete m_textEvtHandler;
-    delete m_extraEvtHandler;
 }
 
 
@@ -1476,23 +1438,68 @@ void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event )
         event.Skip();
 }
 
-void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& )
+void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event)
 {
-    // First click is the first part of double-click
-    // Some platforms don't generate down-less mouse up-event
-    // (Windows does, GTK+2 doesn't), so that's why we have
-    // to do this.
-    m_timeLastMouseUp = ::wxGetLocalTimeMillis();
+    if ( IsPopupShown() )
+    {
+        // pass it to the popped up control
+        GetPopupControl()->GetControl()->AddPendingEvent(event);
+    }
+    else // no popup
+    {
+        int keycode = event.GetKeyCode();
 
-    if ( m_text )
+        if ( keycode == WXK_TAB )
+        {
+            wxNavigationKeyEvent evt;
+            evt.SetFlags(wxNavigationKeyEvent::FromTab|
+                         (!event.ShiftDown() ? wxNavigationKeyEvent::IsForward
+                                             : wxNavigationKeyEvent::IsBackward));
+            evt.SetEventObject(this);
+            GetParent()->GetEventHandler()->AddPendingEvent(evt);
+            return;
+        }
+
+        if ( IsKeyPopupToggle(event) )
+        {
+            OnButtonClick();
+            return;
+        }
+
+        int comboStyle = GetWindowStyle();
+        wxComboPopup* popupInterface = GetPopupControl();
+
+        if ( !popupInterface )
+        {
+            event.Skip();
+            return;
+        }
+
+        if ( (comboStyle & wxCB_READONLY) ||
+             (keycode != WXK_RIGHT && keycode != WXK_LEFT) )
+        {
+            popupInterface->OnComboKeyEvent(event);
+        }
+        else
+            event.Skip();
+    }
+}
+
+void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event )
+{
+    if ( event.GetEventType() == wxEVT_SET_FOCUS )
     {
-        m_text->SetFocus();
+        // First click is the first part of double-click
+        // Some platforms don't generate down-less mouse up-event
+        // (Windows does, GTK+2 doesn't), so that's why we have
+        // to do this.
+        m_timeLastMouseUp = ::wxGetLocalTimeMillis();
+
+        if ( m_text && m_text != ::wxWindow::FindFocus() )
+            m_text->SetFocus();
     }
-    else
-        // no need to check for m_widthCustomPaint - that
-        // area never gets special handling when selected
-        // (in writable mode, that is)
-        Refresh();
+
+    Refresh();
 }
 
 void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
index 5559bff3c81f1e0d7b1707acae63df27f34231fd..8366a70ea0b0b76e290cfc8ae302e14cc54129af 100644 (file)
@@ -161,7 +161,7 @@ bool wxGenericComboControl::Create(wxWindow *parent,
     CreateTextCtrl( wxNO_BORDER, validator );
 
     // Add keyboard input handlers for main control and textctrl
-    InstallInputHandlers( true );
+    InstallInputHandlers();
 
     // Set background
     SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering
@@ -321,6 +321,28 @@ void wxGenericComboControl::OnMouseEvent( wxMouseEvent& event )
 
 }
 
+bool wxGenericComboControl::IsKeyPopupToggle(const wxKeyEvent& event) const
+{
+    int keycode = event.GetKeyCode();
+    bool isPopupShown = IsPopupShown();
+
+    // This code is AFAIK appropriate for wxGTK.
+
+    if ( isPopupShown )
+    {
+        if ( keycode == WXK_ESCAPE ||
+             ( keycode == WXK_UP && event.AltDown() ) )
+            return true;
+    }
+    else
+    {
+        if ( keycode == WXK_DOWN && event.AltDown() )
+            return true;
+    }
+
+    return false;
+}
+
 #ifdef __WXUNIVERSAL__
 
 bool wxGenericComboControl::PerformAction(const wxControlAction& action,
index b48d79347d88a476734f577c3f2366f0e62c5cad..c72efc280cdf16387145d1d0ae24fbe8947edcf1 100644 (file)
@@ -410,17 +410,24 @@ void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent& WXUNUSED(event))
 
 void wxVListBoxComboPopup::OnKey(wxKeyEvent& event)
 {
-    // Select item if ENTER is pressed
-    if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
-    {
-        DismissWithEvent();
-    }
-    // Hide popup if ESC is pressed
-    else if ( event.GetKeyCode() == WXK_ESCAPE )
+    // Hide popup if certain key or key combination was pressed
+    if ( m_combo->IsKeyPopupToggle(event) )
     {
         StopPartialCompletion();
         Dismiss();
     }
+    else if ( event.AltDown() )
+    {
+        // On both wxGTK and wxMSW, pressing Alt down seems to
+        // completely freeze things in popup (ie. arrow keys and
+        // enter won't work).
+        return;
+    }
+    // Select item if ENTER is pressed
+    else if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
+    {
+        DismissWithEvent();
+    }
     else
     {
         int comboStyle = m_combo->GetWindowStyle();
index 401dc1033d282bd915cdca92743062afe770dfbe..255869e59f190d77ab57d4a4f3ed4dcd584f3954 100644 (file)
@@ -135,7 +135,7 @@ bool wxComboCtrl::Create(wxWindow *parent,
     CreateTextCtrl( wxNO_BORDER, validator );
 
     // Add keyboard input handlers for main control and textctrl
-    InstallInputHandlers( true );
+    InstallInputHandlers();
 
     // Prepare background for double-buffering
     SetBackgroundStyle( wxBG_STYLE_CUSTOM );
@@ -529,5 +529,30 @@ wxCoord wxComboCtrl::GetNativeTextIndent() const
     return NATIVE_TEXT_INDENT_CLASSIC;
 }
 
+bool wxComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
+{
+    int keycode = event.GetKeyCode();
+    bool isPopupShown = IsPopupShown();
+
+    if ( isPopupShown && keycode == WXK_ESCAPE )
+        return true;
+
+    // On XP or with writable combo in Classic,
+    // Alt is required, in addition to up/down, to
+    // show the popup.
+    if ( keycode == WXK_DOWN || keycode == WXK_UP )
+    {
+        if ( event.AltDown() ||
+                ( !isPopupShown &&
+                  HasFlag(wxCB_READONLY) &&
+                  !wxUxThemeEngine::GetIfActive()
+                ) )
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
 
 #endif // wxUSE_COMBOCTRL