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"
|
||||
|
||||
#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
|
||||
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:
|
||||
// ctors and such
|
||||
wxControlContainer(wxWindow *winParent = NULL);
|
||||
void SetContainerWindow(wxWindow *winParent) { m_winParent = winParent; }
|
||||
// default ctor, SetContainerWindow() must be called later
|
||||
wxControlContainerBase()
|
||||
{
|
||||
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
|
||||
void HandleOnNavigationKey(wxNavigationKeyEvent& event);
|
||||
@@ -72,9 +173,6 @@ protected:
|
||||
// set the focus to the child which had it the last time
|
||||
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
|
||||
wxWindow *m_winLastFocused;
|
||||
|
||||
@@ -97,19 +195,15 @@ extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
|
||||
public: \
|
||||
void OnNavigationKey(wxNavigationKeyEvent& event); \
|
||||
void OnFocus(wxFocusEvent& event); \
|
||||
void SetFocusIgnoringChildren(); \
|
||||
virtual void OnChildFocus(wxChildFocusEvent& event); \
|
||||
virtual void SetFocus(); \
|
||||
virtual void SetFocusIgnoringChildren(); \
|
||||
virtual void RemoveChild(wxWindowBase *child); \
|
||||
virtual bool AcceptsFocus() const; \
|
||||
\
|
||||
protected: \
|
||||
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
|
||||
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
|
||||
EVT_SET_FOCUS(classname::OnFocus) \
|
||||
@@ -117,43 +211,43 @@ protected: \
|
||||
EVT_NAVIGATION_KEY(classname::OnNavigationKey)
|
||||
|
||||
// implement the methods forwarding to the wxControlContainer
|
||||
#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
|
||||
void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \
|
||||
{ \
|
||||
m_container.HandleOnNavigationKey(event); \
|
||||
} \
|
||||
\
|
||||
void classname::RemoveChild(wxWindowBase *child) \
|
||||
{ \
|
||||
m_container.HandleOnWindowDestroy(child); \
|
||||
\
|
||||
basename::RemoveChild(child); \
|
||||
} \
|
||||
\
|
||||
void classname::SetFocus() \
|
||||
{ \
|
||||
if ( !m_container.DoSetFocus() ) \
|
||||
basename::SetFocus(); \
|
||||
} \
|
||||
\
|
||||
void classname::SetFocusIgnoringChildren() \
|
||||
{ \
|
||||
basename::SetFocus(); \
|
||||
} \
|
||||
\
|
||||
void classname::OnChildFocus(wxChildFocusEvent& event) \
|
||||
{ \
|
||||
m_container.SetLastFocus(event.GetWindow()); \
|
||||
} \
|
||||
\
|
||||
void classname::OnFocus(wxFocusEvent& event) \
|
||||
{ \
|
||||
m_container.HandleOnFocus(event); \
|
||||
} \
|
||||
bool classname::AcceptsFocus() const \
|
||||
{ \
|
||||
return m_container.AcceptsFocus(); \
|
||||
}
|
||||
#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
|
||||
WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
|
||||
\
|
||||
void classname::RemoveChild(wxWindowBase *child) \
|
||||
{ \
|
||||
m_container.HandleOnWindowDestroy(child); \
|
||||
\
|
||||
basename::RemoveChild(child); \
|
||||
\
|
||||
m_container.UpdateCanFocus(); \
|
||||
} \
|
||||
\
|
||||
void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \
|
||||
{ \
|
||||
m_container.HandleOnNavigationKey(event); \
|
||||
} \
|
||||
\
|
||||
void classname::SetFocus() \
|
||||
{ \
|
||||
if ( !m_container.DoSetFocus() ) \
|
||||
basename::SetFocus(); \
|
||||
} \
|
||||
\
|
||||
void classname::SetFocusIgnoringChildren() \
|
||||
{ \
|
||||
basename::SetFocus(); \
|
||||
} \
|
||||
\
|
||||
void classname::OnChildFocus(wxChildFocusEvent& event) \
|
||||
{ \
|
||||
m_container.SetLastFocus(event.GetWindow()); \
|
||||
} \
|
||||
\
|
||||
void classname::OnFocus(wxFocusEvent& event) \
|
||||
{ \
|
||||
m_container.HandleOnFocus(event); \
|
||||
}
|
||||
|
||||
#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
|
||||
|
||||
|
@@ -68,6 +68,7 @@ public:
|
||||
virtual bool IsRetained() const;
|
||||
|
||||
virtual void SetFocus();
|
||||
virtual void SetCanFocus(bool canFocus);
|
||||
|
||||
virtual bool Reparent( wxWindowBase *newParent );
|
||||
|
||||
|
@@ -592,6 +592,9 @@ public:
|
||||
bool CanAcceptFocusFromKeyboard() const
|
||||
{ return AcceptsFocusFromKeyboard() && CanAcceptFocus(); }
|
||||
|
||||
// call this when the return value of AcceptsFocus() changes
|
||||
virtual void SetCanFocus(bool WXUNUSED(canFocus)) { }
|
||||
|
||||
// navigates inside this window
|
||||
bool NavigateIn(int flags = wxNavigationKeyEvent::IsForward)
|
||||
{ return DoNavigateIn(flags); }
|
||||
|
@@ -28,8 +28,6 @@
|
||||
#include "wx/containr.h"
|
||||
#endif
|
||||
|
||||
#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/log.h"
|
||||
#include "wx/event.h"
|
||||
@@ -45,14 +43,25 @@
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
wxControlContainer::wxControlContainer(wxWindow *winParent)
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxControlContainerBase
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxControlContainerBase::SetCanFocus(bool acceptsFocus)
|
||||
{
|
||||
m_winParent = winParent;
|
||||
m_winLastFocused = NULL;
|
||||
m_inSetFocus = false;
|
||||
if ( acceptsFocus == m_acceptsFocus )
|
||||
return;
|
||||
|
||||
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're probably not used as a container) or only when at least one child
|
||||
@@ -61,12 +70,6 @@ bool wxControlContainer::AcceptsFocus() const
|
||||
if ( !node )
|
||||
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 )
|
||||
{
|
||||
wxWindow *child = node->GetData();
|
||||
@@ -75,20 +78,25 @@ bool wxControlContainer::AcceptsFocus() const
|
||||
#ifdef __WXMAC__
|
||||
if ( m_winParent->MacIsWindowScrollbar( child ) )
|
||||
continue;
|
||||
hasRealChildren = true ;
|
||||
#endif
|
||||
|
||||
if ( child->CanAcceptFocus() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __WXMAC__
|
||||
if ( !hasRealChildren )
|
||||
return true ;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// generic wxControlContainer
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxControlContainer::wxControlContainer()
|
||||
{
|
||||
m_winLastFocused = NULL;
|
||||
m_inSetFocus = false;
|
||||
}
|
||||
|
||||
void wxControlContainer::SetLastFocus(wxWindow *win)
|
||||
|
@@ -2532,9 +2532,7 @@ void wxWindowGTK::PostCreation()
|
||||
|
||||
if ( !AcceptsFocusFromKeyboard() )
|
||||
{
|
||||
GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
|
||||
if (m_wxwindow && (m_widget != m_wxwindow))
|
||||
GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
|
||||
SetCanFocus(false);
|
||||
|
||||
g_signal_connect(m_widget, "focus",
|
||||
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 )
|
||||
{
|
||||
wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
|
||||
|
Reference in New Issue
Block a user