]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fontcmn.cpp
Update version to 2.9.4 in version.bkl too and rebake everything.
[wxWidgets.git] / src / common / fontcmn.cpp
index cd65471ef36a7d502117d14c36d4f03bb52a165d..d54521c449fa92cf323fa2c009eb4f2dd5ca09c6 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef WX_PRECOMP
     #include "wx/dc.h"
     #include "wx/intl.h"
+    #include "wx/math.h"
     #include "wx/dcscreen.h"
     #include "wx/log.h"
     #include "wx/gdicmn.h"
@@ -57,20 +58,72 @@ extern const char *wxDumpFont(const wxFont *font)
     s.Printf(wxS("%s-%s-%s-%d-%d"),
              font->GetFaceName(),
              weight == wxFONTWEIGHT_NORMAL
-                ? _T("normal")
+                ? wxT("normal")
                 : weight == wxFONTWEIGHT_BOLD
-                    ? _T("bold")
-                    : _T("light"),
+                    ? wxT("bold")
+                    : wxT("light"),
              font->GetStyle() == wxFONTSTYLE_NORMAL
-                ? _T("regular")
-                : _T("italic"),
+                ? wxT("regular")
+                : wxT("italic"),
              font->GetPointSize(),
              font->GetEncoding());
 
-    wxStrlcpy(buf, s, WXSIZEOF(buf));
+    wxStrlcpy(buf, s.mb_str(), WXSIZEOF(buf));
     return buf;
 }
 
+// ----------------------------------------------------------------------------
+// XTI
+// ----------------------------------------------------------------------------
+
+wxBEGIN_ENUM( wxFontFamily )
+wxENUM_MEMBER( wxFONTFAMILY_DEFAULT )
+wxENUM_MEMBER( wxFONTFAMILY_DECORATIVE )
+wxENUM_MEMBER( wxFONTFAMILY_ROMAN )
+wxENUM_MEMBER( wxFONTFAMILY_SCRIPT )
+wxENUM_MEMBER( wxFONTFAMILY_SWISS )
+wxENUM_MEMBER( wxFONTFAMILY_MODERN )
+wxENUM_MEMBER( wxFONTFAMILY_TELETYPE )
+wxEND_ENUM( wxFontFamily )
+
+wxBEGIN_ENUM( wxFontStyle )
+wxENUM_MEMBER( wxFONTSTYLE_NORMAL )
+wxENUM_MEMBER( wxFONTSTYLE_ITALIC )
+wxENUM_MEMBER( wxFONTSTYLE_SLANT )
+wxEND_ENUM( wxFontStyle )
+
+wxBEGIN_ENUM( wxFontWeight )
+wxENUM_MEMBER( wxFONTWEIGHT_NORMAL )
+wxENUM_MEMBER( wxFONTWEIGHT_LIGHT )
+wxENUM_MEMBER( wxFONTWEIGHT_BOLD )
+wxEND_ENUM( wxFontWeight )
+
+wxIMPLEMENT_DYNAMIC_CLASS_WITH_COPY_XTI(wxFont, wxGDIObject, "wx/font.h")
+
+//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxFont>)
+
+wxBEGIN_PROPERTIES_TABLE(wxFont)
+wxPROPERTY( Size,int, SetPointSize, GetPointSize, 12, 0 /*flags*/, \
+           wxT("Helpstring"), wxT("group"))
+wxPROPERTY( Family, wxFontFamily , SetFamily, GetFamily, (wxFontFamily)wxDEFAULT, \
+           0 /*flags*/, wxT("Helpstring"), wxT("group")) // wxFontFamily
+wxPROPERTY( Style, wxFontStyle, SetStyle, GetStyle, (wxFontStyle)wxNORMAL, 0 /*flags*/, \
+           wxT("Helpstring"), wxT("group")) // wxFontStyle
+wxPROPERTY( Weight, wxFontWeight, SetWeight, GetWeight, (wxFontWeight)wxNORMAL, 0 /*flags*/, \
+           wxT("Helpstring"), wxT("group")) // wxFontWeight
+wxPROPERTY( Underlined, bool, SetUnderlined, GetUnderlined, false, 0 /*flags*/, \
+           wxT("Helpstring"), wxT("group"))
+wxPROPERTY( Face, wxString, SetFaceName, GetFaceName, wxEMPTY_PARAMETER_VALUE, \
+           0 /*flags*/, wxT("Helpstring"), wxT("group"))
+wxPROPERTY( Encoding, wxFontEncoding, SetEncoding, GetEncoding, \
+           wxFONTENCODING_DEFAULT, 0 /*flags*/, wxT("Helpstring"), wxT("group"))
+wxEND_PROPERTIES_TABLE()
+
+wxCONSTRUCTOR_6( wxFont, int, Size, wxFontFamily, Family, wxFontStyle, Style, wxFontWeight, Weight, \
+                bool, Underlined, wxString, Face )
+
+wxEMPTY_HANDLERS_TABLE(wxFont)
+
 // ============================================================================
 // implementation
 // ============================================================================
