git-svn-id: http://svn.robofab.com/branches/ufo3k@527 b5fa9d6c-a76f-4ffd-b3cb-f825fc41095c
1404 lines
39 KiB
Python
Executable File
1404 lines
39 KiB
Python
Executable File
"""
|
|
This is the new doc for the objectsRF module.
|
|
|
|
To Do:
|
|
- make it so that BaseKerning.clear() uses self._kerning.clear() instead of self._kerning = {}
|
|
- check all of BaseKerning to make sure that it doesn't replace self._kerning
|
|
- in BaseKerning.__init__ use if kerningDict is None
|
|
- make BaseGroups subclass BaseObject like BaseKerning does?
|
|
- add __contains__ to all dict-like base objects
|
|
- get right of BaseGroups.findGlyph
|
|
- BaseObject.naked expects the wrapped object to be stored at ._object.
|
|
this is not always true.
|
|
- what should be done about the PSHint objects?
|
|
- the repr methods in ObjectsBase use odd font.info name values
|
|
|
|
|
|
I'm trying to find a way to make it possible for defcon based
|
|
environments to use these objects in a simple way. For now, I
|
|
have overridable methods that return uninstantiated classes
|
|
for each of the sub-object types that are needed by a particular
|
|
object. Subclasses can override these to implement their own
|
|
R* subclasses. In __init__, "path" can be a path or None to open
|
|
a basic defcon font or a defcon.Font (or subclass) object to be wrapped.
|
|
"""
|
|
|
|
import os
|
|
from defcon import Font as DefconFont
|
|
from robofab import RoboFabError, RoboFabWarning
|
|
from robofab.objects.objectsBase import RBaseObject, BaseFont, BaseKerning, BaseGroups, BaseInfo, BaseFeatures, BaseLib,\
|
|
BaseGlyph, BaseContour, BaseSegment, BasePoint, BaseBPoint, BaseAnchor, BaseGuide, BaseComponent, \
|
|
relativeBCPIn, relativeBCPOut, absoluteBCPIn, absoluteBCPOut, _box,\
|
|
_interpolate, _interpolatePt, roundPt, addPt,\
|
|
MOVE, LINE, CORNER, CURVE, QCURVE, OFFCURVE,\
|
|
BasePostScriptFontHintValues, postScriptHintDataLibKey, BasePostScriptGlyphHintValues
|
|
|
|
|
|
__all__ = [ "CurrentFont",
|
|
"CurrentGlyph", 'OpenFont',
|
|
'RFont', 'RGlyph', 'RContour',
|
|
'RPoint', 'RBPoint', 'RAnchor',
|
|
'RComponent'
|
|
]
|
|
|
|
|
|
|
|
def CurrentFont():
|
|
"""CurrentFont is not available in objectsRF."""
|
|
return None
|
|
|
|
def CurrentGlyph():
|
|
"""CurrentGlyph is not available in objectsRF."""
|
|
return None
|
|
|
|
def OpenFont(path=None, note=None):
|
|
"""Open a font from a path. If path is not given, present the user with a dialog (availability of dialogs will vary)"""
|
|
if not note:
|
|
note = 'select a .ufo directory'
|
|
if not path:
|
|
from robofab.interface.all.dialogs import GetFolder
|
|
path = GetFolder(note)
|
|
if path:
|
|
try:
|
|
return RFont(path)
|
|
except OSError:
|
|
from robofab.interface.all.dialogs import Message
|
|
Message("%s is not a valid .UFO font. But considering it's all XML, why don't you have a look inside with a simple text editor."%(path))
|
|
else:
|
|
return None
|
|
|
|
def NewFont(familyName=None, styleName=None):
|
|
"""Make a new font object. Initialise with familyName and styleName."""
|
|
new = RFont()
|
|
if familyName is not None:
|
|
new.info.familyName = familyName
|
|
if styleName is not None:
|
|
new.info.styleName = styleName
|
|
return new
|
|
|
|
def AllFonts():
|
|
"""AllFonts is not available in objectsRF."""
|
|
raise NotImplementedError
|
|
|
|
|
|
class RFont(BaseFont):
|
|
"""
|
|
Font object representing the data in an UFO.
|
|
|
|
- myFontInstace['A'] access the font as a dictionary with glyphnames as key
|
|
|
|
"""
|
|
|
|
_title = "RoboFabFont"
|
|
|
|
def __init__(self, path=None):
|
|
super(RFont, self).__init__()
|
|
if isinstance(path, DefconFont):
|
|
self._object = path
|
|
else:
|
|
self._object = DefconFont(path)
|
|
self._info = None
|
|
self._kerning = None
|
|
self._groups = None
|
|
self._features = None
|
|
self._lib = None
|
|
# XXX PS Hints?
|
|
|
|
# Object Classes
|
|
|
|
def infoClass(self):
|
|
return RInfo
|
|
|
|
def groupsClass(self):
|
|
return RGroups
|
|
|
|
def kerningClass(self):
|
|
return RKerning
|
|
|
|
def featuresClass(self):
|
|
return RFeatures
|
|
|
|
def libClass(self):
|
|
return RLib
|
|
|
|
# Sub-Objects
|
|
|
|
def _get_info(self):
|
|
if self._info is None:
|
|
self._info = self.infoClass()(self._object.info)
|
|
return self._info
|
|
|
|
info = property(_get_info)
|
|
|
|
def _get_groups(self):
|
|
if self._groups is None:
|
|
self._groups = self.groupsClass()(self._object.groups)
|
|
return self._groups
|
|
|
|
groups = property(_get_groups)
|
|
|
|
def _get_kerning(self):
|
|
if self._kerning is None:
|
|
self._kerning = self.kerningClass()(self._object.kerning)
|
|
return self._kerning
|
|
|
|
kerning = property(_get_kerning)
|
|
|
|
def _get_features(self):
|
|
if self._features is None:
|
|
self._features = self.featuresClass()(self._object.features)
|
|
return self._features
|
|
|
|
features = property(_get_features)
|
|
|
|
def _get_lib(self):
|
|
if self._lib is None:
|
|
self._lib = self.libClass()(self._object.lib)
|
|
return self._lib
|
|
|
|
lib = property(_get_lib)
|
|
|
|
# def __setitem__(self, glyphName, glyph):
|
|
# """Set a glyph at key."""
|
|
# self._object[glyphName] = glyph
|
|
#
|
|
# def __cmp__(self, other):
|
|
# """Compare this font with another, compare if they refer to the same file."""
|
|
# if not hasattr(other, '_path'):
|
|
# return -1
|
|
# if self._object._path == other._object._path and self._object._path is not None:
|
|
# return 0
|
|
# else:
|
|
# return -1
|
|
#
|
|
# def __len__(self):
|
|
# if self._glyphSet is None:
|
|
# return 0
|
|
# return len(self._glyphSet)
|
|
#
|
|
# def _loadData(self, path):
|
|
# from ufoLib import UFOReader
|
|
# reader = UFOReader(path)
|
|
# fontLib = reader.readLib()
|
|
# # info
|
|
# reader.readInfo(self.info)
|
|
# # kerning
|
|
# self.kerning.update(reader.readKerning())
|
|
# self.kerning.setChanged(False)
|
|
# # groups
|
|
# self.groups.update(reader.readGroups())
|
|
# # features
|
|
# if reader.formatVersion == 1:
|
|
# # migrate features from the lib
|
|
# features = []
|
|
# classes = fontLib.get("org.robofab.opentype.classes")
|
|
# if classes is not None:
|
|
# del fontLib["org.robofab.opentype.classes"]
|
|
# features.append(classes)
|
|
# splitFeatures = fontLib.get("org.robofab.opentype.features")
|
|
# if splitFeatures is not None:
|
|
# order = fontLib.get("org.robofab.opentype.featureorder")
|
|
# if order is None:
|
|
# order = splitFeatures.keys()
|
|
# order.sort()
|
|
# else:
|
|
# del fontLib["org.robofab.opentype.featureorder"]
|
|
# del fontLib["org.robofab.opentype.features"]
|
|
# for tag in order:
|
|
# oneFeature = splitFeatures.get(tag)
|
|
# if oneFeature is not None:
|
|
# features.append(oneFeature)
|
|
# features = "\n".join(features)
|
|
# else:
|
|
# features = reader.readFeatures()
|
|
# self.features.text = features
|
|
# # hint data
|
|
# self.psHints = PostScriptFontHintValues(self)
|
|
# if postScriptHintDataLibKey in fontLib:
|
|
# del fontLib[postScriptHintDataLibKey]
|
|
# # lib
|
|
# self.lib.update(fontLib)
|
|
# # glyphs
|
|
# self._glyphSet = reader.getGlyphSet()
|
|
# self._hasNotChanged(doGlyphs=False)
|
|
#
|
|
# def _loadGlyph(self, glyphName):
|
|
# """Load a single glyph from the glyphSet, on request."""
|
|
# from robofab.pens.rfUFOPen import RFUFOPointPen
|
|
# g = RGlyph()
|
|
# g.name = glyphName
|
|
# pen = RFUFOPointPen(g)
|
|
# self._glyphSet.readGlyph(glyphName=glyphName, glyphObject=g, pointPen=pen)
|
|
# g.setParent(self)
|
|
# g.psHints._loadFromLib(g.lib)
|
|
# self._object[glyphName] = g
|
|
# self._object[glyphName]._hasNotChanged()
|
|
# return g
|
|
#
|
|
# #def _prepareSaveDir(self, dir):
|
|
# # path = os.path.join(dir, 'glyphs')
|
|
# # if not os.path.exists(path):
|
|
# # os.makedirs(path)
|
|
#
|
|
# def _hasNotChanged(self, doGlyphs=True):
|
|
# #set the changed state of the font
|
|
# if doGlyphs:
|
|
# for glyph in self:
|
|
# glyph._hasNotChanged()
|
|
# self.setChanged(False)
|
|
#
|
|
# #
|
|
# # attributes
|
|
# #
|
|
#
|
|
# def _get_path(self):
|
|
# return self._path
|
|
#
|
|
# path = property(_get_path, doc="path of the font")
|
|
#
|
|
# #
|
|
# # methods for imitating GlyphSet?
|
|
# #
|
|
#
|
|
# def keys(self):
|
|
# # the keys are the superset of self._objects.keys() and
|
|
# # self._glyphSet.keys(), minus self._scheduledForDeletion
|
|
# keys = self._object.keys()
|
|
# if self._glyphSet is not None:
|
|
# keys.extend(self._glyphSet.keys())
|
|
# d = dict()
|
|
# for glyphName in keys:
|
|
# d[glyphName] = None
|
|
# for glyphName in self._scheduledForDeletion:
|
|
# if glyphName in d:
|
|
# del d[glyphName]
|
|
# return d.keys()
|
|
#
|
|
# def has_key(self, glyphName):
|
|
# # XXX ditto, see above.
|
|
# if self._glyphSet is not None:
|
|
# hasGlyph = glyphName in self._object or glyphName in self._glyphSet
|
|
# else:
|
|
# hasGlyph = glyphName in self._object
|
|
# return hasGlyph and not glyphName in self._scheduledForDeletion
|
|
#
|
|
# __contains__ = has_key
|
|
#
|
|
# def getWidth(self, glyphName):
|
|
# if self._object.has_key(glyphName):
|
|
# return self._object[glyphName].width
|
|
# raise IndexError # or return None?
|
|
#
|
|
# def getReverseComponentMapping(self):
|
|
# """
|
|
# Get a reversed map of component references in the font.
|
|
# {
|
|
# 'A' : ['Aacute', 'Aring']
|
|
# 'acute' : ['Aacute']
|
|
# 'ring' : ['Aring']
|
|
# etc.
|
|
# }
|
|
# """
|
|
# # a NON-REVERESED map is stored in the lib.
|
|
# # this is done because a reveresed map could
|
|
# # contain faulty data. for example: "Aacute" contains
|
|
# # a component that references "A". Glyph "Aacute" is
|
|
# # then deleted. The reverse map would still say that
|
|
# # "A" is referenced by "Aacute" even though the
|
|
# # glyph has been deleted. So, the stored lib works like this:
|
|
# # {
|
|
# # 'Aacute' : [
|
|
# # # the last known mod time of the GLIF
|
|
# # 1098706856.75,
|
|
# # # component references in a glyph
|
|
# # ['A', 'acute']
|
|
# # ]
|
|
# # }
|
|
# import time
|
|
# import os
|
|
# import re
|
|
# componentSearch_RE = re.compile(
|
|
# "<component\s+" # <component
|
|
# "[^>]*?" # anything EXCEPT >
|
|
# "base\s*=\s*[\"\']" # base="
|
|
# "(.*?)" # foo
|
|
# "[\"\']" # "
|
|
# )
|
|
# rightNow = time.time()
|
|
# libKey = "org.robofab.componentMapping"
|
|
# previousMap = None
|
|
# if self.lib.has_key(libKey):
|
|
# previousMap = self.lib[libKey]
|
|
# basicMap = {}
|
|
# reverseMap = {}
|
|
# for glyphName in self.keys():
|
|
# componentsToMap = None
|
|
# modTime = None
|
|
# # get the previous bits of data
|
|
# previousModTime = None
|
|
# previousList = None
|
|
# if previousMap is not None and previousMap.has_key(glyphName):
|
|
# previousModTime, previousList = previousMap[glyphName]
|
|
# # the glyph has been loaded.
|
|
# # simply get the components from it.
|
|
# if self._object.has_key(glyphName):
|
|
# componentsToMap = [component.baseGlyph for component in self._object[glyphName].components]
|
|
# # the glyph has not been loaded.
|
|
# else:
|
|
# glyphPath = os.path.join(self._glyphSet.dirName, self._glyphSet.contents[glyphName])
|
|
# scanGlyph = True
|
|
# # test the modified time of the GLIF
|
|
# fileModTime = os.path.getmtime(glyphPath)
|
|
# if previousModTime is not None and fileModTime == previousModTime:
|
|
# # the GLIF almost* certianly has not changed.
|
|
# # *theoretically, a user could replace a GLIF
|
|
# # with another GLIF that has precisely the same
|
|
# # mod time.
|
|
# scanGlyph = False
|
|
# componentsToMap = previousList
|
|
# modTime = previousModTime
|
|
# else:
|
|
# # the GLIF is different
|
|
# modTime = fileModTime
|
|
# if scanGlyph:
|
|
# # use regex to extract component
|
|
# # base glyphs from the file
|
|
# f = open(glyphPath, 'rb')
|
|
# data = f.read()
|
|
# f.close()
|
|
# componentsToMap = componentSearch_RE.findall(data)
|
|
# if componentsToMap is not None:
|
|
# # store the non-reversed map
|
|
# basicMap[glyphName] = (modTime, componentsToMap)
|
|
# # reverse the map for the user
|
|
# if componentsToMap:
|
|
# for baseGlyphName in componentsToMap:
|
|
# if not reverseMap.has_key(baseGlyphName):
|
|
# reverseMap[baseGlyphName] = []
|
|
# reverseMap[baseGlyphName].append(glyphName)
|
|
# # if a glyph has been loaded, we do not store data about it in the lib.
|
|
# # this is done becuase there is not way to determine the proper mod time
|
|
# # for a loaded glyph.
|
|
# if modTime is None:
|
|
# del basicMap[glyphName]
|
|
# # store the map in the lib for re-use
|
|
# self.lib[libKey] = basicMap
|
|
# return reverseMap
|
|
#
|
|
#
|
|
# def save(self, destDir=None, doProgress=False, formatVersion=2):
|
|
# """Save the Font in UFO format."""
|
|
# # XXX note that when doing "save as" by specifying the destDir argument
|
|
# # _all_ glyphs get loaded into memory. This could be optimized by either
|
|
# # copying those .glif files that have not been edited or (not sure how
|
|
# # well that would work) by simply clearing out self._objects after the
|
|
# # save.
|
|
# from ufoLib import UFOWriter
|
|
# from robofab.tools.fontlabFeatureSplitter import splitFeaturesForFontLab
|
|
# # if no destination is given, or if
|
|
# # the given destination is the current
|
|
# # path, this is not a save as operation
|
|
# if destDir is None or destDir == self._path:
|
|
# saveAs = False
|
|
# destDir = self._path
|
|
# else:
|
|
# saveAs = True
|
|
# # start a progress bar
|
|
# nonGlyphCount = 5
|
|
# bar = None
|
|
# if doProgress:
|
|
# from robofab.interface.all.dialogs import ProgressBar
|
|
# bar = ProgressBar("Exporting UFO", nonGlyphCount + len(self._object.keys()))
|
|
# # write
|
|
# writer = UFOWriter(destDir, formatVersion=formatVersion)
|
|
# try:
|
|
# # make a shallow copy of the lib. stuff may be added to it.
|
|
# fontLib = dict(self.lib)
|
|
# # info
|
|
# if bar:
|
|
# bar.label("Saving info...")
|
|
# writer.writeInfo(self.info)
|
|
# if bar:
|
|
# bar.tick()
|
|
# # kerning
|
|
# if self.kerning.changed or saveAs:
|
|
# if bar:
|
|
# bar.label("Saving kerning...")
|
|
# writer.writeKerning(self.kerning.asDict())
|
|
# if bar:
|
|
# bar.tick()
|
|
# # groups
|
|
# if bar:
|
|
# bar.label("Saving groups...")
|
|
# writer.writeGroups(self.groups)
|
|
# if bar:
|
|
# bar.tick()
|
|
# # features
|
|
# if bar:
|
|
# bar.label("Saving features...")
|
|
# features = self.features.text
|
|
# if features is None:
|
|
# features = ""
|
|
# if formatVersion == 2:
|
|
# writer.writeFeatures(features)
|
|
# elif formatVersion == 1:
|
|
# classes, features = splitFeaturesForFontLab(features)
|
|
# if classes:
|
|
# fontLib["org.robofab.opentype.classes"] = classes.strip() + "\n"
|
|
# if features:
|
|
# featureDict = {}
|
|
# for featureName, featureText in features:
|
|
# featureDict[featureName] = featureText.strip() + "\n"
|
|
# fontLib["org.robofab.opentype.features"] = featureDict
|
|
# fontLib["org.robofab.opentype.featureorder"] = [featureName for featureName, featureText in features]
|
|
# if bar:
|
|
# bar.tick()
|
|
# # lib
|
|
# if formatVersion == 1:
|
|
# fontLib[postScriptHintDataLibKey] = self.psHints.asDict()
|
|
# if bar:
|
|
# bar.label("Saving lib...")
|
|
# writer.writeLib(fontLib)
|
|
# if bar:
|
|
# bar.tick()
|
|
# # glyphs
|
|
# glyphNameToFileNameFunc = self.getGlyphNameToFileNameFunc()
|
|
#
|
|
# glyphSet = writer.getGlyphSet(glyphNameToFileNameFunc)
|
|
# if len(self._scheduledForDeletion) != 0:
|
|
# if bar:
|
|
# bar.label("Removing deleted glyphs...")
|
|
# for glyphName in self._scheduledForDeletion:
|
|
# if glyphSet.has_key(glyphName):
|
|
# glyphSet.deleteGlyph(glyphName)
|
|
# if bar:
|
|
# bar.tick()
|
|
# if bar:
|
|
# bar.label("Saving glyphs...")
|
|
# count = nonGlyphCount
|
|
# if saveAs:
|
|
# glyphNames = self.keys()
|
|
# else:
|
|
# glyphNames = self._object.keys()
|
|
# for glyphName in glyphNames:
|
|
# glyph = self[glyphName]
|
|
# glyph.psHints._saveToLib(glyph.lib)
|
|
# glyph._saveToGlyphSet(glyphSet, glyphName=glyphName, force=saveAs)
|
|
# if bar and not count % 10:
|
|
# bar.tick(count)
|
|
# count = count + 1
|
|
# glyphSet.writeContents()
|
|
# self._glyphSet = glyphSet
|
|
# # only blindly stop if the user says to
|
|
# except KeyboardInterrupt:
|
|
# bar.close()
|
|
# bar = None
|
|
# # kill the progress bar
|
|
# if bar:
|
|
# bar.close()
|
|
# # reset internal stuff
|
|
# self._path = destDir
|
|
# self._scheduledForDeletion = []
|
|
# self.setChanged(False)
|
|
#
|
|
# def newGlyph(self, glyphName, clear=True):
|
|
# """Make a new glyph with glyphName
|
|
# if the glyph exists and clear=True clear the glyph"""
|
|
# if clear and glyphName in self:
|
|
# g = self[glyphName]
|
|
# g.clear()
|
|
# w = self.info.postscriptDefaultWidthX
|
|
# if w is None:
|
|
# w = 0
|
|
# g.width = w
|
|
# return g
|
|
# g = RGlyph()
|
|
# g.setParent(self)
|
|
# g.name = glyphName
|
|
# w = self.info.postscriptDefaultWidthX
|
|
# if w is None:
|
|
# w = 0
|
|
# g.width = w
|
|
# g._hasChanged()
|
|
# self._object[glyphName] = g
|
|
# # is the user adding a glyph that has the same
|
|
# # name as one that was deleted earlier?
|
|
# if glyphName in self._scheduledForDeletion:
|
|
# self._scheduledForDeletion.remove(glyphName)
|
|
# return self.getGlyph(glyphName)
|
|
#
|
|
# def insertGlyph(self, glyph, name=None):
|
|
# """returns a new glyph that has been inserted into the font"""
|
|
# if name is None:
|
|
# name = glyph.name
|
|
# glyph = glyph.copy()
|
|
# glyph.name = name
|
|
# glyph.setParent(self)
|
|
# glyph._hasChanged()
|
|
# self._object[name] = glyph
|
|
# # is the user adding a glyph that has the same
|
|
# # name as one that was deleted earlier?
|
|
# if name in self._scheduledForDeletion:
|
|
# self._scheduledForDeletion.remove(name)
|
|
# return self.getGlyph(name)
|
|
#
|
|
# def removeGlyph(self, glyphName):
|
|
# """remove a glyph from the font"""
|
|
# # XXX! Potential issue with removing glyphs.
|
|
# # if a glyph is removed from a font, but it is still referenced
|
|
# # by a component, it will give pens some trouble.
|
|
# # where does the resposibility for catching this fall?
|
|
# # the removeGlyph method? the addComponent method
|
|
# # of the various pens? somewhere else? hm... tricky.
|
|
# #
|
|
# #we won't actually remove it, we will just store it for removal
|
|
# # but only if the glyph does exist
|
|
# if self.has_key(glyphName) and glyphName not in self._scheduledForDeletion:
|
|
# self._scheduledForDeletion.append(glyphName)
|
|
# # now delete the object
|
|
# if self._object.has_key(glyphName):
|
|
# del self._object[glyphName]
|
|
# self._hasChanged()
|
|
#
|
|
# def getGlyph(self, glyphName):
|
|
# # XXX getGlyph may have to become private, to avoid duplication
|
|
# # with __getitem__
|
|
# n = None
|
|
# if self._object.has_key(glyphName):
|
|
# # have we served this glyph before? it should be in _object
|
|
# n = self._object[glyphName]
|
|
# else:
|
|
# # haven't served it before, is it in the glyphSet then?
|
|
# if self._glyphSet is not None and glyphName in self._glyphSet:
|
|
# # yes, read the .glif file from disk
|
|
# n = self._loadGlyph(glyphName)
|
|
# if n is None:
|
|
# raise KeyError, glyphName
|
|
# return n
|
|
#
|
|
#
|
|
#class RGlyph(BaseGlyph):
|
|
#
|
|
# _title = "RGlyph"
|
|
#
|
|
# def __init__(self):
|
|
# BaseGlyph.__init__(self)
|
|
# self.contours = []
|
|
# self.components = []
|
|
# self.anchors = []
|
|
# self._unicodes = []
|
|
# self.width = 0
|
|
# self.note = None
|
|
# self._name = "Unnamed Glyph"
|
|
# self.selected = False
|
|
# self._properties = None
|
|
# self._lib = RLib()
|
|
# self._lib.setParent(self)
|
|
# self.psHints = PostScriptGlyphHintValues()
|
|
# self.psHints.setParent(self)
|
|
#
|
|
# def __len__(self):
|
|
# return len(self.contours)
|
|
#
|
|
# def __getitem__(self, index):
|
|
# if index < len(self.contours):
|
|
# return self.contours[index]
|
|
# raise IndexError
|
|
#
|
|
# def _hasNotChanged(self):
|
|
# for contour in self.contours:
|
|
# contour.setChanged(False)
|
|
# for segment in contour.segments:
|
|
# segment.setChanged(False)
|
|
# for point in segment.points:
|
|
# point.setChanged(False)
|
|
# for component in self.components:
|
|
# component.setChanged(False)
|
|
# for anchor in self.anchors:
|
|
# anchor.setChanged(False)
|
|
# self.setChanged(False)
|
|
#
|
|
# #
|
|
# # attributes
|
|
# #
|
|
#
|
|
# def _get_lib(self):
|
|
# return self._lib
|
|
#
|
|
# def _set_lib(self, obj):
|
|
# self._lib.clear()
|
|
# self._lib.update(obj)
|
|
#
|
|
# lib = property(_get_lib, _set_lib)
|
|
#
|
|
# def _get_name(self):
|
|
# return self._name
|
|
#
|
|
# def _set_name(self, value):
|
|
# prevName = self._name
|
|
# newName = value
|
|
# if newName == prevName:
|
|
# return
|
|
# self._name = newName
|
|
# self.setChanged(True)
|
|
# font = self.getParent()
|
|
# if font is not None:
|
|
# # but, this glyph could be linked to a
|
|
# # FontLab font, because objectsFL.RGlyph.copy()
|
|
# # creates an objectsRF.RGlyph with the parent
|
|
# # set to an objectsFL.RFont object. so, check to see
|
|
# # if this is a legitimate RFont before trying to
|
|
# # do the objectsRF.RFont glyph name change
|
|
# if isinstance(font, RFont):
|
|
# font._object[newName] = self
|
|
# # is the user changing a glyph's name to the
|
|
# # name of a glyph that was deleted earlier?
|
|
# if newName in font._scheduledForDeletion:
|
|
# font._scheduledForDeletion.remove(newName)
|
|
# font.removeGlyph(prevName)
|
|
#
|
|
# name = property(_get_name, _set_name)
|
|
#
|
|
# def _get_unicodes(self):
|
|
# return self._unicodes
|
|
#
|
|
# def _set_unicodes(self, value):
|
|
# if not isinstance(value, list):
|
|
# raise RoboFabError, "unicodes must be a list"
|
|
# self._unicodes = value
|
|
# self._hasChanged()
|
|
#
|
|
# unicodes = property(_get_unicodes, _set_unicodes, doc="all unicode values for the glyph")
|
|
#
|
|
# def _get_unicode(self):
|
|
# if len(self._unicodes) == 0:
|
|
# return None
|
|
# return self._unicodes[0]
|
|
#
|
|
# def _set_unicode(self, value):
|
|
# uni = self._unicodes
|
|
# if value is not None:
|
|
# if value not in uni:
|
|
# self.unicodes.insert(0, value)
|
|
# elif uni.index(value) != 0:
|
|
# uni.insert(0, uni.pop(uni.index(value)))
|
|
# self.unicodes = uni
|
|
#
|
|
# unicode = property(_get_unicode, _set_unicode, doc="first unicode value for the glyph")
|
|
#
|
|
# def getPointPen(self):
|
|
# from robofab.pens.rfUFOPen import RFUFOPointPen
|
|
# return RFUFOPointPen(self)
|
|
#
|
|
# def appendComponent(self, baseGlyph, offset=(0, 0), scale=(1, 1)):
|
|
# """append a component to the glyph"""
|
|
# new = RComponent(baseGlyph, offset, scale)
|
|
# new.setParent(self)
|
|
# self.components.append(new)
|
|
# self._hasChanged()
|
|
#
|
|
# def appendAnchor(self, name, position, mark=None):
|
|
# """append an anchor to the glyph"""
|
|
# new = RAnchor(name, position, mark)
|
|
# new.setParent(self)
|
|
# self.anchors.append(new)
|
|
# self._hasChanged()
|
|
#
|
|
# def removeContour(self, index):
|
|
# """remove a specific contour from the glyph"""
|
|
# del self.contours[index]
|
|
# self._hasChanged()
|
|
#
|
|
# def removeAnchor(self, anchor):
|
|
# """remove a specific anchor from the glyph"""
|
|
# del self.anchors[anchor.index]
|
|
# self._hasChanged()
|
|
#
|
|
# def removeComponent(self, component):
|
|
# """remove a specific component from the glyph"""
|
|
# del self.components[component.index]
|
|
# self._hasChanged()
|
|
#
|
|
# def center(self, padding=None):
|
|
# """Equalise sidebearings, set to padding if wanted."""
|
|
# left = self.leftMargin
|
|
# right = self.rightMargin
|
|
# if padding:
|
|
# e_left = e_right = padding
|
|
# else:
|
|
# e_left = (left + right)/2
|
|
# e_right = (left + right) - e_left
|
|
# self.leftMargin = e_left
|
|
# self.rightMargin = e_right
|
|
#
|
|
# def decompose(self):
|
|
# """Decompose all components"""
|
|
# for i in range(len(self.components)):
|
|
# self.components[-1].decompose()
|
|
# self._hasChanged()
|
|
#
|
|
# def clear(self, contours=True, components=True, anchors=True, guides=True):
|
|
# """Clear all items marked as True from the glyph"""
|
|
# if contours:
|
|
# self.clearContours()
|
|
# if components:
|
|
# self.clearComponents()
|
|
# if anchors:
|
|
# self.clearAnchors()
|
|
# if guides:
|
|
# self.clearHGuides()
|
|
# self.clearVGuides()
|
|
#
|
|
# def clearContours(self):
|
|
# """clear all contours"""
|
|
# self.contours = []
|
|
# self._hasChanged()
|
|
#
|
|
# def clearComponents(self):
|
|
# """clear all components"""
|
|
# self.components = []
|
|
# self._hasChanged()
|
|
#
|
|
# def clearAnchors(self):
|
|
# """clear all anchors"""
|
|
# self.anchors = []
|
|
# self._hasChanged()
|
|
#
|
|
# def clearHGuides(self):
|
|
# """clear all horizontal guides"""
|
|
# self.hGuides = []
|
|
# self._hasChanged()
|
|
#
|
|
# def clearVGuides(self):
|
|
# """clear all vertical guides"""
|
|
# self.vGuides = []
|
|
# self._hasChanged()
|
|
#
|
|
# def getAnchors(self):
|
|
# return self.anchors
|
|
#
|
|
# def getComponents(self):
|
|
# return self.components
|
|
#
|
|
# #
|
|
# # stuff related to Glyph Properties
|
|
# #
|
|
#
|
|
#
|
|
#
|
|
#class RContour(BaseContour):
|
|
#
|
|
# _title = "RoboFabContour"
|
|
#
|
|
# def __init__(self, object=None):
|
|
# #BaseContour.__init__(self)
|
|
# self.segments = []
|
|
# self.selected = False
|
|
#
|
|
# def __len__(self):
|
|
# return len(self.segments)
|
|
#
|
|
# def __getitem__(self, index):
|
|
# if index < len(self.segments):
|
|
# return self.segments[index]
|
|
# raise IndexError
|
|
#
|
|
# def _get_index(self):
|
|
# return self.getParent().contours.index(self)
|
|
#
|
|
# def _set_index(self, index):
|
|
# ogIndex = self.index
|
|
# if index != ogIndex:
|
|
# contourList = self.getParent().contours
|
|
# contourList.insert(index, contourList.pop(ogIndex))
|
|
#
|
|
#
|
|
# index = property(_get_index, _set_index, doc="index of the contour")
|
|
#
|
|
# def _get_points(self):
|
|
# points = []
|
|
# for segment in self.segments:
|
|
# for point in segment.points:
|
|
# points.append(point)
|
|
# return points
|
|
#
|
|
# points = property(_get_points, doc="view the contour as a list of points")
|
|
#
|
|
# def _get_bPoints(self):
|
|
# bPoints = []
|
|
# for segment in self.segments:
|
|
# segType = segment.type
|
|
# if segType == MOVE:
|
|
# bType = CORNER
|
|
# elif segType == LINE:
|
|
# bType = CORNER
|
|
# elif segType == CURVE:
|
|
# if segment.smooth:
|
|
# bType = CURVE
|
|
# else:
|
|
# bType = CORNER
|
|
# else:
|
|
# raise RoboFabError, "encountered unknown segment type"
|
|
# b = RBPoint()
|
|
# b.setParent(segment)
|
|
# bPoints.append(b)
|
|
# return bPoints
|
|
#
|
|
# bPoints = property(_get_bPoints, doc="view the contour as a list of bPoints")
|
|
#
|
|
# def appendSegment(self, segmentType, points, smooth=False):
|
|
# """append a segment to the contour"""
|
|
# segment = self.insertSegment(index=len(self.segments), segmentType=segmentType, points=points, smooth=smooth)
|
|
# return segment
|
|
#
|
|
# def insertSegment(self, index, segmentType, points, smooth=False):
|
|
# """insert a segment into the contour"""
|
|
# segment = RSegment(segmentType, points, smooth)
|
|
# segment.setParent(self)
|
|
# self.segments.insert(index, segment)
|
|
# self._hasChanged()
|
|
# return segment
|
|
#
|
|
# def removeSegment(self, index):
|
|
# """remove a segment from the contour"""
|
|
# del self.segments[index]
|
|
# self._hasChanged()
|
|
#
|
|
# def reverseContour(self):
|
|
# """reverse the contour"""
|
|
# from robofab.pens.reverseContourPointPen import ReverseContourPointPen
|
|
# index = self.index
|
|
# glyph = self.getParent()
|
|
# pen = glyph.getPointPen()
|
|
# reversePen = ReverseContourPointPen(pen)
|
|
# self.drawPoints(reversePen)
|
|
# # we've drawn the reversed contour onto our parent glyph,
|
|
# # so it sits at the end of the contours list:
|
|
# newContour = glyph.contours.pop(-1)
|
|
# for segment in newContour.segments:
|
|
# segment.setParent(self)
|
|
# self.segments = newContour.segments
|
|
# self._hasChanged()
|
|
#
|
|
# def setStartSegment(self, segmentIndex):
|
|
# """set the first segment on the contour"""
|
|
# # this obviously does not support open contours
|
|
# if len(self.segments) < 2:
|
|
# return
|
|
# if segmentIndex == 0:
|
|
# return
|
|
# if segmentIndex > len(self.segments)-1:
|
|
# raise IndexError, 'segment index not in segments list'
|
|
# oldStart = self.segments[0]
|
|
# oldLast = self.segments[-1]
|
|
# #check to see if the contour ended with a curve on top of the move
|
|
# #if we find one delete it,
|
|
# if oldLast.type == CURVE or oldLast.type == QCURVE:
|
|
# startOn = oldStart.onCurve
|
|
# lastOn = oldLast.onCurve
|
|
# if startOn.x == lastOn.x and startOn.y == lastOn.y:
|
|
# del self.segments[0]
|
|
# # since we deleted the first contour, the segmentIndex needs to shift
|
|
# segmentIndex = segmentIndex - 1
|
|
# # if we DO have a move left over, we need to convert it to a line
|
|
# if self.segments[0].type == MOVE:
|
|
# self.segments[0].type = LINE
|
|
# # slice up the segments and reassign them to the contour
|
|
# segments = self.segments[segmentIndex:]
|
|
# self.segments = segments + self.segments[:segmentIndex]
|
|
# # now, draw the contour onto the parent glyph
|
|
# glyph = self.getParent()
|
|
# pen = glyph.getPointPen()
|
|
# self.drawPoints(pen)
|
|
# # we've drawn the new contour onto our parent glyph,
|
|
# # so it sits at the end of the contours list:
|
|
# newContour = glyph.contours.pop(-1)
|
|
# for segment in newContour.segments:
|
|
# segment.setParent(self)
|
|
# self.segments = newContour.segments
|
|
# self._hasChanged()
|
|
#
|
|
#
|
|
#class RSegment(BaseSegment):
|
|
#
|
|
# _title = "RoboFabSegment"
|
|
#
|
|
# def __init__(self, segmentType=None, points=[], smooth=False):
|
|
# BaseSegment.__init__(self)
|
|
# self.selected = False
|
|
# self.points = []
|
|
# self.smooth = smooth
|
|
# if points:
|
|
# #the points in the segment should be RPoints, so create those objects
|
|
# for point in points[:-1]:
|
|
# x, y = point
|
|
# p = RPoint(x, y, pointType=OFFCURVE)
|
|
# p.setParent(self)
|
|
# self.points.append(p)
|
|
# aX, aY = points[-1]
|
|
# p = RPoint(aX, aY, segmentType)
|
|
# p.setParent(self)
|
|
# self.points.append(p)
|
|
#
|
|
# def _get_type(self):
|
|
# return self.points[-1].type
|
|
#
|
|
# def _set_type(self, pointType):
|
|
# onCurve = self.points[-1]
|
|
# ocType = onCurve.type
|
|
# if ocType == pointType:
|
|
# return
|
|
# #we are converting a cubic line into a cubic curve
|
|
# if pointType == CURVE and ocType == LINE:
|
|
# onCurve.type = pointType
|
|
# parent = self.getParent()
|
|
# prev = parent._prevSegment(self.index)
|
|
# p1 = RPoint(prev.onCurve.x, prev.onCurve.y, pointType=OFFCURVE)
|
|
# p1.setParent(self)
|
|
# p2 = RPoint(onCurve.x, onCurve.y, pointType=OFFCURVE)
|
|
# p2.setParent(self)
|
|
# self.points.insert(0, p2)
|
|
# self.points.insert(0, p1)
|
|
# #we are converting a cubic move to a curve
|
|
# elif pointType == CURVE and ocType == MOVE:
|
|
# onCurve.type = pointType
|
|
# parent = self.getParent()
|
|
# prev = parent._prevSegment(self.index)
|
|
# p1 = RPoint(prev.onCurve.x, prev.onCurve.y, pointType=OFFCURVE)
|
|
# p1.setParent(self)
|
|
# p2 = RPoint(onCurve.x, onCurve.y, pointType=OFFCURVE)
|
|
# p2.setParent(self)
|
|
# self.points.insert(0, p2)
|
|
# self.points.insert(0, p1)
|
|
# #we are converting a quad curve to a cubic curve
|
|
# elif pointType == CURVE and ocType == QCURVE:
|
|
# onCurve.type == CURVE
|
|
# #we are converting a cubic curve into a cubic line
|
|
# elif pointType == LINE and ocType == CURVE:
|
|
# p = self.points.pop(-1)
|
|
# self.points = [p]
|
|
# onCurve.type = pointType
|
|
# self.smooth = False
|
|
# #we are converting a cubic move to a line
|
|
# elif pointType == LINE and ocType == MOVE:
|
|
# onCurve.type = pointType
|
|
# #we are converting a quad curve to a line:
|
|
# elif pointType == LINE and ocType == QCURVE:
|
|
# p = self.points.pop(-1)
|
|
# self.points = [p]
|
|
# onCurve.type = pointType
|
|
# self.smooth = False
|
|
# # we are converting to a quad curve where just about anything is legal
|
|
# elif pointType == QCURVE:
|
|
# onCurve.type = pointType
|
|
# else:
|
|
# raise RoboFabError, 'unknown segment type'
|
|
#
|
|
# type = property(_get_type, _set_type, doc="type of the segment")
|
|
#
|
|
# def _get_index(self):
|
|
# return self.getParent().segments.index(self)
|
|
#
|
|
# index = property(_get_index, doc="index of the segment")
|
|
#
|
|
# def insertPoint(self, index, pointType, point):
|
|
# x, y = point
|
|
# p = RPoint(x, y, pointType=pointType)
|
|
# p.setParent(self)
|
|
# self.points.insert(index, p)
|
|
# self._hasChanged()
|
|
#
|
|
# def removePoint(self, index):
|
|
# del self.points[index]
|
|
# self._hasChanged()
|
|
#
|
|
#
|
|
#class RBPoint(BaseBPoint):
|
|
#
|
|
# _title = "RoboFabBPoint"
|
|
#
|
|
# def _setAnchorChanged(self, value):
|
|
# self._anchorPoint.setChanged(value)
|
|
#
|
|
# def _setNextChanged(self, value):
|
|
# self._nextOnCurve.setChanged(value)
|
|
#
|
|
# def _get__parentSegment(self):
|
|
# return self.getParent()
|
|
#
|
|
# _parentSegment = property(_get__parentSegment, doc="")
|
|
#
|
|
# def _get__nextOnCurve(self):
|
|
# pSeg = self._parentSegment
|
|
# contour = pSeg.getParent()
|
|
# #could this potentially return an incorrect index? say, if two segments are exactly the same?
|
|
# return contour.segments[(contour.segments.index(pSeg) + 1) % len(contour.segments)]
|
|
#
|
|
# _nextOnCurve = property(_get__nextOnCurve, doc="")
|
|
#
|
|
# def _get_index(self):
|
|
# return self._parentSegment.index
|
|
#
|
|
# index = property(_get_index, doc="index of the bPoint on the contour")
|
|
#
|
|
#
|
|
#class RPoint(BasePoint):
|
|
#
|
|
# _title = "RoboFabPoint"
|
|
#
|
|
# def __init__(self, x=0, y=0, pointType=None, name=None):
|
|
# self.selected = False
|
|
# self._type = pointType
|
|
# self._x = x
|
|
# self._y = y
|
|
# self._name = None
|
|
#
|
|
# def _get_x(self):
|
|
# return self._x
|
|
#
|
|
# def _set_x(self, value):
|
|
# self._x = value
|
|
# self._hasChanged()
|
|
#
|
|
# x = property(_get_x, _set_x, doc="")
|
|
#
|
|
# def _get_y(self):
|
|
# return self._y
|
|
#
|
|
# def _set_y(self, value):
|
|
# self._y = value
|
|
# self._hasChanged()
|
|
#
|
|
# y = property(_get_y, _set_y, doc="")
|
|
#
|
|
# def _get_type(self):
|
|
# return self._type
|
|
#
|
|
# def _set_type(self, value):
|
|
# self._type = value
|
|
# self._hasChanged()
|
|
#
|
|
# type = property(_get_type, _set_type, doc="")
|
|
#
|
|
# def _get_name(self):
|
|
# return self._name
|
|
#
|
|
# def _set_name(self, value):
|
|
# self._name = value
|
|
# self._hasChanged()
|
|
#
|
|
# name = property(_get_name, _set_name, doc="")
|
|
#
|
|
#
|
|
#class RAnchor(BaseAnchor):
|
|
#
|
|
# _title = "RoboFabAnchor"
|
|
#
|
|
# def __init__(self, name=None, position=None, mark=None):
|
|
# BaseAnchor.__init__(self)
|
|
# self.selected = False
|
|
# self.name = name
|
|
# if position is None:
|
|
# self.x = self.y = None
|
|
# else:
|
|
# self.x, self.y = position
|
|
# self.mark = mark
|
|
#
|
|
# def _get_index(self):
|
|
# if self.getParent() is None: return None
|
|
# return self.getParent().anchors.index(self)
|
|
#
|
|
# index = property(_get_index, doc="index of the anchor")
|
|
#
|
|
# def _get_position(self):
|
|
# return (self.x, self.y)
|
|
#
|
|
# def _set_position(self, value):
|
|
# self.x = value[0]
|
|
# self.y = value[1]
|
|
# self._hasChanged()
|
|
#
|
|
# position = property(_get_position, _set_position, doc="position of the anchor")
|
|
#
|
|
# def move(self, (x, y)):
|
|
# """Move the anchor"""
|
|
# self.x = self.x + x
|
|
# self.y = self.y + y
|
|
# self._hasChanged()
|
|
#
|
|
#
|
|
#class RComponent(BaseComponent):
|
|
#
|
|
# _title = "RoboFabComponent"
|
|
#
|
|
# def __init__(self, baseGlyphName=None, offset=(0,0), scale=(1,1)):
|
|
# BaseComponent.__init__(self)
|
|
# self.selected = False
|
|
# self._baseGlyph = baseGlyphName
|
|
# self._offset = offset
|
|
# self._scale = scale
|
|
#
|
|
# def _get_index(self):
|
|
# if self.getParent() is None: return None
|
|
# return self.getParent().components.index(self)
|
|
#
|
|
# index = property(_get_index, doc="index of the component")
|
|
#
|
|
# def _get_baseGlyph(self):
|
|
# return self._baseGlyph
|
|
#
|
|
# def _set_baseGlyph(self, glyphName):
|
|
# # XXXX needs to be implemented in objectsFL for symmetricity's sake. Eventually.
|
|
# self._baseGlyph = glyphName
|
|
# self._hasChanged()
|
|
#
|
|
# baseGlyph = property(_get_baseGlyph, _set_baseGlyph, doc="")
|
|
#
|
|
# def _get_offset(self):
|
|
# return self._offset
|
|
#
|
|
# def _set_offset(self, value):
|
|
# self._offset = value
|
|
# self._hasChanged()
|
|
#
|
|
# offset = property(_get_offset, _set_offset, doc="the offset of the component")
|
|
#
|
|
# def _get_scale(self):
|
|
# return self._scale
|
|
#
|
|
# def _set_scale(self, (x, y)):
|
|
# self._scale = (x, y)
|
|
# self._hasChanged()
|
|
#
|
|
# scale = property(_get_scale, _set_scale, doc="the scale of the component")
|
|
#
|
|
# def move(self, (x, y)):
|
|
# """Move the component"""
|
|
# self.offset = (self.offset[0] + x, self.offset[1] + y)
|
|
#
|
|
# def decompose(self):
|
|
# """Decompose the component"""
|
|
# baseGlyphName = self.baseGlyph
|
|
# parentGlyph = self.getParent()
|
|
# # if there is no parent glyph, there is nothing to decompose to
|
|
# if baseGlyphName is not None and parentGlyph is not None:
|
|
# parentFont = parentGlyph.getParent()
|
|
# # we must have a parent glyph with the baseGlyph
|
|
# # if not, we will simply remove the component from
|
|
# # the parent glyph thereby decomposing the component
|
|
# # to nothing.
|
|
# if parentFont is not None and parentFont.has_key(baseGlyphName):
|
|
# from robofab.pens.adapterPens import TransformPointPen
|
|
# oX, oY = self.offset
|
|
# sX, sY = self.scale
|
|
# baseGlyph = parentFont[baseGlyphName]
|
|
# for contour in baseGlyph.contours:
|
|
# pointPen = parentGlyph.getPointPen()
|
|
# transPen = TransformPointPen(pointPen, (sX, 0, 0, sY, oX, oY))
|
|
# contour.drawPoints(transPen)
|
|
# parentGlyph.components.remove(self)
|
|
#
|
|
|
|
# ----
|
|
# Info
|
|
# ----
|
|
|
|
class RInfo(BaseInfo):
|
|
|
|
_title = "RoboFabFontInfo"
|
|
|
|
def __init__(self, info):
|
|
super(RInfo, self).__init__()
|
|
self._object = info
|
|
|
|
def _environmentSetAttr(self, attr, value):
|
|
setattr(self._object, attr, value)
|
|
|
|
def _environmentGetAttr(self, attr):
|
|
return getattr(self._object, attr)
|
|
|
|
|
|
# ------
|
|
# Groups
|
|
# ------
|
|
|
|
class _RDict(RBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super(_RDict, self).__init__()
|
|
self._object = obj
|
|
|
|
def __len__(self):
|
|
return len(self._object)
|
|
|
|
def __contains__(self, key):
|
|
return key in self._object
|
|
|
|
has_key = __contains__
|
|
|
|
def __setitem__(self, key, value):
|
|
self._object[key] = value
|
|
|
|
def __getitem__(self, key):
|
|
return self._object[key]
|
|
|
|
def __delitem__(self, key):
|
|
del self._object[key]
|
|
|
|
def __iter__(self):
|
|
for key in self.keys():
|
|
yield key
|
|
|
|
def clear(self):
|
|
self._object.clear()
|
|
|
|
def keys(self):
|
|
return self._object.keys()
|
|
|
|
def values(self):
|
|
return self._object.values()
|
|
|
|
def items(self):
|
|
return self._object.items()
|
|
|
|
def pop(self, key, default=None):
|
|
return self._object.pop(key, default)
|
|
|
|
def popitem(self):
|
|
return self._object.popitem()
|
|
|
|
def update(self, other):
|
|
self._object.update(other)
|
|
|
|
|
|
class RGroups(_RDict):
|
|
|
|
# We can't use BaseGroups here since it subclasses dict instead of BaseObject.
|
|
# We can't point to defcon as a result of that.
|
|
|
|
_title = "RoboFabGroups"
|
|
|
|
|
|
# -------
|
|
# Kerning
|
|
# -------
|
|
|
|
class RKerning(BaseKerning):
|
|
|
|
_title = "RoboFabKerning"
|
|
|
|
def clear(self):
|
|
self._kerning.clear()
|
|
|
|
|
|
# --------
|
|
# Features
|
|
# --------
|
|
|
|
class RFeatures(BaseFeatures):
|
|
|
|
_title = "RoboFabFeatures"
|
|
|
|
def __init__(self, featuresObject):
|
|
super(RFeatures, self).__init__()
|
|
self._object = featuresObject
|
|
|
|
def _get_text(self):
|
|
return self._object.text
|
|
|
|
def _set_text(self, value):
|
|
assert isinstance(value, (basestring, None))
|
|
self._object.text = value
|
|
|
|
text = property(_get_text, _set_text, doc="raw feature text.")
|
|
|
|
# these _text methods are necessary because BaseFeatures
|
|
# stores text at _text. we need to reroute that to the
|
|
# defcon object for proper storage.
|
|
|
|
def _get__text(self):
|
|
return self.text
|
|
|
|
def _set__text(self, value):
|
|
# __init__ hack:
|
|
# during __init__ BaseFetaures tries self._text = "".
|
|
# In these objects, the text must not be maintained independently
|
|
# of the defcon object, so hack around this when self._object
|
|
# is a dict (as is the case when starting up)
|
|
if self._object == {}:
|
|
return
|
|
self.text = value
|
|
|
|
_text = property(_get__text, _set__text)
|
|
|
|
|
|
# ---
|
|
# Lib
|
|
# ---
|
|
|
|
class RLib(_RDict):
|
|
|
|
# We can't use BaseLib here since it subclasses dict instead of BaseObject.
|
|
# We can't point to defcon as a result of that.
|
|
|
|
_title = "RoboFabLib"
|
|
|
|
|
|
#class PostScriptFontHintValues(BasePostScriptFontHintValues):
|
|
# """ Font level PostScript hints object for objectsRF usage.
|
|
#
|
|
# If there are values in the lib, use those.
|
|
# If there are no values in the lib, use defaults.
|
|
#
|
|
# The psHints attribute for objectsRF.RFont is basically just the
|
|
# data read from the Lib. When the object saves to UFO, the
|
|
# hints are written back to the lib, which is then saved.
|
|
#
|
|
# """
|
|
#
|
|
# def __init__(self, aFont=None, data=None):
|
|
# self.setParent(aFont)
|
|
# BasePostScriptFontHintValues.__init__(self)
|
|
# if aFont is not None:
|
|
# # in version 1, this data was stored in the lib
|
|
# # if it is still there, guess that it is correct
|
|
# # move it to font info and remove it from the lib.
|
|
# libData = aFont.lib.get(postScriptHintDataLibKey)
|
|
# if libData is not None:
|
|
# self.fromDict(libData)
|
|
# del libData[postScriptHintDataLibKey]
|
|
# if data is not None:
|
|
# self.fromDict(data)
|
|
#
|
|
#def getPostScriptHintDataFromLib(aFont, fontLib):
|
|
# hintData = fontLib.get(postScriptHintDataLibKey)
|
|
# psh = PostScriptFontHintValues(aFont)
|
|
# psh.fromDict(hintData)
|
|
# return psh
|
|
#
|
|
#class PostScriptGlyphHintValues(BasePostScriptGlyphHintValues):
|
|
# """ Glyph level PostScript hints object for objectsRF usage.
|
|
# If there are values in the lib, use those.
|
|
# If there are no values in the lib, be empty.
|
|
#
|
|
# """
|
|
# def __init__(self, aGlyph=None, data=None):
|
|
# # read the data from the glyph.lib, it won't be anywhere else
|
|
# BasePostScriptGlyphHintValues.__init__(self)
|
|
# if aGlyph is not None:
|
|
# self.setParent(aGlyph)
|
|
# self._loadFromLib(aGlyph.lib)
|
|
# if data is not None:
|
|
# self.fromDict(data)
|
|
|
|
if __name__ == "__main__":
|
|
from defcon.test.testTools import getTestFontPath
|
|
font = RFont(getTestFontPath())
|
|
print font
|
|
print font.info
|
|
print font.groups
|
|
print font.kerning
|
|
print font.features
|
|
print font.lib
|
|
|