]> git.saurik.com Git - wxWidgets.git/commitdiff
patch from Utensil Candel which refactors and documents the AutoCaptureMechanism...
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Wed, 14 Jan 2009 13:26:37 +0000 (13:26 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Wed, 14 Jan 2009 13:26:37 +0000 (13:26 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58091 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

utils/screenshotgen/src/autocapture.cpp
utils/screenshotgen/src/autocapture.h
utils/screenshotgen/src/screenshot_main.cpp
utils/screenshotgen/src/screenshot_main.h

index 62ae1b88dce94d1d447635a712a6e6ef15a31eda..3a4abe2e3e52c38a7acaf6726616acb9a2310c49 100644 (file)
@@ -31,6 +31,9 @@
 // AutoCaptureMechanism
 // ----------------------------------------------------------------------------
 
+/* static */
+wxString AutoCaptureMechanism::default_dir = _T("screenshots");
+
 /* static */
 void AutoCaptureMechanism::Delay(int seconds)
 {
@@ -73,6 +76,8 @@ wxBitmap AutoCaptureMechanism::Capture(int x, int y, int width, int height, int
 
 #else // Under other paltforms, take a real screenshot
 
+    wxUnusedVar(delay);
+
     // Create a DC for the whole screen area
     wxScreenDC dcScreen;
 
@@ -114,6 +119,23 @@ wxBitmap AutoCaptureMechanism::Capture(wxRect rect, int delay)
     return Capture(origin.x, origin.y, rect.GetWidth(), rect.GetHeight(), delay);
 }
 
+/* static */
+void AutoCaptureMechanism::Save(wxBitmap screenshot, wxString fileName)
+{
+    // make sure default_dir exists
+    if (!wxDirExists(default_dir))
+        wxMkdir(default_dir);
+
+    wxFileName fullFileName(default_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);
+}
+
 void AutoCaptureMechanism::CaptureAll()
 {
     // start from the first page
@@ -133,10 +155,25 @@ void AutoCaptureMechanism::CaptureAll()
             continue;
         }
 
+//        // create the screenshot
+//        wxBitmap screenshot = Capture(ctrl);
+//        if (ctrl.flag & AJ_Union)
+//            screenshot = Union(screenshot, Capture(*(++it)));
+//
+//        // and save it
+//        Save(screenshot, ctrl.name);
         // create the screenshot
         wxBitmap screenshot = Capture(ctrl);
-        if (ctrl.flag & AJ_Union)
-            screenshot = Union(screenshot, Capture(*(++it)));
+
+        if(ctrl.flag & AJ_Union)
+        {
+            do
+            {
+                ctrl = *(++it);
+                screenshot = Union(screenshot, Capture(ctrl));
+            }
+            while(!(ctrl.flag & AJ_UnionEnd));
+        }
 
         // and save it
         Save(screenshot, ctrl.name);
@@ -209,14 +246,8 @@ wxBitmap AutoCaptureMechanism::Union(wxBitmap pic1, wxBitmap pic2)
 
     wxBitmap result(w, h, -1);
 
-    wxMemoryDC dstDC;
-    dstDC.SelectObject(result);
-
-    dstDC.DrawBitmap(pic1, 0, 0, false);
-    dstDC.DrawBitmap(pic2, 0, h1 + gap_between, false);
-
-    dstDC.SelectObject(wxNullBitmap);
-
+#if 0
+    //Mask the bitmap "result"
     wxMemoryDC maskDC;
     wxBitmap mask(w, h, 1);
     maskDC.SelectObject(mask);
@@ -231,24 +262,20 @@ wxBitmap AutoCaptureMechanism::Union(wxBitmap pic1, wxBitmap pic2)
     maskDC.SelectObject(wxNullBitmap);
 
     result.SetMask(new wxMask(mask));
+#endif
 
-    return result;
-}
-
-void AutoCaptureMechanism::Save(wxBitmap screenshot, wxString fileName)
-{
-    // make sure m_dir exists
-    if (!wxDirExists(m_dir))
-        wxMkdir(m_dir);
+    wxMemoryDC dstDC;
+    dstDC.SelectObject(result);
 
-    wxFileName fullFileName(m_dir, fileName + ".png");
+    dstDC.SetPen(*wxTRANSPARENT_PEN);
+    dstDC.SetBrush(*wxWHITE_BRUSH);
+    dstDC.DrawRectangle(-1, -1, w + 1, h + 1);
+    dstDC.DrawBitmap(pic1, 0, 0, false);
+    dstDC.DrawBitmap(pic2, 0, h1 + gap_between, false);
 
-    // do not overwrite already existing files with this name
-    while (fullFileName.FileExists())
-        fullFileName.SetName(fullFileName.GetName() + "_");
+    dstDC.SelectObject(wxNullBitmap);
 
-    // save the screenshot as a PNG
-    screenshot.SaveFile(fullFileName.GetFullPath(), wxBITMAP_TYPE_PNG);
+    return result;
 }
 
 wxRect AutoCaptureMechanism::GetRect(wxWindow* ctrl, int flag)
@@ -272,7 +299,7 @@ wxRect AutoCaptureMechanism::GetRect(wxWindow* ctrl, int flag)
             +---------+-----------+---------+
            */
 
-            m_grid = new wxFlexGridSizer(3, 3, m_border, m_border);
+            m_grid = new wxFlexGridSizer(3, 3, m_margin, m_margin);
 
             wxStaticText* l[4];
 
@@ -302,12 +329,12 @@ wxRect AutoCaptureMechanism::GetRect(wxWindow* ctrl, int flag)
         }
         else  // Actually it won't get here working with the current guiframe.h/guiframe.cpp
         {
-            return ctrl->GetScreenRect().Inflate(m_border);
+            return ctrl->GetScreenRect().Inflate(m_margin);
         }
     }
     else
     {
-       return ctrl->GetScreenRect().Inflate(m_border);
+       return ctrl->GetScreenRect().Inflate(m_margin);
     }
 }
 
