X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/789367e10d91dff77ed0069c4f5079eb7a00db09..9c34a216817028bc533e07873d047208a96b05a2:/include/wx/containr.h?ds=sidebyside diff --git a/include/wx/containr.h b/include/wx/containr.h index 34823cfab3..b465e33c30 100644 --- a/include/wx/containr.h +++ b/include/wx/containr.h @@ -1,84 +1,107 @@ /////////////////////////////////////////////////////////////////////////////// // Name: wx/containr.h -// Purpose: wxControlContainer class declration: a "mix-in" class which -// implements the TAB navigation between the controls +// Purpose: wxControlContainer and wxNavigationEnabled declarations // Author: Vadim Zeitlin // Modified by: // Created: 06.08.01 // RCS-ID: $Id$ -// Copyright: (c) 2001 Vadim Zeitlin +// Copyright: (c) 2001, 2011 Vadim Zeitlin // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// #ifndef _WX_CONTAINR_H_ #define _WX_CONTAINR_H_ -class WXDLLEXPORT wxFocusEvent; -class WXDLLEXPORT wxNavigationKeyEvent; -class WXDLLEXPORT wxWindow; -class WXDLLEXPORT wxWindowBase; +#include "wx/defs.h" + +#ifndef wxHAS_NATIVE_TAB_TRAVERSAL + // We need wxEVT_XXX declarations in this case. + #include "wx/event.h" +#endif + +class WXDLLIMPEXP_FWD_CORE wxWindow; +class WXDLLIMPEXP_FWD_CORE wxWindowBase; /* - Implementation note: wxControlContainer is not a real mix-in but rather - a class meant to be agregated 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. + This header declares wxControlContainer class however it's not a real + container of controls but rather just a helper used to implement TAB + navigation among the window children. You should rarely need to use it + directly, derive from the documented public wxNavigationEnabled<> class to + implement TAB navigation in a custom composite window. */ // ---------------------------------------------------------------------------- -// wxControlContainer +// wxControlContainerBase: common part used in both native and generic cases // ---------------------------------------------------------------------------- -class WXDLLEXPORT wxControlContainer +class WXDLLIMPEXP_CORE 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; - // default item access: we have a permanent default item which is the one - // set by the user code but we may also have a temporary default item which - // would be chosen if the user pressed "Enter" now but the default action - // reverts to the "permanent" default as soon as this temporary default - // item lsoes focus + // By default, we accept focus ourselves. + m_acceptsFocusSelf = true; - // get the default item, temporary or permanent - wxWindow *GetDefaultItem() const - { return m_winTmpDefault ? m_winTmpDefault : m_winDefault; } + // But we don't have any children accepting it yet. + m_acceptsFocusChildren = false; - // set the permanent default item, return its old value - wxWindow *SetDefaultItem(wxWindow *win) - { wxWindow *winOld = m_winDefault; m_winDefault = win; return winOld; } + m_inSetFocus = false; + m_winLastFocused = NULL; + } + virtual ~wxControlContainerBase() {} - // set a temporary default item, SetTmpDefaultItem(NULL) should be called - // soon after a call to SetTmpDefaultItem(window) - void SetTmpDefaultItem(wxWindow *win) { m_winTmpDefault = win; } + void SetContainerWindow(wxWindow *winParent) + { + wxASSERT_MSG( !m_winParent, wxT("shouldn't be called twice") ); - // return the temporary default item, can be NULL - wxWindow *GetTmpDefaultItem() const { return m_winTmpDefault; } + m_winParent = winParent; + } + // This can be called by the window to indicate that it never wants to have + // the focus for itself. + void DisableSelfFocus() + { m_acceptsFocusSelf = false; UpdateParentCanFocus(); } - // the methods to be called from the window event handlers - void HandleOnNavigationKey(wxNavigationKeyEvent& event); - void HandleOnFocus(wxFocusEvent& event); - void HandleOnWindowDestroy(wxWindowBase *child); + // This can be called to undo the effect of a previous DisableSelfFocus() + // (otherwise calling it is not necessary as the window does accept focus + // by default). + void EnableSelfFocus() + { m_acceptsFocusSelf = true; UpdateParentCanFocus(); } // should be called from SetFocus(), returns false if we did nothing with // the focus and the default processing should take place bool DoSetFocus(); - // can our child get the focus? - bool AcceptsFocus() const; + // returns whether we should accept focus ourselves or not + bool AcceptsFocus() const + { return m_acceptsFocusSelf && m_winParent->CanBeFocused(); } - // called from OnChildFocus() handler, i.e. when one of our (grand) - // children gets the focus - void SetLastFocus(wxWindow *win); + // Returns whether we or one of our children accepts focus. + bool AcceptsFocusRecursively() const + { return AcceptsFocus() || + (m_acceptsFocusChildren && HasAnyChildrenAcceptingFocus()); } + + // We accept focus from keyboard if we accept it at all. + bool AcceptsFocusFromKeyboard() const { return AcceptsFocusRecursively(); } + + // Call this when the number of children of the window changes. + // + // Returns true if we have any focusable children, false otherwise. + bool UpdateCanFocusChildren(); protected: // set the focus to the child which had it the last time - bool SetFocusToChild(); + virtual bool SetFocusToChild(); + + // return true if we have any children accepting focus + bool HasAnyFocusableChildren() const; + + // return true if we have any children that do accept focus right now + bool HasAnyChildrenAcceptingFocus() const; + // the parent window we manage the children for wxWindow *m_winParent; @@ -86,44 +109,266 @@ protected: // the child which had the focus last time this panel was activated wxWindow *m_winLastFocused; - // a default window (usually a button) or NULL - wxWindow *m_winDefault; +private: + // Update the window status to reflect whether it is getting focus or not. + void UpdateParentCanFocus(); - // a temporary override of m_winDefault, use the latter if NULL - wxWindow *m_winTmpDefault; + // Indicates whether the associated window can ever have focus itself. + // + // Usually this is the case, e.g. a wxPanel can be used either as a + // container for its children or just as a normal window which can be + // focused. But sometimes, e.g. for wxStaticBox, we can never have focus + // ourselves and can only get it if we have any focusable children. + bool m_acceptsFocusSelf; + + // Cached value remembering whether we have any children accepting focus. + bool m_acceptsFocusChildren; // a guard against infinite recursion bool m_inSetFocus; +}; + +#ifdef wxHAS_NATIVE_TAB_TRAVERSAL + +// ---------------------------------------------------------------------------- +// wxControlContainer for native TAB navigation +// ---------------------------------------------------------------------------- + +// this must be a real class as we forward-declare it elsewhere +class WXDLLIMPEXP_CORE wxControlContainer : public wxControlContainerBase +{ +protected: + // set the focus to the child which had it the last time + virtual bool SetFocusToChild(); +}; + +#else // !wxHAS_NATIVE_TAB_TRAVERSAL + +// ---------------------------------------------------------------------------- +// wxControlContainer for TAB navigation implemented in wx itself +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE 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); + void HandleOnFocus(wxFocusEvent& event); + void HandleOnWindowDestroy(wxWindowBase *child); + + // called from OnChildFocus() handler, i.e. when one of our (grand) + // children gets the focus + void SetLastFocus(wxWindow *win); + +protected: - DECLARE_NO_COPY_CLASS(wxControlContainer) + wxDECLARE_NO_COPY_CLASS(wxControlContainer); }; +#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL + // this function is for wxWidgets internal use only -extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child); +extern WXDLLIMPEXP_CORE bool wxSetFocusToChild(wxWindow *win, wxWindow **child); // ---------------------------------------------------------------------------- -// macros which may be used by the classes wishing to implement TAB navigation -// among their children +// wxNavigationEnabled: Derive from this class to support keyboard navigation +// among window children in a wxWindow-derived class. The details of this class +// don't matter, you just need to derive from it to make navigation work. // ---------------------------------------------------------------------------- -// declare the methods to be forwarded -#define WX_DECLARE_CONTROL_CONTAINER() \ -public: \ - void OnNavigationKey(wxNavigationKeyEvent& event); \ - void OnFocus(wxFocusEvent& event); \ - virtual void OnChildFocus(wxChildFocusEvent& event); \ - virtual void SetFocus(); \ - virtual void SetFocusIgnoringChildren(); \ - virtual void RemoveChild(wxWindowBase *child); \ - virtual wxWindow *GetDefaultItem() const; \ - virtual wxWindow *SetDefaultItem(wxWindow *child); \ - virtual void SetTmpDefaultItem(wxWindow *win); \ - virtual wxWindow *GetTmpDefaultItem() const; \ - virtual bool AcceptsFocus() const; \ -\ -protected: \ +// The template parameter W must be a wxWindow-derived class. +template +class wxNavigationEnabled : public W +{ +public: + typedef W BaseWindowClass; + + wxNavigationEnabled() + { + m_container.SetContainerWindow(this); + +#ifndef wxHAS_NATIVE_TAB_TRAVERSAL + BaseWindowClass::Connect(wxEVT_NAVIGATION_KEY, + wxNavigationKeyEventHandler(wxNavigationEnabled::OnNavigationKey)); + + BaseWindowClass::Connect(wxEVT_SET_FOCUS, + wxFocusEventHandler(wxNavigationEnabled::OnFocus)); + + BaseWindowClass::Connect(wxEVT_CHILD_FOCUS, + wxChildFocusEventHandler(wxNavigationEnabled::OnChildFocus)); +#endif // !wxHAS_NATIVE_TAB_TRAVERSAL + } + + WXDLLIMPEXP_INLINE_CORE virtual bool AcceptsFocus() const + { + return m_container.AcceptsFocus(); + } + + WXDLLIMPEXP_INLINE_CORE virtual bool AcceptsFocusRecursively() const + { + return m_container.AcceptsFocusRecursively(); + } + + WXDLLIMPEXP_INLINE_CORE virtual bool AcceptsFocusFromKeyboard() const + { + return m_container.AcceptsFocusFromKeyboard(); + } + + WXDLLIMPEXP_INLINE_CORE virtual void AddChild(wxWindowBase *child) + { + BaseWindowClass::AddChild(child); + + if ( m_container.UpdateCanFocusChildren() ) + { + // Under MSW we must have wxTAB_TRAVERSAL style for TAB navigation + // to work. + if ( !BaseWindowClass::HasFlag(wxTAB_TRAVERSAL) ) + BaseWindowClass::ToggleWindowStyle(wxTAB_TRAVERSAL); + } + } + + WXDLLIMPEXP_INLINE_CORE virtual void RemoveChild(wxWindowBase *child) + { +#ifndef wxHAS_NATIVE_TAB_TRAVERSAL + m_container.HandleOnWindowDestroy(child); +#endif // !wxHAS_NATIVE_TAB_TRAVERSAL + + BaseWindowClass::RemoveChild(child); + + // We could reset wxTAB_TRAVERSAL here but it doesn't seem to do any + // harm to keep it. + m_container.UpdateCanFocusChildren(); + } + + WXDLLIMPEXP_INLINE_CORE virtual void SetFocus() + { + if ( !m_container.DoSetFocus() ) + BaseWindowClass::SetFocus(); + } + + void SetFocusIgnoringChildren() + { + BaseWindowClass::SetFocus(); + } + +protected: +#ifndef wxHAS_NATIVE_TAB_TRAVERSAL + void OnNavigationKey(wxNavigationKeyEvent& event) + { + m_container.HandleOnNavigationKey(event); + } + + void OnFocus(wxFocusEvent& event) + { + m_container.HandleOnFocus(event); + } + + void OnChildFocus(wxChildFocusEvent& event) + { + m_container.SetLastFocus(event.GetWindow()); + event.Skip(); + } +#endif // !wxHAS_NATIVE_TAB_TRAVERSAL + + wxControlContainer m_container; + + + wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxNavigationEnabled, W); +}; + +// ---------------------------------------------------------------------------- +// Compatibility macros from now on, do NOT use them and preferably do not even +// look at them. +// ---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_8 + +// 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 bool AcceptsFocusRecursively() const; \ + virtual bool AcceptsFocusFromKeyboard() const; \ + virtual void AddChild(wxWindowBase *child); \ + virtual void RemoveChild(wxWindowBase *child); \ + virtual void SetFocus(); \ + void SetFocusIgnoringChildren(); \ + \ +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.UpdateCanFocusChildren(); \ + } \ + \ + bool classname::AcceptsFocusRecursively() const \ + { \ + return m_container.AcceptsFocusRecursively(); \ + } \ + \ + void classname::SetFocus() \ + { \ + if ( !m_container.DoSetFocus() ) \ + basename::SetFocus(); \ + } \ + \ + bool classname::AcceptsFocus() const \ + { \ + return m_container.AcceptsFocus(); \ + } \ + \ + bool classname::AcceptsFocusFromKeyboard() const \ + { \ + return m_container.AcceptsFocusFromKeyboard(); \ + } + + +#ifdef wxHAS_NATIVE_TAB_TRAVERSAL + +#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.UpdateCanFocusChildren(); \ + } \ + \ + void classname::SetFocusIgnoringChildren() \ + { \ + basename::SetFocus(); \ + } + +#else // !wxHAS_NATIVE_TAB_TRAVERSAL + +// declare the methods to be forwarded +#define WX_DECLARE_CONTROL_CONTAINER() \ + WX_DECLARE_CONTROL_CONTAINER_BASE(); \ + \ +public: \ + void OnNavigationKey(wxNavigationKeyEvent& event); \ + void OnFocus(wxFocusEvent& event); \ + virtual void OnChildFocus(wxChildFocusEvent& event) + // implement the event table entries for wxControlContainer #define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \ EVT_SET_FOCUS(classname::OnFocus) \ @@ -131,63 +376,41 @@ protected: \ EVT_NAVIGATION_KEY(classname::OnNavigationKey) // implement the methods forwarding to the wxControlContainer -#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname) \ -wxWindow *classname::SetDefaultItem(wxWindow *child) \ -{ \ - return m_container.SetDefaultItem(child); \ -} \ - \ -void classname::SetTmpDefaultItem(wxWindow *child) \ -{ \ - m_container.SetTmpDefaultItem(child); \ -} \ - \ -wxWindow *classname::GetDefaultItem() const \ -{ \ - return m_container.GetDefaultItem(); \ -} \ - \ -wxWindow *classname::GetTmpDefaultItem() const \ -{ \ - return m_container.GetTmpDefaultItem(); \ -} \ - \ -void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \ -{ \ - m_container.HandleOnNavigationKey(event); \ -} \ - \ -void classname::RemoveChild(wxWindowBase *child) \ -{ \ - m_container.HandleOnWindowDestroy(child); \ - \ - wxWindow::RemoveChild(child); \ -} \ - \ -void classname::SetFocus() \ -{ \ - if ( !m_container.DoSetFocus() ) \ - wxWindow::SetFocus(); \ -} \ - \ -void classname::SetFocusIgnoringChildren() \ -{ \ - wxWindow::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.UpdateCanFocusChildren(); \ + } \ + \ + void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \ + { \ + m_container.HandleOnNavigationKey(event); \ + } \ + \ + void classname::SetFocusIgnoringChildren() \ + { \ + basename::SetFocus(); \ + } \ + \ + void classname::OnChildFocus(wxChildFocusEvent& event) \ + { \ + m_container.SetLastFocus(event.GetWindow()); \ + event.Skip(); \ + } \ + \ + void classname::OnFocus(wxFocusEvent& event) \ + { \ + m_container.HandleOnFocus(event); \ + } + +#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL +#endif // WXWIN_COMPATIBILITY_2_8 #endif // _WX_CONTAINR_H_