A number of focus handling improvements:
Left clicking on a window only focuses the window if not processed. wxControlContainer::SetFocus moved to wxControlContainerBase so that a container now focuses the first child even on wxGTK. wxAuiBook is now a container, need for correct navigation on wxGTK. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@48154 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
		@@ -1,4 +1,4 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Name:        wx/aui/auibook.h
 | 
			
		||||
// Purpose:     wxaui: wx advanced user interface - notebook
 | 
			
		||||
// Author:      Benjamin I. Williams
 | 
			
		||||
@@ -576,7 +576,7 @@ public:
 | 
			
		||||
    virtual bool HasMultiplePages() const { return true; }
 | 
			
		||||
 | 
			
		||||
    // we don't want focus for ourselves
 | 
			
		||||
    virtual bool AcceptsFocus() const { return false; }
 | 
			
		||||
    // virtual bool AcceptsFocus() const { return false; }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
@@ -641,6 +641,9 @@ protected:
 | 
			
		||||
    DECLARE_CLASS(wxAuiNotebook)
 | 
			
		||||
    DECLARE_EVENT_TABLE()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    WX_DECLARE_CONTROL_CONTAINER();
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,10 @@ public:
 | 
			
		||||
        // do accept focus initially, we'll stop doing it if/when any children
 | 
			
		||||
        // are added
 | 
			
		||||
        m_acceptsFocus = true;
 | 
			
		||||
        m_inSetFocus = false;
 | 
			
		||||
        m_winLastFocused = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    virtual ~wxControlContainerBase() {}
 | 
			
		||||
 | 
			
		||||
    void SetContainerWindow(wxWindow *winParent)
 | 
			
		||||
    {
 | 
			
		||||
@@ -51,6 +54,10 @@ public:
 | 
			
		||||
        m_winParent = winParent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // should be called from SetFocus(), returns false if we did nothing with
 | 
			
		||||
    // the focus and the default processing should take place
 | 
			
		||||
    bool DoSetFocus();
 | 
			
		||||
 | 
			
		||||
    // should be called when we decide that we should [stop] accepting focus
 | 
			
		||||
    void SetCanFocus(bool acceptsFocus);
 | 
			
		||||
 | 
			
		||||
@@ -70,6 +77,9 @@ public:
 | 
			
		||||
    void UpdateCanFocus() { SetCanFocus(!HasAnyFocusableChildren()); }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    // set the focus to the child which had it the last time
 | 
			
		||||
    virtual bool SetFocusToChild();
 | 
			
		||||
 | 
			
		||||
    // return true if we have any children accepting focus
 | 
			
		||||
    bool HasAnyFocusableChildren() const;
 | 
			
		||||
 | 
			
		||||
@@ -80,6 +90,13 @@ private:
 | 
			
		||||
    // value returned by AcceptsFocus(), should be changed using SetCanFocus()
 | 
			
		||||
    // only
 | 
			
		||||
    bool m_acceptsFocus;
 | 
			
		||||
 | 
			
		||||
    // a guard against infinite recursion
 | 
			
		||||
    bool m_inSetFocus;
 | 
			
		||||
 | 
			
		||||
    // the child which had the focus last time this panel was activated
 | 
			
		||||
    wxWindow *m_winLastFocused;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// common part of WX_DECLARE_CONTROL_CONTAINER in the native and generic cases,
 | 
			
		||||
@@ -90,6 +107,7 @@ public:                                                                       \
 | 
			
		||||
    virtual bool AcceptsFocusRecursively() const;                             \
 | 
			
		||||
    virtual void AddChild(wxWindowBase *child);                               \
 | 
			
		||||
    virtual void RemoveChild(wxWindowBase *child);                            \
 | 
			
		||||
    virtual void SetFocus();                                                  \
 | 
			
		||||
    void SetFocusIgnoringChildren();                                          \
 | 
			
		||||
    void AcceptFocus(bool acceptFocus)                                        \
 | 
			
		||||
    {                                                                         \
 | 
			
		||||
@@ -118,6 +136,12 @@ protected:                                                                    \
 | 
			
		||||
        return m_container.AcceptsFocusRecursively();                         \
 | 
			
		||||
    }                                                                         \
 | 
			
		||||
                                                                              \
 | 
			
		||||
    void classname::SetFocus()                                                \
 | 
			
		||||
    {                                                                         \
 | 
			
		||||
        if ( !m_container.DoSetFocus() )                                      \
 | 
			
		||||
            basename::SetFocus();                                             \
 | 
			
		||||
    }                                                                         \
 | 
			
		||||
                                                                              \
 | 
			
		||||
    bool classname::AcceptsFocus() const                                      \
 | 
			
		||||
    {                                                                         \
 | 
			
		||||
        return m_container.AcceptsFocus();                                    \
 | 
			
		||||
@@ -133,6 +157,9 @@ protected:                                                                    \
 | 
			
		||||
// this must be a real class as we forward-declare it elsewhere
 | 
			
		||||
class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
 | 
			
		||||
{
 | 
			
		||||
protected:
 | 
			
		||||
    // set the focus to the child which had it the last time
 | 
			
		||||
    virtual bool SetFocusToChild();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname)
 | 
			
		||||
@@ -174,30 +201,15 @@ public:
 | 
			
		||||
    void HandleOnFocus(wxFocusEvent& event);
 | 
			
		||||
    void HandleOnWindowDestroy(wxWindowBase *child);
 | 
			
		||||
 | 
			
		||||
    // should be called from SetFocus(), returns false if we did nothing with
 | 
			
		||||
    // the focus and the default processing should take place
 | 
			
		||||
    bool DoSetFocus();
 | 
			
		||||
 | 
			
		||||
    // called from OnChildFocus() handler, i.e. when one of our (grand)
 | 
			
		||||
    // children gets the focus
 | 
			
		||||
    void SetLastFocus(wxWindow *win);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    // set the focus to the child which had it the last time
 | 
			
		||||
    bool SetFocusToChild();
 | 
			
		||||
 | 
			
		||||
    // the child which had the focus last time this panel was activated
 | 
			
		||||
    wxWindow *m_winLastFocused;
 | 
			
		||||
 | 
			
		||||
    // a guard against infinite recursion
 | 
			
		||||
    bool m_inSetFocus;
 | 
			
		||||
 | 
			
		||||
    DECLARE_NO_COPY_CLASS(wxControlContainer)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// this function is for wxWidgets internal use only
 | 
			
		||||
extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// macros which may be used by the classes wishing to implement TAB navigation
 | 
			
		||||
// among their children
 | 
			
		||||
@@ -210,8 +222,7 @@ extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
 | 
			
		||||
public:                                                                       \
 | 
			
		||||
    void OnNavigationKey(wxNavigationKeyEvent& event);                        \
 | 
			
		||||
    void OnFocus(wxFocusEvent& event);                                        \
 | 
			
		||||
    virtual void OnChildFocus(wxChildFocusEvent& event);                      \
 | 
			
		||||
    virtual void SetFocus()
 | 
			
		||||
    virtual void OnChildFocus(wxChildFocusEvent& event)
 | 
			
		||||
 | 
			
		||||
// implement the event table entries for wxControlContainer
 | 
			
		||||
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
 | 
			
		||||
@@ -237,12 +248,6 @@ public:                                                                       \
 | 
			
		||||
        m_container.HandleOnNavigationKey(event);                             \
 | 
			
		||||
    }                                                                         \
 | 
			
		||||
                                                                              \
 | 
			
		||||
    void classname::SetFocus()                                                \
 | 
			
		||||
    {                                                                         \
 | 
			
		||||
        if ( !m_container.DoSetFocus() )                                      \
 | 
			
		||||
            basename::SetFocus();                                             \
 | 
			
		||||
    }                                                                         \
 | 
			
		||||
                                                                              \
 | 
			
		||||
    void classname::SetFocusIgnoringChildren()                                \
 | 
			
		||||
    {                                                                         \
 | 
			
		||||
        basename::SetFocus();                                                 \
 | 
			
		||||
@@ -260,4 +265,7 @@ public:                                                                       \
 | 
			
		||||
 | 
			
		||||
#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
 | 
			
		||||
 | 
			
		||||
// this function is for wxWidgets internal use only
 | 
			
		||||
extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
 | 
			
		||||
 | 
			
		||||
#endif // _WX_CONTAINR_H_
 | 
			
		||||
 
 | 
			
		||||
@@ -2168,6 +2168,7 @@ wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
 | 
			
		||||
                           const wxSize& size,
 | 
			
		||||
                           long style) : wxControl(parent, id, pos, size, style)
 | 
			
		||||
{
 | 
			
		||||
    SetName(wxT("wxAuiTabCtrl"));
 | 
			
		||||
    m_click_pt = wxDefaultPosition;
 | 
			
		||||
    m_is_dragging = false;
 | 
			
		||||
    m_hover_button = NULL;
 | 
			
		||||
@@ -2712,8 +2713,12 @@ BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
 | 
			
		||||
                      wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP,
 | 
			
		||||
                      wxAuiNotebook::OnTabRightUp)
 | 
			
		||||
    EVT_NAVIGATION_KEY(wxAuiNotebook::OnNavigationKey)
 | 
			
		||||
 | 
			
		||||
    WX_EVENT_TABLE_CONTROL_CONTAINER(wxAuiNotebook)
 | 
			
		||||
END_EVENT_TABLE()
 | 
			
		||||
 | 
			
		||||
WX_DELEGATE_TO_CONTROL_CONTAINER(wxAuiNotebook, wxControl)
 | 
			
		||||
 | 
			
		||||
wxAuiNotebook::wxAuiNotebook()
 | 
			
		||||
{
 | 
			
		||||
    m_curpage = -1;
 | 
			
		||||
@@ -2754,6 +2759,10 @@ bool wxAuiNotebook::Create(wxWindow* parent,
 | 
			
		||||
// code called by all constructors
 | 
			
		||||
void wxAuiNotebook::InitNotebook(long style)
 | 
			
		||||
{
 | 
			
		||||
    WX_INIT_CONTROL_CONTAINER();
 | 
			
		||||
    // SetCanFocus(false);
 | 
			
		||||
 | 
			
		||||
    SetName(wxT("wxAuiNotebook"));
 | 
			
		||||
    m_curpage = -1;
 | 
			
		||||
    m_tab_id_counter = wxAuiBaseTabCtrlId;
 | 
			
		||||
    m_dummy_wnd = NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -77,6 +77,52 @@ bool wxControlContainerBase::HasAnyFocusableChildren() const
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool wxControlContainerBase::DoSetFocus()
 | 
			
		||||
{
 | 
			
		||||
    wxLogTrace(TRACE_FOCUS, _T("SetFocus on wxPanel 0x%p."),
 | 
			
		||||
               m_winParent->GetHandle());
 | 
			
		||||
 | 
			
		||||
    if (m_inSetFocus)
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    // when the panel gets the focus we move the focus to either the last
 | 
			
		||||
    // window that had the focus or the first one that can get it unless the
 | 
			
		||||
    // focus had been already set to some other child
 | 
			
		||||
 | 
			
		||||
    wxWindow *win = wxWindow::FindFocus();
 | 
			
		||||
    while ( win )
 | 
			
		||||
    {
 | 
			
		||||
        if ( win == m_winParent )
 | 
			
		||||
        {
 | 
			
		||||
            // our child already has focus, don't take it away from it
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ( win->IsTopLevel() )
 | 
			
		||||
        {
 | 
			
		||||
            // don't look beyond the first top level parent - useless and
 | 
			
		||||
            // unnecessary
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        win = win->GetParent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // protect against infinite recursion:
 | 
			
		||||
    m_inSetFocus = true;
 | 
			
		||||
 | 
			
		||||
    bool ret = SetFocusToChild();
 | 
			
		||||
 | 
			
		||||
    m_inSetFocus = false;
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool wxControlContainerBase::SetFocusToChild()
 | 
			
		||||
{
 | 
			
		||||
    return wxSetFocusToChild(m_winParent, &m_winLastFocused);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
@@ -86,7 +132,6 @@ bool wxControlContainerBase::HasAnyFocusableChildren() const
 | 
			
		||||
wxControlContainer::wxControlContainer()
 | 
			
		||||
{
 | 
			
		||||
    m_winLastFocused = NULL;
 | 
			
		||||
    m_inSetFocus = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wxControlContainer::SetLastFocus(wxWindow *win)
 | 
			
		||||
@@ -552,47 +597,6 @@ void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child)
 | 
			
		||||
// focus handling
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
bool wxControlContainer::DoSetFocus()
 | 
			
		||||
{
 | 
			
		||||
    wxLogTrace(TRACE_FOCUS, _T("SetFocus on wxPanel 0x%p."),
 | 
			
		||||
               m_winParent->GetHandle());
 | 
			
		||||
 | 
			
		||||
    if (m_inSetFocus)
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    // when the panel gets the focus we move the focus to either the last
 | 
			
		||||
    // window that had the focus or the first one that can get it unless the
 | 
			
		||||
    // focus had been already set to some other child
 | 
			
		||||
 | 
			
		||||
    wxWindow *win = wxWindow::FindFocus();
 | 
			
		||||
    while ( win )
 | 
			
		||||
    {
 | 
			
		||||
        if ( win == m_winParent )
 | 
			
		||||
        {
 | 
			
		||||
            // our child already has focus, don't take it away from it
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ( win->IsTopLevel() )
 | 
			
		||||
        {
 | 
			
		||||
            // don't look beyond the first top level parent - useless and
 | 
			
		||||
            // unnecessary
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        win = win->GetParent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // protect against infinite recursion:
 | 
			
		||||
    m_inSetFocus = true;
 | 
			
		||||
 | 
			
		||||
    bool ret = SetFocusToChild();
 | 
			
		||||
 | 
			
		||||
    m_inSetFocus = false;
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
 | 
			
		||||
{
 | 
			
		||||
    wxLogTrace(TRACE_FOCUS, _T("OnFocus on wxPanel 0x%p, name: %s"),
 | 
			
		||||
@@ -604,11 +608,18 @@ void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
 | 
			
		||||
    event.Skip();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
  // wxHAS_NATIVE_TAB_TRAVERSAL
 | 
			
		||||
 | 
			
		||||
bool wxControlContainer::SetFocusToChild()
 | 
			
		||||
{
 | 
			
		||||
    return wxSetFocusToChild(m_winParent, &m_winLastFocused);
 | 
			
		||||
    return wxSetFocusToChild(m_winParent, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // !wxHAS_NATIVE_TAB_TRAVERSAL
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in
 | 
			
		||||
// wxMSW, this is why it is outside of wxControlContainer class
 | 
			
		||||
@@ -617,10 +628,10 @@ bool wxControlContainer::SetFocusToChild()
 | 
			
		||||
bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
 | 
			
		||||
{
 | 
			
		||||
    wxCHECK_MSG( win, false, _T("wxSetFocusToChild(): invalid window") );
 | 
			
		||||
    wxCHECK_MSG( childLastFocused, false,
 | 
			
		||||
                 _T("wxSetFocusToChild(): NULL child poonter") );
 | 
			
		||||
    //    wxCHECK_MSG( childLastFocused, false,
 | 
			
		||||
    //             _T("wxSetFocusToChild(): NULL child poonter") );
 | 
			
		||||
 | 
			
		||||
    if ( *childLastFocused )
 | 
			
		||||
    if ( childLastFocused && *childLastFocused )
 | 
			
		||||
    {
 | 
			
		||||
        // It might happen that the window got reparented
 | 
			
		||||
        if ( (*childLastFocused)->GetParent() == win )
 | 
			
		||||
@@ -670,7 +681,8 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
 | 
			
		||||
                       _T("SetFocusToChild() => first child (0x%p)."),
 | 
			
		||||
                       child->GetHandle());
 | 
			
		||||
 | 
			
		||||
            *childLastFocused = child;
 | 
			
		||||
            if (childLastFocused)
 | 
			
		||||
                *childLastFocused = child;
 | 
			
		||||
            child->SetFocusFromKbd();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
@@ -679,4 +691,3 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // !wxHAS_NATIVE_TAB_TRAVERSAL
 | 
			
		||||
 
 | 
			
		||||
@@ -1440,11 +1440,6 @@ gtk_window_button_press_callback( GtkWidget *widget,
 | 
			
		||||
 | 
			
		||||
    g_lastButtonNumber = gdk_event->button;
 | 
			
		||||
 | 
			
		||||
    if (win->m_wxwindow && (g_focusWindow != win) && win->IsFocusable())
 | 
			
		||||
    {
 | 
			
		||||
        gtk_widget_grab_focus( win->m_wxwindow );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // GDK sends surplus button down events
 | 
			
		||||
    // before a double click event. We
 | 
			
		||||
    // need to filter these out.
 | 
			
		||||
@@ -1576,9 +1571,9 @@ gtk_window_button_press_callback( GtkWidget *widget,
 | 
			
		||||
        return TRUE;
 | 
			
		||||
 | 
			
		||||
    if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() && 
 | 
			
		||||
        (g_focusWindow != win) && win->IsFocusable())
 | 
			
		||||
        (g_focusWindow != win) /* && win->IsFocusable() */)
 | 
			
		||||
    {
 | 
			
		||||
        gtk_widget_grab_focus( win->m_wxwindow );
 | 
			
		||||
        win->SetFocus();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (event_type == wxEVT_RIGHT_DOWN)
 | 
			
		||||
@@ -1870,7 +1865,9 @@ gtk_window_focus_out_callback( GtkWidget *widget,
 | 
			
		||||
        // Disable default focus handling for custom windows
 | 
			
		||||
        // since the default GTK+ handler issues a repaint
 | 
			
		||||
        if ( has_wxwindow )
 | 
			
		||||
	{
 | 
			
		||||
            return TRUE;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // continue with normal processing
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user