Allow using windows that can't be focused with wxNavigationEnabled<>.
[wxWidgets.git] / include / wx / containr.h
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: wx/containr.h
3 // Purpose: wxControlContainer and wxNavigationEnabled declarations
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 06.08.01
7 // RCS-ID: $Id$
8 // Copyright: (c) 2001, 2011 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifndef _WX_CONTAINR_H_
13 #define _WX_CONTAINR_H_
14
15 #include "wx/defs.h"
16
17 #ifndef wxHAS_NATIVE_TAB_TRAVERSAL
18 // We need wxEVT_XXX declarations in this case.
19 #include "wx/event.h"
20 #endif
21
22 class WXDLLIMPEXP_FWD_CORE wxWindow;
23 class WXDLLIMPEXP_FWD_CORE wxWindowBase;
24
25 /*
26 This header declares wxControlContainer class however it's not a real
27 container of controls but rather just a helper used to implement TAB
28 navigation among the window children. You should rarely need to use it
29 directly, derive from the documented public wxNavigationEnabled<> class to
30 implement TAB navigation in a custom composite window.
31 */
32
33 // ----------------------------------------------------------------------------
34 // wxControlContainerBase: common part used in both native and generic cases
35 // ----------------------------------------------------------------------------
36
37 class WXDLLIMPEXP_CORE wxControlContainerBase
38 {
39 public:
40 // default ctor, SetContainerWindow() must be called later
41 wxControlContainerBase()
42 {
43 m_winParent = NULL;
44
45 // By default, we accept focus ourselves.
46 m_acceptsFocusSelf = true;
47
48 // But we don't have any children accepting it yet.
49 m_acceptsFocusChildren = false;
50
51 m_inSetFocus = false;
52 m_winLastFocused = NULL;
53 }
54 virtual ~wxControlContainerBase() {}
55
56 void SetContainerWindow(wxWindow *winParent)
57 {
58 wxASSERT_MSG( !m_winParent, wxT("shouldn't be called twice") );
59
60 m_winParent = winParent;
61 }
62
63 // This can be called by the window to indicate that it never wants to have
64 // the focus for itself.
65 void DisableSelfFocus() { m_acceptsFocusSelf = false; }
66
67 // should be called from SetFocus(), returns false if we did nothing with
68 // the focus and the default processing should take place
69 bool DoSetFocus();
70
71 // returns whether we should accept focus ourselves or not
72 bool AcceptsFocus() const { return m_acceptsFocusSelf; }
73
74 // Returns whether we or one of our children accepts focus.
75 bool AcceptsFocusRecursively() const
76 bool AcceptsFocus() const { return m_acceptsFocus; }
77
78 // We accept focus from keyboard if we accept it at all.
79 bool AcceptsFocusFromKeyboard() const { return AcceptsFocusRecursively(); }
80
81 // Call this when the number of children of the window changes.
82 //
83 // Returns true if we have any focusable children, false otherwise.
84 bool UpdateCanFocusChildren();
85
86 protected:
87 // set the focus to the child which had it the last time
88 virtual bool SetFocusToChild();
89
90 // return true if we have any children accepting focus
91 bool HasAnyFocusableChildren() const;
92
93 // the parent window we manage the children for
94 wxWindow *m_winParent;
95
96 // the child which had the focus last time this panel was activated
97 wxWindow *m_winLastFocused;
98
99 private:
100 // Indicates whether the associated window can ever have focus itself.
101 //
102 // Usually this is the case, e.g. a wxPanel can be used either as a
103 // container for its children or just as a normal window which can be
104 // focused. But sometimes, e.g. for wxStaticBox, we can never have focus
105 // ourselves and can only get it if we have any focusable children.
106 bool m_acceptsFocusSelf;
107
108 // Cached value remembering whether we have any children accepting focus.
109 bool m_acceptsFocusChildren;
110
111 // a guard against infinite recursion
112 bool m_inSetFocus;
113 };
114
115 #ifdef wxHAS_NATIVE_TAB_TRAVERSAL
116
117 // ----------------------------------------------------------------------------
118 // wxControlContainer for native TAB navigation
119 // ----------------------------------------------------------------------------
120
121 // this must be a real class as we forward-declare it elsewhere
122 class WXDLLIMPEXP_CORE wxControlContainer : public wxControlContainerBase
123 {
124 protected:
125 // set the focus to the child which had it the last time
126 virtual bool SetFocusToChild();
127 };
128
129 #else // !wxHAS_NATIVE_TAB_TRAVERSAL
130
131 // ----------------------------------------------------------------------------
132 // wxControlContainer for TAB navigation implemented in wx itself
133 // ----------------------------------------------------------------------------
134
135 class WXDLLIMPEXP_CORE wxControlContainer : public wxControlContainerBase
136 {
137 public:
138 // default ctor, SetContainerWindow() must be called later
139 wxControlContainer();
140
141 // the methods to be called from the window event handlers
142 void HandleOnNavigationKey(wxNavigationKeyEvent& event);
143 void HandleOnFocus(wxFocusEvent& event);
144 void HandleOnWindowDestroy(wxWindowBase *child);
145
146 // called from OnChildFocus() handler, i.e. when one of our (grand)
147 // children gets the focus
148 void SetLastFocus(wxWindow *win);
149
150 protected:
151
152 wxDECLARE_NO_COPY_CLASS(wxControlContainer);
153 };
154
155 #endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
156
157 // this function is for wxWidgets internal use only
158 extern WXDLLIMPEXP_CORE bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
159
160 // ----------------------------------------------------------------------------
161 // wxNavigationEnabled: Derive from this class to support keyboard navigation
162 // among window children in a wxWindow-derived class. The details of this class
163 // don't matter, you just need to derive from it to make navigation work.
164 // ----------------------------------------------------------------------------
165
166 // The template parameter W must be a wxWindow-derived class.
167 template <class W>
168 class wxNavigationEnabled : public W
169 {
170 public:
171 typedef W BaseWindowClass;
172
173 wxNavigationEnabled()
174 {
175 m_container.SetContainerWindow(this);
176
177 #ifndef wxHAS_NATIVE_TAB_TRAVERSAL
178 BaseWindowClass::Connect(wxEVT_NAVIGATION_KEY,
179 wxNavigationKeyEventHandler(wxNavigationEnabled::OnNavigationKey));
180
181 BaseWindowClass::Connect(wxEVT_SET_FOCUS,
182 wxFocusEventHandler(wxNavigationEnabled::OnFocus));
183
184 BaseWindowClass::Connect(wxEVT_CHILD_FOCUS,
185 wxChildFocusEventHandler(wxNavigationEnabled::OnChildFocus));
186 #endif // !wxHAS_NATIVE_TAB_TRAVERSAL
187 }
188
189 WXDLLIMPEXP_INLINE_CORE virtual bool AcceptsFocus() const
190 {
191 return m_container.AcceptsFocus();
192 }
193
194 WXDLLIMPEXP_INLINE_CORE virtual bool AcceptsFocusRecursively() const
195 {
196 return m_container.AcceptsFocusRecursively();
197 }
198
199 WXDLLIMPEXP_INLINE_CORE virtual bool AcceptsFocusFromKeyboard() const
200 {
201 return m_container.AcceptsFocusFromKeyboard();
202 }
203
204 WXDLLIMPEXP_INLINE_CORE virtual void AddChild(wxWindowBase *child)
205 {
206 BaseWindowClass::AddChild(child);
207
208 m_container.UpdateCanFocusChildren();
209 }
210
211 WXDLLIMPEXP_INLINE_CORE virtual void RemoveChild(wxWindowBase *child)
212 {
213 #ifndef wxHAS_NATIVE_TAB_TRAVERSAL
214 m_container.HandleOnWindowDestroy(child);
215 #endif // !wxHAS_NATIVE_TAB_TRAVERSAL
216
217 BaseWindowClass::RemoveChild(child);
218
219 m_container.UpdateCanFocusChildren();
220 }
221
222 WXDLLIMPEXP_INLINE_CORE virtual void SetFocus()
223 {
224 if ( !m_container.DoSetFocus() )
225 BaseWindowClass::SetFocus();
226 }
227
228 void SetFocusIgnoringChildren()
229 {
230 BaseWindowClass::SetFocus();
231 }
232
233 protected:
234 #ifndef wxHAS_NATIVE_TAB_TRAVERSAL
235 void OnNavigationKey(wxNavigationKeyEvent& event)
236 {
237 m_container.HandleOnNavigationKey(event);
238 }
239
240 void OnFocus(wxFocusEvent& event)
241 {
242 m_container.HandleOnFocus(event);
243 }
244
245 void OnChildFocus(wxChildFocusEvent& event)
246 {
247 m_container.SetLastFocus(event.GetWindow());
248 event.Skip();
249 }
250 #endif // !wxHAS_NATIVE_TAB_TRAVERSAL
251
252 wxControlContainer m_container;
253
254
255 wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxNavigationEnabled, W);
256 };
257
258 // ----------------------------------------------------------------------------
259 // Compatibility macros from now on, do NOT use them and preferably do not even
260 // look at them.
261 // ----------------------------------------------------------------------------
262
263 #if WXWIN_COMPATIBILITY_2_8
264
265 // common part of WX_DECLARE_CONTROL_CONTAINER in the native and generic cases,
266 // it should be used in the wxWindow-derived class declaration
267 #define WX_DECLARE_CONTROL_CONTAINER_BASE() \
268 public: \
269 virtual bool AcceptsFocus() const; \
270 virtual bool AcceptsFocusRecursively() const; \
271 virtual bool AcceptsFocusFromKeyboard() const; \
272 virtual void AddChild(wxWindowBase *child); \
273 virtual void RemoveChild(wxWindowBase *child); \
274 virtual void SetFocus(); \
275 void SetFocusIgnoringChildren(); \
276 \
277 protected: \
278 wxControlContainer m_container
279
280 // this macro must be used in the derived class ctor
281 #define WX_INIT_CONTROL_CONTAINER() \
282 m_container.SetContainerWindow(this)
283
284 // common part of WX_DELEGATE_TO_CONTROL_CONTAINER in the native and generic
285 // cases, must be used in the wxWindow-derived class implementation
286 #define WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
287 void classname::AddChild(wxWindowBase *child) \
288 { \
289 basename::AddChild(child); \
290 \
291 m_container.UpdateCanFocusChildren(); \
292 } \
293 \
294 bool classname::AcceptsFocusRecursively() const \
295 { \
296 return m_container.AcceptsFocusRecursively(); \
297 } \
298 \
299 void classname::SetFocus() \
300 { \
301 if ( !m_container.DoSetFocus() ) \
302 basename::SetFocus(); \
303 } \
304 \
305 bool classname::AcceptsFocus() const \
306 { \
307 return m_container.AcceptsFocus(); \
308 } \
309 \
310 bool classname::AcceptsFocusFromKeyboard() const \
311 { \
312 return m_container.AcceptsFocusFromKeyboard(); \
313 }
314
315
316 #ifdef wxHAS_NATIVE_TAB_TRAVERSAL
317
318 #define WX_EVENT_TABLE_CONTROL_CONTAINER(classname)
319
320 #define WX_DECLARE_CONTROL_CONTAINER WX_DECLARE_CONTROL_CONTAINER_BASE
321
322 #define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
323 WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
324 \
325 void classname::RemoveChild(wxWindowBase *child) \
326 { \
327 basename::RemoveChild(child); \
328 \
329 m_container.UpdateCanFocusChildren(); \
330 } \
331 \
332 void classname::SetFocusIgnoringChildren() \
333 { \
334 basename::SetFocus(); \
335 }
336
337 #else // !wxHAS_NATIVE_TAB_TRAVERSAL
338
339 // declare the methods to be forwarded
340 #define WX_DECLARE_CONTROL_CONTAINER() \
341 WX_DECLARE_CONTROL_CONTAINER_BASE(); \
342 \
343 public: \
344 void OnNavigationKey(wxNavigationKeyEvent& event); \
345 void OnFocus(wxFocusEvent& event); \
346 virtual void OnChildFocus(wxChildFocusEvent& event)
347
348 // implement the event table entries for wxControlContainer
349 #define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
350 EVT_SET_FOCUS(classname::OnFocus) \
351 EVT_CHILD_FOCUS(classname::OnChildFocus) \
352 EVT_NAVIGATION_KEY(classname::OnNavigationKey)
353
354 // implement the methods forwarding to the wxControlContainer
355 #define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, basename) \
356 WX_DELEGATE_TO_CONTROL_CONTAINER_BASE(classname, basename) \
357 \
358 void classname::RemoveChild(wxWindowBase *child) \
359 { \
360 m_container.HandleOnWindowDestroy(child); \
361 \
362 basename::RemoveChild(child); \
363 \
364 m_container.UpdateCanFocusChildren(); \
365 } \
366 \
367 void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \
368 { \
369 m_container.HandleOnNavigationKey(event); \
370 } \
371 \
372 void classname::SetFocusIgnoringChildren() \
373 { \
374 basename::SetFocus(); \
375 } \
376 \
377 void classname::OnChildFocus(wxChildFocusEvent& event) \
378 { \
379 m_container.SetLastFocus(event.GetWindow()); \
380 event.Skip(); \
381 } \
382 \
383 void classname::OnFocus(wxFocusEvent& event) \
384 { \
385 m_container.HandleOnFocus(event); \
386 }
387
388 #endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
389
390 #endif // WXWIN_COMPATIBILITY_2_8
391
392 #endif // _WX_CONTAINR_H_