]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fontcmn.cpp
there is no sqrt(int) in standard C++ (although glibc seems to provide it); select...
[wxWidgets.git] / src / common / fontcmn.cpp
index e973ffbc0d0924395040bc25efbdca8402298fb7..a5ff16a10fef310b384d9394ebf549589f2b3210 100644 (file)
@@ -1,12 +1,12 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        common/fontcmn.cpp
+// Name:        src/common/fontcmn.cpp
 // Purpose:     implementation of wxFontBase methods
 // Author:      Vadim Zeitlin
 // Modified by:
 // Created:     20.09.99
 // RCS-ID:      $Id$
-// Copyright:   (c) wxWindows team
-// Licence:     wxWindows license
+// Copyright:   (c) wxWidgets team
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // ============================================================================
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __GNUG__
-    #pragma implementation "fontbase.h"
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
     #pragma hdrstop
 #endif
 
+#include "wx/font.h"
+
 #ifndef WX_PRECOMP
-    #include "wx/font.h"
+    #include "wx/dc.h"
+    #include "wx/intl.h"
+    #include "wx/dcscreen.h"
+    #include "wx/log.h"
+    #include "wx/gdicmn.h"
 #endif // WX_PRECOMP
 
-#include "wx/gdicmn.h"
+#if defined(__WXMSW__)
+    #include  "wx/msw/private.h"  // includes windows.h for LOGFONT
+    #include  "wx/msw/winundef.h"
+#endif
+
 #include "wx/fontutil.h" // for wxNativeFontInfo
+#include "wx/fontmap.h"
+#include "wx/fontenum.h"
 
 #include "wx/tokenzr.h"
 
 // implementation
 // ============================================================================
 
+// ----------------------------------------------------------------------------
+// helper functions
+// ----------------------------------------------------------------------------
+
+static void AdjustFontSize(wxFont& font, wxDC& dc, const wxSize& pixelSize)
+{
+    int largestGood = 0;
+    int smallestBad = 0;
+
+    bool initialGoodFound = false;
+    bool initialBadFound = false;
+
+    // NB: this assignment was separated from the variable definition
+    // in order to fix a gcc v3.3.3 compiler crash
+    int currentSize = font.GetPointSize();
+    while (currentSize > 0)
+    {
+        dc.SetFont(font);
+
+        // if currentSize (in points) results in a font that is smaller
+        // than required by pixelSize it is considered a good size
+        if (dc.GetCharHeight() <= pixelSize.GetHeight() &&
+                (!pixelSize.GetWidth() ||
+                 dc.GetCharWidth() <= pixelSize.GetWidth()))
+        {
+            largestGood = currentSize;
+            initialGoodFound = true;
+        }
+        else
+        {
+            smallestBad = currentSize;
+            initialBadFound = true;
+        }
+        if (!initialGoodFound)
+        {
+            currentSize /= 2;
+        }
+        else if (!initialBadFound)
+        {
+            currentSize *= 2;
+        }
+        else
+        {
+            int distance = smallestBad - largestGood;
+            if (distance == 1)
+                break;
+
+            currentSize = largestGood + distance / 2;
+        }
+
+        font.SetPointSize(currentSize);
+    }
+
+    if (currentSize != largestGood)
+        font.SetPointSize(largestGood);
+}
+
 // ----------------------------------------------------------------------------
 // wxFontBase
 // ----------------------------------------------------------------------------
 
 wxFontEncoding wxFontBase::ms_encodingDefault = wxFONTENCODING_SYSTEM;
 
+/* static */
+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") );
+
+    ms_encodingDefault = encoding;
+}
+
+wxFontBase::~wxFontBase()
+{
+    // this destructor is required for Darwin
+}
+
 /* static */
 wxFont *wxFontBase::New(int size,
-                        int family,
-                        int style,
-                        int weight,
+                        wxFontFamily family,
+                        wxFontStyle style,
+                        wxFontWeight weight,
                         bool underlined,
                         const wxString& face,
                         wxFontEncoding encoding)