index e0aed4d36e89c64423a7335322d8f940cd494838..4adf3936b888ae14f741d6f0fcbcf7f0ce53bee5 100644 (file)
 
 #include <wx/notebook.h>
 
+/**
+    GlobalAdjustFlags works with AutoCaptureMechanism's constructor, to disbale/enable
+    some auto-adjustment for all controls.
 
-// TODO: document what these flags mean
+    They are used to make AutoCaptureMechanism more configurable and provide a fallback
+    to detect the bugs that the adjustments intended to avoid.
+
+    @see AdjustFlags
+*/
+enum GlobalAdjustFlags
+{
+    /**
+        This is the default. All adjustments instructed in
+        AutoCaptureMechanism::RegisterControl() will be performed.
+    */
+    AJ_NormalAll = 0,
+
+    /**
+        Disable region adjustment for all controls.
+    */
+    AJ_DisableRegionAdjust =  1 << 0,
+
+    /**
+        Enable region adjustment for all controls.
+    */
+    AJ_AlwaysRegionAdjust =  1 << 1,
+
+    /**
+        Disable name adjustment for all controls.
+    */
+    AJ_DisableNameAdjust = 1 << 2,
+
+    /**
+        For all the "Drop-down Controls", e.g. wxChoice, do not prompt the user about whether
+        to capture their drop-down state, and always capture only its non-drop-down state.
+    */
+    AJ_DisableDropdown = 1 << 3
+};
+
+/**
+    AdjustFlags works with AutoCaptureMechanism::RegisterControl() to specify how to
+    adjust the screenshot of the current control.
+
+    They are used to avoid bugs, look better or interact with user etc.
+
+    @see GlobalAdjustFlags
+*/
 enum AdjustFlags
 {
+    /**
+        This is the default. Perform no adjustment for this control.
+    */
     AJ_Normal = 0,
+
+    /**
+        Perform region adjustment for this control.
+
+        On some platforms and for some controls, wxWindow::GetScreenRect() will return
+        a smaller or deflected region. In these cases, the screenshots we get are incomplete.
+        It's recommended for everyone to fix the controls' code, yet this flag provides a
+        workaround to get a guaranteed correct region without using wxWindow::GetScreenRect().
+
+        This workaround("label trick") is inspired by (or say stolen from) Auria's work.
+    */
     AJ_RegionAdjust = 1 << 0,
+
+    /**
+        This flag provides a way to capture the drop-down state of "Drop-down Controls",
+        e.g. wxChoice.
+
+        For all the "Drop-down Controls", prompt the user about whether to capture their
+        drop-down state, if the user chooses YES, he should drop down the control in about
+        3 seconds and wait util it's captured in that state.
+    */
     AJ_Dropdown = 1 << 1,
+
+    /**
+        This flag is used internally by RegisterPageTurn(). Don't use it directly unless you
+        know what you are doing.
+    */
     AJ_TurnPage = 1 << 2,
+
+    /**
+        This flag provides a functionality to union screenshots of different controls into
+        one image.
+
+        It's especially useful to demonstrate different modes/states of a control,
+        e.g. the single-line/multi-line modes of a wxTextCtrl.
+
+        For a series of controls to be unioned, you should specify AJ_Union for the first,
+        and AJ_UnionEnd for the last. For the controls between them, you can either specify
+        AJ_Union or not.
+    */
     AJ_Union = 1 << 3,
+
+    /**
+        @see AJ_Union.
+    */
     AJ_UnionEnd = 1 << 4
 };
 
