]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/screenshotgen/src/autocapture.cpp
Include <fcntl.h> from a header using fcntl().
[wxWidgets.git] / utils / screenshotgen / src / autocapture.cpp
index 026a797cce5bd1e9760e9beba01ae6a40354382d..1ad9723dbb736b765bbd6043334d89c29c651c27 100644 (file)
 // Purpose:     Implement wxCtrlMaskOut class
 // Author:      Utensil Candel (UtensilCandel@@gmail.com)
 // RCS-ID:      $Id$
-// Licence:     wxWindows license
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-    #pragma hdrstop
+#pragma hdrstop
 #endif
 
-// for all others, include the necessary headers
+#include "autocapture.h"
+
 #ifndef WX_PRECOMP
-    #include "wx/wx.h"
+#include "wx/wx.h"
 #endif
 
-#include <wx/filename.h>
-#include "autocapture.h"
+#include "wx/bitmap.h"
+#include "wx/filename.h"
+#include "wx/notebook.h"
+
+#include <ctime>
+
+#ifdef __WXMAC__
+#include <cstring>
+#endif
 
 
 // ----------------------------------------------------------------------------
 // AutoCaptureMechanism
 // ----------------------------------------------------------------------------
 
+AutoCaptureMechanism::AutoCaptureMechanism(wxNotebook *notebook,
+                                           int flag, int margin)
+: m_notebook(notebook),
+  m_flag(flag),
+  m_margin(margin),
+  m_grid(NULL)
+{
+}
+
 /* static */
-wxBitmap AutoCaptureMechanism::Capture(int x, int y, int width, int height)
+wxString AutoCaptureMechanism::default_dir = wxT("screenshots");
+
+/* static */
+wxString AutoCaptureMechanism::GetDefaultDirectoryAbsPath()
+{
+    wxFileName output = wxFileName::DirName(GetDefaultDirectory());
+    output.MakeAbsolute();
+    return output.GetFullPath();
+}
+
+/* static */
+void AutoCaptureMechanism::Delay(int seconds)
+{
+    // TODO: Switch this to use wxTimer.
+
+    // Wait for 3 seconds
+    clock_t start = clock();
+    while ( clock() - start < (clock_t)CLOCKS_PER_SEC * seconds)
+        wxYieldIfNeeded();
+}
+
+/* static */
+bool AutoCaptureMechanism::Capture(wxBitmap* bitmap, int x, int y,
+                                   int width, int height, int delay)
 {
     // Somehow wxScreenDC.Blit() doesn't work under Mac for now. Here is a trick.
 #ifdef __WXMAC__
 
-    // wxExecute(_T("screencapture -x ") + tempfile, wxEXEC_SYNC);
+    // wxExecute(wxT("screencapture -x ") + tempfile, wxEXEC_SYNC);
 
-    system("screencapture -x /tmp/wx_screen_capture.png");
+    char captureCommand[80] =""; // a reasonable max size is 80
+    sprintf(captureCommand, "sleep %d;%s", delay, "screencapture -x /tmp/wx_screen_capture.png");
+    system(captureCommand);
 
-    wxBitmap fullscreen;
+    if(delay) Delay(delay);
 
+    wxBitmap fullscreen;
     do
     {
-        fullscreen = wxBitmap(_T("/tmp/wx_screen_capture.png"), wxBITMAP_TYPE_PNG);
+        fullscreen = wxBitmap(wxT("/tmp/wx_screen_capture.png"), wxBITMAP_TYPE_PNG);
     }
     while(!fullscreen.IsOk());
 
-    wxBitmap screenshot = fullscreen.GetSubBitmap(wxRect(x,y,width,height));
+    *bitmap = fullscreen.GetSubBitmap(wxRect(x, y, width, height));
+
+    // to prevent loading the old screenshot next time
+    system("rm /tmp/wx_screen_capture.png");
+
+    return true;
 
 #else // Under other paltforms, take a real screenshot
 
+    if(delay) Delay(delay);
+
     // Create a DC for the whole screen area
     wxScreenDC dcScreen;
 
-    // Create a Bitmap that will later on hold the screenshot image
-    // Note that the Bitmap must have a size big enough to hold the screenshot
-    // -1 means using the current default colour depth
-    wxBitmap screenshot(width, height, -1);
+    bitmap->Create(width, height);
 
     // Create a memory DC that will be used for actually taking the screenshot
     wxMemoryDC memDC;
-
-    // Tell the memory DC to use our Bitmap
-    // all drawing action on the memory DC will go to the Bitmap now
-    memDC.SelectObject(screenshot);
+    memDC.SelectObject((*bitmap));
+    memDC.Clear();
 
     // Blit (in this case copy) the actual screen on the memory DC
     // and thus the Bitmap
@@ -79,14 +124,32 @@ wxBitmap AutoCaptureMechanism::Capture(int x, int y, int width, int height)
     memDC.SelectObject(wxNullBitmap);
 #endif // #ifdef __WXMAC__
 
-    return screenshot;
+    return true;
 }
 
 /* static */
