From 1b69c815746d9ca7cbfcbe96423e2021ed3fbdb2 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Thu, 1 Apr 2004 00:05:13 +0000
Subject: [PATCH] added Get(Class)DefaultAttributes()

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@26522 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/control.tex |   9 +-
 docs/latex/wx/window.tex  |  46 +++++++++++
 include/wx/window.h       |  72 ++++++++++++----
 src/common/wincmn.cpp     | 170 +++++++++++++++++++++++++++-----------
 4 files changed, 229 insertions(+), 68 deletions(-)

diff --git a/docs/latex/wx/control.tex b/docs/latex/wx/control.tex
index 8cf69429ac..75c4e5f975 100644
--- a/docs/latex/wx/control.tex
+++ b/docs/latex/wx/control.tex
@@ -1,9 +1,9 @@
 \section{\class{wxControl}}\label{wxcontrol}
 
-This is the base class for a control or `widget'.
+This is the base class for a control or ``widget''.
 
-A control is generally a small window which processes user input and/or displays one or more item
-of data.
+A control is generally a small window which processes user input and/or
+displays one or more item of data.
 
 \wxheading{Derived from}
 
@@ -21,18 +21,21 @@ of data.
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
+
 \membersection{wxControl::Command}\label{wxcontrolcommand}
 
 \func{void}{Command}{\param{wxCommandEvent\& }{event}}
 
 Simulates the effect of the user issuing a command to the item. See \helpref{wxCommandEvent}{wxcommandevent}.
 
+
 \membersection{wxControl::GetLabel}\label{wxcontrolgetlabel}
 
 \func{wxString\&}{GetLabel}{\void}
 
 Returns the control's text.
 
+
 \membersection{wxControl::SetLabel}\label{wxcontrolsetlabel}
 
 \func{void}{SetLabel}{\param{const wxString\& }{label}}
diff --git a/docs/latex/wx/window.tex b/docs/latex/wx/window.tex
index 3e6abfa4bb..d7d86c9631 100644
--- a/docs/latex/wx/window.tex
+++ b/docs/latex/wx/window.tex
@@ -755,6 +755,33 @@ Returns the average character width for this window.
 Returns a reference to the list of the window's children.
 
 
+\membersection{wxControl::GetClassDefaultAttributes}\label{wxwindowgetclassdefaultattributes}
+
+\func{static wxVisualAttributes}{GetClassDefaultAttributes}{\param{wxWindowVariant}{ variant = \texttt{wxWINDOW\_VARIANT\_NORMAL}}}
+
+Returns the default font and colours which are used by the control. This is
+useful if you want to use the same font or colour in your own control as in a
+standard control -- which is a much better idea than hard coding specific
+colours or fonts which might look completely out of place on the users
+system, especially if it uses themes.
+
+The \arg{variant} parameter is only relevant under Mac currently and is
+ignore under other platforms. Under Mac, it will change the size of the
+returned font. See \helpref{wxWindow::SetWindowVariant}{wxwindowsetwindowvariant} 
+for more about this.
+
+This static method is ``overridden'' in many derived classes and so calling,
+for example, \helpref{wxButton}::GetClassDefaultAttributes() will typically
+return the values appropriate for a button which will be normally different
+from those returned by, say, \helpref{wxListCtrl}::GetClassDefaultAttributes().
+
+The \texttt{wxVisualAttributes} structure has at least the fields 
+\texttt{font}, \texttt{colFg} and \texttt{colBg}. All of them may be invalid
+if it was not possible to determine the default control appearance or,
+especially for the background colour, if the field doesn't make sense as is
+the case for \texttt{colBg} for the controls with themed background.
+
+
 \membersection{wxWindow::GetClientSize}\label{wxwindowgetclientsize}
 
 \constfunc{void}{GetClientSize}{\param{int* }{width}, \param{int* }{height}}
@@ -815,6 +842,25 @@ Return the cursor associated with this window.
 \helpref{wxWindow::SetCursor}{wxwindowsetcursor}
 
 
+\membersection{wxControl::GetDefaultAttributes}\label{wxwindowgetdefaultattributes}
+
+\constfunc{virtual wxVisualAttributes}{GetDefaultAttributes}{\void}
+
+Currently this is the same as calling 
+\helpref{GetClassDefaultAttributes}{wxwindowgetclassdefaultattributes}(\helpref{GetWindowVariant}{wxwindowgetwindowvariant}()).
+
+One advantage of using this function compared to the static version is that
+the call is automatically dispatched to the correct class (as usual with
+virtual functions) and you don't have to specify the class name explicitly.
+
+The other one is that in the future this function could return different
+results, for example it might return a different font for an ``Ok'' button
+than for a generic button if the users GUI is configured to show such buttons
+in bold font. Of course, the down side is that it is impossible to call this
+function without actually having an object to apply it to whereas the static
+version can be used without having to create an object first.
+
+
 \membersection{wxWindow::GetDropTarget}\label{wxwindowgetdroptarget}
 
 \constfunc{wxDropTarget*}{GetDropTarget}{\void}
diff --git a/include/wx/window.h b/include/wx/window.h
index bd26e0c557..662c0e53e0 100644
--- a/include/wx/window.h
+++ b/include/wx/window.h
@@ -73,6 +73,35 @@ class WXDLLEXPORT wxWindow;
 class WXDLLEXPORT wxAccessible;
 #endif
 
+// ----------------------------------------------------------------------------
+// helper stuff used by wxWindow
+// ----------------------------------------------------------------------------
+
+// struct containing all the visual attributes of a control
+struct WXDLLEXPORT wxVisualAttributes
+{
+    // the font used for control label/text inside it
+    wxFont font;
+
+    // the foreground colour
+    wxColour colFg;
+
+    // the background colour, may be wxNullColour if the controls background
+    // colour is not solid
+    wxColour colBg;
+};
+
+// different window variants, on platforms like eg mac uses different
+// rendering sizes
+enum wxWindowVariant 
+{
+    wxWINDOW_VARIANT_NORMAL,  // Normal size
+    wxWINDOW_VARIANT_SMALL,   // Smaller size (about 25 % smaller than normal)
+    wxWINDOW_VARIANT_MINI,    // Mini size (about 33 % smaller than normal)
+    wxWINDOW_VARIANT_LARGE,   // Large size (about 25 % larger than normal)
+    wxWINDOW_VARIANT_MAX
+};
+
 // ----------------------------------------------------------------------------
 // (pseudo)template list classes
 // ----------------------------------------------------------------------------
@@ -96,16 +125,6 @@ WXDLLEXPORT_DATA(extern wxWindowList) wxTopLevelWindows;
 // temporarily switches event handlers).
 // ----------------------------------------------------------------------------
 
-// different window variants, on platforms like eg mac uses different rendering sizes
-
-enum wxWindowVariant 
-{
-    wxWINDOW_VARIANT_NORMAL,        // Normal size
-    wxWINDOW_VARIANT_SMALL,         // Smaller size (about 25 % smaller than normal )
-    wxWINDOW_VARIANT_MINI,          // Mini size (about 33 % smaller than normal )
-    wxWINDOW_VARIANT_LARGE,         // Large size (about 25 % larger than normal )
-};
-
 class WXDLLEXPORT wxWindowBase : public wxEvtHandler
 {
 public:
@@ -648,13 +667,28 @@ public:
     // colours, fonts and cursors
     // --------------------------
 
+        // get the default attributes for the controls of this class: we
+        // provide a virtual function which can be used to query the default
+        // attributes of an existing control and a static function which can
+        // be used even when no existing object of the given class is
+        // available, but which won't return any styles specific to this
+        // particular control, of course (e.g. "Ok" button might have
+        // different -- bold for example -- font)
+    virtual wxVisualAttributes GetDefaultAttributes() const
+    {
+        return GetClassDefaultAttributes(GetWindowVariant());
+    }
+
+    static wxVisualAttributes
+    GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
+
         // set/retrieve the window colours (system defaults are used by
         // default): Set functions return true if colour was changed
     virtual bool SetBackgroundColour( const wxColour &colour );
     virtual bool SetForegroundColour( const wxColour &colour );
 
-    wxColour GetBackgroundColour() const { return m_backgroundColour; }
-    wxColour GetForegroundColour() const { return m_foregroundColour; }
+    wxColour GetBackgroundColour() const;
+    wxColour GetForegroundColour() const;
 
         // set/retrieve the cursor for this window (SetCursor() returns true
         // if the cursor was really changed)
@@ -665,8 +699,8 @@ public:
         // set/retrieve the font for the window (SetFont() returns true if the
         // font really changed)
     virtual bool SetFont( const wxFont &font ) = 0;
-    const wxFont& GetFont() const { return m_font; }
-    wxFont& GetFont() { return m_font; }
+    const wxFont& GetFont() const { return DoGetFont(); }
+    wxFont& GetFont() { return DoGetFont(); }
 
 #if wxUSE_CARET
         // associate a caret with the window
@@ -979,8 +1013,9 @@ protected:
 
     // visual window attributes
     wxCursor             m_cursor;
-    wxFont               m_font;
-    wxColour             m_backgroundColour, m_foregroundColour;
+    wxFont               m_font;                // see m_hasFont
+    wxColour             m_backgroundColour,    //     m_hasBgCol
+                         m_foregroundColour;    //     m_hasFgCol
 
 #if wxUSE_CARET
     wxCaret             *m_caret;
@@ -1152,13 +1187,16 @@ protected:
     virtual void DoSetWindowVariant( wxWindowVariant variant ) ;
 
 private:
-
     // contains the last id generated by NewControlId
     static int ms_lastControlId;
 
     // the stack of windows which have captured the mouse
     static struct WXDLLEXPORT wxWindowNext *ms_winCaptureNext;
 
+    // implementation of both const and non-const versions of GetFont()
+    wxFont& DoGetFont() const;
+
+
     DECLARE_ABSTRACT_CLASS(wxWindowBase)
     DECLARE_NO_COPY_CLASS(wxWindowBase)
     DECLARE_EVENT_TABLE()
diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp
index 5f892e172d..25a98cc3d2 100644
--- a/src/common/wincmn.cpp
+++ b/src/common/wincmn.cpp
@@ -133,24 +133,12 @@ wxWindowBase::wxWindowBase()
     m_windowValidator = (wxValidator *) NULL;
 #endif // wxUSE_VALIDATORS
 
-    // use the system default colours
-    m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
-    m_foregroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
-
-    // don't set the font here for wxMSW as we don't call WM_SETFONT here and
-    // so the font is *not* really set - but calls to SetFont() later won't do
-    // anything because m_font appears to be already set!
-#ifndef __WXMSW__
-    m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
-#endif // __WXMSW__
-
-    // the colours/fonts are default for now
+    // the colours/fonts are default for now, so leave m_font,
+    // m_backgroundColour and m_foregroundColour uninitialized and set those
     m_hasBgCol =
     m_hasFgCol =
     m_hasFont = false;
 
-    m_isBeingDeleted = false;
-
     // no style bits
     m_exStyle =
     m_windowStyle = 0;
@@ -186,16 +174,19 @@ wxWindowBase::wxWindowBase()
 #endif
 
     m_virtualSize = wxDefaultSize;
-    
+
     m_minVirtualWidth =
     m_minVirtualHeight =
     m_maxVirtualWidth =
     m_maxVirtualHeight = -1;
 
-    m_windowVariant = wxWINDOW_VARIANT_NORMAL ;
+    m_windowVariant = wxWINDOW_VARIANT_NORMAL;
 
     // Whether we're using the current theme for this window (wxGTK only for now)
     m_themeEnabled = false;
+
+    // VZ: this one shouldn't exist...
+    m_isBeingDeleted = false;
 }
 
 // common part of window creation process
@@ -625,37 +616,47 @@ void wxWindowBase::SetSizeHints(int minW, int minH,
 
 void wxWindowBase::SetWindowVariant( wxWindowVariant variant )
 {
-    if ( m_windowVariant == variant )
-        return ;
-    
-    m_windowVariant = variant ; 
+    if ( m_windowVariant != variant )
+    {
+        m_windowVariant = variant;
 
-    DoSetWindowVariant( variant ) ;
-    return ;
+        DoSetWindowVariant(variant);
+    }
 }
 
 void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant )
 {
-    wxFont font = wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) ;
-    int size = font.GetPointSize() ;
+    // adjust the font height to correspond to our new variant (notice that
+    // we're only called if something really changed)
+    wxFont font = GetFont();
+    int size = font.GetPointSize();
     switch ( variant )
     {
-        case wxWINDOW_VARIANT_NORMAL :
-            break ;
-        case wxWINDOW_VARIANT_SMALL :
-            font.SetPointSize( size * 3 / 4 ) ;
-            break ;
-        case wxWINDOW_VARIANT_MINI :
-            font.SetPointSize( size * 2 / 3 ) ;
-            break ;
-        case wxWINDOW_VARIANT_LARGE :
-            font.SetPointSize( size * 5 / 4 ) ;
-            break ;
+        case wxWINDOW_VARIANT_NORMAL:
+            break;
+
+        case wxWINDOW_VARIANT_SMALL:
+            size *= 3;
+            size /= 4;
+            break;
+
+        case wxWINDOW_VARIANT_MINI:
+            size *= 2;
+            size /= 3;
+            break;
+
+        case wxWINDOW_VARIANT_LARGE:
+            size *= 5;
+            size /= 4;
+            break;
+
         default:
             wxFAIL_MSG(_T("unexpected window variant"));
-            break ;
+            break;
     }
-    SetFont( font ) ;  
+
+    font.SetPointSize(size);
+    SetFont(font);
 }
 
 void wxWindowBase::SetVirtualSizeHints( int minW, int minH,
@@ -866,9 +867,64 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
 }
 
 // ----------------------------------------------------------------------------
-// cursors, fonts &c
+// colours, fonts &c
 // ----------------------------------------------------------------------------
 
+/* static */ wxVisualAttributes
+wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
+{
+    // it is important to return valid values for all attributes from here,
+    // GetXXX() below rely on this
+    wxVisualAttributes attrs;
+    attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+    attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
+    attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
+
+    return attrs;
+}
+
+wxColour wxWindowBase::GetBackgroundColour() const
+{
+    if ( !m_backgroundColour.Ok() )
+    {
+        wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") );
+
+        // get our default background colour
+        wxColour colBg = GetDefaultAttributes().colBg;
+
+        // we must return some valid colour to avoid redoing this every time
+        // and also to avoid surprizing the applications written for older
+        // wxWindows versions where GetBackgroundColour() always returned
+        // something -- so give them something even if it doesn't make sense
+        // for this window (e.g. it has a themed background)
+        if ( !colBg.Ok() )
+            colBg = GetClassDefaultAttributes().colBg;
+
+        // cache it for the next call
+        wxConstCast(this, wxWindowBase)->m_backgroundColour = colBg;
+    }
+
+    return m_backgroundColour;
+}
+
+wxColour wxWindowBase::GetForegroundColour() const
+{
+    // logic is the same as above
+    if ( !m_hasFgCol && !m_foregroundColour.Ok() )
+    {
+        wxASSERT_MSG( !m_hasFgCol, _T("we have invalid explicit fg colour?") );
+
+        wxColour colFg = GetDefaultAttributes().colFg;
+
+        if ( !colFg.Ok() )
+            colFg = GetClassDefaultAttributes().colFg;
+
+        wxConstCast(this, wxWindowBase)->m_foregroundColour = colFg;
+    }
+
+    return m_foregroundColour;
+}
+
 bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
 {
     if ( !colour.Ok() || (colour == m_backgroundColour) )
@@ -908,18 +964,36 @@ bool wxWindowBase::SetCursor(const wxCursor& cursor)
     return true;
 }
 
+wxFont& wxWindowBase::DoGetFont() const
+{
+    // logic is the same as in GetBackgroundColour()
+    if ( !m_font.Ok() )
+    {
+        wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") );
+
+        wxFont font = GetDefaultAttributes().font;
+        if ( !font.Ok() )
+            font = GetClassDefaultAttributes().font;
+
+        wxConstCast(this, wxWindowBase)->m_font = font;
+    }
+
+    // cast is here for non-const GetFont() convenience
+    return wxConstCast(this, wxWindowBase)->m_font;
+}
+
 bool wxWindowBase::SetFont(const wxFont& font)
 {
-    // don't try to set invalid font, always fall back to the default
-    const wxFont& fontOk = font.Ok() ? font : *wxSWISS_FONT;
+    if ( !font.Ok() )
+        return false;
 
-    if ( fontOk == m_font )
+    if ( font == m_font )
     {
         // no change
         return false;
     }
 
-    m_font = fontOk;
+    m_font = font;
 
     m_hasFont = true;
 
@@ -982,7 +1056,7 @@ void wxWindowBase::SetValidator(const wxValidator& validator)
     m_windowValidator = (wxValidator *)validator.Clone();
 
     if ( m_windowValidator )
-        m_windowValidator->SetWindow(this) ;
+        m_windowValidator->SetWindow(this);
 }
 #endif // wxUSE_VALIDATORS
 
@@ -1505,7 +1579,7 @@ void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld)
 {
     if ( sizer == m_windowSizer)
         return;
-    
+
     if ( deleteOld )
         delete m_windowSizer;
 
@@ -1906,9 +1980,9 @@ wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt)
     int charHeight = GetCharHeight();
     wxPoint pt2(-1, -1);
     if (pt.x != -1)
-        pt2.x = (int) ((pt.x * 4) / charWidth) ;
+        pt2.x = (int) ((pt.x * 4) / charWidth);
     if (pt.y != -1)
-        pt2.y = (int) ((pt.y * 8) / charHeight) ;
+        pt2.y = (int) ((pt.y * 8) / charHeight);
 
     return pt2;
 }
@@ -1919,9 +1993,9 @@ wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
     int charHeight = GetCharHeight();
     wxPoint pt2(-1, -1);
     if (pt.x != -1)
-        pt2.x = (int) ((pt.x * charWidth) / 4) ;
+        pt2.x = (int) ((pt.x * charWidth) / 4);
     if (pt.y != -1)
-        pt2.y = (int) ((pt.y * charHeight) / 8) ;
+        pt2.y = (int) ((pt.y * charHeight) / 8);
 
     return pt2;
 }
-- 
2.50.0