@@ -114,7 +167,7 @@ void wxFontBase::SetDefaultEncoding(wxFontEncoding encoding)
     // GetDefaultEncoding() should return something != wxFONTENCODING_DEFAULT
     // and, besides, using this value here doesn't make any sense
     wxCHECK_RET( encoding != wxFONTENCODING_DEFAULT,
-                 _T("can't set default encoding to wxFONTENCODING_DEFAULT") );
+                 wxT("can't set default encoding to wxFONTENCODING_DEFAULT") );
 
     ms_encodingDefault = encoding;
 }
@@ -214,7 +267,7 @@ void wxFontBase::SetPixelSize( const wxSize& pixelSize )
     // NOTE: this algorithm for adjusting the font size is used by all
     //       implementations of wxFont except under wxMSW and wxGTK where
     //       native support to font creation using pixel-size is provided.
-    
+
     int largestGood = 0;
     int smallestBad = 0;
 
@@ -284,6 +337,8 @@ void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info)
 
 wxString wxFontBase::GetNativeFontInfoDesc() const
 {
+    wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
+
     wxString fontDesc;
     const wxNativeFontInfo *fontInfo = GetNativeFontInfo();
     if ( fontInfo )
@@ -301,6 +356,8 @@ wxString wxFontBase::GetNativeFontInfoDesc() const
 
 wxString wxFontBase::GetNativeFontInfoUserDesc() const
 {
+    wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
+
     wxString fontDesc;
     const wxNativeFontInfo *fontInfo = GetNativeFontInfo();
     if ( fontInfo )
@@ -363,6 +420,20 @@ bool wxFontBase::operator==(const wxFont& font) const
            );
 }
 
+wxFontFamily wxFontBase::GetFamily() const
+{
+    wxCHECK_MSG( IsOk(), wxFONTFAMILY_UNKNOWN, wxS("invalid font") );
+
+    // Don't return wxFONTFAMILY_UNKNOWN from here because it prevents the code
+    // like wxFont(size, wxNORMAL_FONT->GetFamily(), ...) from working (see
+    // #12330). This is really just a hack but it allows to keep compatibility
+    // and doesn't really have any bad drawbacks so do this until someone comes
+    // up with a better idea.
+    const wxFontFamily family = DoGetFamily();
+
+    return family == wxFONTFAMILY_UNKNOWN ? wxFONTFAMILY_DEFAULT : family;
+}
+
 wxString wxFontBase::GetFamilyString() const
 {
     wxCHECK_MSG( IsOk(), "wxFONTFAMILY_DEFAULT", "invalid font" );
@@ -375,6 +446,7 @@ wxString wxFontBase::GetFamilyString() const
         case wxFONTFAMILY_SWISS:        return "wxFONTFAMILY_SWISS";
         case wxFONTFAMILY_MODERN:       return "wxFONTFAMILY_MODERN";
         case wxFONTFAMILY_TELETYPE:     return "wxFONTFAMILY_TELETYPE";
+        case wxFONTFAMILY_UNKNOWN:      return "wxFONTFAMILY_UNKNOWN";
         default:                        return "wxFONTFAMILY_DEFAULT";
     }
 }
@@ -420,6 +492,80 @@ bool wxFontBase::SetFaceName(const wxString& facename)
     return true;
 }
 