+/**
+    @class AutoCaptureMechanism
+
+    AutoCaptureMechanism provides an easy-to-use and adjustable facility to take the screenshots
+    for all controls fully automaticly and correctly. It also provides an advanced feature to
+    union screenshots of different states/modes of a control.
+
+    @section tag_filename_convention Screenshot File Name Convention
+
+    All screenshots are generated as PNG files. For a control named wxName, its screenshot file
+    name would be "name.png", e.g. "button.png" for wxButton. This is the protocol with the
+    doxygen document of wxWidgets.
+
+    By default, screenshots are generated under the subdirectory "screenshots" of current working
+    directory. During updating or adding new screenshots, first make sure screenshots are generated
+    correctly, and then copy them to the following subdirectory of docs/doxygen/images:
+
+    "wxmsw" for MS Windows, "wxgtk" for Linux and "wxmac" for Mac OS.
+
+    @section tag_gui_assumption The Assumption of GUI
+
+    Unfortunately, this class have an assumption about the structure of GUI:
+    It must have the follwoing top-down structure:
+
+    wxNotebook->wxPanel->wxSizer->wxControl
+
+    That means, in the wxNotebook associated with this class, controls that needs to be
+    taken screenshots are placed on different panels(for grouping) and layed out by wxSizers.
+
+    @section tag_tutorial Tutorial
+
+    In the contruction, you should associate a wxNotebook with this class, in that wxNotebook,
+    controls that needs to be captured are placed on different panels(for grouping).
+
+    When you register controls, you should do it in order: Register the controls on the first
+    panel(using RegisterControl()), and then register a page turn(using RegisterPageTurn()),
+    so this class can turn a page of the wxNotebook to present the second page. And then
+    you register the controls on the second panel, then a page turn, and so on.
+
+    When you are done, simply call CaptureAll(), then screenshots of all controls will be
+    automaticly generated.
+
+    @section tag_autoadjust Make Use of Auto Adjustments
 
-// ----------------------------------------------------------------------------
-// class AutoCaptureMechanism
-// ----------------------------------------------------------------------------
+    First take a look at the document of RegisterControl(), enum AdjustFlags and
+    GlobalAdjustFlags.
 
+    And then, ScreenshotFrame::OnCaptureAllControls() is a good example of making use of
+    auto adjustment. Taking a look at it will get you started.
+
+    @section tag_developer_note Notes for Developers
+
+    @subsection tag_cnc CaptureAll() and Capture()
+
+    The implementation of Auto Adjustments is in CaptureAll() and Capture(), the code is
+    short, quite readable and well commented, please read the codes before any modification.
+
+    If you need the class to do something sepcial for you, consider introducing a new flag
+    and implement it in them. For an operation performed on multiple controls, implemente
+    its logic in CaptureAll(), otherwise in the private member Capture().
+
+    @subsection tag_yield_issue wxYield Issues
+
+    Not quite a good habit, but this class made a lot of use of wxYield()/wxYieldIfNeeded().
+    They are used to ensure the update of GUI(e.g. the page turn of wxNotebook) is done
+    before any further screenshot-taking, or to do the timing(in Delay()). Without their use,
+    there would be subtle bugs.
+
+    I've read documents about wxYield() and understand the down side of it before using it.
+    But I didn't find a better approach to do those things, and I used them carefully. So
+    please DO NOT remove any of these wxYield()s unless you're sure that it won't cause problems
+    on all of MS Windows XP/Vista, Linux(Ubuntu/Fedora), Mac OS Tiger/Leopard. And please
+    help me to find a better approach, thank you :)
+*/
 class AutoCaptureMechanism
 {
 public:
+    /**
+        Constructor.
+
+        @param notebook
+        The wxNotebook associated with this class.Please see @ref tag_gui_assumption
+        and @ref tag_tutorial.
+
+        @param flag
+        It's one of or a combination of GlobalAdjustFlags, to disbale/enable some auto-adjustment
+        for all controls.
+
+        @param margin
+        It's the margin around every control in the sreenshots.
+    */
     AutoCaptureMechanism(wxNotebook *notebook,
-                         wxString directory = wxT("screenshots"),
-                         int border = 5)
-        : m_notebook(notebook), m_dir(directory), m_border(border) {}
+                         int flag = AJ_NormalAll,
+                         int margin = 5)
+        : m_notebook(notebook), m_flag(flag),
+          m_margin(margin), m_grid(NULL) {}
 
     ~AutoCaptureMechanism(){}
 
