]>
Commit | Line | Data |
---|---|---|
1 | /////////////////////////////////////////////////////////////////////////////// | |
2 | // Name: wx/compositewin.h | |
3 | // Purpose: wxCompositeWindow<> declaration | |
4 | // Author: Vadim Zeitlin | |
5 | // Created: 2011-01-02 | |
6 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org> | |
8 | // Licence: wxWindows licence | |
9 | /////////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef _WX_COMPOSITEWIN_H_ | |
12 | #define _WX_COMPOSITEWIN_H_ | |
13 | ||
14 | #include "wx/window.h" | |
15 | #include "wx/containr.h" | |
16 | ||
17 | class WXDLLIMPEXP_FWD_CORE wxToolTip; | |
18 | ||
19 | // NB: This is an experimental and, as for now, undocumented class used only by | |
20 | // wxWidgets itself internally. Don't use it in your code until its API is | |
21 | // officially stabilized unless you are ready to change it with the next | |
22 | // wxWidgets release. | |
23 | ||
24 | // ---------------------------------------------------------------------------- | |
25 | // wxCompositeWindow is a helper for implementing composite windows: to define | |
26 | // a class using subwindows, simply inherit from it specialized with the real | |
27 | // base class name and implement GetCompositeWindowParts() pure virtual method. | |
28 | // ---------------------------------------------------------------------------- | |
29 | ||
30 | // The template parameter W must be a wxWindow-derived class. | |
31 | template <class W> | |
32 | class wxCompositeWindow : public W | |
33 | { | |
34 | public: | |
35 | typedef W BaseWindowClass; | |
36 | ||
37 | // Default ctor doesn't do anything. | |
38 | wxCompositeWindow() | |
39 | { | |
40 | this->Connect | |
41 | ( | |
42 | wxEVT_CREATE, | |
43 | wxWindowCreateEventHandler(wxCompositeWindow::OnWindowCreate) | |
44 | ); | |
45 | ||
46 | } | |
47 | ||
48 | #ifndef __VISUALC6__ | |
49 | // FIXME-VC6: This compiler can't compile DoSetForAllParts() template function, | |
50 | // it can't determine whether the deduced type should be "T" or "const T&". And | |
51 | // without this function wxCompositeWindow is pretty useless so simply disable | |
52 | // this code for it, this does mean that setting colours/fonts/... for | |
53 | // composite controls won't work in the library compiled with it but so far | |
54 | // this only affects the generic wxDatePickerCtrl which is not used by default | |
55 | // under MSW anyhow so it doesn't seem to be worth it to spend time and uglify | |
56 | // the code to fix it. | |
57 | ||
58 | // Override all wxWindow methods which must be forwarded to the composite | |
59 | // window parts. | |
60 | ||
61 | // Attribute setters group. | |
62 | // | |
63 | // NB: Unfortunately we can't factor out the call for the setter itself | |
64 | // into DoSetForAllParts() because we can't call the function passed to | |
65 | // it non-virtually and we need to do this to avoid infinite recursion, | |
66 | // so we work around this by calling the method of this object itself | |
67 | // manually in each function. | |
68 | virtual bool SetForegroundColour(const wxColour& colour) | |
69 | { | |
70 | if ( !BaseWindowClass::SetForegroundColour(colour) ) | |
71 | return false; | |
72 | ||
73 | SetForAllParts(&wxWindowBase::SetForegroundColour, colour); | |
74 | ||
75 | return true; | |
76 | } | |
77 | ||
78 | virtual bool SetBackgroundColour(const wxColour& colour) | |
79 | { | |
80 | if ( !BaseWindowClass::SetBackgroundColour(colour) ) | |
81 | return false; | |
82 | ||
83 | SetForAllParts(&wxWindowBase::SetBackgroundColour, colour); | |
84 | ||
85 | return true; | |
86 | } | |
87 | ||
88 | virtual bool SetFont(const wxFont& font) | |
89 | { | |
90 | if ( !BaseWindowClass::SetFont(font) ) | |
91 | return false; | |
92 | ||
93 | SetForAllParts(&wxWindowBase::SetFont, font); | |
94 | ||
95 | return true; | |
96 | } | |
97 | ||
98 | virtual bool SetCursor(const wxCursor& cursor) | |
99 | { | |
100 | if ( !BaseWindowClass::SetCursor(cursor) ) | |
101 | return false; | |
102 | ||
103 | SetForAllParts(&wxWindowBase::SetCursor, cursor); | |
104 | ||
105 | return true; | |
106 | } | |
107 | ||
108 | #if wxUSE_TOOLTIPS | |
109 | virtual void DoSetToolTip(wxToolTip *tip) | |
110 | { | |
111 | BaseWindowClass::DoSetToolTip(tip); | |
112 | ||
113 | SetForAllParts(&wxWindowBase::CopyToolTip, tip); | |
114 | } | |
115 | #endif // wxUSE_TOOLTIPS | |
116 | ||
117 | #endif // !__VISUALC6__ | |
118 | ||
119 | virtual void SetFocus() | |
120 | { | |
121 | wxSetFocusToChild(this, NULL); | |
122 | } | |
123 | ||
124 | private: | |
125 | // Must be implemented by the derived class to return all children to which | |
126 | // the public methods we override should forward to. | |
127 | virtual wxWindowList GetCompositeWindowParts() const = 0; | |
128 | ||
129 | void OnWindowCreate(wxWindowCreateEvent& event) | |
130 | { | |
131 | event.Skip(); | |
132 | ||
133 | // Attach a few event handlers to all parts of the composite window. | |
134 | // This makes the composite window behave more like a simple control | |
135 | // and allows other code (such as wxDataViewCtrl's inline editing | |
136 | // support) to hook into its event processing. | |
137 | ||
138 | wxWindow *child = event.GetWindow(); | |
139 | if ( child == this ) | |
140 | return; // not a child, we don't want to Connect() to ourselves | |
141 | ||
142 | // Always capture wxEVT_KILL_FOCUS: | |
143 | child->Connect(wxEVT_KILL_FOCUS, | |
144 | wxFocusEventHandler(wxCompositeWindow::OnKillFocus), | |
145 | NULL, this); | |
146 | ||
147 | // Some events should be only handled for non-toplevel children. For | |
148 | // example, we want to close the control in wxDataViewCtrl when Enter | |
149 | // is pressed in the inline editor, but not when it's pressed in a | |
150 | // popup dialog it opens. | |
151 | wxWindow *win = child; | |
152 | while ( win && win != this ) | |
153 | { | |
154 | if ( win->IsTopLevel() ) | |
155 | return; | |
156 | win = win->GetParent(); | |
157 | } | |
158 | ||
159 | child->Connect(wxEVT_CHAR, | |
160 | wxKeyEventHandler(wxCompositeWindow::OnChar), | |
161 | NULL, this); | |
162 | } | |
163 | ||
164 | void OnChar(wxKeyEvent& event) | |
165 | { | |
166 | if ( !this->ProcessWindowEvent(event) ) | |
167 | event.Skip(); | |
168 | } | |
169 | ||
170 | void OnKillFocus(wxFocusEvent& event) | |
171 | { | |
172 | // Ignore focus changes within the composite control: | |
173 | wxWindow *win = event.GetWindow(); | |
174 | while ( win ) | |
175 | { | |
176 | if ( win == this ) | |
177 | { | |
178 | event.Skip(); | |
179 | return; | |
180 | } | |
181 | ||
182 | // Note that we don't use IsTopLevel() check here, because we do | |
183 | // want to ignore focus changes going to toplevel window that have | |
184 | // the composite control as its parent; these would typically be | |
185 | // some kind of control's popup window. | |
186 | win = win->GetParent(); | |
187 | } | |
188 | ||
189 | // The event shouldn't be ignored, forward it to the main control: | |
190 | if ( !this->ProcessWindowEvent(event) ) | |
191 | event.Skip(); | |
192 | } | |
193 | ||
194 | #ifndef __VISUALC6__ | |
195 | template <class T> | |
196 | void SetForAllParts(bool (wxWindowBase::*func)(const T&), const T& arg) | |
197 | { | |
198 | DoSetForAllParts<const T&>(func, arg); | |
199 | } | |
200 | ||
201 | template <class T> | |
202 | void SetForAllParts(bool (wxWindowBase::*func)(T*), T* arg) | |
203 | { | |
204 | DoSetForAllParts<T*>(func, arg); | |
205 | } | |
206 | ||
207 | template <class T> | |
208 | void DoSetForAllParts(bool (wxWindowBase::*func)(T), T arg) | |
209 | { | |
210 | // Simply call the setters for all parts of this composite window. | |
211 | const wxWindowList parts = GetCompositeWindowParts(); | |
212 | for ( wxWindowList::const_iterator i = parts.begin(); | |
213 | i != parts.end(); | |
214 | ++i ) | |
215 | { | |
216 | wxWindow * const child = *i; | |
217 | ||
218 | // Allow NULL elements in the list, this makes the code of derived | |
219 | // composite controls which may have optionally shown children | |
220 | // simpler and it doesn't cost us much here. | |
221 | if ( child ) | |
222 | (child->*func)(arg); | |
223 | } | |
224 | } | |
225 | #endif // !__VISUALC6__ | |
226 | ||
227 | wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxCompositeWindow, W); | |
228 | }; | |
229 | ||
230 | #endif // _WX_COMPOSITEWIN_H_ |