/kiva/fonttools/font.py
Python | 161 lines | 112 code | 16 blank | 33 comment | 25 complexity | 2daf2f26419c194399d7f483ce86f04f MD5 | raw file
- """
- Defines the Kiva Font class and a utility method to parse free-form font
- specification strings into Font instances.
- """
- import copy
- from kiva.constants import DEFAULT, DECORATIVE, ROMAN, SCRIPT, \
- SWISS, MODERN, TELETYPE, NORMAL, ITALIC, BOLD, BOLD_ITALIC
- from font_manager import FontProperties, fontManager
- # Various maps used by str_to_font
- font_families = {
- 'default': DEFAULT,
- 'decorative': DECORATIVE,
- 'roman': ROMAN,
- 'script': SCRIPT,
- 'swiss': SWISS,
- 'modern': MODERN
- }
- font_styles = { 'italic': ITALIC }
- font_weights = { 'bold': BOLD }
- font_noise = [ 'pt', 'point', 'family' ]
- def str_to_font(fontspec):
- """
- Converts a string specification of a font into a Font instance.
- string specifications are of the form: "modern 12", "9 roman italic",
- and so on.
- """
- point_size = 10
- family = DEFAULT
- style = NORMAL
- weight = NORMAL
- underline = 0
- facename = []
- for word in fontspec.split():
- lword = word.lower()
- if font_families.has_key( lword ):
- family = font_families[ lword ]
- elif font_styles.has_key( lword ):
- style = font_styles[ lword ]
- elif font_weights.has_key( lword ):
- weight = font_weights[ lword ]
- elif lword == 'underline':
- underline = 1
- elif lword not in font_noise:
- try:
- point_size = int( lword )
- except:
- facename.append( word )
- return Font( size=point_size, family=family, weight=weight, style=style,
- underline=underline, face_name=' '.join( facename ) )
- class Font(object):
- """ Font class for device independent font specification.
- It is primarily based on wxPython, but looks to be similar to
- the needs of Mac OS X, etc.
- The family defaults to SWISS so that font rotation will work
- correctly under wxPython. Revisit as we get more platforms
- defined.
- """
- # Maps the constants for font families to names to use when searching for
- # fonts.
- familymap = {DEFAULT : "serif",
- SWISS : "sans-serif",
- ROMAN : "serif",
- MODERN : "sans-serif",
- DECORATIVE : "fantasy",
- SCRIPT : "script",
- TELETYPE : "monospace" }
- def __init__(self, face_name="", size = 12,family = SWISS, weight=NORMAL,
- style=NORMAL, underline = 0, encoding=DEFAULT):
- if (type(size) != int) or (type(family) != type(SWISS)) or \
- (type(weight) != type(NORMAL)) or (type(style) != type(NORMAL)) or \
- (type(underline) != int) or (not isinstance(face_name, basestring)) or \
- (type(encoding) != type(DEFAULT)):
- raise RuntimeError, "Bad value in Font() constructor."
- ### HACK: C++ stuff expects a string (not unicode) for the face_name, so fix
- ### if needed. See ticket #2111 in the CP Trac.
- if isinstance(face_name, unicode):
- face_name = face_name.encode("latin1")
- self.size = size
- self.family = family
- self.weight = weight
- self.style = style
- self.underline = underline
- self.face_name = face_name
- self.encoding = encoding
- def findfont(self):
- """ Returns the file name containing the font that most closely matches
- our font properties.
- """
- fp = self._make_font_props()
- return str(fontManager.findfont(fp))
- def findfontname(self):
- """ Returns the name of the font that most closely matches our font
- properties
- """
- fp = self._make_font_props()
- return fp.get_name()
- def _make_font_props(self):
- """ Returns a font_manager.FontProperties object that encapsulates our
- font properties
- """
- # XXX: change the weight to a numerical value
- if self.style == BOLD or self.style == BOLD_ITALIC:
- weight = "bold"
- else:
- weight = "normal"
- if self.style == ITALIC or self.style == BOLD_ITALIC:
- style = "italic"
- else:
- style = "normal"
- fp = FontProperties(family = self.familymap[self.family], style=style, weight=weight,
- size = self.size)
- if self.face_name != "":
- fp.set_name(self.face_name)
- return fp
- def _get_name(self):
- return self.face_name
- def _set_name(self, val):
- self.face_name = val
- name = property(_get_name, _set_name)
- def copy(self):
- """ Returns a copy of the font object.
- """
- return copy.deepcopy(self)
- def __eq__(self, other):
- result = False
- try:
- if (self.family == other.family and
- self.size == other.size and
- self.weight == other.weight and
- self.style == other.style and
- self.underline == other.underline and
- self.face_name == other.face_name and
- self.encoding == other.encoding):
- result = True
- except AttributeError:
- pass
- return result
- def __ne__(self, other):
- return not self.__eq__(other)
- def __repr__(self):
- return "Font(size=%d,family=%d,weight=%d, style=%d, face_name='%s',encoding=%d )" % \
- (self.size, self.family, self.weight, self.style, self.face_name, self.encoding)