]> git.saurik.com Git - wxWidgets.git/commitdiff
make wxControlContainer accept focus depending on whether it has any focusable childr...
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 5 Apr 2007 22:29:14 +0000 (22:29 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 5 Apr 2007 22:29:14 +0000 (22:29 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45267 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/containr.h
include/wx/gtk/window.h
include/wx/window.h
src/common/containr.cpp
src/gtk/window.cpp

index 551c7c63f1aca18cd1b2cc1fa642311f8f07be8f..e44b507a33a40f30f8161d0a4c7e81f8c0d06a4f 100644 (file)
 
 #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
 
@@ -32,25 +143,15 @@ 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
-   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);
@@ -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
 
index 82b9f99d8cc8f1b6728c8cb89a46a5eb5b4552cf..2646c5c4bf8946f2fdfab6392ee7017c9174af60 100644 (file)
@@ -68,6 +68,7 @@ public:
     virtual bool IsRetained() const;
 
     virtual void SetFocus();
+    virtual void SetCanFocus(bool canFocus);
 
     virtual bool Reparent( wxWindowBase *newParent );
 
index 2dde62f41fe18e06dd5d7fd6dcc4113be83618c0..4c62a7d035ed58a1e3ae65e07469265efc24e722 100644 (file)
@@ -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); }
index 84be03d1462d980da5ad0ac0434d8519fd6ac7a2..bbc5d48b6186a8c10c545a7b5ccc97d40da628b6 100644 (file)
@@ -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"
 // 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)
index 83368e7c24c7dd45a54062aefd59e406a50f16cb..731161383936942929852d8835e025bfde42ba15 100644 (file)
@@ -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") );