@@ -59,6 +140,89 @@ wxFont *wxFontBase::New(int size,
     return new wxFont(size, family, style, weight, underlined, face, encoding);
 }
 
+static inline int flags2Style(int flags)
+{
+    return flags & wxFONTFLAG_ITALIC
+                    ? wxFONTSTYLE_ITALIC
+                    : flags & wxFONTFLAG_SLANT
+                        ? wxFONTSTYLE_SLANT
+                        : wxFONTSTYLE_NORMAL;
+}
+
+static inline int flags2Weight(int flags)
+{
+    return flags & wxFONTFLAG_LIGHT
+                    ? wxFONTWEIGHT_LIGHT
+                    : flags & wxFONTFLAG_BOLD
+                        ? wxFONTWEIGHT_BOLD
+                        : wxFONTWEIGHT_NORMAL;
+}
+
+static inline bool flags2Underlined(int flags)
+{
+    return (flags & wxFONTFLAG_UNDERLINED) != 0;
+}
+
+/* static */
+wxFont *wxFontBase::New(int pointSize,
+                        wxFontFamily family,
+                        int flags,
+                        const wxString& face,
+                        wxFontEncoding encoding)
+{
+    return New(pointSize, family, flags2Style(flags), flags2Weight(flags),
+               flags2Underlined(flags), face, encoding);
+}
+
+/* static */
+wxFont *wxFontBase::New(const wxSize& pixelSize,
+                        wxFontFamily family,
+                        wxFontStyle style,
+                        wxFontWeight weight,
+                        bool underlined,
+                        const wxString& face,
+                        wxFontEncoding encoding)
+{
+#if defined(__WXMSW__)
+    return new wxFont(pixelSize, family, style, weight, underlined,
+                      face, encoding);
+#else
+    wxFont *self = New(10, family, style, weight, underlined, face, encoding);
+    wxScreenDC dc;
+    AdjustFontSize(*(wxFont *)self, dc, pixelSize);
+    return self;
+#endif
+}
+
+/* static */
+wxFont *wxFontBase::New(const wxSize& pixelSize,
+                        wxFontFamily family,
+                        int flags,
+                        const wxString& face,
+                        wxFontEncoding encoding)
+{
+    return New(pixelSize, family, flags2Style(flags), flags2Weight(flags),
+               flags2Underlined(flags), face, encoding);
+}
+
+wxSize wxFontBase::GetPixelSize() const
+{
+    wxScreenDC dc;
+    dc.SetFont(*(wxFont *)this);
+    return wxSize(dc.GetCharWidth(), dc.GetCharHeight());
+}
+
+bool wxFontBase::IsUsingSizeInPixels() const
+{
+    return false;
+}
+
+void wxFontBase::SetPixelSize( const wxSize& pixelSize )
+{
+    wxScreenDC dc;
+    AdjustFontSize(*(wxFont *)this, dc, pixelSize);
+}
+
 /* static */
 wxFont *wxFontBase::New(const wxNativeFontInfo& info)
 {
@@ -75,28 +239,14 @@ wxFont *wxFontBase::New(const wxString& strNativeFontDesc)
     return New(fontInfo);
 }
 
-wxNativeFontInfo *wxFontBase::GetNativeFontInfo() const
+bool wxFontBase::IsFixedWidth() const
 {
-#if !defined(__WXGTK__) && !defined(__WXMSW__)
-    wxNativeFontInfo *fontInfo = new wxNativeFontInfo;
-
-    fontInfo->pointSize = GetPointSize();
-    fontInfo->family = GetFamily();
-    fontInfo->style = GetStyle();
-    fontInfo->weight = GetWeight();
-    fontInfo->underlined = GetUnderlined();
-    fontInfo->faceName = GetFaceName();
-    fontInfo->encoding = GetEncoding();
-
-    return fontInfo;
-#else
-    return (wxNativeFontInfo *)NULL;
-#endif
+    return GetFamily() == wxFONTFAMILY_TELETYPE;
 }
 
