]> git.saurik.com Git - wxWidgets.git/blob - utils/screenshotgen/src/autocapture.h
Applied Peter Most's EVT_SPIN crash fix
[wxWidgets.git] / utils / screenshotgen / src / autocapture.h
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: autocapture.h
3 // Purpose: Defines the AutoCaptureMechanism class
4 // Author: Utensil Candel (UtensilCandel@@gmail.com)
5 // RCS-ID: $Id$
6 // Licence: wxWindows license
7 /////////////////////////////////////////////////////////////////////////////
8
9 #ifndef _AUTOCAPTURE_H_
10 #define _AUTOCAPTURE_H_
11
12 #include <vector>
13 #include <ctime>
14
15 #include <wx/notebook.h>
16
17 /**
18 GlobalAdjustFlags works with AutoCaptureMechanism's constructor, to disbale/enable
19 some auto-adjustment for all controls.
20
21 They are used to make AutoCaptureMechanism more configurable and provide a fallback
22 to detect the bugs that the adjustments intended to avoid.
23
24 @see AdjustFlags
25 */
26 enum GlobalAdjustFlags
27 {
28 /**
29 This is the default. All adjustments instructed in
30 AutoCaptureMechanism::RegisterControl() will be performed.
31 */
32 AJ_NormalAll = 0,
33
34 /**
35 Disable region adjustment for all controls.
36 */
37 AJ_DisableRegionAdjust = 1 << 0,
38
39 /**
40 Enable region adjustment for all controls.
41 */
42 AJ_AlwaysRegionAdjust = 1 << 1,
43
44 /**
45 Disable name adjustment for all controls.
46 */
47 AJ_DisableNameAdjust = 1 << 2,
48
49 /**
50 For all the "Drop-down Controls", e.g. wxChoice, do not prompt the user about whether
51 to capture their drop-down state, and always capture only its non-drop-down state.
52 */
53 AJ_DisableDropdown = 1 << 3
54 };
55
56 /**
57 AdjustFlags works with AutoCaptureMechanism::RegisterControl() to specify how to
58 adjust the screenshot of the current control.
59
60 They are used to avoid bugs, look better or interact with user etc.
61
62 @see GlobalAdjustFlags
63 */
64 enum AdjustFlags
65 {
66 /**
67 This is the default. Perform no adjustment for this control.
68 */
69 AJ_Normal = 0,
70
71 /**
72 Perform region adjustment for this control.
73
74 On some platforms and for some controls, wxWindow::GetScreenRect() will return
75 a smaller or deflected region. In these cases, the screenshots we get are incomplete.
76 It's recommended for everyone to fix the controls' code, yet this flag provides a
77 workaround to get a guaranteed correct region without using wxWindow::GetScreenRect().
78
79 This workaround("label trick") is inspired by (or say stolen from) Auria's work.
80 */
81 AJ_RegionAdjust = 1 << 0,
82
83 /**
84 This flag provides a way to capture the drop-down state of "Drop-down Controls",
85 e.g. wxChoice.
86
87 For all the "Drop-down Controls", prompt the user about whether to capture their
88 drop-down state, if the user chooses YES, he should drop down the control in about
89 3 seconds and wait util it's captured in that state.
90 */
91 AJ_Dropdown = 1 << 1,
92
93 /**
94 This flag is used internally by RegisterPageTurn(). Don't use it directly unless you
95 know what you are doing.
96 */
97 AJ_TurnPage = 1 << 2,
98
99 /**
100 This flag provides a functionality to union screenshots of different controls into
101 one image.
102
103 It's especially useful to demonstrate different modes/states of a control,
104 e.g. the single-line/multi-line modes of a wxTextCtrl.
105
106 For a series of controls to be unioned, you should specify AJ_Union for the first,
107 and AJ_UnionEnd for the last. For the controls between them, you can either specify
108 AJ_Union or not.
109 */
110 AJ_Union = 1 << 3,
111
112 /**
113 @see AJ_Union.
114 */
115 AJ_UnionEnd = 1 << 4
116 };
117
118 /**
119 @class AutoCaptureMechanism
120
121 AutoCaptureMechanism provides an easy-to-use and adjustable facility to take the screenshots
122 for all controls fully automaticly and correctly. It also provides an advanced feature to
123 union screenshots of different states/modes of a control.
124
125 @section tag_filename_convention Screenshot File Name Convention
126
127 All screenshots are generated as PNG files. For a control named wxName, its screenshot file
128 name would be "name.png", e.g. "button.png" for wxButton. This is the protocol with the
129 doxygen document of wxWidgets.
130
131 By default, screenshots are generated under the subdirectory "screenshots" of current working
132 directory. During updating or adding new screenshots, first make sure screenshots are generated
133 correctly, and then copy them to the following subdirectory of docs/doxygen/images:
134
135 "wxmsw" for MS Windows, "wxgtk" for Linux and "wxmac" for Mac OS.
136
137 @section tag_gui_assumption The Assumption of GUI
138
139 Unfortunately, this class have an assumption about the structure of GUI:
140 It must have the follwoing top-down structure:
141
142 wxNotebook->wxPanel->wxSizer->wxControl
143
144 That means, in the wxNotebook associated with this class, controls that needs to be
145 taken screenshots are placed on different panels(for grouping) and layed out by wxSizers.
146
147 @section tag_tutorial Tutorial
148
149 In the contruction, you should associate a wxNotebook with this class, in that wxNotebook,
150 controls that needs to be captured are placed on different panels(for grouping).
151
152 When you register controls, you should do it in order: Register the controls on the first
153 panel(using RegisterControl()), and then register a page turn(using RegisterPageTurn()),
154 so this class can turn a page of the wxNotebook to present the second page. And then
155 you register the controls on the second panel, then a page turn, and so on.
156
157 When you are done, simply call CaptureAll(), then screenshots of all controls will be
158 automaticly generated.
159
160 @section tag_autoadjust Make Use of Auto Adjustments
161
162 First take a look at the document of RegisterControl(), enum AdjustFlags and
163 GlobalAdjustFlags.
164
165 And then, ScreenshotFrame::OnCaptureAllControls() is a good example of making use of
166 auto adjustment. Taking a look at it will get you started.
167
168 @section tag_developer_note Notes for Developers
169
170 @subsection tag_cnc CaptureAll() and Capture()
171
172 The implementation of Auto Adjustments is in CaptureAll() and Capture(), the code is
173 short, quite readable and well commented, please read the codes before any modification.
174
175 If you need the class to do something sepcial for you, consider introducing a new flag
176 and implement it in them. For an operation performed on multiple controls, implemente
177 its logic in CaptureAll(), otherwise in the private member Capture().
178
179 @subsection tag_yield_issue wxYield Issues
180
181 Not quite a good habit, but this class made a lot of use of wxYield()/wxYieldIfNeeded().
182 They are used to ensure the update of GUI(e.g. the page turn of wxNotebook) is done
183 before any further screenshot-taking, or to do the timing(in Delay()). Without their use,
184 there would be subtle bugs.
185
186 I've read documents about wxYield() and understand the down side of it before using it.
187 But I didn't find a better approach to do those things, and I used them carefully. So
188 please DO NOT remove any of these wxYield()s unless you're sure that it won't cause problems
189 on all of MS Windows XP/Vista, Linux(Ubuntu/Fedora), Mac OS Tiger/Leopard. And please
190 help me to find a better approach, thank you :)
191 */
192 class AutoCaptureMechanism
193 {
194 public:
195 /**
196 Constructor.
197
198 @param notebook
199 The wxNotebook associated with this class.Please see @ref tag_gui_assumption
200 and @ref tag_tutorial.
201
202 @param flag
203 It's one of or a combination of GlobalAdjustFlags, to disbale/enable some auto-adjustment
204 for all controls.
205
206 @param margin
207 It's the margin around every control in the sreenshots.
208 */
209 AutoCaptureMechanism(wxNotebook *notebook,
210 int flag = AJ_NormalAll,
211 int margin = 5)
212 : m_notebook(notebook), m_flag(flag),
213 m_margin(margin), m_grid(NULL) {}
214
215 ~AutoCaptureMechanism(){}
216
217 /**
218 Register a control and perform specifid auto adjustments.
219
220 @param ctrl
221 The pointer to the control to be taken a screenshot.
222
223 @param name
224 If you find out that the screenshot for this control was generated under an incorrect
225 file name, specify @a name. e.g. for wxButton, "wxButton" or "button" are both OK.
226
227 @param flag
228
229 If you end up with an a smaller or deflected screenshot, use AJ_RegionAdjust.
230
231 If you want to caputure the "drop-down" state of a "drop-down" control, use AJ_Dropdown.
232
233 If you want to present different states of a control in one screenshot, use AJ_Union
234 and AJ_UnionEnd.
235
236 Please read the document of enum AdjustFlags, and notice that this flag could be enabled/
237 disabled by global flag GlobalAdjustFlags.
238 */
239 void RegisterControl(wxWindow * ctrl, wxString name = _T(""), int flag = AJ_Normal)
240 {
241 m_controlList.push_back(Control(ctrl, name, flag));
242 }
243
244 /**
245 Register a control and perform specifid auto adjustments.
246
247 This is the same as RegisterControl(wxWindow * ctrl, wxString name, int flag),
248 But with it, you won't have to specify the name if you only want to auto-adjust something
249 other than name adjustment.
250 */
251 void RegisterControl(wxWindow * ctrl, int flag)
252 {
253 RegisterControl(ctrl, _T(""), flag);
254 }
255
256 /**
257 Register a page turn.
258
259 When you finished registering the controls on a panel, remember to call it to turn the
260 wxNotebook to the next panel.
261 */
262 void RegisterPageTurn()
263 {
264 m_controlList.push_back(Control(0, _T(""), AJ_TurnPage));
265 }
266
267 /**
268 Capture all registered controls of the associated wxNotebook.
269 */
270 void CaptureAll();
271
272 /*
273 Static Members
274 */
275 /**
276 Take a screenshot for the given region.
277
278 @param rect is the given rectangular region.
279
280 @param delay is only useful for Mac, for fixing a delay bug. It seems that it didn't
281 fix the bug, so it might be removed soon.
282 */
283 static wxBitmap Capture(wxRect rect, int delay = 0);
284
285 /**
286 Take a screenshot for the given region.
287
288 @see Capture(wxRect rect, int delay)
289 */
290 static wxBitmap Capture(int x, int y, int width, int height, int delay = 0);
291
292 /**
293 Save the screenshot as the name of @a fileName in the default directory.
294
295 @a fileName should be without ".png".
296 */
297 static void Save(wxBitmap screenshot, wxString fileName);
298
299 /**
300 Set the default directory where the screenshots will be generated.
301 */
302 static void SetDefaultDirectory(wxString dir) { default_dir = dir; }
303
304 /**
305 Get the default directory where the screenshots will be generated.
306 */
307 static wxString GetDefaultDirectory() { return default_dir; }
308
309 /**
310 Get the absolute path of the default directory where the screenshots will be generated.
311 */
312 static wxString GetDefaultDirectoryAbsPath()
313 {
314 wxFileName output = wxFileName::DirName(GetDefaultDirectory());
315 output.MakeAbsolute();
316 return output.GetFullPath();
317 }
318
319 private:
320
321 /*
322 Internal Data Structures
323
324 They might go public in future to provide reuse of ControlList.
325 */
326 struct Control
327 {
328 Control() {}
329
330 Control(wxWindow * _ctrl, wxString _name, int _flag)
331 : ctrl(_ctrl), name(_name), flag(_flag) {}
332
333 wxWindow * ctrl;
334 wxString name;
335 int flag;
336 };
337
338 typedef std::vector<Control> ControlList;
339
340 /*
341 Internal Functions
342
343 They are only used to clearify the logic of some public functions and it's nonsense
344 to call them elsewhere.
345 */
346
347 /*
348 Capture and auto adjust the control. Used by CaptureAll().
349 */
350 wxBitmap Capture(Control & ctrl);
351
352 /*
353 Get the correct rectangular region that the control occupies. Used by
354 Capture(Control & ctrl).
355
356 If AJ_RegionAdjust is specified, it will use the "label trick" to perform
357 region auto adjustment.
358
359 The "label trick" is to reattach the control to a wxFlexGridSizer m_grid,
360 surround the control with labels and get the control's region by label's positions.
361 Just like this:
362
363 +---------+-----------+---------+
364 | 0 | label | 1 |
365 +---------+-----------+---------+
366 | label | ctrl | label |
367 +---------+-----------+---------+
368 | 2 | label | 3 |
369 +---------+-----------+---------+
370
371 So, there will be a side effect: the control is moved to a new position. So after taking the
372 screenshot, Capture(Control & ctrl) should call PutBack(wxWindow * ctrl) to put it back.
373
374 If AJ_RegionAdjust isn't specified, it will simply call wxWindow::GetScreenRect().
375 */
376 wxRect GetRect(wxWindow* ctrl, int flag);
377
378 /*
379 Put the control back after the label trick used in GetRect(). Used by
380 Capture(Control & ctrl).
381 */
382 void PutBack(wxWindow * ctrl);
383
384 /*
385 Union two screenshots in the vertical direction, and leave a gap between the
386 screenshots. Used by CaptureAll().
387
388 The gap is 20 pixels by default. Currently it isn't configurable.
389 */
390 static wxBitmap Union(wxBitmap pic1, wxBitmap pic2);
391
392 static void Delay(int seconds);
393
394 /*
395 Data Members
396 */
397 ControlList m_controlList;
398
399 wxNotebook* m_notebook;
400
401 int m_flag;
402
403 int m_margin;
404
405 wxFlexGridSizer* m_grid;
406
407 static wxString default_dir;
408 };
409
410 #endif // _AUTOCAPTURE_H_
411
412