+void wxFontBase::SetSymbolicSize(wxFontSymbolicSize size)
+{
+    SetSymbolicSizeRelativeTo(size, wxNORMAL_FONT->GetPointSize());
+}
+
+/* static */
+int wxFontBase::AdjustToSymbolicSize(wxFontSymbolicSize size, int base)
+{
+    // Using a fixed factor (1.2, from CSS2) is a bad idea as explained at
+    // http://www.w3.org/TR/CSS21/fonts.html#font-size-props so use the values
+    // from http://style.cleverchimp.com/font_size_intervals/altintervals.html
+    // instead.
+    static const float factors[] = { 0.60f, 0.75f, 0.89f, 1.f, 1.2f, 1.5f, 2.f };
+
+    wxCOMPILE_TIME_ASSERT
+    (
+        WXSIZEOF(factors) == wxFONTSIZE_XX_LARGE - wxFONTSIZE_XX_SMALL + 1,
+        WrongFontSizeFactorsSize
+    );
+
+    return wxRound(factors[size - wxFONTSIZE_XX_SMALL]*base);
+}
+
+wxFont& wxFont::MakeBold()
+{
+    SetWeight(wxFONTWEIGHT_BOLD);
+    return *this;
+}
+
+wxFont wxFont::Bold() const
+{
+    wxFont font(*this);
+    font.MakeBold();
+    return font;
+}
+
+wxFont& wxFont::MakeItalic()
+{
+    SetStyle(wxFONTSTYLE_ITALIC);
+    return *this;
+}
+
+wxFont wxFont::Italic() const
+{
+    wxFont font(*this);
+    font.MakeItalic();
+    return font;
+}
+
+wxFont& wxFont::MakeUnderlined()
+{
+    SetUnderlined(true);
+    return *this;
+}
+
+wxFont wxFont::Underlined() const
+{
+    wxFont font(*this);
+    font.MakeUnderlined();
+    return font;
+}
+
+wxFont& wxFont::Scale(float x)
+{
+    SetPointSize(int(x*GetPointSize() + 0.5));
+    return *this;
+}
+
+wxFont wxFont::Scaled(float x) const
+{
+    wxFont font(*this);
+    font.Scale(x);
+    return font;
+}
 
 // ----------------------------------------------------------------------------
 // wxNativeFontInfo