-    /*
-        If wxRTTI can't get the name correctly, specify name;
-        If wxWindow::GetScreenRect doesn't get the rect correctly, set flag to AJ_RegionAdjust
+    /**
+        Register a control and perform specifid auto adjustments.
+
+        @param ctrl
+        The pointer to the control to be taken a screenshot.
+
+        @param name
+        If you find out that the screenshot for this control was generated under an incorrect
+        file name, specify @a name. e.g. for wxButton, "wxButton" or "button" are both OK.
+
+        @param flag
+
+        If you end up with an a smaller or deflected screenshot, use AJ_RegionAdjust.
+
+        If you want to caputure the "drop-down" state of a "drop-down" control, use AJ_Dropdown.
+
+        If you want to present different states of a control in one screenshot, use AJ_Union
+        and AJ_UnionEnd.
+
+        Please read the document of enum AdjustFlags, and notice that this flag could be enabled/
+        disabled by global flag GlobalAdjustFlags.
     */
-    void RegisterControl(wxWindow * ctrl, wxString name = wxT(""),
-                         int flag = AJ_Normal)
+    void RegisterControl(wxWindow * ctrl, wxString name = _T(""), int flag = AJ_Normal)
     {
         m_controlList.push_back(Control(ctrl, name, flag));
     }
 
+    /**
+        Register a control and perform specifid auto adjustments.
+
+        This is the same as RegisterControl(wxWindow * ctrl, wxString name, int flag),
+        But with it, you won't have to specify the name if you only want to auto-adjust something
+        other than name adjustment.
+    */
     void RegisterControl(wxWindow * ctrl, int flag)
     {
-        RegisterControl(ctrl, wxT(""), flag);
+        RegisterControl(ctrl, _T(""), flag);
     }
 
+    /**
+        Register a page turn.
+
+        When you finished registering the controls on a panel, remember to call it to turn the
+        wxNotebook to the next panel.
+    */
     void RegisterPageTurn()
     {
-        m_controlList.push_back(Control(0, wxT(""), AJ_TurnPage));
+        m_controlList.push_back(Control(0, _T(""), AJ_TurnPage));
     }
 
