added the automatic screenshot generator utility by Utensil Candel (with some revisio...
[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 AUTOCAP_H
10 #define AUTOCAP_H
11
12 #include <wx/notebook.h>
13 #include <wx/settings.h>
14 #include <vector>
15 #include <ctime>
16
17 // Global helper functions. to take screenshot for a rect region
18 wxBitmap Capture(wxRect rect);
19 wxBitmap Capture(int x, int y, int width, int height);
20
21 enum AdjustFlags
22 {
23 AJ_Normal = 0,
24 AJ_RegionAdjust = 1 << 0,
25 AJ_Dropdown = 1 << 1,
26 AJ_TurnPage = 1 << 2,
27 AJ_Union = 1 << 3,
28 AJ_UnionEnd = 1 << 4
29 };
30
31 class AutoCaptureMechanism
32 {
33 public:
34 AutoCaptureMechanism(wxNotebook * notebook,
35 wxString directory = wxT("screenshots"),
36 int border = 5)
37 : m_notebook(notebook), m_dir(directory), m_border(border) {}
38 ~AutoCaptureMechanism(){}
39
40 /*
41 If wxRTTI can't get the name correctly, specify name;
42 If wxWindow::GetScreenRect doesn't get the rect correctly, set flag to AJ_RegionAdjust
43 */
44 void RegisterControl(wxWindow * ctrl, wxString name = wxT(""),
45 int flag = AJ_Normal)
46 {
47 m_controlList.push_back(Control(ctrl, name, flag));
48 }
49
50 void RegisterControl(wxWindow * ctrl, int flag)
51 {
52 RegisterControl(ctrl, wxT(""), flag);
53 }
54
55 void RegisterPageTurn()
56 {
57 m_controlList.push_back(Control(0, wxT(""), AJ_TurnPage));
58 }
59
60 void CaptureAll()
61 {
62 m_notebook->SetSelection(0);
63 wxYield();
64
65 for(ControlList::iterator it = m_controlList.begin();
66 it != m_controlList.end();
67 ++it)
68 {
69 Control & ctrl = *it;
70
71 if(ctrl.flag == AJ_TurnPage) // Turn to next page
72 {
73 m_notebook->SetSelection(m_notebook->GetSelection() + 1);
74 wxYield();
75 continue;
76 }
77
78 wxBitmap screenshot = Capture(ctrl);
79
80 if(ctrl.flag & AJ_Union)
81 {
82 screenshot = Union(screenshot, Capture(*(++it)));
83 }
84
85 Save(screenshot, ctrl.name);
86 }
87 }
88
89 private:
90 struct Control
91 {
92 Control() {}
93
94 Control(wxWindow * _ctrl, wxString _name, int _flag)
95 : ctrl(_ctrl), name(_name), flag(_flag) {}
96
97 wxWindow * ctrl;
98 wxString name;
99 int flag;
100 };
101
102 typedef std::vector<Control> ControlList;
103 ControlList m_controlList;
104
105 // here we introduce the dependency on wxNotebook.
106 // The assumption of this whole class is that the gui has the following top-down structure
107 // wxNotebook wxPanel wxSizer wxControls
108 wxNotebook* m_notebook;
109
110 wxFlexGridSizer* m_grid;
111
112 wxString m_dir;
113 int m_border;
114
115
116
117 wxBitmap Capture(Control & ctrl)
118 {
119 if(ctrl.name == wxT("")) //no mannual specification for the control name
120 {
121 //Get name from wxRTTI
122 ctrl.name = ctrl.ctrl->GetClassInfo()->GetClassName();
123 }
124
125 int choice = wxNO;
126
127 if(ctrl.flag & AJ_Dropdown)
128 {
129 wxString caption = _("Do you wish to capture the dropdown list of ") + ctrl.name + _("?");
130 wxString notice = _("Click YES to capture it.\nAnd you MUST drop down the ") + ctrl.name + _(" in 3 seconds after close me.\n");
131 notice += _("Click NO otherwise.");
132
133 choice = wxMessageBox(notice, caption, wxYES_NO, m_notebook);
134
135 if(choice == wxYES)
136 {
137 //Wait for 3 seconds
138 using std::clock;
139 using std::clock_t;
140
141 clock_t start = clock();
142 while(clock() - start < CLOCKS_PER_SEC * 3)
143 {
144 wxYieldIfNeeded();
145 }
146 }
147 }
148
149 wxRect rect = GetRect(ctrl.ctrl, ctrl.flag);
150
151 //Do some rect adjust so it can include the dropdown list
152 //Currently it only works well under MSW, not adjusted for Linux and Mac OS
153 if(ctrl.flag & AJ_Dropdown && choice == wxYES)
154 {
155 // #ifdef __WXMSW__
156 int h = rect.GetHeight();
157 rect.SetHeight(h * 4);
158 // #endif
159 }
160
161 //cut off "wx" and change them into lowercase.
162 // e.g. wxButton will have a name of "button" at the end
163 ctrl.name.StartsWith(_T("wx"), &(ctrl.name));
164 ctrl.name.MakeLower();
165
166 wxBitmap screenshot = ::Capture(rect);
167
168 if(ctrl.flag & AJ_RegionAdjust)
169 {
170 PutBack(ctrl.ctrl);
171 }
172
173 return screenshot;
174 }
175
176 //if AJ_RegionAdjust is specified, the following line will use the label trick to adjust
177 //the region position and size
178 wxRect GetRect(wxWindow* ctrl, int flag);
179 //put the control back after the label trick(Using reparent/resizer approach)
180 void PutBack(wxWindow * ctrl);
181
182 wxBitmap Union(wxBitmap pic1, wxBitmap pic2)
183 {
184 int w1, w2, h1, h2, w, h;
185 w1 = pic1.GetWidth();
186 w2 = pic2.GetWidth();
187 h1 = pic1.GetHeight();
188 h2 = pic2.GetHeight();
189
190 const int gap_between = 20;
191
192 w = (w1 >= w2) ? w1 : w2;
193 h = h1 + h2 + gap_between;
194
195 wxBitmap result(w, h, -1);
196
197 wxMemoryDC dstDC;
198 dstDC.SelectObject(result);
199
200 dstDC.DrawBitmap(pic1, 0, 0, false);
201 dstDC.DrawBitmap(pic2, 0, h1 + gap_between, false);
202
203 dstDC.SelectObject(wxNullBitmap);
204
205 wxMemoryDC maskDC;
206 wxBitmap mask(w, h, 1);
207 maskDC.SelectObject(mask);
208
209 maskDC.SetPen(*wxTRANSPARENT_PEN);
210 maskDC.SetBrush(*wxBLACK_BRUSH);
211 maskDC.DrawRectangle(0, 0, w + 1, h + 1);
212
213 maskDC.SetBrush(*wxWHITE_BRUSH);
214 maskDC.DrawRectangle(0, 0, w1, h1);
215 maskDC.DrawRectangle(0, h1 + gap_between, w2, h2);
216 maskDC.SelectObject(wxNullBitmap);
217
218 result.SetMask(new wxMask(mask));
219
220 return result;
221 }
222
223 void Save(wxBitmap screenshot, wxString fileName);
224 };
225
226 #endif // AUTOCAP_H
227
228