1 /////////////////////////////////////////////////////////////////////////////
2 // Name: autocapture.cpp
3 // Purpose: Implement wxCtrlMaskOut class
4 // Author: Utensil Candel (UtensilCandel@@gmail.com)
5 // Licence: wxWindows licence
6 /////////////////////////////////////////////////////////////////////////////
8 // For compilers that support precompilation, includes "wx/wx.h".
15 #include "autocapture.h"
21 #include "wx/bitmap.h"
22 #include "wx/filename.h"
23 #include "wx/notebook.h"
32 // ----------------------------------------------------------------------------
33 // AutoCaptureMechanism
34 // ----------------------------------------------------------------------------
36 AutoCaptureMechanism
::AutoCaptureMechanism(wxNotebook
*notebook
,
38 : m_notebook(notebook
),
46 wxString AutoCaptureMechanism
::default_dir
= wxT("screenshots");
49 wxString AutoCaptureMechanism
::GetDefaultDirectoryAbsPath()
51 wxFileName output
= wxFileName
::DirName(GetDefaultDirectory());
52 output
.MakeAbsolute();
53 return output
.GetFullPath();
57 void AutoCaptureMechanism
::Delay(int seconds
)
59 // TODO: Switch this to use wxTimer.
62 clock_t start
= clock();
63 while ( clock() - start
< (clock_t)CLOCKS_PER_SEC
* seconds
)
68 bool AutoCaptureMechanism
::Capture(wxBitmap
* bitmap
, int x
, int y
,
69 int width
, int height
, int delay
)
71 // Somehow wxScreenDC.Blit() doesn't work under Mac for now. Here is a trick.
74 // wxExecute(wxT("screencapture -x ") + tempfile, wxEXEC_SYNC);
76 char captureCommand
[80] =""; // a reasonable max size is 80
77 sprintf(captureCommand
, "sleep %d;%s", delay
, "screencapture -x /tmp/wx_screen_capture.png");
78 system(captureCommand
);
80 if(delay
) Delay(delay
);
85 fullscreen
= wxBitmap(wxT("/tmp/wx_screen_capture.png"), wxBITMAP_TYPE_PNG
);
87 while(!fullscreen
.IsOk());
89 *bitmap
= fullscreen
.GetSubBitmap(wxRect(x
, y
, width
, height
));
91 // to prevent loading the old screenshot next time
92 system("rm /tmp/wx_screen_capture.png");
96 #else // Under other paltforms, take a real screenshot
98 if(delay
) Delay(delay
);
100 // Create a DC for the whole screen area
103 bitmap
->Create(width
, height
);
105 // Create a memory DC that will be used for actually taking the screenshot
107 memDC
.SelectObject((*bitmap
));
110 // Blit (in this case copy) the actual screen on the memory DC
111 // and thus the Bitmap
112 memDC
.Blit( 0, // Copy to this X coordinate
113 0, // Copy to this Y coordinate
114 width
, // Copy this width
115 height
, // Copy this height
116 &dcScreen
, // From where do we copy?
117 x
, // What's the X offset in the original DC?
118 y
// What's the Y offset in the original DC?
121 // Select the Bitmap out of the memory DC by selecting a new
122 // uninitialized Bitmap
123 memDC
.SelectObject(wxNullBitmap
);
124 #endif // #ifdef __WXMAC__
130 bool AutoCaptureMechanism
::Capture(wxBitmap
* bitmap
, wxRect rect
, int delay
)
132 wxPoint origin
= rect
.GetPosition();
133 return Capture(bitmap
, origin
.x
, origin
.y
, rect
.GetWidth(), rect
.GetHeight(), delay
);
137 void AutoCaptureMechanism
::Save(wxBitmap
* screenshot
, const wxString
& fileName
)
139 // make sure default_dir exists
140 if (!wxDirExists(default_dir
))
141 wxMkdir(default_dir
);
143 wxFileName
fullFileName(default_dir
, "appear-" + fileName
+
144 "-" + wxPlatformInfo
::Get().GetPortIdShortName() + ".png");
146 // do not overwrite already existing files with this name
147 while (fullFileName
.FileExists())
148 fullFileName
.SetName(fullFileName
.GetName() + "_");
150 // save the screenshot as a PNG
151 screenshot
->SaveFile(fullFileName
.GetFullPath(), wxBITMAP_TYPE_PNG
);
154 void AutoCaptureMechanism
::CaptureAll()
156 // start from the first page
157 m_notebook
->SetSelection(0);
160 for (ControlList
::iterator it
= m_controlList
.begin();
161 it
!= m_controlList
.end();
166 if (ctrl
.flag
== AJ_TurnPage
) // Turn to next page
168 m_notebook
->SetSelection(m_notebook
->GetSelection() + 1);
173 // create the screenshot
174 wxBitmap
screenshot(1, 1);
175 Capture(&screenshot
, ctrl
);
177 if(ctrl
.flag
& AJ_Union
)
179 // union screenshots until AJ_UnionEnd
183 it
->name
= ctrl
.name
; //preserving the name
184 wxBitmap
screenshot2(1, 1);
185 Capture(&screenshot2
, *it
);
186 wxBitmap
combined(1, 1);
187 Union(&screenshot
, &screenshot2
, &combined
);
188 screenshot
= combined
;
190 while(!(it
->flag
& AJ_UnionEnd
));
194 Save(&screenshot
, ctrl
.name
);
198 bool AutoCaptureMechanism
::Capture(wxBitmap
* bitmap
, Control
& ctrl
)
200 // no manual specification for the control name
201 // or name adjustment is disabled globally
202 if (ctrl
.name
== wxT("") || m_flag
& AJ_DisableNameAdjust
)
204 // Get its name from wxRTTI
205 ctrl
.name
= ctrl
.ctrl
->GetClassInfo()->GetClassName();
210 wxRect rect
= GetRect(ctrl
.ctrl
, ctrl
.flag
);
212 if (ctrl
.flag
& AJ_Dropdown
&& !(m_flag
& AJ_DisableDropdown
))
214 // for drop-down controls we need the help of the user
215 wxString caption
= _("Drop-down screenshot...");
217 wxString
::Format(_("Do you wish to capture the drop-down list of '%s' ?\n\n If YES, please drop down the list of '%s' in 5 seconds after closing this message box.\n If NO, the screenshot for this control won't contain its drop-down list."),
218 ctrl
.name
, ctrl
.name
);
220 choice
= wxMessageBox(msg
, caption
, wxYES_NO
, m_notebook
);
225 ctrl
.ctrl
->SetCursor(wxCursor(wxCURSOR_HAND
));
227 // Do some rect adjust so it can include the dropdown list
228 // This adjust isn't pretty, but it works fine on all three paltforms.
229 // Looking forward to a better solution
230 int h
= rect
.GetHeight();
231 rect
.SetHeight(h
* 4);
235 // cut off "wx" and change the name into lowercase.
236 // e.g. wxButton will have a name of "button" at the end
237 ctrl
.name
.StartsWith(wxT("wx"), &(ctrl
.name
));
238 ctrl
.name
.MakeLower();
240 // take the screenshot
241 Capture(bitmap
, rect
, (choice
== wxYES
)?
5:0);
243 if (choice
== wxYES
) ctrl
.ctrl
->SetCursor(wxNullCursor
);
245 if (ctrl
.flag
& AJ_RegionAdjust
)
252 bool AutoCaptureMechanism
::Union(wxBitmap
* top
, wxBitmap
* bottom
, wxBitmap
* result
)
254 int w1
, w2
, h1
, h2
, w
, h
;
255 w1
= top
->GetWidth();
256 w2
= bottom
->GetWidth();
257 h1
= top
->GetHeight();
258 h2
= bottom
->GetHeight();
260 const int gap_between
= 20;
262 w
= (w1
>= w2
) ? w1
: w2
;
263 h
= h1
+ h2
+ gap_between
;
265 result
->Create(w
, h
);
268 dstDC
.SelectObject((*result
));
270 dstDC
.SetBrush(*wxWHITE_BRUSH
);
272 dstDC
.DrawBitmap((*top
), 0, 0);
273 dstDC
.DrawBitmap((*bottom
), 0, h1
+ gap_between
);
275 dstDC
.SelectObject(wxNullBitmap
);
280 wxRect AutoCaptureMechanism
::GetRect(wxWindow
* ctrl
, int flag
)
282 if( (!(m_flag
& AJ_DisableRegionAdjust
) && (flag
& AJ_RegionAdjust
))
283 || (m_flag
& AJ_AlwaysRegionAdjust
) )
285 wxWindow
* parent
= ctrl
->GetParent();
286 wxSizer
* sizer
= parent
->GetSizer();
288 //The assertion won't fail if controls are still managed by wxSizer, and it's unlikely to
289 //change in the future.
291 "The GUI that AutoCaptureMechanism working with doesn't manage controls with wxSizer");
296 +---------+-----------+---------+
298 +---------+-----------+---------+
299 | label | ctrl | label |
300 +---------+-----------+---------+
302 +---------+-----------+---------+
305 m_grid
= new wxFlexGridSizer(3, 3, m_margin
, m_margin
);
309 for (int i
= 0; i
< 4; ++i
)
310 l
[i
] = new wxStaticText(parent
, wxID_ANY
, wxT(" "));
313 m_grid
->Add(new wxStaticText(parent
, wxID_ANY
, wxT(" ")));
315 m_grid
->Add(new wxStaticText(parent
, wxID_ANY
, wxT(" ")));
316 m_grid
->Add(ctrl
, 1, wxEXPAND
);
317 m_grid
->Add(new wxStaticText(parent
, wxID_ANY
, wxT(" ")));
319 m_grid
->Add(new wxStaticText(parent
, wxID_ANY
, wxT(" ")));
323 parent
->SetSizer(sizer
);
329 return wxRect(l
[0]->GetScreenRect().GetBottomRight(),
330 l
[3]->GetScreenRect().GetTopLeft());
334 return ctrl
->GetScreenRect().Inflate(m_margin
);
338 void AutoCaptureMechanism
::PutBack(wxWindow
* ctrl
)
342 m_grid
->Detach(ctrl
);
344 wxSizerItemList children
= m_grid
->GetChildren();
346 for (wxSizerItemList
::iterator it
= children
.begin(); it
!= children
.end(); ++it
)
348 wxSizerItem
* item
= *it
;
349 if (item
->IsWindow()) delete (*it
)->GetWindow();
352 wxSizer
* sizer
= ctrl
->GetParent()->GetSizer();
354 //The assertion won't fail if controls are still managed by wxSizer, and it's unlikely to
355 //change in the future.
357 "The GUI that AutoCaptureMechanism working with doesn't manage controls with wxSizer");
359 sizer
->Detach(m_grid
);