-    // capture all controls of the associated notebook
+    /**
+        Capture all registered controls of the associated wxNotebook.
+    */
     void CaptureAll();
 
-    // take a screenshot only of the given rect
-    // delay is only useful for Mac, for fixing a delay bug
+    /*
+        Static Members
+    */
+    /**
+        Take a screenshot for the given region.
+
+        @param rect is the given rectangular region.
+
+        @param delay is only useful for Mac, for fixing a delay bug. It seems that it didn't
+        fix the bug, so it might be removed soon.
+    */
     static wxBitmap Capture(wxRect rect, int delay = 0);
+
+    /**
+        Take a screenshot for the given region.
+
+        @see Capture(wxRect rect, int delay)
+    */
     static wxBitmap Capture(int x, int y, int width, int height, int delay = 0);
 
-    static void Delay(int seconds);
+    /**
+        Save the screenshot as the name of @a fileName in the default directory.
+
+        @a fileName should be without ".png".
+    */
+    static void Save(wxBitmap screenshot, wxString fileName);
+
+    /**
+        Set the default directory where the screenshots will be generated.
+    */
+    static void SetDefaultDirectory(wxString dir) { default_dir = dir; }
+
+    /**
+        Get the default directory where the screenshots will be generated.
+    */
+    static wxString GetDefaultDirectory() { return default_dir; }
+
+    /**
+        Get the absolute path of the default directory where the screenshots will be generated.
+    */
+    static wxString GetDefaultDirectoryAbsPath()
+    {
+        wxFileName output = wxFileName::DirName(GetDefaultDirectory());
+        output.MakeAbsolute();
+        return output.GetFullPath();
+    }
 
+private:
 
-private:      // internal utils
+    /*
+        Internal Data Structures
+
+        They might go public in future to provide reuse of ControlList.
+    */
     struct Control
     {
         Control() {}
@@ -85,31 +335,76 @@ private:      // internal utils
         int flag;
     };
 
+    typedef std::vector<Control> ControlList;
+
+    /*
+        Internal Functions
+
+        They are only used to clearify the logic of some public functions and it's nonsense
+        to call them elsewhere.
+    */
+
+    /*
+        Capture and auto adjust the control. Used by CaptureAll().
+    */
     wxBitmap Capture(Control & ctrl);
 
-    // if AJ_RegionAdjust is specified, the following line will use the label
-    // trick to adjust the region position and size
+    /*
+        Get the correct rectangular region that the control occupies. Used by
+        Capture(Control & ctrl).
+
+        If AJ_RegionAdjust is specified, it will use the "label trick" to perform
+        region auto adjustment.
+
+        The "label trick" is to reattach the control to a wxFlexGridSizer m_grid,
+        surround the control with labels and get the control's region by label's positions.
+        Just like this:
+
+        +---------+-----------+---------+
+        |    0    |   label   |    1    |
+        +---------+-----------+---------+
+        |  label  |    ctrl   |  label  |
+        +---------+-----------+---------+
+        |    2    |   label   |    3    |
+        +---------+-----------+---------+
+
+        So, there will be a side effect: the control is moved to a new position. So after taking the
+        screenshot, Capture(Control & ctrl) should call PutBack(wxWindow * ctrl) to put it back.
+
+        If AJ_RegionAdjust isn't specified, it will simply call wxWindow::GetScreenRect().
+    */
     wxRect GetRect(wxWindow* ctrl, int flag);
 
-    // put the control back after the label trick(Using reparent/resizer approach)
+    /*
+        Put the control back after the label trick used in GetRect(). Used by
+        Capture(Control & ctrl).
+    */
     void PutBack(wxWindow * ctrl);
 
-    wxBitmap Union(wxBitmap pic1, wxBitmap pic2);
+    /*
+        Union two screenshots in the vertical direction, and leave a gap between the
+        screenshots. Used by CaptureAll().
+
+        The gap is 20 pixels by default. Currently it isn't configurable.
+    */
+    static wxBitmap Union(wxBitmap pic1, wxBitmap pic2);
 
