From e6ef9ea4ed13bee3ea5d830270986eab571876e6 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 18 Nov 2007 19:33:34 +0000
Subject: [PATCH] preserve custom colours between calls to
 wxGetColourFromUser(), also allow passing a custom wxColourData to it
 (modified patch 1832582)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@50056 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/function.tex  |  6 ++-
 include/wx/cmndata.h        | 20 +++++++---
 include/wx/colordlg.h       |  6 ++-
 samples/dialogs/dialogs.cpp | 41 ++++++++++++++-------
 samples/dialogs/dialogs.h   |  2 +
 src/common/cmndata.cpp      | 73 ++++++++++++++++++++++++++++++++++---
 src/common/utilscmn.cpp     | 46 +++++++++++++++++++----
 7 files changed, 162 insertions(+), 32 deletions(-)

diff --git a/docs/latex/wx/function.tex b/docs/latex/wx/function.tex
index ec4bbee62b..f3e5b28410 100644
--- a/docs/latex/wx/function.tex
+++ b/docs/latex/wx/function.tex
@@ -2109,7 +2109,7 @@ customization.
 
 \membersection{::wxGetColourFromUser}\label{wxgetcolourfromuser}
 
-\func{wxColour}{wxGetColourFromUser}{\param{wxWindow *}{parent}, \param{const wxColour\& }{colInit}, \param{const wxString\& }{caption = wxEmptyString}}
+\func{wxColour}{wxGetColourFromUser}{\param{wxWindow *}{parent}, \param{const wxColour\& }{colInit}, \param{const wxString\& }{caption = wxEmptyString}, \param{wxColourData *}{data = \NULL}}
 
 Shows the colour selection dialog and returns the colour selected by user or
 invalid colour (use \helpref{wxColour:IsOk}{wxcolourisok} to test whether a colour
@@ -2123,6 +2123,10 @@ is valid) if the dialog was cancelled.
 
 \docparam{caption}{If given, this will be used for the dialog caption.}
 
+\docparam{data}{Optional object storing additional colour dialog settings, such
+as custom colours. If none is provided the same settings as the last time are
+used.}
+
 \wxheading{Include files}
 
 <wx/colordlg.h>
diff --git a/include/wx/cmndata.h b/include/wx/cmndata.h
index 5aa5f102f7..3ecfc402a8 100644
--- a/include/wx/cmndata.h
+++ b/include/wx/cmndata.h
@@ -26,11 +26,18 @@
 class WXDLLIMPEXP_FWD_CORE wxPrintNativeDataBase;
 
 
-class WXDLLEXPORT wxColourData: public wxObject
+class WXDLLEXPORT wxColourData : public wxObject
 {
 public:
+    // number of custom colours we store
+    enum
+    {
+        NUM_CUSTOM = 16
+    };
+
     wxColourData();
     wxColourData(const wxColourData& data);
+    void operator=(const wxColourData&);
     virtual ~wxColourData();
 
     void SetChooseFull(bool flag) { m_chooseFull = flag; }
@@ -39,15 +46,18 @@ public:
     const wxColour& GetColour() const { return m_dataColour; }
     wxColour& GetColour() { return m_dataColour; }
 
-    // Array of 16 custom colours
+    // These functions modify colours in an internal array of NUM_CUSTOM custom
+    // colours
     void SetCustomColour(int i, const wxColour& colour);
     wxColour GetCustomColour(int i);
 
-    void operator=(const wxColourData& data);
+    // Serialize the object to a string and restore it from it
+    wxString ToString() const;
+    bool FromString(const wxString& str);
 
-public:
+public: // TODO: make these fields private
     wxColour        m_dataColour;
-    wxColour        m_custColours[16];
+    wxColour        m_custColours[NUM_CUSTOM];
     bool            m_chooseFull;
 
 private:
diff --git a/include/wx/colordlg.h b/include/wx/colordlg.h
index 8fb0ff6af2..6bff18a13b 100644
--- a/include/wx/colordlg.h
+++ b/include/wx/colordlg.h
@@ -30,10 +30,14 @@
     #define wxColourDialog wxGenericColourDialog
 #endif
 
+class WXDLLIMPEXP_FWD_CORE wxColourData;
+
 // get the colour from user and return it
 wxColour WXDLLEXPORT
 wxGetColourFromUser(wxWindow *parent = (wxWindow *)NULL,
-                    const wxColour& colInit = wxNullColour, const wxString& caption = wxEmptyString);
+                    const wxColour& colInit = wxNullColour,
+                    const wxString& caption = wxEmptyString,
+                    wxColourData *data = NULL);
 
 #endif // wxUSE_COLOURDLG
 
diff --git a/samples/dialogs/dialogs.cpp b/samples/dialogs/dialogs.cpp
index 18b12f67b8..6b837a6dfe 100644
--- a/samples/dialogs/dialogs.cpp
+++ b/samples/dialogs/dialogs.cpp
@@ -119,6 +119,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
 
 #if wxUSE_COLOURDLG
     EVT_MENU(DIALOGS_CHOOSE_COLOUR,                 MyFrame::ChooseColour)