-void wxFontBase::SetNativeFontInfo(const wxNativeFontInfo& info)
+void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info)
 {
-#if !defined(__WXGTK__) && !defined(__WXMSW__)
+#ifdef wxNO_NATIVE_FONTINFO
     SetPointSize(info.pointSize);
     SetFamily(info.family);
     SetStyle(info.style);
@@ -104,39 +254,90 @@ void wxFontBase::SetNativeFontInfo(const wxNativeFontInfo& info)
     SetUnderlined(info.underlined);
     SetFaceName(info.faceName);
     SetEncoding(info.encoding);
+#else
+    (void)info;
 #endif
 }
 
 wxString wxFontBase::GetNativeFontInfoDesc() const
 {
     wxString fontDesc;
-    wxNativeFontInfo *fontInfo = GetNativeFontInfo();
+    const wxNativeFontInfo *fontInfo = GetNativeFontInfo();
     if ( fontInfo )
     {
         fontDesc = fontInfo->ToString();
-        delete fontInfo;
+        wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!"));
+    }
+    else
+    {
+        wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!"));
     }
 
     return fontDesc;
 }
 
-wxFont& wxFont::operator=(const wxFont& font)
+wxString wxFontBase::GetNativeFontInfoUserDesc() const
 {
-    if ( this != &font )
-        Ref(font);
+    wxString fontDesc;
+    const wxNativeFontInfo *fontInfo = GetNativeFontInfo();
+    if ( fontInfo )
+    {
+        fontDesc = fontInfo->ToUserString();
+        wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!"));
+    }
+    else
+    {
+        wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!"));
+    }
 
-    return (wxFont &)*this;
+    return fontDesc;
 }
 
-// VZ: is it correct to compare pointers and not the contents? (FIXME)
-bool wxFontBase::operator==(const wxFont& font) const
+bool wxFontBase::SetNativeFontInfo(const wxString& info)
 {
-    return GetFontData() == font.GetFontData();
+    wxNativeFontInfo fontInfo;
+    if ( !info.empty() && fontInfo.FromString(info) )
+    {
+        SetNativeFontInfo(fontInfo);
+        return true;
+    }
+
+    return false;
 }
 
-bool wxFontBase::operator!=(const wxFont& font) const
+bool wxFontBase::SetNativeFontInfoUserDesc(const wxString& info)
 {
-    return GetFontData() != font.GetFontData();
+    wxNativeFontInfo fontInfo;
+    if ( !info.empty() && fontInfo.FromUserString(info) )
+    {
+        SetNativeFontInfo(fontInfo);
+        return true;
+    }
+
+    return false;
+}
+
+bool wxFontBase::operator==(const wxFont& font) const
+{
+    // either it is the same font, i.e. they share the same common data or they
+    // have different ref datas but still describe the same font
+    return IsSameAs(font) ||
+           (
+            Ok() == font.Ok() &&
+            GetPointSize() == font.GetPointSize() &&
+            // in wxGTK1 GetPixelSize() calls GetInternalFont() which uses
+            // operator==() resulting in infinite recursion so we can't use it
+            // in that port
+#if !defined(__WXGTK__) || defined(__WXGTK20__)
+            GetPixelSize() == font.GetPixelSize() &&
+#endif
+            GetFamily() == font.GetFamily() &&
+            GetStyle() == font.GetStyle() &&
+            GetWeight() == font.GetWeight() &&
+            GetUnderlined() == font.GetUnderlined() &&
+            GetFaceName().IsSameAs(font.GetFaceName(), false) &&
+            GetEncoding() == font.GetEncoding()
+           );
 }
 
 wxString wxFontBase::GetFamilyString() const
@@ -181,12 +382,51 @@ wxString wxFontBase::GetWeightString() const
     }
 }
 
-#if !defined(__WXGTK__) && !defined(__WXMSW__)
+bool wxFontBase::SetFaceName(const wxString& facename)
+{
+#if wxUSE_FONTENUM
+    if (!wxFontEnumerator::IsValidFacename(facename))
+    {
+        UnRef();        // make Ok() return false
+        return false;
+    }
+#else // !wxUSE_FONTENUM
+    wxUnusedVar(facename);
+#endif // wxUSE_FONTENUM/!wxUSE_FONTENUM
+
+    return true;
+}
+
 
 // ----------------------------------------------------------------------------
 // wxNativeFontInfo
 // ----------------------------------------------------------------------------
 
