Halfway reasonable implementation of wxFont for wxCocoa.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@49213 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
ada162b932
commit
51146826fc
@ -16,12 +16,30 @@
|
||||
// wxFont
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DECLARE_WXCOCOA_OBJC_CLASS(NSFont);
|
||||
|
||||
// Internal class that bridges us with code like wxSystemSettings
|
||||
class wxCocoaFontFactory;
|
||||
// We have c-tors/methods taking pointers of these
|
||||
class wxFontRefData;
|
||||
|
||||
/*! @discussion
|
||||
wxCocoa's implementation of wxFont is very incomplete. In particular,
|
||||
a lot of work needs to be done on wxNativeFontInfo which is currently
|
||||
using the totally generic implementation.
|
||||
|
||||
See the documentation in src/cocoa/font.mm for more implementatoin details.
|
||||
*/
|
||||
class WXDLLEXPORT wxFont : public wxFontBase
|
||||
{
|
||||
friend class wxCocoaFontFactory;
|
||||
public:
|
||||
// ctors and such
|
||||
/*! @abstract Default construction of invalid font for 2-step construct then Create process.
|
||||
*/
|
||||
wxFont() { }
|
||||
|
||||
/*! @abstract Platform-independent construction with individual properties
|
||||
*/
|
||||
wxFont(int size,
|
||||
int family,
|
||||
int style,
|
||||
@ -33,13 +51,20 @@ public:
|
||||
(void)Create(size, family, style, weight, underlined, face, encoding);
|
||||
}
|
||||
|
||||
/*! @abstract Construction with opaque wxNativeFontInfo
|
||||
*/
|
||||
wxFont(const wxNativeFontInfo& info)
|
||||
{
|
||||
(void)Create(info);
|
||||
}
|
||||
|
||||
/*! @abstract Construction with platform-dependent font descriptor string.
|
||||
@param fontDesc Usually the result of wxNativeFontInfo::ToUserString()
|
||||
*/
|
||||
wxFont(const wxString& fontDesc);
|
||||
|
||||
// NOTE: Copy c-tor and assignment from wxObject is fine
|
||||
|
||||
bool Create(int size,
|
||||
int family,
|
||||
int style,
|
||||
@ -73,11 +98,36 @@ public:
|
||||
// implementation only from now on
|
||||
// -------------------------------
|
||||
|
||||
/*! @abstract Defined on some ports (not including this one) in wxGDIObject
|
||||
@discussion
|
||||
The intention here I suppose is to allow one to create a wxFont without yet
|
||||
creating the underlying native object. There's no point not to create the
|
||||
NSFont immediately in wxCocoa so this is useless.
|
||||
This method came from the stub code copied in the early days of wxCocoa.
|
||||
FIXME(1): Remove this in trunk. FIXME(2): Is it really a good idea for this to
|
||||
be part of the public API for wxGDIObject?
|
||||
*/
|
||||
virtual bool RealizeResource();
|
||||
|
||||
protected:
|
||||
/*! @abstract Helper method for COW.
|
||||
@discussion
|
||||
wxFont can be considered a mutable holder of an immutable opaque implementation object.
|
||||
All methods that mutate the font should first call Unshare() to ensure that mutating
|
||||
the implementation object does not cause another wxFont that happened to share the
|
||||
same ref data to mutate.
|
||||
*/
|
||||
void Unshare();
|
||||
|
||||
/*! @abstract Internal constructor with ref data
|
||||
@discussion
|
||||
Takes ownership of @a refData. That is, it is assumed that refData has either just been
|
||||
created using new (which initializes its m_refCount to 1) or if you are sharing a ref that
|
||||
you have called IncRef on it before passing it to this method.
|
||||
*/
|
||||
explicit wxFont(wxFontRefData *refData)
|
||||
{ Create(refData); }
|
||||
bool Create(wxFontRefData *refData);
|
||||
private:
|
||||
DECLARE_DYNAMIC_CLASS(wxFont)
|
||||
};
|
||||
|
@ -9,6 +9,68 @@
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*! @file font.mm
|
||||
@disucssion
|
||||
Cocoa has three classes which interact to form the font system:
|
||||
|
||||
NSFont: Represents a specific font (e.g. Times-Bold) at a specific size
|
||||
with specific attributes. That is, it's basically like this class.
|
||||
Notably, it doesn't hold an underlined flag, so this class does.
|
||||
Available on all OS X versions.
|
||||
|
||||
NSFontManager: Fairly broad controller class which ties together the
|
||||
model (NSFont) with the view (NSFontPanel). We are ignoring NSFontPanel
|
||||
in this discussion. NSFontManager is actually a little broader than just
|
||||
a controller though. It's also the traditional way of mutating fonts
|
||||
and asking for a font with a certain family and certain attributes.
|
||||
For example, you can use NSFont's factor methods to create a font named
|
||||
@"Times-Roman" then use NSFontManager to imbue attributes like italic and
|
||||
bold. You might do this if, for instance, you already have times at the
|
||||
Roman weight but want to make it bold.
|
||||
|
||||
Alternatively, you can use NSFontManager to ask for a font in the @"Times"
|
||||
family with the bold attribute.
|
||||
|
||||
NSFontManager is available on all OS X versions.
|
||||
|
||||
NSFontDescriptor: Added in OS X 10.3. Prior to this there was no specific
|
||||
class to represent all of the attributes of a font. Instead, a regular
|
||||
NSDictionary was used with a set of well-defined keys. Unfortunately,
|
||||
there was no method accepting the attributes dictionary, only a method
|
||||
to retrieve it from an NSFont. That meant that in order to create
|
||||
a new font by imbueing certain attributes like Bold one would need
|
||||
to use the specific method in NSFontManager to do so.
|
||||
|
||||
The NSFontDescriptor class, on the other hand, has factory methods which
|
||||
can create a new font descriptor with an attributes dictionary as well
|
||||
as mutate (by copy) an existing font descriptor using attributes from
|
||||
an attributes dictionary.
|
||||
|
||||
In theory, most of what can be done using NSFontDescriptor can just as
|
||||
well be done without it. NSFontDescriptor is basically just a shell
|
||||
around an NSMutableDictionary with well-defined keys.
|
||||
|
||||
|
||||
Getting back to the broad overview, font matching is one of the weaker points
|
||||
in Cocoa's API and NSFontDescriptor is the easier to use solution.
|
||||
|
||||
That said, it's not impossible to implement font matching without it. For instance,
|
||||
if you have a family name and want to list available variants (e.g. Bold, italic,
|
||||
underlined) then you can ask NSFontManager for availableMembersOfFontFamily:.
|
||||
|
||||
The problem is that you can either match on family name or on font attributes
|
||||
but not on both. To match both you have to do one then the other.
|
||||
NSFontDescriptor allows you to get a list of fonts matching both a family name
|
||||
and a particular set of attributes. Furthermore, the attributes instead of
|
||||
being flags as in NSFontManager are instead well-defined keys in a dictionary.
|
||||
|
||||
The only way to get that behavior without NSFontManager is to pare down the
|
||||
list as much as possible using the classic NSFontManager methods and then
|
||||
to instantiate each font in the list and match on each font's afmDictionary.
|
||||
|
||||
A reasonable guess is that that's probably more or less exactly what
|
||||
NSFontDescriptor does internally.
|
||||
*/
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#include "wx/font.h"
|
||||
@ -21,29 +83,67 @@
|
||||
#include "wx/fontutil.h"
|
||||
#include "wx/encinfo.h"
|
||||
|
||||
#include "wx/cocoa/string.h"
|
||||
#include "wx/cocoa/private/fontfactory.h"
|
||||
#include "wx/cocoa/autorelease.h"
|
||||
|
||||
#include <AppKit/NSFont.h>
|
||||
#include <AppKit/NSFontManager.h>
|
||||
|
||||
// Helper methods for NSFont/wxNativeFontInfo
|
||||
static NSFont* GetNSFontForNativeFontInfo(const wxNativeFontInfo &info);
|
||||
static void UpdateNativeFontInfoWithNSFont(wxNativeFontInfo &info, NSFont *cocoaNSFont);
|
||||
static wxNativeFontInfo MakeNativeFontInfoForNSFont(NSFont *cocoaNSFont, bool underlined = false);
|
||||
static wxNativeFontInfo MakeNativeFontInfo(int size, int family, int style, int weight, bool underlined, const wxString& faceName, wxFontEncoding encoding);
|
||||
|
||||
/*! @discussion
|
||||
Due to 2.8 ABI compatibility concerns we probably don't want to change wxNativeFontInfo
|
||||
although this may be unfounded because this class is supposed to be internal as is
|
||||
wxNativeFontInfo so anyone who subclassed it or created one without going through
|
||||
wxFont should expect what they get (i.e. horrible breakage)
|
||||
There's a concern that wxFontRefData was in the public header when 2.8 shipped so
|
||||
it's possible that someone did subclass it to get better font behavior.
|
||||
|
||||
For right now, the plan is to write it strictly ABI compatible with 2.8 and eventually
|
||||
to enhance it in trunk to accurately represent font attributes as Cocoa sees them.
|
||||
|
||||
I'd like to let at least one 2.8 release go out the door and get feedback as to whether
|
||||
this is going to be a problem or not. If so, we'll keep it strictly ABI compatible.
|
||||
If not, we'll update it.
|
||||
*/
|
||||
class WXDLLEXPORT wxFontRefData: public wxGDIRefData
|
||||
{
|
||||
friend class WXDLLIMPEXP_FWD_CORE wxFont;
|
||||
public:
|
||||
wxFontRefData()
|
||||
: m_fontId(0)
|
||||
: m_cocoaNSFont(nil)
|
||||
, m_info(MakeNativeFontInfo(10, wxDEFAULT, wxNORMAL, wxNORMAL, FALSE,
|
||||
wxT("Geneva"), wxFONTENCODING_DEFAULT))
|
||||
{
|
||||
Init(10, wxDEFAULT, wxNORMAL, wxNORMAL, FALSE,
|
||||
wxT("Geneva"), wxFONTENCODING_DEFAULT);
|
||||
CreateNSFontAndUpdateInfo();
|
||||
}
|
||||
|
||||
wxFontRefData(const wxFontRefData& data)
|
||||
: wxGDIRefData()
|
||||
, m_fontId(data.m_fontId)
|
||||
, m_cocoaNSFont([data.m_cocoaNSFont retain])
|
||||
, m_info(data.m_info)
|
||||
{
|
||||
}
|
||||
|
||||
wxFontRefData(NSFont *cocoaNSFont, bool underlined)
|
||||
: wxGDIRefData()
|
||||
, m_cocoaNSFont([cocoaNSFont retain])
|
||||
, m_info(MakeNativeFontInfoForNSFont(m_cocoaNSFont, underlined))
|
||||
{
|
||||
}
|
||||
|
||||
wxFontRefData(const wxNativeFontInfo& info)
|
||||
: wxGDIRefData()
|
||||
, m_fontId(0)
|
||||
, m_cocoaNSFont(nil)
|
||||
, m_info(info)
|
||||
{}
|
||||
{
|
||||
CreateNSFontAndUpdateInfo();
|
||||
}
|
||||
|
||||
wxFontRefData(int size,
|
||||
int family,
|
||||
@ -52,14 +152,19 @@ public:
|
||||
bool underlined,
|
||||
const wxString& faceName,
|
||||
wxFontEncoding encoding)
|
||||
: m_fontId(0)
|
||||
: m_cocoaNSFont(nil)
|
||||
, m_info(MakeNativeFontInfo(size, family, style, weight, underlined, faceName, encoding))
|
||||
{
|
||||
Init(size, family, style, weight, underlined, faceName, encoding);
|
||||
CreateNSFontAndUpdateInfo();
|
||||
}
|
||||
|
||||
virtual ~wxFontRefData();
|
||||
protected:
|
||||
// common part of all ctors
|
||||
/*! @abstract common part of some ctors
|
||||
@discussion
|
||||
This is a leftover of sorts from the old stub code.
|
||||
FIXME: Remove from trunk
|
||||
*/
|
||||
void Init(int size,
|
||||
int family,
|
||||
int style,
|
||||
@ -68,17 +173,119 @@ protected:
|
||||
const wxString& faceName,
|
||||
wxFontEncoding encoding);
|
||||
|
||||
/*! @discussion
|
||||
Uses the native font info to create an NSFont and then updates that info with
|
||||
the attributes of the font. This is necessary because, for example, a font
|
||||
can be created with an empty faceName in which case some concrete typeface must
|
||||
be chosen.
|
||||
We choose to handle this by first initializing the wxNativeFontInfo with the
|
||||
properties as given by the user and then creating the NSFont and updating
|
||||
the wxNativeFontInfo to match the NSFont.
|
||||
*/
|
||||
void CreateNSFontAndUpdateInfo()
|
||||
{
|
||||
wxAutoNSAutoreleasePool pool;
|
||||
[m_cocoaNSFont release];
|
||||
m_cocoaNSFont = [GetNSFontForNativeFontInfo(m_info) retain];
|
||||
UpdateNativeFontInfoWithNSFont(m_info, m_cocoaNSFont);
|
||||
}
|
||||
|
||||
// font characterstics
|
||||
int m_fontId;
|
||||
NSFont *m_cocoaNSFont;
|
||||
wxNativeFontInfo m_info;
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
NSString *GetFamilyName(wxFontFamily family)
|
||||
{
|
||||
switch(family)
|
||||
{
|
||||
case wxFONTFAMILY_DEFAULT:
|
||||
default:
|
||||
return @"Times";
|
||||
case wxFONTFAMILY_DECORATIVE:
|
||||
case wxFONTFAMILY_ROMAN:
|
||||
case wxFONTFAMILY_SCRIPT:
|
||||
return @"Times";
|
||||
case wxFONTFAMILY_SWISS:
|
||||
return @"Lucida Grande";
|
||||
case wxFONTFAMILY_MODERN:
|
||||
case wxFONTFAMILY_TELETYPE:
|
||||
return @"Monaco";
|
||||
};
|
||||
}
|
||||
// Returns an NSFont given the native font info
|
||||
// NOTE: It is not considered alloc'd (i.e. this is a get method not an alloc/new method)
|
||||
static NSFont* GetNSFontForNativeFontInfo(const wxNativeFontInfo &info)
|
||||
{
|
||||
if(!info.faceName.empty())
|
||||
{
|
||||
NSFont *font = [NSFont fontWithName:wxNSStringWithWxString(info.faceName) size:info.pointSize];
|
||||
// TODO: use NSFontManager to mix in the weights and whatnot
|
||||
if(font != nil)
|
||||
return font;
|
||||
// To err or not to err?
|
||||
}
|
||||
// No font with that face name or no face name
|
||||
|
||||
NSFontTraitMask cocoaTraits = 0;
|
||||
int cocoaWeight = 5;
|
||||
NSFont *font = [[NSFontManager sharedFontManager] fontWithFamily:GetFamilyName(info.family) traits:cocoaTraits weight:cocoaWeight size:info.pointSize];
|
||||
return font;
|
||||
}
|
||||
|
||||
/*! @discussion
|
||||
Updates all fields of @a info except for underlined which is not a property of NSFont.
|
||||
*/
|
||||
static void UpdateNativeFontInfoWithNSFont(wxNativeFontInfo &info, NSFont *cocoaNSFont)
|
||||
{
|
||||
info.pointSize = [cocoaNSFont pointSize];
|
||||
|
||||
// FIXME: We could maybe improve on this?
|
||||
info.family = wxFONTFAMILY_DEFAULT;
|
||||
|
||||
// FIXME: italicAngle might indicate a slanted rather than truly italic font?
|
||||
info.style = [cocoaNSFont italicAngle] == 0.0?wxFONTSTYLE_NORMAL:wxFONTSTYLE_ITALIC;
|
||||
|
||||
int cocoaWeight = [[NSFontManager sharedFontManager] weightOfFont:cocoaNSFont];
|
||||
if(cocoaWeight < 5)
|
||||
info.weight = wxFONTWEIGHT_LIGHT;
|
||||
else if(cocoaWeight < 9)
|
||||
info.weight = wxFONTWEIGHT_NORMAL;
|
||||
else
|
||||
info.weight = wxFONTWEIGHT_BOLD;
|
||||
|
||||
// FIXME: Is this right? I think so.
|
||||
info.faceName = wxStringWithNSString([cocoaNSFont fontName]);
|
||||
|
||||
// TODO: Translate NSStringEncoding to wxFontEncoding
|
||||
info.encoding = wxFONTENCODING_SYSTEM;
|
||||
}
|
||||
|
||||
/*! @discussion
|
||||
Creates a new generic wxNativeFontInfo from an NSFont and an underlined flag.
|
||||
Uses UpdateNativeFontInfoWithNSFont to do the work and sets the underlined field
|
||||
of wxNativeFontInfo to the @a underlined argument.
|
||||
*/
|
||||
static wxNativeFontInfo MakeNativeFontInfoForNSFont(NSFont *cocoaNSFont, bool underlined)
|
||||
{
|
||||
wxNativeFontInfo info;
|
||||
UpdateNativeFontInfoWithNSFont(info, cocoaNSFont);
|
||||
|
||||
// NSFont are never underlined.. that's a function of the drawing system
|
||||
info.underlined = underlined;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
//#include "_font_test_2_8_abi_compat.h"
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject)
|
||||
|
||||
void wxFontRefData::Init(int size, int family, int style, int weight, bool underlined, const wxString& faceName, wxFontEncoding encoding)
|
||||
static wxNativeFontInfo MakeNativeFontInfo(int size, int family, int style, int weight, bool underlined, const wxString& faceName, wxFontEncoding encoding)
|
||||
{
|
||||
wxNativeFontInfo m_info; // NOTE: not an i-var despite name
|
||||
m_info.pointSize = size;
|
||||
m_info.family = static_cast<wxFontFamily>(family);
|
||||
m_info.style = static_cast<wxFontStyle>(style);
|
||||
@ -86,15 +293,36 @@ void wxFontRefData::Init(int size, int family, int style, int weight, bool under
|
||||
m_info.underlined = underlined;
|
||||
m_info.faceName = faceName;
|
||||
m_info.encoding = encoding;
|
||||
return m_info;
|
||||
}
|
||||
|
||||
void wxFontRefData::Init(int size, int family, int style, int weight, bool underlined, const wxString& faceName, wxFontEncoding encoding)
|
||||
{
|
||||
m_info = MakeNativeFontInfo(size, family, style, weight, underlined, faceName, encoding);
|
||||
}
|
||||
|
||||
wxFontRefData::~wxFontRefData()
|
||||
{
|
||||
[m_cocoaNSFont release];
|
||||
m_cocoaNSFont = nil;
|
||||
// TODO: delete font data
|
||||
}
|
||||
|
||||
#define M_FONTDATA ((wxFontRefData*)m_refData)
|
||||
|
||||
wxFont wxCocoaFontFactory::InstanceForNSFont(WX_NSFont cocoaFont, bool underlined)
|
||||
{
|
||||
return wxFont(new wxFontRefData(cocoaFont, underlined));
|
||||
}
|
||||
|
||||
bool wxFont::Create(wxFontRefData *refData)
|
||||
{
|
||||
UnRef();
|
||||
m_refData = refData;
|
||||
|
||||
return m_refData != NULL;
|
||||
}
|
||||
|
||||
bool wxFont::Create(const wxNativeFontInfo& nativeFontInfo)
|
||||
{
|
||||
UnRef();
|
||||
|
@ -19,8 +19,10 @@
|
||||
#endif
|
||||
|
||||
#include "wx/cocoa/autorelease.h"
|
||||
#include "wx/cocoa/private/fontfactory.h"
|
||||
|
||||
#import <AppKit/NSColor.h>
|
||||
#import <AppKit/NSFont.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSystemSettingsNative
|
||||
@ -106,8 +108,10 @@ wxColour wxSystemSettingsNative::GetColour(wxSystemColour index)
|
||||
|
||||
wxFont wxSystemSettingsNative::GetFont(wxSystemFont index)
|
||||
{
|
||||
// return a nonworking font object, crash from wxInitializeStockObjects
|
||||
return wxFont();
|
||||
// Return the system font for now
|
||||
{ wxAutoNSAutoreleasePool pool;
|
||||
return wxCocoaFontFactory::InstanceForNSFont([NSFont systemFontOfSize:0.0], false);
|
||||
}
|
||||
switch (index)
|
||||
{
|
||||
case wxSYS_ANSI_VAR_FONT :
|
||||
|
Loading…
Reference in New Issue
Block a user