A number of focus handling improvements:
[wxWidgets.git] / include / wx / containr.h
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: wx/containr.h
3 // Purpose: wxControlContainer class declration: a "mix-in" class which
4 // implements the TAB navigation between the controls
5 // Author: Vadim Zeitlin
6 // Modified by:
7 // Created: 06.08.01
8 // RCS-ID: $Id$
9 // Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10 // Licence: wxWindows licence
11 ///////////////////////////////////////////////////////////////////////////////
12
13 #ifndef _WX_CONTAINR_H_
14 #define _WX_CONTAINR_H_
15
16 #include "wx/defs.h"
17
18 class WXDLLIMPEXP_FWD_CORE wxWindow;
19 class WXDLLIMPEXP_FWD_CORE wxWindowBase;
20
21 /*
22 Implementation note: wxControlContainer is not a real mix-in but rather
23 a class meant to be aggregated with (and not inherited from). Although
24 logically it should be a mix-in, doing it like this has no advantage from
25 the point of view of the existing code but does have some problems (we'd
26 need to play tricks with event handlers which may be difficult to do
27 safely). The price we pay for this simplicity is the ugly macros below.
28 */
29
30 // ----------------------------------------------------------------------------
31 // wxControlContainerBase: common part used in both native and generic cases
32 // ----------------------------------------------------------------------------
33
34 class WXDLLEXPORT wxControlContainerBase
35 {
36 public:
37 // default ctor, SetContainerWindow() must be called later
38 wxControlContainerBase()
39 {
40 m_winParent = NULL;
41
42 // do accept focus initially, we'll stop doing it if/when any children
43 // are added
44 m_acceptsFocus = true;
45 m_inSetFocus = false;
46 m_winLastFocused = NULL;
47 }
48 virtual ~wxControlContainerBase() {}
49
50 void SetContainerWindow(wxWindow *winParent)
51 {
52 wxASSERT_MSG( !m_winParent, _T("shouldn't be called twice") );
53
54 m_winParent = winParent;
55 }
56
57 // should be called from SetFocus(), returns false if we did nothing with
58 // the focus and the default processing should take place
59 bool DoSetFocus();
60
61 // should be called when we decide that we should [stop] accepting focus
62 void SetCanFocus(bool acceptsFocus);
63
64 // returns whether we should accept focus ourselves or not
65 bool AcceptsFocus() const { return m_acceptsFocus; }
66
67 // returns whether we or one of our children accepts focus: we always do
68 // because if we don't have any focusable children it probably means that
69 // we're not being used as a container at all (think of wxGrid or generic
70 // wxListCtrl) and so should get focus for ourselves
71 bool AcceptsFocusRecursively() const { return true; }
72
73 // call this when the number of children of the window changes
74 //
75 // note that we have any children, this panel (used just as container for
76 // them) shouldn't get focus for itself
77 void UpdateCanFocus() { SetCanFocus(!HasAnyFocusableChildren()); }
78
79 protected:
80 // set the focus to the child which had it the last time
81 virtual bool SetFocusToChild();
82
83 // return true if we have any children accepting focus
84 bool HasAnyFocusableChildren() const;
85
86 // the parent window we manage the children for
87 wxWindow *m_winParent;
88
89 private:
90 // value returned by AcceptsFocus(), should be changed using SetCanFocus()
91 // only
92 bool m_acceptsFocus;
93
94 // a guard against infinite recursion
95 bool m_inSetFocus;
96
97 // the child which had the focus last time this panel was activated
98 wxWindow *m_winLastFocused;
99
100 };
101
102 // common part of WX_DECLARE_CONTROL_CONTAINER in the native and generic cases,
103 // it should be used in the wxWindow-derived class declaration
104 #define WX_DECLARE_CONTROL_CONTAINER_BASE() \
105 public: \
106 virtual bool AcceptsFocus() const; \
107 virtual bool AcceptsFocusRecursively() const; \
108 virtual void AddChild(wxWindowBase *child); \
109 virtual void RemoveChild(wxWindowBase *child); \
110 virtual void SetFocus(); \
111 void SetFocusIgnoringChildren(); \
112 void AcceptFocus(bool acceptFocus) \
113 { \
114 m_container.SetCanFocus(acceptFocus); \
115 } \
116 \
117 protected: \
118 wxControlContainer m_container
119
120 // this macro must be used in the derived class ctor
121 #define WX_INIT_CONTROL_CONTAINER() \
122 m_container.SetContainerWindow(this)
123
124 // common part of WX_DELEGATE_TO_CONTROL_CONTAINER in the native and generic
125 // cases, must be used in the wxWindow-derived class implementation
126 #define WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
127 void classname::AddChild(wxWindowBase *child) \
128 { \
129 basename::AddChild(child); \
130 \
131 m_container.UpdateCanFocus(); \
132 } \
133 \
134 bool classname::AcceptsFocusRecursively() const \
135 { \
136 return m_container.AcceptsFocusRecursively(); \
137 } \
138 \
139 void classname::SetFocus() \
140 { \
141 if ( !m_container.DoSetFocus() ) \
142 basename::SetFocus(); \
143 } \
144 \
145 bool classname::AcceptsFocus() const \
146 { \
147 return m_container.AcceptsFocus(); \
148 }
149
150
151 #ifdef wxHAS_NATIVE_TAB_TRAVERSAL
152
153 // ----------------------------------------------------------------------------
154 // wxControlContainer for native TAB navigation
155 // ----------------------------------------------------------------------------
156
157 // this must be a real class as we forward-declare it elsewhere
158 class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
159 {
160 protected:
161 // set the focus to the child which had it the last time
162 virtual bool SetFocusToChild();
163 };
164
165 #define WX_EVENT_TABLE_CONTROL_CONTAINER(classname)
166
167 #define WX_DECLARE_CONTROL_CONTAINER WX_DECLARE_CONTROL_CONTAINER_BASE
168
169 #define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
170 WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
171 \
172 void classname::RemoveChild(wxWindowBase *child) \
173 { \
174 basename::RemoveChild(child); \
175 \
176 m_container.UpdateCanFocus(); \
177 } \
178 \
179 void classname::SetFocusIgnoringChildren() \
180 { \
181 SetFocus(); \
182 }
183
184 #else // !wxHAS_NATIVE_TAB_TRAVERSAL
185
186 class WXDLLIMPEXP_FWD_CORE wxFocusEvent;
187 class WXDLLIMPEXP_FWD_CORE wxNavigationKeyEvent;
188
189 // ----------------------------------------------------------------------------
190 // wxControlContainer for TAB navigation implemented in wx itself
191 // ----------------------------------------------------------------------------
192
193 class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
194 {
195 public:
196 // default ctor, SetContainerWindow() must be called later
197 wxControlContainer();
198
199 // the methods to be called from the window event handlers
200 void HandleOnNavigationKey(wxNavigationKeyEvent& event);
201 void HandleOnFocus(wxFocusEvent& event);
202 void HandleOnWindowDestroy(wxWindowBase *child);
203
204 // called from OnChildFocus() handler, i.e. when one of our (grand)
205 // children gets the focus
206 void SetLastFocus(wxWindow *win);
207
208 protected:
209
210 DECLARE_NO_COPY_CLASS(wxControlContainer)
211 };
212
213 // ----------------------------------------------------------------------------
214 // macros which may be used by the classes wishing to implement TAB navigation
215 // among their children
216 // ----------------------------------------------------------------------------
217
218 // declare the methods to be forwarded
219 #define WX_DECLARE_CONTROL_CONTAINER() \
220 WX_DECLARE_CONTROL_CONTAINER_BASE(); \
221 \
222 public: \
223 void OnNavigationKey(wxNavigationKeyEvent& event); \
224 void OnFocus(wxFocusEvent& event); \
225 virtual void OnChildFocus(wxChildFocusEvent& event)
226
227 // implement the event table entries for wxControlContainer
228 #define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
229 EVT_SET_FOCUS(classname::OnFocus) \
230 EVT_CHILD_FOCUS(classname::OnChildFocus) \
231 EVT_NAVIGATION_KEY(classname::OnNavigationKey)
232
233 // implement the methods forwarding to the wxControlContainer
234 #define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
235 WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
236 \
237 void classname::RemoveChild(wxWindowBase *child) \
238 { \
239 m_container.HandleOnWindowDestroy(child); \
240 \
241 basename::RemoveChild(child); \
242 \
243 m_container.UpdateCanFocus(); \
244 } \
245 \
246 void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \
247 { \
248 m_container.HandleOnNavigationKey(event); \
249 } \
250 \
251 void classname::SetFocusIgnoringChildren() \
252 { \
253 basename::SetFocus(); \
254 } \
255 \
256 void classname::OnChildFocus(wxChildFocusEvent& event) \
257 { \
258 m_container.SetLastFocus(event.GetWindow()); \
259 } \
260 \
261 void classname::OnFocus(wxFocusEvent& event) \
262 { \
263 m_container.HandleOnFocus(event); \
264 }
265
266 #endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
267
268 // this function is for wxWidgets internal use only
269 extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
270
271 #endif // _WX_CONTAINR_H_