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