+// Up to now, there are no native implementations of this function:
+void wxNativeFontInfo::SetFaceName(const wxArrayString& facenames)
+{
+#if wxUSE_FONTENUM
+    for (size_t i=0; i < facenames.GetCount(); i++)
+    {
+        if (wxFontEnumerator::IsValidFacename(facenames[i]))
+        {
+            SetFaceName(facenames[i]);
+            return;
+        }
+    }
+
+    // set the first valid facename we can find on this system
+    wxString validfacename = wxFontEnumerator::GetFacenames().Item(0);
+    wxLogTrace(wxT("font"), wxT("Falling back to '%s'"), validfacename.c_str());
+    SetFaceName(validfacename);
+#else // !wxUSE_FONTENUM
+    SetFaceName(facenames[0]);
+#endif // wxUSE_FONTENUM/!wxUSE_FONTENUM
+}
+
+
+#ifdef wxNO_NATIVE_FONTINFO
+
 // These are the generic forms of FromString()/ToString.
 //
 // convert to/from the string representation: format is
@@ -202,42 +442,45 @@ bool wxNativeFontInfo::FromString(const wxString& s)
     //
     //  Ignore the version for now
     //
-    
+
     token = tokenizer.GetNextToken();
     if ( !token.ToLong(&l) )
-        return FALSE;
+        return false;
     pointSize = (int)l;
 
     token = tokenizer.GetNextToken();
     if ( !token.ToLong(&l) )
-        return FALSE;
-    family = (int)l;
+        return false;
+    family = (wxFontFamily)l;
 
     token = tokenizer.GetNextToken();
     if ( !token.ToLong(&l) )
-        return FALSE;
-    style = (int)l;
+        return false;
+    style = (wxFontStyle)l;
 
     token = tokenizer.GetNextToken();
     if ( !token.ToLong(&l) )
-        return FALSE;
-    weight = (int)l;
+        return false;
+    weight = (wxFontWeight)l;
 
     token = tokenizer.GetNextToken();
     if ( !token.ToLong(&l) )
-        return FALSE;
+        return false;
     underlined = l != 0;
 
     faceName = tokenizer.GetNextToken();
+
+#ifndef __WXMAC__
     if( !faceName )
-        return FALSE;
+        return false;
+#endif
 
     token = tokenizer.GetNextToken();
     if ( !token.ToLong(&l) )
-        return FALSE;
+        return false;
     encoding = (wxFontEncoding)l;
 
-    return TRUE;
+    return true;
 }
 
 wxString wxNativeFontInfo::ToString() const
@@ -248,8 +491,8 @@ wxString wxNativeFontInfo::ToString() const
              0,                                 // version
              pointSize,
              family,
-             style,
-             weight,
+             (int)style,
+             (int)weight,
              underlined,
              faceName.GetData(),
              (int)encoding);
@@ -257,5 +500,319 @@ wxString wxNativeFontInfo::ToString() const
     return s;
 }
 