@@ -459,7 +605,7 @@ bool wxNativeFontInfo::FromString(const wxString& s)
 {
     long l;
 
-    wxStringTokenizer tokenizer(s, _T(";"));
+    wxStringTokenizer tokenizer(s, wxT(";"));
 
     wxString token = tokenizer.GetNextToken();
     //
@@ -510,7 +656,7 @@ wxString wxNativeFontInfo::ToString() const
 {
     wxString s;
 
-    s.Printf(_T("%d;%d;%d;%d;%d;%d;%s;%d"),
+    s.Printf(wxT("%d;%d;%d;%d;%d;%d;%s;%d"),
              0,                                 // version
              pointSize,
              family,
@@ -628,7 +774,7 @@ wxString wxNativeFontInfo::ToUserString() const
     switch ( GetWeight() )
     {
         default:
-            wxFAIL_MSG( _T("unknown font weight") );
+            wxFAIL_MSG( wxT("unknown font weight") );
             // fall through
 
         case wxFONTWEIGHT_NORMAL:
@@ -646,7 +792,7 @@ wxString wxNativeFontInfo::ToUserString() const
     switch ( GetStyle() )
     {
         default:
-            wxFAIL_MSG( _T("unknown font style") );
+            wxFAIL_MSG( wxT("unknown font style") );
             // fall through
 
         case wxFONTSTYLE_NORMAL:
@@ -662,20 +808,74 @@ wxString wxNativeFontInfo::ToUserString() const
     wxString face = GetFaceName();
     if ( !face.empty() )
     {
-        desc << _T(' ') << face;
+        if (face.Contains(' ') || face.Contains(';') || face.Contains(','))
+        {
+            face.Replace("'", "");
+                // eventually remove quote characters: most systems do not
+                // allow them in a facename anyway so this usually does nothing
+
+            // make it possible for FromUserString() function to understand
+            // that the different words which compose this facename are
+            // not different adjectives or other data but rather all parts
+            // of the facename
+            desc << wxT(" '") << face << _("'");
+        }
+        else
+            desc << wxT(' ') << face;
+    }
+    else // no face name specified
+    {
+        // use the family
+        wxString familyStr;
+        switch ( GetFamily() )
+        {
+            case wxFONTFAMILY_DECORATIVE:
+                familyStr = "decorative";
+                break;
+
+            case wxFONTFAMILY_ROMAN:
+                familyStr = "roman";
+                break;
+
+            case wxFONTFAMILY_SCRIPT:
+                familyStr = "script";
+                break;
+
+            case wxFONTFAMILY_SWISS:
+                familyStr = "swiss";
+                break;
+
+            case wxFONTFAMILY_MODERN:
+                familyStr = "modern";
+                break;
+
+            case wxFONTFAMILY_TELETYPE:
+                familyStr = "teletype";
+                break;
+
+            case wxFONTFAMILY_DEFAULT:
+            case wxFONTFAMILY_UNKNOWN:
+                break;
+
+            default:
+                wxFAIL_MSG( "unknown font family" );
+        }
+
+        if ( !familyStr.empty() )
+            desc << " '" << familyStr << " family'";
     }
 
     int size = GetPointSize();
     if ( size != wxNORMAL_FONT->GetPointSize() )
     {
-        desc << _T(' ') << size;
+        desc << wxT(' ') << size;
     }
 
 #if wxUSE_FONTMAP
     wxFontEncoding enc = GetEncoding();
     if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM )
     {
-        desc << _T(' ') << wxFontMapper::GetEncodingName(enc);
+        desc << wxT(' ') << wxFontMapper::GetEncodingName(enc);
     }
 #endif // wxUSE_FONTMAP
 
@@ -687,10 +887,13 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
     // reset to the default state
     Init();
 
+    // ToUserString() will quote the facename if it contains spaces, commas
+    // or semicolons: we must be able to understand that quoted text is
+    // a single token:
+    wxString toparse(s);
+
     // parse a more or less free form string
-    //
-    // TODO: we should handle at least the quoted facenames
-    wxStringTokenizer tokenizer(s, _T(";, "), wxTOKEN_STRTOK);
+    wxStringTokenizer tokenizer(toparse, wxT(";, "), wxTOKEN_STRTOK);
 
     wxString face;
     unsigned long size;
@@ -698,6 +901,7 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
 #if wxUSE_FONTMAP
     bool encodingfound = false;
 #endif
+    bool insideQuotes = false;
 
     while ( tokenizer.HasMoreTokens() )
     {
@@ -705,23 +909,51 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
 
         // normalize it
         token.Trim(true).Trim(false).MakeLower();
+        if (insideQuotes)
+        {
+            if (token.StartsWith("'") ||
+                token.EndsWith("'"))
+            {
+                insideQuotes = false;
+
+                // add this last token to the facename:
+                face += " " + token;
+
+                // normalize facename:
+                face = face.Trim(true).Trim(false);
+                face.Replace("'", "");
+
+                continue;
+            }
+        }
+        else
+        {
+            if (token.StartsWith("'"))
+                insideQuotes = true;
+        }
 
         // look for the known tokens
-        if ( token == _T("underlined") || token == _("underlined") )
+        if ( insideQuotes )
+        {
+            // only the facename may be quoted:
+            face += " " + token;
+            continue;
+        }
+        if ( token == wxT("underlined") || token == _("underlined") )
         {
             SetUnderlined(true);
         }
-        else if ( token == _T("light") || token == _("light") )
+        else if ( token == wxT("light") || token == _("light") )
         {
             SetWeight(wxFONTWEIGHT_LIGHT);
             weightfound = true;
         }
-        else if ( token == _T("bold") || token == _("bold") )
+        else if ( token == wxT("bold") || token == _("bold") )
         {
             SetWeight(wxFONTWEIGHT_BOLD);
             weightfound = true;
         }
-        else if ( token == _T("italic") || token == _("italic") )
+        else if ( token == wxT("italic") || token == _("italic") )
         {
             SetStyle(wxFONTSTYLE_ITALIC);
         }
@@ -748,7 +980,7 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
                 // assume it is the face name
             if ( !face.empty() )
             {
-                face += _T(' ');
+                face += wxT(' ');
             }
 
             face += token;
@@ -766,10 +998,32 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
         // bar")
         if ( !face.empty() )
         {
+            wxString familyStr;
+            if ( face.EndsWith(" family", &familyStr) )
+            {
+                // it's not a facename but rather a font family
+                wxFontFamily family;
+                if ( familyStr == "decorative" )
+                    family = wxFONTFAMILY_DECORATIVE;
+                else if ( familyStr == "roman" )
+                    family = wxFONTFAMILY_ROMAN;
+                else if ( familyStr == "script" )
+                    family = wxFONTFAMILY_SCRIPT;
+                else if ( familyStr == "swiss" )
+                    family = wxFONTFAMILY_SWISS;
+                else if ( familyStr == "modern" )
+                    family = wxFONTFAMILY_MODERN;
+                else if ( familyStr == "teletype" )
+                    family = wxFONTFAMILY_TELETYPE;
+                else
+                    return false;
+
+                SetFamily(family);
+            }
             // NB: the check on the facename is implemented in wxFontBase::SetFaceName
-            //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitely
+            //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitly
             //     call here wxFontEnumerator::IsValidFacename
-            if (
+            else if (
 #if wxUSE_FONTENUM
                     !wxFontEnumerator::IsValidFacename(face) ||
 #endif // wxUSE_FONTENUM
@@ -786,7 +1040,7 @@ bool wxNativeFontInfo::FromUserString(const wxString& s)
     if ( !face.empty() )
     {
         // NB: the check on the facename is implemented in wxFontBase::SetFaceName
-        //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitely
+        //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitly
         //     call here wxFontEnumerator::IsValidFacename
         if (
 #if wxUSE_FONTENUM
@@ -827,7 +1081,7 @@ wxString wxToString(const wxFontBase& font)
 
 bool wxFromString(const wxString& str, wxFontBase *font)
 {
-    wxCHECK_MSG( font, false, _T("NULL output parameter") );
+    wxCHECK_MSG( font, false, wxT("NULL output parameter") );
 
     if ( str.empty() )
     {