-    void Save(wxBitmap screenshot, wxString fileName);
+    static void Delay(int seconds);
 
-    typedef std::vector<Control> ControlList;
+    /*
+        Data Members
+    */
     ControlList m_controlList;
 
-    // here we introduce the dependency on wxNotebook.
-    // The assumption of this whole class is that the gui has the following top-down structure
-    //  wxNotebook wxPanel wxSizer wxControls
     wxNotebook* m_notebook;
 
+    int m_flag;
+
+    int m_margin;
+
     wxFlexGridSizer* m_grid;
 
-    wxString m_dir;
-    int m_border;
+    static wxString default_dir;
 };
 
 #endif // _AUTOCAPTURE_H_
index 0970262c1a9071d61866a156232bb933a55918a7..6814f68b7b01644ff70463788eca035aa939eb21 100644 (file)
@@ -54,15 +54,12 @@ void ScreenshotFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 
 void ScreenshotFrame::OnSeeScreenshots(wxCommandEvent& WXUNUSED(event))
 {
-    wxFileName defaultDir = wxFileName::DirName(GetDefaultDirectory());
-    defaultDir.MakeAbsolute();
+    wxString defaultDir = AutoCaptureMechanism::GetDefaultDirectoryAbsPath();
 
-    // Check if defaultDir already existed
-    if (!defaultDir.DirExists())
-        defaultDir.Mkdir();
-
-    // Use the native file browser to open defaultDir
-    wxLaunchDefaultBrowser(defaultDir.GetFullPath());
+    if (wxFileName::DirExists(defaultDir))
+        wxLaunchDefaultBrowser(defaultDir);
+    else
+        wxMessageBox(_("There isn't any screenshots yet."));
 }
 
 void ScreenshotFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
@@ -85,20 +82,18 @@ void ScreenshotFrame::OnCaptureFullScreen(wxCommandEvent& WXUNUSED(event))
     wxCoord screenWidth, screenHeight;
     dcScreen.GetSize(&screenWidth, &screenHeight);
 
-    const wxString fullscreen_filename = GetDefaultDirectoryAbsPath() + _T("fullscreen.png");
-
     wxBitmap fullscreen = AutoCaptureMechanism::Capture(0, 0, screenWidth, screenHeight);
 
-    fullscreen.SaveFile(fullscreen_filename, wxBITMAP_TYPE_PNG);
+    AutoCaptureMechanism::Save(fullscreen, _T("fullscreen"));
 
     wxMessageBox(_("A screenshot of the entire screen was saved as:\n\n  ")
-                + fullscreen_filename,
+                + AutoCaptureMechanism::GetDefaultDirectoryAbsPath() + _T("fullscreen.png"),
                  _("Full screen capture"), wxICON_INFORMATION|wxOK, this);
 }
 
 void ScreenshotFrame::OnCaptureAllControls(wxCommandEvent& WXUNUSED(event))
 {
-    wxString dir = GetDefaultDirectoryAbsPath();
+    wxString dir = AutoCaptureMechanism::GetDefaultDirectoryAbsPath();
 
     // check if there are other screenshots taken before
     if (wxFileName::DirExists(dir))
index a81ce1352b785fe007f55c242422ff8986d28e4e..c44fb51744d865dc5cb796c22feff3fdcd53abae 100644 (file)
@@ -26,20 +26,6 @@ protected:      // event handlers
 
     virtual void OnCaptureFullScreen( wxCommandEvent& event );
     virtual void OnCaptureAllControls( wxCommandEvent& event );
-
-
-private:
-
-    // Before a config class is written, these two functions are placed here.
-    // It's only a transition and they wil be removed soon
-    wxString GetDefaultDirectory() const { return _T("screenshots"); }
-
-    wxString GetDefaultDirectoryAbsPath() const
-    {
-        wxFileName output = wxFileName::DirName(GetDefaultDirectory());
-        output.MakeAbsolute();
-        return output.GetFullPath();
-    }
 };
 
 #endif // _SCREENSHOT_MAIN_H_