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