-wxBitmap AutoCaptureMechanism::Capture(wxRect rect)
+bool AutoCaptureMechanism::Capture(wxBitmap* bitmap, wxRect rect, int delay)
 {
     wxPoint origin = rect.GetPosition();
-    return Capture(origin.x, origin.y, rect.GetWidth(), rect.GetHeight());
+    return Capture(bitmap, origin.x, origin.y, rect.GetWidth(), rect.GetHeight(), delay);
+}
+
+/* static */
+void AutoCaptureMechanism::Save(wxBitmap* screenshot, const wxString& fileName)
+{
+    // make sure default_dir exists
+    if (!wxDirExists(default_dir))
+        wxMkdir(default_dir);
+
+    wxFileName fullFileName(default_dir, "appear-" + fileName +
+        "-" + wxPlatformInfo::Get().GetPortIdShortName() + ".png");
+
+    // do not overwrite already existing files with this name
+    while (fullFileName.FileExists())
+        fullFileName.SetName(fullFileName.GetName() + "_");
+
+    // save the screenshot as a PNG
+    screenshot->SaveFile(fullFileName.GetFullPath(), wxBITMAP_TYPE_PNG);
 }
 
 void AutoCaptureMechanism::CaptureAll()
@@ -109,18 +172,35 @@ void AutoCaptureMechanism::CaptureAll()
         }
 
         // create the screenshot
-        wxBitmap screenshot = Capture(ctrl);
-        if (ctrl.flag & AJ_Union)
-            screenshot = Union(screenshot, Capture(*(++it)));
+        wxBitmap screenshot(1, 1);
+        Capture(&screenshot, ctrl);
+
+        if(ctrl.flag & AJ_Union)
+        {
+            // union screenshots until AJ_UnionEnd
+            do
+            {
+                ++it;
+                it->name = ctrl.name; //preserving the name
+                wxBitmap screenshot2(1, 1);
+                Capture(&screenshot2, *it);
+                wxBitmap combined(1, 1);
+                Union(&screenshot, &screenshot2, &combined);
+                screenshot = combined;
+            }
+            while(!(it->flag & AJ_UnionEnd));
+        }
 
         // and save it
-        Save(screenshot, ctrl.name);
+        Save(&screenshot, ctrl.name);
     }
 }
 