+void wxNativeFontInfo::Init()
+{
+    pointSize = 0;
+    family = wxFONTFAMILY_DEFAULT;
+    style = wxFONTSTYLE_NORMAL;
+    weight = wxFONTWEIGHT_NORMAL;
+    underlined = false;
+    faceName.clear();
+    encoding = wxFONTENCODING_DEFAULT;
+}
+
+int wxNativeFontInfo::GetPointSize() const
+{
+    return pointSize;
+}
+
+wxFontStyle wxNativeFontInfo::GetStyle() const
+{
+    return style;
+}
+
+wxFontWeight wxNativeFontInfo::GetWeight() const
+{
+    return weight;
+}
+
+bool wxNativeFontInfo::GetUnderlined() const
+{
+    return underlined;
+}
+
+wxString wxNativeFontInfo::GetFaceName() const
+{
+    return faceName;
+}
+
+wxFontFamily wxNativeFontInfo::GetFamily() const
+{
+    return family;
+}
+
+wxFontEncoding wxNativeFontInfo::GetEncoding() const
+{
+    return encoding;
+}
+
+void wxNativeFontInfo::SetPointSize(int pointsize)
+{
+    pointSize = pointsize;
+}
+
+void wxNativeFontInfo::SetStyle(wxFontStyle style_)
+{
+    style = style_;
+}
+
+void wxNativeFontInfo::SetWeight(wxFontWeight weight_)
+{
+    weight = weight_;
+}
+
+void wxNativeFontInfo::SetUnderlined(bool underlined_)
+{
+    underlined = underlined_;
+}
+
+bool wxNativeFontInfo::SetFaceName(const wxString& facename_)
+{
+    faceName = facename_;
+    return true;
+}
+
+void wxNativeFontInfo::SetFamily(wxFontFamily family_)
+{
+    family = family_;
+}
+
+void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding_)
+{
+    encoding = encoding_;
+}
+
 #endif // generic wxNativeFontInfo implementation
 
