From: Julian Smart Date: Sat, 18 Aug 2007 10:54:31 +0000 (+0000) Subject: A number of focus handling improvements: X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/c7bfb76a2cf367dcdbff8f9a97e3250053a1adca 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 --- diff --git a/include/wx/aui/auibook.h b/include/wx/aui/auibook.h index b62ec91d30..a3de9e25ca 100644 --- a/include/wx/aui/auibook.h +++ b/include/wx/aui/auibook.h @@ -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(); + }; diff --git a/include/wx/containr.h b/include/wx/containr.h index 6ac64a4616..2d4cd3d099 100644 --- a/include/wx/containr.h +++ b/include/wx/containr.h @@ -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_ diff --git a/src/aui/auibook.cpp b/src/aui/auibook.cpp index 1676de5b21..6288695abe 100644 --- a/src/aui/auibook.cpp +++ b/src/aui/auibook.cpp @@ -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; diff --git a/src/common/containr.cpp b/src/common/containr.cpp index c62e2ebd42..2f702e6f1a 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -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 diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 5c68e602d4..e8b8ed1719 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -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