+    EVT_MENU(DIALOGS_GET_COLOUR,                    MyFrame::GetColour)
 #endif // wxUSE_COLOURDLG
 
 #if wxUSE_FONTDLG
@@ -271,7 +272,8 @@ bool MyApp::OnInit()
     wxMenu *choices_menu = new wxMenu;
 
     #if wxUSE_COLOURDLG
-        choices_menu->Append(DIALOGS_CHOOSE_COLOUR, _T("&Choose colour"));
+        choices_menu->Append(DIALOGS_CHOOSE_COLOUR, _T("&Choose bg colour"));
+        choices_menu->Append(DIALOGS_GET_COLOUR, _T("&Choose fg colour"));
     #endif // wxUSE_COLOURDLG
 
     #if wxUSE_FONTDLG
@@ -463,16 +465,10 @@ MyFrame::MyFrame(wxWindow *parent,
 
 #if wxUSE_COLOURDLG
     m_clrData.SetChooseFull(true);
-    for (int i = 0; i < 16; i++)
+    for (int i = 0; i < wxColourData::NUM_CUSTOM; i++)
     {
-        m_clrData.SetCustomColour(
-          i,
-          wxColour(
-            (unsigned char)(i*16),
-            (unsigned char)(i*16),
-            (unsigned char)(i*16)
-          )
-        );
+        unsigned char n = i*16;
+        m_clrData.SetCustomColour(i, wxColour(n, n, n));
     }
 #endif // wxUSE_COLOURDLG
 
@@ -482,13 +478,14 @@ MyFrame::MyFrame(wxWindow *parent,
 }
 
 #if wxUSE_COLOURDLG
-void MyFrame::ChooseColour(wxCommandEvent& WXUNUSED(event) )
+
+void MyFrame::ChooseColour(wxCommandEvent& WXUNUSED(event))
 {
     m_clrData.SetColour(myCanvas->GetBackgroundColour());
 
     wxColourDialog dialog(this, &m_clrData);
-    dialog.SetTitle(_T("Choose the background colour"));
-    if (dialog.ShowModal() == wxID_OK)
+    dialog.SetTitle(_("Please choose the background colour"));
+    if ( dialog.ShowModal() == wxID_OK )
     {
         m_clrData = dialog.GetColourData();
         myCanvas->SetBackgroundColour(m_clrData.GetColour());
@@ -496,8 +493,26 @@ void MyFrame::ChooseColour(wxCommandEvent& WXUNUSED(event) )
         myCanvas->Refresh();
     }
 }
+
+void MyFrame::GetColour(wxCommandEvent& WXUNUSED(event))
+{
+    wxColour clr = wxGetColourFromUser
+                   (
+                    this,
+                    wxGetApp().m_canvasTextColour,
+                    "Please choose the foreground colour"
+                   );
+    if ( clr.IsOk() )
+    {
+        wxGetApp().m_canvasTextColour = clr;
+        myCanvas->Refresh();
+    }
+    //else: dialog cancelled by user
+}
+
 #endif // wxUSE_COLOURDLG
 
+
 #if USE_COLOURDLG_GENERIC
 void MyFrame::ChooseColourGeneric(wxCommandEvent& WXUNUSED(event))
 {
diff --git a/samples/dialogs/dialogs.h b/samples/dialogs/dialogs.h
index 62ff683de9..b371fbd106 100644
--- a/samples/dialogs/dialogs.h
+++ b/samples/dialogs/dialogs.h
@@ -211,6 +211,7 @@ public:
 
 #if wxUSE_COLOURDLG
     void ChooseColour(wxCommandEvent& event);
+    void GetColour(wxCommandEvent& event);
 #endif // wxUSE_COLOURDLG
 
 #if wxUSE_FONTDLG
@@ -341,6 +342,7 @@ public:
 enum
 {
     DIALOGS_CHOOSE_COLOUR = wxID_HIGHEST,
+    DIALOGS_GET_COLOUR,
     DIALOGS_CHOOSE_COLOUR_GENERIC,
     DIALOGS_CHOOSE_FONT,
     DIALOGS_CHOOSE_FONT_GENERIC,
diff --git a/src/common/cmndata.cpp b/src/common/cmndata.cpp
index f50447a3f5..40e6073529 100644
--- a/src/common/cmndata.cpp
+++ b/src/common/cmndata.cpp
@@ -89,14 +89,14 @@ wxColourData::~wxColourData()
 
 void wxColourData::SetCustomColour(int i, const wxColour& colour)
 {
-    wxCHECK_RET( (i >= 0 && i < 16), _T("custom colour index out of range") );
+    wxCHECK_RET( (i >= 0 && i < WXSIZEOF(m_custColours)), _T("custom colour index out of range") );
 
     m_custColours[i] = colour;
 }
 
 wxColour wxColourData::GetCustomColour(int i)
 {
-    wxCHECK_MSG( (i >= 0 && i < 16), wxColour(0,0,0),
+    wxCHECK_MSG( (i >= 0 && i < WXSIZEOF(m_custColours)), wxColour(0,0,0),
                  _T("custom colour index out of range") );
 
     return m_custColours[i];
@@ -104,14 +104,77 @@ wxColour wxColourData::GetCustomColour(int i)
 
 void wxColourData::operator=(const wxColourData& data)
 {
-    int i;
-    for (i = 0; i < 16; i++)
+    for (int i = 0; i < WXSIZEOF(m_custColours); i++)
         m_custColours[i] = data.m_custColours[i];
 
-    m_dataColour = (wxColour&)data.m_dataColour;
+    m_dataColour = data.m_dataColour;
     m_chooseFull = data.m_chooseFull;
 }
 
+// ----------------------------------------------------------------------------
+// [de]serialization
+// ----------------------------------------------------------------------------
+
+// separator used between different fields
+static const char wxCOL_DATA_SEP = ',';
+
+wxString wxColourData::ToString() const
+{
+    wxString str(m_chooseFull ? '1' : '0');
+
+    for ( int i = 0; i < WXSIZEOF(m_custColours); i++ )
+    {
+        str += wxCOL_DATA_SEP;
+
+        const wxColour& clr = m_custColours[i];
+        if ( clr.IsOk() )
+            str += clr.GetAsString(wxC2S_HTML_SYNTAX);
+    }
+
+    return str;
+}
+
+bool wxColourData::FromString(const wxString& str)
+{
+    wxString token;
+    int n = -1; // index of the field, -1 corresponds to m_chooseFull
+    for ( wxString::const_iterator i = str.begin(); i != str.end(); ++i )
+    {
+        if ( *i == wxCOL_DATA_SEP )
+        {
+            if ( n == -1 )
+            {
+                if ( token == '0' )
+                    m_chooseFull = false;
+                else if ( token == '1' )
+                    m_chooseFull = true;
+                else // only '0' and '1' are used in ToString()
+                    return false;
+            }
+            else // custom colour
+            {
+                if ( n == WXSIZEOF(m_custColours) )
+                    return false;   // too many custom colours
+
+                // empty strings are used by ToString() for colours not used
+                if ( token.empty() )
+                    m_custColours[n] = wxNullColour;
+                else if ( !m_custColours[n].Set(token) )
+                    return false;   // invalid colour string
+            }
+
+            token.clear();
+            n++;
+        }
+        else // continuation of the current field
+        {
+            token += *i;
+        }
+    }
+
+    return true;
+}
+
 // ----------------------------------------------------------------------------
 // Font data
 // ----------------------------------------------------------------------------
diff --git a/src/common/utilscmn.cpp b/src/common/utilscmn.cpp
index 00436e7679..4ba9c856e1 100644
--- a/src/common/utilscmn.cpp
+++ b/src/common/utilscmn.cpp
@@ -1419,24 +1419,56 @@ wxString wxGetPasswordFromUser(const wxString& message,
 
 #if wxUSE_COLOURDLG
 
-wxColour wxGetColourFromUser(wxWindow *parent, const wxColour& colInit, const wxString& caption)
+wxColour wxGetColourFromUser(wxWindow *parent, 
+                             const wxColour& colInit, 
+                             const wxString& caption,
+                             wxColourData *ptrData)
 {
+    // contains serialized representation of wxColourData used the last time
+    // the dialog was shown: we want to reuse it the next time in order to show
+    // the same custom colours to the user (and we can't just have static
+    // wxColourData itself because it's a GUI object and so should be destroyed
+    // before GUI shutdown and doing it during static cleanup is too late)
+    static wxString s_strColourData;
+
     wxColourData data;
-    data.SetChooseFull(true);
-    if ( colInit.Ok() )
+    if ( !ptrData )
     {
-        data.SetColour((wxColour &)colInit); // const_cast
+        ptrData = &data;
+        if ( !s_strColourData.empty() )
+        {
+            if ( !data.FromString(s_strColourData) )
+            {
+                wxFAIL_MSG( "bug in wxColourData::FromString()?" );
+            }
+
+#ifdef __WXMSW__
+            // we don't get back the "choose full" flag value from the native
+            // dialog and so we can't preserve it between runs, so we decide to
+            // always use it as it seems better than not using it (user can
+            // just ignore the extra controls in the dialog but having to click
+            // a button each time to show them would be very annoying
+            data.SetChooseFull(true);
+#endif // __WXMSW__
+        }
+    }
+
+    if ( colInit.IsOk() )
+    {
+        ptrData->SetColour(colInit);
     }
 
     wxColour colRet;
-    wxColourDialog dialog(parent, &data);
+    wxColourDialog dialog(parent, ptrData);
     if (!caption.empty())
         dialog.SetTitle(caption);
     if ( dialog.ShowModal() == wxID_OK )
     {
-        colRet = dialog.GetColourData().GetColour();
+        *ptrData = dialog.GetColourData();
+        colRet = ptrData->GetColour();
+        s_strColourData = ptrData->ToString();
     }
-    //else: leave it invalid
+    //else: leave colRet invalid
 
     return colRet;
 }
-- 
2.45.2