+// conversion to/from user-readable string: this is used in the generic
+// versions and under MSW as well because there is no standard font description
+// format there anyhow (but there is a well-defined standard for X11 fonts used
+// by wxGTK and wxMotif)
+
+#if defined(wxNO_NATIVE_FONTINFO) || defined(__WXMSW__) || defined (__WXPM__)
+
+wxString wxNativeFontInfo::ToUserString() const
+{
+    wxString desc;
+
+    // first put the adjectives, if any - this is English-centric, of course,
+    // but what else can we do?
+    if ( GetUnderlined() )
+    {
+        desc << _("underlined");
+    }
+
+    switch ( GetWeight() )
+    {
+        default:
+            wxFAIL_MSG( _T("unknown font weight") );
+            // fall through
+
+        case wxFONTWEIGHT_NORMAL:
+            break;
+
+        case wxFONTWEIGHT_LIGHT:
+            desc << _(" light");
+            break;
+
+        case wxFONTWEIGHT_BOLD:
+            desc << _(" bold");
+            break;
+    }
+
+    switch ( GetStyle() )
+    {
+        default:
+            wxFAIL_MSG( _T("unknown font style") );
+            // fall through
+
+        case wxFONTSTYLE_NORMAL:
+            break;
+
+            // we don't distinguish between the two for now anyhow...
+        case wxFONTSTYLE_ITALIC:
+        case wxFONTSTYLE_SLANT:
+            desc << _(" italic");
+            break;
+    }
+
+    wxString face = GetFaceName();
+    if ( !face.empty() )
+    {
+        desc << _T(' ') << face;
+    }
+
+    int size = GetPointSize();
+    if ( size != wxNORMAL_FONT->GetPointSize() )
+    {
+        desc << _T(' ') << size;
+    }
+
+#if wxUSE_FONTMAP
+    wxFontEncoding enc = GetEncoding();
+    if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM )
+    {
+        desc << _T(' ') << wxFontMapper::GetEncodingName(enc);
+    }
+#endif // wxUSE_FONTMAP
+
+    return desc.Strip(wxString::both).MakeLower();
+}
+
+bool wxNativeFontInfo::FromUserString(const wxString& s)
+{
+    // reset to the default state
+    Init();
+
+    // parse a more or less free form string
+    //
+    // TODO: we should handle at least the quoted facenames
+    wxStringTokenizer tokenizer(s, _T(";, "), wxTOKEN_STRTOK);
+
+    wxString face;
+    unsigned long size;
+    bool weightfound = false, pointsizefound = false;
+#if wxUSE_FONTMAP
+    bool encodingfound = false;
+#endif
+
+    while ( tokenizer.HasMoreTokens() )
+    {
+        wxString token = tokenizer.GetNextToken();
+
+        // normalize it
+        token.Trim(true).Trim(false).MakeLower();
+
+        // look for the known tokens
+        if ( token == _T("underlined") || token == _("underlined") )
+        {
+            SetUnderlined(true);
+        }
+        else if ( token == _T("light") || token == _("light") )
+        {
+            SetWeight(wxFONTWEIGHT_LIGHT);
+            weightfound = true;
+        }
+        else if ( token == _T("bold") || token == _("bold") )
+        {
+            SetWeight(wxFONTWEIGHT_BOLD);
+            weightfound = true;
+        }
+        else if ( token == _T("italic") || token == _("italic") )
+        {
+            SetStyle(wxFONTSTYLE_ITALIC);
+        }
+        else if ( token.ToULong(&size) )
+        {
+            SetPointSize(size);
+            pointsizefound = true;
+        }
+        else
+        {
+#if wxUSE_FONTMAP
+            // try to interpret this as an encoding
+            wxFontEncoding encoding = wxFontMapper::Get()->CharsetToEncoding(token, false);
+            if ( encoding != wxFONTENCODING_DEFAULT &&
+                 encoding != wxFONTENCODING_SYSTEM )    // returned when the recognition failed
+        {
+            SetEncoding(encoding);
+                encodingfound = true;
+        }
+            else
+        {
+#endif // wxUSE_FONTMAP
+
+                // assume it is the face name
+            if ( !face.empty() )
+            {
+                face += _T(' ');
+            }
+
+            face += token;
+
+            // skip the code which resets face below
+            continue;
+
+#if wxUSE_FONTMAP
+        }
+#endif // wxUSE_FONTMAP
+        }
+
+        // if we had had the facename, we shouldn't continue appending tokens
+        // to it (i.e. "foo bold bar" shouldn't result in the facename "foo
+        // bar")
+        if ( !face.empty() )
+        {
+            // NB: the check on the facename is implemented in wxFontBase::SetFaceName
+            //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitely
+            //     call here wxFontEnumerator::IsValidFacename
+            if (
+#if wxUSE_FONTENUM
+                    !wxFontEnumerator::IsValidFacename(face) ||
+#endif // wxUSE_FONTENUM
+                    !SetFaceName(face) )
+            {
+                SetFaceName(wxNORMAL_FONT->GetFaceName());
+            }
+
+            face.clear();
+        }
+    }
+
+    // we might not have flushed it inside the loop
+    if ( !face.empty() )
+    {
+        // NB: the check on the facename is implemented in wxFontBase::SetFaceName
+        //     and not in wxNativeFontInfo::SetFaceName thus we need to explicitely
+        //     call here wxFontEnumerator::IsValidFacename
+        if (
+#if wxUSE_FONTENUM
+                !wxFontEnumerator::IsValidFacename(face) ||
+#endif // wxUSE_FONTENUM
+                !SetFaceName(face) )
+            {
+                SetFaceName(wxNORMAL_FONT->GetFaceName());
+            }
+    }
+
+    // set point size to default value if size was not given
+    if ( !pointsizefound )
+        SetPointSize(wxNORMAL_FONT->GetPointSize());
+
+    // set font weight to default value if weight was not given
+    if ( !weightfound )
+        SetWeight(wxFONTWEIGHT_NORMAL);
+
+#if wxUSE_FONTMAP
+    // set font encoding to default value if encoding was not given
+    if ( !encodingfound )
+        SetEncoding(wxFONTENCODING_SYSTEM);
+#endif // wxUSE_FONTMAP
+
+    return true;
+}
+
+#endif // generic or wxMSW or wxOS2
+
+
+// wxFont <-> wxString utilities, used by wxConfig
+wxString wxToString(const wxFontBase& font)
+{
+    return font.IsOk() ? font.GetNativeFontInfoDesc()
+                       : wxString();
+}
+
+bool wxFromString(const wxString& str, wxFontBase *font)
+{
+    wxCHECK_MSG( font, false, _T("NULL output parameter") );
+
+    if ( str.empty() )
+    {
+        *font = wxNullFont;
+        return true;
+    }
+
+    return font->SetNativeFontInfo(str);
+}
+
+