-wxBitmap AutoCaptureMechanism::Capture(Control& ctrl)
+bool AutoCaptureMechanism::Capture(wxBitmap* bitmap, Control& ctrl)
 {
-    if (ctrl.name == wxT(""))  // no manual specification for the control name
+    // no manual specification for the control name
+    // or name adjustment is disabled globally
+    if (ctrl.name == wxT("") || m_flag & AJ_DisableNameAdjust)
     {
         // Get its name from wxRTTI
         ctrl.name = ctrl.ctrl->GetClassInfo()->GetClassName();
@@ -128,172 +208,138 @@ wxBitmap AutoCaptureMechanism::Capture(Control& ctrl)
 
     int choice = wxNO;
 
-    // for drop-down controls we need the help of the user
-    if (ctrl.flag & AJ_Dropdown)
+    wxRect rect = GetRect(ctrl.ctrl, ctrl.flag);
+
+    if (ctrl.flag & AJ_Dropdown && !(m_flag & AJ_DisableDropdown))
     {
+        // for drop-down controls we need the help of the user
         wxString caption = _("Drop-down screenshot...");
         wxString msg =
-            wxString::Format(_("Do you wish to capture the drop-down list of '%s' ?\n\nIf you click YES you must drop-down the list of '%s' in 3 seconds after closing this message box.\nIf you click NO the screenshot for this control won't contain its drop-down list."),
+            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."),
                              ctrl.name, ctrl.name);
 
         choice = wxMessageBox(msg, caption, wxYES_NO, m_notebook);
+
         if (choice == wxYES)
         {
-            using std::clock;
-            using std::clock_t;
-
-            // Wait for 3 seconds
-            clock_t start = clock();
-            while (clock() - start < CLOCKS_PER_SEC * 3)
-                wxYieldIfNeeded();
+            //A little hint
+            ctrl.ctrl->SetCursor(wxCursor(wxCURSOR_HAND));
+
+            // Do some rect adjust so it can include the dropdown list
+            // This adjust isn't pretty, but it works fine on all three paltforms.
+            // Looking forward to a better solution
+            int h = rect.GetHeight();
+            rect.SetHeight(h * 4);
         }
     }
 
-    wxRect rect = GetRect(ctrl.ctrl, ctrl.flag);
-
-    // Do some rect adjust so it can include the dropdown list;
-    // currently this only works well under MSW; not adjusted for Linux and Mac OS
-    if (ctrl.flag & AJ_Dropdown && choice == wxYES)
-    {
-//          #ifdef __WXMSW__
-        int h = rect.GetHeight();
-        rect.SetHeight(h * 4);
-//          #endif
-    }
-
     // cut off "wx" and change the name into lowercase.
     // e.g. wxButton will have a name of "button" at the end
-    ctrl.name.StartsWith(_T("wx"), &(ctrl.name));
+    ctrl.name.StartsWith(wxT("wx"), &(ctrl.name));
     ctrl.name.MakeLower();
 
     // take the screenshot
-    wxBitmap screenshot = Capture(rect);
+    Capture(bitmap, rect, (choice == wxYES)?5:0);
+
+    if (choice == wxYES) ctrl.ctrl->SetCursor(wxNullCursor);
 
     if (ctrl.flag & AJ_RegionAdjust)
         PutBack(ctrl.ctrl);
 
-    return screenshot;
+    return true;
 }
 
-wxBitmap AutoCaptureMechanism::Union(wxBitmap pic1, wxBitmap pic2)
+/* static */
+bool AutoCaptureMechanism::Union(wxBitmap* top, wxBitmap* bottom, wxBitmap* result)
 {
     int w1, w2, h1, h2, w, h;
-    w1 = pic1.GetWidth();
-    w2 = pic2.GetWidth();
-    h1 = pic1.GetHeight();
-    h2 = pic2.GetHeight();
+    w1 = top->GetWidth();
+    w2 = bottom->GetWidth();
+    h1 = top->GetHeight();
+    h2 = bottom->GetHeight();
 
     const int gap_between = 20;
 
     w = (w1 >= w2) ? w1 : w2;
     h = h1 + h2 + gap_between;
 
-    wxBitmap result(w, h, -1);
+    result->Create(w, h);
 
     wxMemoryDC dstDC;
-    dstDC.SelectObject(result);
+    dstDC.SelectObject((*result));
 
-    dstDC.DrawBitmap(pic1, 0, 0, false);
-    dstDC.DrawBitmap(pic2, 0, h1 + gap_between, false);
+    dstDC.SetBrush(*wxWHITE_BRUSH);
+    dstDC.Clear();
+    dstDC.DrawBitmap((*top), 0, 0);
+    dstDC.DrawBitmap((*bottom), 0, h1 + gap_between);
 
     dstDC.SelectObject(wxNullBitmap);
 
-    wxMemoryDC maskDC;
-    wxBitmap mask(w, h, 1);
-    maskDC.SelectObject(mask);
-
-    maskDC.SetPen(*wxTRANSPARENT_PEN);
-    maskDC.SetBrush(*wxBLACK_BRUSH);
-    maskDC.DrawRectangle(0, 0, w + 1, h + 1);
-
-    maskDC.SetBrush(*wxWHITE_BRUSH);
-    maskDC.DrawRectangle(0, 0, w1, h1);
-    maskDC.DrawRectangle(0, h1 + gap_between, w2, h2);
-    maskDC.SelectObject(wxNullBitmap);
-
-    result.SetMask(new wxMask(mask));
-
-    return result;
-}
-
-void AutoCaptureMechanism::Save(wxBitmap screenshot, wxString fileName)
-{
-    // make sure m_dir exists
-    if (!wxDirExists(m_dir))
-        wxMkdir(m_dir);
-
-    wxFileName fullFileName(m_dir, fileName + ".png");
-
-    // do not overwrite already existing files with this name
-    while (fullFileName.FileExists())
-        fullFileName.SetName(fullFileName.GetName() + "_");
-
-    // save the screenshot as a PNG
-    screenshot.SaveFile(fullFileName.GetFullPath(), wxBITMAP_TYPE_PNG);
+    return true;
 }
 
 wxRect AutoCaptureMechanism::GetRect(wxWindow* ctrl, int flag)
 {
-    if (flag & AJ_RegionAdjust)
+    if( (!(m_flag & AJ_DisableRegionAdjust) && (flag & AJ_RegionAdjust))
+        || (m_flag & AJ_AlwaysRegionAdjust) )
     {
         wxWindow * parent = ctrl->GetParent();
         wxSizer * sizer = parent->GetSizer();
 
-        if (sizer)
-        {
-            sizer->Detach(ctrl);
-
-            /*
-            +---------+-----------+---------+
-            |    0    |   label   |    1    |
-            +---------+-----------+---------+
-            |  label  |    ctrl   |  label  |
-            +---------+-----------+---------+
-            |    2    |   label   |    3    |
-            +---------+-----------+---------+
-           */
-
-            m_grid = new wxFlexGridSizer(3, 3, m_border, m_border);
-
-            wxStaticText* l[4];
-
-            for (int i = 0; i < 4; ++i)
-                l[i] = new wxStaticText(parent, wxID_ANY, wxT(" "));
-
-            m_grid->Add(l[0]);
-            m_grid->Add(new wxStaticText(parent, wxID_ANY, wxT(" ")));
-            m_grid->Add(l[1]);
-            m_grid->Add(new wxStaticText(parent, wxID_ANY, wxT(" ")));
-            m_grid->Add(ctrl);
-            m_grid->Add(new wxStaticText(parent, wxID_ANY, wxT(" ")));
-            m_grid->Add(l[2]);
-            m_grid->Add(new wxStaticText(parent, wxID_ANY, wxT(" ")));
-            m_grid->Add(l[3]);
-
-            sizer->Add(m_grid);
-            parent->SetSizer(sizer);
-            parent->Layout();
-
-            parent->Refresh();
-            wxYield();
-
-            return wxRect(l[0]->GetScreenRect().GetBottomRight(),
-                    l[3]->GetScreenRect().GetTopLeft());
-
-        }
-        else  // Actually it won't get here working with the current guiframe.h/guiframe.cpp
-        {
-            return ctrl->GetScreenRect().Inflate(m_border);
-        }
+        //The assertion won't fail if controls are still managed by wxSizer, and it's unlikely to
+        //change in the future.
+        wxASSERT_MSG(sizer,
+        "The GUI that AutoCaptureMechanism working with doesn't manage controls with wxSizer");
+
+        sizer->Detach(ctrl);
+
+        /*
+        +---------+-----------+---------+
+        |    0    |   label   |    1    |
+        +---------+-----------+---------+
+        |  label  |    ctrl   |  label  |
+        +---------+-----------+---------+
+        |    2    |   label   |    3    |
+        +---------+-----------+---------+
+       */
+
+        m_grid = new wxFlexGridSizer(3, 3, m_margin, m_margin);
+
+        wxStaticText* l[4];
+
+        for (int i = 0; i < 4; ++i)
+            l[i] = new wxStaticText(parent, wxID_ANY, wxT(" "));
+
+        m_grid->Add(l[0]);
+        m_grid->Add(new wxStaticText(parent, wxID_ANY, wxT(" ")));
+        m_grid->Add(l[1]);
+        m_grid->Add(new wxStaticText(parent, wxID_ANY, wxT(" ")));
+        m_grid->Add(ctrl, 1, wxEXPAND);
+        m_grid->Add(new wxStaticText(parent, wxID_ANY, wxT(" ")));
+        m_grid->Add(l[2]);
+        m_grid->Add(new wxStaticText(parent, wxID_ANY, wxT(" ")));
+        m_grid->Add(l[3]);
+
+        sizer->Add(m_grid);
+        parent->SetSizer(sizer);
+        parent->Layout();
+
+        parent->Refresh();
+        wxYield();
+
+        return wxRect(l[0]->GetScreenRect().GetBottomRight(),
+                l[3]->GetScreenRect().GetTopLeft());
     }
     else
     {
-       return ctrl->GetScreenRect().Inflate(m_border);
+       return ctrl->GetScreenRect().Inflate(m_margin);
     }
 }
 
 void AutoCaptureMechanism::PutBack(wxWindow * ctrl)
 {
+    if(!m_grid) return;
+
     m_grid->Detach(ctrl);
 
     wxSizerItemList children = m_grid->GetChildren();
@@ -305,8 +351,16 @@ void AutoCaptureMechanism::PutBack(wxWindow * ctrl)
     }
 
     wxSizer * sizer = ctrl->GetParent()->GetSizer();
+
+    //The assertion won't fail if controls are still managed by wxSizer, and it's unlikely to
+    //change in the future.
+    wxASSERT_MSG(sizer,
+    "The GUI that AutoCaptureMechanism working with doesn't manage controls with wxSizer");
+
     sizer->Detach(m_grid);
     delete m_grid;
+    m_grid = NULL;
+
     sizer->Add(ctrl);
 }