make wxControlContainer accept focus depending on whether it has any focusable children when using native TAB navigation too but also allow to manually override this automatic detection; added wxWindow::SetCanFocus() to notify GTK+ about changed focus state
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45267 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -15,23 +15,6 @@
|
|||||||
|
|
||||||
#include "wx/defs.h"
|
#include "wx/defs.h"
|
||||||
|
|
||||||
#ifdef wxHAS_NATIVE_TAB_TRAVERSAL
|
|
||||||
|
|
||||||
#define WX_DECLARE_CONTROL_CONTAINER() \
|
|
||||||
virtual bool AcceptsFocus() const { return false; } \
|
|
||||||
void SetFocusIgnoringChildren() { SetFocus(); }
|
|
||||||
|
|
||||||
#define WX_INIT_CONTROL_CONTAINER()
|
|
||||||
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname)
|
|
||||||
#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename)
|
|
||||||
|
|
||||||
#else // !wxHAS_NATIVE_TAB_TRAVERSAL
|
|
||||||
|
|
||||||
class WXDLLEXPORT wxFocusEvent;
|
|
||||||
class WXDLLEXPORT wxNavigationKeyEvent;
|
|
||||||
class WXDLLEXPORT wxWindow;
|
|
||||||
class WXDLLEXPORT wxWindowBase;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Implementation note: wxControlContainer is not a real mix-in but rather
|
Implementation note: wxControlContainer is not a real mix-in but rather
|
||||||
a class meant to be aggregated with (and not inherited from). Although
|
a class meant to be aggregated with (and not inherited from). Although
|
||||||
@@ -42,15 +25,133 @@ class WXDLLEXPORT wxWindowBase;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxControlContainer
|
// wxControlContainerBase: common part used in both native and generic cases
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
class WXDLLEXPORT wxControlContainer
|
class WXDLLEXPORT wxControlContainerBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// ctors and such
|
// default ctor, SetContainerWindow() must be called later
|
||||||
wxControlContainer(wxWindow *winParent = NULL);
|
wxControlContainerBase()
|
||||||
void SetContainerWindow(wxWindow *winParent) { m_winParent = winParent; }
|
{
|
||||||
|
m_winParent = NULL;
|
||||||
|
|
||||||
|
// do accept focus initially, we'll stop doing it if/when any children
|
||||||
|
// are added
|
||||||
|
m_acceptsFocus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetContainerWindow(wxWindow *winParent)
|
||||||
|
{
|
||||||
|
wxASSERT_MSG( !m_winParent, _T("shouldn't be called twice") );
|
||||||
|
|
||||||
|
m_winParent = winParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should be called when we decide that we should [stop] accepting focus
|
||||||
|
void SetCanFocus(bool acceptsFocus);
|
||||||
|
|
||||||
|
// returns whether we should accept focus ourselves or not
|
||||||
|
bool AcceptsFocus() const { return m_acceptsFocus; }
|
||||||
|
|
||||||
|
// call this when the number of children of the window changes
|
||||||
|
void UpdateCanFocus() { SetCanFocus(ShouldAcceptFocus()); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// return true if we should be focusable
|
||||||
|
bool ShouldAcceptFocus() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// the parent window we manage the children for
|
||||||
|
wxWindow *m_winParent;
|
||||||
|
|
||||||
|
// value returned by AcceptsFocus(), should be changed using SetCanFocus()
|
||||||
|
// only
|
||||||
|
bool m_acceptsFocus;
|
||||||
|
};
|
||||||
|
|
||||||
|
// common part of WX_DECLARE_CONTROL_CONTAINER in the native and generic cases,
|
||||||
|
// it should be used in the wxWindow-derived class declaration
|
||||||
|
#define WX_DECLARE_CONTROL_CONTAINER_BASE() \
|
||||||
|
public: \
|
||||||
|
virtual bool AcceptsFocus() const; \
|
||||||
|
virtual void AddChild(wxWindowBase *child); \
|
||||||
|
virtual void RemoveChild(wxWindowBase *child); \
|
||||||
|
void SetFocusIgnoringChildren(); \
|
||||||
|
void AcceptFocus(bool acceptFocus) \
|
||||||
|
{ \
|
||||||
|
m_container.SetCanFocus(acceptFocus); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
protected: \
|
||||||
|
wxControlContainer m_container
|
||||||
|
|
||||||
|
// this macro must be used in the derived class ctor
|
||||||
|
#define WX_INIT_CONTROL_CONTAINER() \
|
||||||
|
m_container.SetContainerWindow(this)
|
||||||
|
|
||||||
|
// common part of WX_DELEGATE_TO_CONTROL_CONTAINER in the native and generic
|
||||||
|
// cases, must be used in the wxWindow-derived class implementation
|
||||||
|
#define WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
|
||||||
|
void classname::AddChild(wxWindowBase *child) \
|
||||||
|
{ \
|
||||||
|
basename::AddChild(child); \
|
||||||
|
\
|
||||||
|
m_container.UpdateCanFocus(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool classname::AcceptsFocus() const \
|
||||||
|
{ \
|
||||||
|
return m_container.AcceptsFocus(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef wxHAS_NATIVE_TAB_TRAVERSAL
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxControlContainer for native TAB navigation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// this must be a real class as we forward-declare it elsewhere
|
||||||
|
class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname)
|
||||||
|
|
||||||
|
#define WX_DECLARE_CONTROL_CONTAINER WX_DECLARE_CONTROL_CONTAINER_BASE
|
||||||
|
|
||||||
|
#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
|
||||||
|
WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
|
||||||
|
\
|
||||||
|
void classname::RemoveChild(wxWindowBase *child) \
|
||||||
|
{ \
|
||||||
|
basename::RemoveChild(child); \
|
||||||
|
\
|
||||||
|
m_container.UpdateCanFocus(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void classname::SetFocusIgnoringChildren() \
|
||||||
|
{ \
|
||||||
|
SetFocus(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !wxHAS_NATIVE_TAB_TRAVERSAL
|
||||||
|
|
||||||
|
class WXDLLEXPORT wxFocusEvent;
|
||||||
|
class WXDLLEXPORT wxNavigationKeyEvent;
|
||||||
|
class WXDLLEXPORT wxWindow;
|
||||||
|
class WXDLLEXPORT wxWindowBase;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxControlContainer for TAB navigation implemented in wx itself
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// default ctor, SetContainerWindow() must be called later
|
||||||
|
wxControlContainer();
|
||||||
|
|
||||||
// the methods to be called from the window event handlers
|
// the methods to be called from the window event handlers
|
||||||
void HandleOnNavigationKey(wxNavigationKeyEvent& event);
|
void HandleOnNavigationKey(wxNavigationKeyEvent& event);
|
||||||
@@ -72,9 +173,6 @@ protected:
|
|||||||
// set the focus to the child which had it the last time
|
// set the focus to the child which had it the last time
|
||||||
bool SetFocusToChild();
|
bool SetFocusToChild();
|
||||||
|
|
||||||
// the parent window we manage the children for
|
|
||||||
wxWindow *m_winParent;
|
|
||||||
|
|
||||||
// the child which had the focus last time this panel was activated
|
// the child which had the focus last time this panel was activated
|
||||||
wxWindow *m_winLastFocused;
|
wxWindow *m_winLastFocused;
|
||||||
|
|
||||||
@@ -97,19 +195,15 @@ extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
|
|||||||
public: \
|
public: \
|
||||||
void OnNavigationKey(wxNavigationKeyEvent& event); \
|
void OnNavigationKey(wxNavigationKeyEvent& event); \
|
||||||
void OnFocus(wxFocusEvent& event); \
|
void OnFocus(wxFocusEvent& event); \
|
||||||
|
void SetFocusIgnoringChildren(); \
|
||||||
virtual void OnChildFocus(wxChildFocusEvent& event); \
|
virtual void OnChildFocus(wxChildFocusEvent& event); \
|
||||||
virtual void SetFocus(); \
|
virtual void SetFocus(); \
|
||||||
virtual void SetFocusIgnoringChildren(); \
|
|
||||||
virtual void RemoveChild(wxWindowBase *child); \
|
virtual void RemoveChild(wxWindowBase *child); \
|
||||||
virtual bool AcceptsFocus() const; \
|
virtual bool AcceptsFocus() const; \
|
||||||
\
|
\
|
||||||
protected: \
|
protected: \
|
||||||
wxControlContainer m_container
|
wxControlContainer m_container
|
||||||
|
|
||||||
// this macro must be used in the derived class ctor
|
|
||||||
#define WX_INIT_CONTROL_CONTAINER() \
|
|
||||||
m_container.SetContainerWindow(this)
|
|
||||||
|
|
||||||
// implement the event table entries for wxControlContainer
|
// implement the event table entries for wxControlContainer
|
||||||
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
|
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
|
||||||
EVT_SET_FOCUS(classname::OnFocus) \
|
EVT_SET_FOCUS(classname::OnFocus) \
|
||||||
@@ -117,43 +211,43 @@ protected: \
|
|||||||
EVT_NAVIGATION_KEY(classname::OnNavigationKey)
|
EVT_NAVIGATION_KEY(classname::OnNavigationKey)
|
||||||
|
|
||||||
// implement the methods forwarding to the wxControlContainer
|
// implement the methods forwarding to the wxControlContainer
|
||||||
#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
|
#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
|
||||||
void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \
|
WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
|
||||||
{ \
|
\
|
||||||
m_container.HandleOnNavigationKey(event); \
|
void classname::RemoveChild(wxWindowBase *child) \
|
||||||
} \
|
{ \
|
||||||
\
|
m_container.HandleOnWindowDestroy(child); \
|
||||||
void classname::RemoveChild(wxWindowBase *child) \
|
\
|
||||||
{ \
|
basename::RemoveChild(child); \
|
||||||
m_container.HandleOnWindowDestroy(child); \
|
\
|
||||||
\
|
m_container.UpdateCanFocus(); \
|
||||||
basename::RemoveChild(child); \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \
|
||||||
void classname::SetFocus() \
|
{ \
|
||||||
{ \
|
m_container.HandleOnNavigationKey(event); \
|
||||||
if ( !m_container.DoSetFocus() ) \
|
} \
|
||||||
basename::SetFocus(); \
|
\
|
||||||
} \
|
void classname::SetFocus() \
|
||||||
\
|
{ \
|
||||||
void classname::SetFocusIgnoringChildren() \
|
if ( !m_container.DoSetFocus() ) \
|
||||||
{ \
|
basename::SetFocus(); \
|
||||||
basename::SetFocus(); \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
void classname::SetFocusIgnoringChildren() \
|
||||||
void classname::OnChildFocus(wxChildFocusEvent& event) \
|
{ \
|
||||||
{ \
|
basename::SetFocus(); \
|
||||||
m_container.SetLastFocus(event.GetWindow()); \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
void classname::OnChildFocus(wxChildFocusEvent& event) \
|
||||||
void classname::OnFocus(wxFocusEvent& event) \
|
{ \
|
||||||
{ \
|
m_container.SetLastFocus(event.GetWindow()); \
|
||||||
m_container.HandleOnFocus(event); \
|
} \
|
||||||
} \
|
\
|
||||||
bool classname::AcceptsFocus() const \
|
void classname::OnFocus(wxFocusEvent& event) \
|
||||||
{ \
|
{ \
|
||||||
return m_container.AcceptsFocus(); \
|
m_container.HandleOnFocus(event); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
|
#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
|
||||||
|
|
||||||
|
@@ -68,6 +68,7 @@ public:
|
|||||||
virtual bool IsRetained() const;
|
virtual bool IsRetained() const;
|
||||||
|
|
||||||
virtual void SetFocus();
|
virtual void SetFocus();
|
||||||
|
virtual void SetCanFocus(bool canFocus);
|
||||||
|
|
||||||
virtual bool Reparent( wxWindowBase *newParent );
|
virtual bool Reparent( wxWindowBase *newParent );
|
||||||
|
|
||||||
|
@@ -592,6 +592,9 @@ public:
|
|||||||
bool CanAcceptFocusFromKeyboard() const
|
bool CanAcceptFocusFromKeyboard() const
|
||||||
{ return AcceptsFocusFromKeyboard() && CanAcceptFocus(); }
|
{ return AcceptsFocusFromKeyboard() && CanAcceptFocus(); }
|
||||||
|
|
||||||
|
// call this when the return value of AcceptsFocus() changes
|
||||||
|
virtual void SetCanFocus(bool WXUNUSED(canFocus)) { }
|
||||||
|
|
||||||
// navigates inside this window
|
// navigates inside this window
|
||||||
bool NavigateIn(int flags = wxNavigationKeyEvent::IsForward)
|
bool NavigateIn(int flags = wxNavigationKeyEvent::IsForward)
|
||||||
{ return DoNavigateIn(flags); }
|
{ return DoNavigateIn(flags); }
|
||||||
|
@@ -28,8 +28,6 @@
|
|||||||
#include "wx/containr.h"
|
#include "wx/containr.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
|
|
||||||
|
|
||||||
#ifndef WX_PRECOMP
|
#ifndef WX_PRECOMP
|
||||||
#include "wx/log.h"
|
#include "wx/log.h"
|
||||||
#include "wx/event.h"
|
#include "wx/event.h"
|
||||||
@@ -45,14 +43,25 @@
|
|||||||
// implementation
|
// implementation
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
wxControlContainer::wxControlContainer(wxWindow *winParent)
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxControlContainerBase
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void wxControlContainerBase::SetCanFocus(bool acceptsFocus)
|
||||||
{
|
{
|
||||||
m_winParent = winParent;
|
if ( acceptsFocus == m_acceptsFocus )
|
||||||
m_winLastFocused = NULL;
|
return;
|
||||||
m_inSetFocus = false;
|
|
||||||
|
m_acceptsFocus = acceptsFocus;
|
||||||
|
|
||||||
|
m_winParent->SetCanFocus(m_acceptsFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxControlContainer::AcceptsFocus() const
|
// if the window has a focusable child, it shouldn't be focusable itself (think
|
||||||
|
// of wxPanel used for grouping different controls) but if it doesn't have any
|
||||||
|
// (focusable) children, then it should be possible to give it focus (think of
|
||||||
|
// wxGrid or generic wxListCtrl)
|
||||||
|
bool wxControlContainerBase::ShouldAcceptFocus() const
|
||||||
{
|
{
|
||||||
// we can accept focus either if we have no children at all (in this case
|
// we can accept focus either if we have no children at all (in this case
|
||||||
// we're probably not used as a container) or only when at least one child
|
// we're probably not used as a container) or only when at least one child
|
||||||
@@ -61,12 +70,6 @@ bool wxControlContainer::AcceptsFocus() const
|
|||||||
if ( !node )
|
if ( !node )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#ifdef __WXMAC__
|
|
||||||
// wxMac has eventually the two scrollbars as children, they don't count
|
|
||||||
// as real children in the algorithm mentioned above
|
|
||||||
bool hasRealChildren = false ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while ( node )
|
while ( node )
|
||||||
{
|
{
|
||||||
wxWindow *child = node->GetData();
|
wxWindow *child = node->GetData();
|
||||||
@@ -75,20 +78,25 @@ bool wxControlContainer::AcceptsFocus() const
|
|||||||
#ifdef __WXMAC__
|
#ifdef __WXMAC__
|
||||||
if ( m_winParent->MacIsWindowScrollbar( child ) )
|
if ( m_winParent->MacIsWindowScrollbar( child ) )
|
||||||
continue;
|
continue;
|
||||||
hasRealChildren = true ;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( child->CanAcceptFocus() )
|
if ( child->CanAcceptFocus() )
|
||||||
{
|
return false;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __WXMAC__
|
return true;
|
||||||
if ( !hasRealChildren )
|
}
|
||||||
return true ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// generic wxControlContainer
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
wxControlContainer::wxControlContainer()
|
||||||
|
{
|
||||||
|
m_winLastFocused = NULL;
|
||||||
|
m_inSetFocus = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxControlContainer::SetLastFocus(wxWindow *win)
|
void wxControlContainer::SetLastFocus(wxWindow *win)
|
||||||
|
@@ -2532,9 +2532,7 @@ void wxWindowGTK::PostCreation()
|
|||||||
|
|
||||||
if ( !AcceptsFocusFromKeyboard() )
|
if ( !AcceptsFocusFromKeyboard() )
|
||||||
{
|
{
|
||||||
GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
|
SetCanFocus(false);
|
||||||
if (m_wxwindow && (m_widget != m_wxwindow))
|
|
||||||
GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
|
|
||||||
|
|
||||||
g_signal_connect(m_widget, "focus",
|
g_signal_connect(m_widget, "focus",
|
||||||
G_CALLBACK(wx_window_focus_callback), this);
|
G_CALLBACK(wx_window_focus_callback), this);
|
||||||
@@ -3242,6 +3240,22 @@ void wxWindowGTK::SetFocus()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxWindowGTK::SetCanFocus(bool canFocus)
|
||||||
|
{
|
||||||
|
if ( canFocus )
|
||||||
|
GTK_WIDGET_SET_FLAGS(m_widget, GTK_CAN_FOCUS);
|
||||||
|
else
|
||||||
|
GTK_WIDGET_UNSET_FLAGS(m_widget, GTK_CAN_FOCUS);
|
||||||
|
|
||||||
|
if ( m_wxwindow && (m_widget != m_wxwindow) )
|
||||||
|
{
|
||||||
|
if ( canFocus )
|
||||||
|
GTK_WIDGET_SET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
|
||||||
|
else
|
||||||
|
GTK_WIDGET_UNSET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
|
bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
|
||||||
{
|
{
|
||||||
wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
|
wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
|
||||||
|
Reference in New Issue
Block a user