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