#include "wx/defs.h"
+/*
+ Implementation note: wxControlContainer is not a real mix-in but rather
+ a class meant to be aggregated with (and not inherited from). Although
+ logically it should be a mix-in, doing it like this has no advantage from
+ the point of view of the existing code but does have some problems (we'd
+ need to play tricks with event handlers which may be difficult to do
+ safely). The price we pay for this simplicity is the ugly macros below.
+ */
+
+// ----------------------------------------------------------------------------
+// wxControlContainerBase: common part used in both native and generic cases
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxControlContainerBase
+{
+public:
+ // 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
-#define WX_DECLARE_CONTROL_CONTAINER() \
- virtual bool AcceptsFocus() const { return false; } \
- void SetFocusIgnoringChildren() { SetFocus(); }
+// ----------------------------------------------------------------------------
+// wxControlContainer for native TAB navigation
+// ----------------------------------------------------------------------------
+
+// this must be a real class as we forward-declare it elsewhere
+class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
+{
+};
-#define WX_INIT_CONTROL_CONTAINER()
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname)
-#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename)
+
+#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 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
- logically it should be a mix-in, doing it like this has no advantage from
- the point of view of the existing code but does have some problems (we'd
- need to play tricks with event handlers which may be difficult to do
- safely). The price we pay for this simplicity is the ugly macros below.
- */
-
// ----------------------------------------------------------------------------
-// wxControlContainer
+// wxControlContainer for TAB navigation implemented in wx itself
// ----------------------------------------------------------------------------
-class WXDLLEXPORT wxControlContainer
+class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
{
public:
- // ctors and such
- wxControlContainer(wxWindow *winParent = NULL);
- void SetContainerWindow(wxWindow *winParent) { m_winParent = winParent; }
+ // default ctor, SetContainerWindow() must be called later
+ wxControlContainer();
// the methods to be called from the window event handlers
void HandleOnNavigationKey(wxNavigationKeyEvent& event);
// 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;
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) \
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
#include "wx/containr.h"
#endif
-#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
-
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/event.h"
// 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
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();
#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)