| 1 |
"""UFO for GlifLib""" |
|---|
| 2 |
|
|---|
| 3 |
from robofab import RoboFabError, RoboFabWarning |
|---|
| 4 |
from robofab.objects.objectsBase import BaseFont, BaseKerning, BaseGroups, BaseInfo, BaseLib,\ |
|---|
| 5 |
BaseGlyph, BaseContour, BaseSegment, BasePoint, BaseBPoint, BaseAnchor, BaseGuide, BaseComponent, \ |
|---|
| 6 |
relativeBCPIn, relativeBCPOut, absoluteBCPIn, absoluteBCPOut, _box,\ |
|---|
| 7 |
_interpolate, _interpolatePt, roundPt, addPt,\ |
|---|
| 8 |
MOVE, LINE, CORNER, CURVE, QCURVE, OFFCURVE,\ |
|---|
| 9 |
BasePostScriptFontHintValues, postScriptHintDataLibKey |
|---|
| 10 |
|
|---|
| 11 |
import os |
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
__all__ = [ "CurrentFont", |
|---|
| 15 |
"CurrentGlyph", 'OpenFont', |
|---|
| 16 |
'RFont', 'RGlyph', 'RContour', |
|---|
| 17 |
'RPoint', 'RBPoint', 'RAnchor', |
|---|
| 18 |
'RComponent' |
|---|
| 19 |
] |
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
def CurrentFont(): |
|---|
| 24 |
return None |
|---|
| 25 |
|
|---|
| 26 |
def CurrentGlyph(): |
|---|
| 27 |
return None |
|---|
| 28 |
|
|---|
| 29 |
def OpenFont(path=None, note=None): |
|---|
| 30 |
"""Open a font from a path. If path is not given, present the user with a dialog.""" |
|---|
| 31 |
if not note: |
|---|
| 32 |
note = 'select a .ufo directory' |
|---|
| 33 |
if not path: |
|---|
| 34 |
from robofab.interface.all.dialogs import GetFolder |
|---|
| 35 |
path = GetFolder(note) |
|---|
| 36 |
if path: |
|---|
| 37 |
try: |
|---|
| 38 |
return RFont(path) |
|---|
| 39 |
except OSError: |
|---|
| 40 |
from robofab.interface.all.dialogs import Message |
|---|
| 41 |
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)) |
|---|
| 42 |
else: |
|---|
| 43 |
return None |
|---|
| 44 |
|
|---|
| 45 |
def NewFont(familyName=None, styleName=None): |
|---|
| 46 |
"""Make a new font""" |
|---|
| 47 |
new = RFont() |
|---|
| 48 |
new.info.familyName = familyName |
|---|
| 49 |
new.info.styleName = styleName |
|---|
| 50 |
return new |
|---|
| 51 |
|
|---|
| 52 |
def AllFonts(): |
|---|
| 53 |
"""AllFonts can't work in plain python usage. It's really up to some sort of application |
|---|
| 54 |
to keep track of which fonts are open.""" |
|---|
| 55 |
raise NotImplementedError |
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
class PostScriptFontHintValues(BasePostScriptFontHintValues): |
|---|
| 59 |
""" PostScript hints object for objectsRF usage. |
|---|
| 60 |
If there are values in the lib, use those. |
|---|
| 61 |
If there are no values in the lib, use defaults. |
|---|
| 62 |
""" |
|---|
| 63 |
|
|---|
| 64 |
def __init__(self, aFont=None): |
|---|
| 65 |
|
|---|
| 66 |
BasePostScriptFontHintValues.__init__(self) |
|---|
| 67 |
data = None |
|---|
| 68 |
if aFont is not None: |
|---|
| 69 |
self.setParent(aFont) |
|---|
| 70 |
data = aFont.lib.get(postScriptHintDataLibKey) |
|---|
| 71 |
if data is not None: |
|---|
| 72 |
self.fromDict(data) |
|---|
| 73 |
|
|---|
| 74 |
def getPostScriptHintDataFromLib(aFont, fontLib): |
|---|
| 75 |
hintData = fontLib.get(postScriptHintDataLibKey) |
|---|
| 76 |
psh = PostScriptFontHintValues(aFont) |
|---|
| 77 |
psh.fromDict(hintData) |
|---|
| 78 |
return psh |
|---|
| 79 |
|
|---|
| 80 |
class RFont(BaseFont): |
|---|
| 81 |
"""UFO font object which reads and writes glif, and keeps the data in memory in between. |
|---|
| 82 |
Bahviour: |
|---|
| 83 |
- comparable to Font |
|---|
| 84 |
- comparable to GlyphSet so that it can be passed to Glif widgets |
|---|
| 85 |
""" |
|---|
| 86 |
|
|---|
| 87 |
_title = "RoboFabFont" |
|---|
| 88 |
|
|---|
| 89 |
def __init__(self, path=None): |
|---|
| 90 |
BaseFont.__init__(self) |
|---|
| 91 |
if path is not None: |
|---|
| 92 |
self._path = os.path.normpath(os.path.abspath(path)) |
|---|
| 93 |
else: |
|---|
| 94 |
self._path = None |
|---|
| 95 |
self._object = {} |
|---|
| 96 |
|
|---|
| 97 |
self._glyphSet = None |
|---|
| 98 |
self._scheduledForDeletion = [] |
|---|
| 99 |
|
|---|
| 100 |
self.kerning = RKerning() |
|---|
| 101 |
self.kerning.setParent(self) |
|---|
| 102 |
self.info = RInfo() |
|---|
| 103 |
self.info.setParent(self) |
|---|
| 104 |
self.groups = RGroups() |
|---|
| 105 |
self.groups.setParent(self) |
|---|
| 106 |
self.lib = RLib() |
|---|
| 107 |
self.lib.setParent(self) |
|---|
| 108 |
|
|---|
| 109 |
if path: |
|---|
| 110 |
self._loadData(path) |
|---|
| 111 |
|
|---|
| 112 |
def __setitem__(self, glyphName, glyph): |
|---|
| 113 |
"""Set a glyph at key.""" |
|---|
| 114 |
self._object[glyphName] = glyph |
|---|
| 115 |
|
|---|
| 116 |
def __cmp__(self, other): |
|---|
| 117 |
"""Compare this font with another, compare if they refer to the same file.""" |
|---|
| 118 |
if not hasattr(other, '_path'): |
|---|
| 119 |
return -1 |
|---|
| 120 |
if self._object._path == other._object._path and self._object._path is not None: |
|---|
| 121 |
return 0 |
|---|
| 122 |
else: |
|---|
| 123 |
return -1 |
|---|
| 124 |
|
|---|
| 125 |
def __len__(self): |
|---|
| 126 |
if self._glyphSet is None: |
|---|
| 127 |
return 0 |
|---|
| 128 |
return len(self._glyphSet) |
|---|
| 129 |
|
|---|
| 130 |
def _loadData(self, path): |
|---|
| 131 |
|
|---|
| 132 |
from robofab.ufoLib import UFOReader |
|---|
| 133 |
u = UFOReader(path) |
|---|
| 134 |
u.readInfo(self.info) |
|---|
| 135 |
self.kerning.update(u.readKerning()) |
|---|
| 136 |
self.kerning.setChanged(False) |
|---|
| 137 |
self.groups.update(u.readGroups()) |
|---|
| 138 |
self.lib.update(u.readLib()) |
|---|
| 139 |
|
|---|
| 140 |
self.psHints = PostScriptFontHintValues(self) |
|---|
| 141 |
self._glyphSet = u.getGlyphSet() |
|---|
| 142 |
self._hasNotChanged(doGlyphs=False) |
|---|
| 143 |
|
|---|
| 144 |
def _loadGlyph(self, glyphName): |
|---|
| 145 |
"""Load a single glyph from the glyphSet, on request.""" |
|---|
| 146 |
from robofab.pens.rfUFOPen import RFUFOPointPen |
|---|
| 147 |
g = RGlyph() |
|---|
| 148 |
g.name = glyphName |
|---|
| 149 |
pen = RFUFOPointPen(g) |
|---|
| 150 |
self._glyphSet.readGlyph(glyphName=glyphName, glyphObject=g, pointPen=pen) |
|---|
| 151 |
g.setParent(self) |
|---|
| 152 |
self._object[glyphName] = g |
|---|
| 153 |
self._object[glyphName]._hasNotChanged() |
|---|
| 154 |
return g |
|---|
| 155 |
|
|---|
| 156 |
|
|---|
| 157 |
|
|---|
| 158 |
|
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 |
def _hasNotChanged(self, doGlyphs=True): |
|---|
| 162 |
|
|---|
| 163 |
if doGlyphs: |
|---|
| 164 |
for glyph in self: |
|---|
| 165 |
glyph._hasNotChanged() |
|---|
| 166 |
self.setChanged(False) |
|---|
| 167 |
|
|---|
| 168 |
|
|---|
| 169 |
|
|---|
| 170 |
|
|---|
| 171 |
|
|---|
| 172 |
def _get_path(self): |
|---|
| 173 |
return self._path |
|---|
| 174 |
|
|---|
| 175 |
path = property(_get_path, doc="path of the font") |
|---|
| 176 |
|
|---|
| 177 |
|
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 |
|
|---|
| 181 |
def keys(self): |
|---|
| 182 |
|
|---|
| 183 |
|
|---|
| 184 |
keys = self._object.keys() |
|---|
| 185 |
if self._glyphSet is not None: |
|---|
| 186 |
keys.extend(self._glyphSet.keys()) |
|---|
| 187 |
d = dict() |
|---|
| 188 |
for glyphName in keys: |
|---|
| 189 |
d[glyphName] = None |
|---|
| 190 |
for glyphName in self._scheduledForDeletion: |
|---|
| 191 |
if glyphName in d: |
|---|
| 192 |
del d[glyphName] |
|---|
| 193 |
return d.keys() |
|---|
| 194 |
|
|---|
| 195 |
def has_key(self, glyphName): |
|---|
| 196 |
|
|---|
| 197 |
if self._glyphSet is not None: |
|---|
| 198 |
hasGlyph = glyphName in self._object or glyphName in self._glyphSet |
|---|
| 199 |
else: |
|---|
| 200 |
hasGlyph = glyphName in self._object |
|---|
| 201 |
return hasGlyph and not glyphName in self._scheduledForDeletion |
|---|
| 202 |
|
|---|
| 203 |
__contains__ = has_key |
|---|
| 204 |
|
|---|
| 205 |
def getWidth(self, glyphName): |
|---|
| 206 |
if self._object.has_key(glyphName): |
|---|
| 207 |
return self._object[glyphName].width |
|---|
| 208 |
raise IndexError |
|---|
| 209 |
|
|---|
| 210 |
def getReverseComponentMapping(self): |
|---|
| 211 |
""" |
|---|
| 212 |
Get a reversed map of component references in the font. |
|---|
| 213 |
{ |
|---|
| 214 |
'A' : ['Aacute', 'Aring'] |
|---|
| 215 |
'acute' : ['Aacute'] |
|---|
| 216 |
'ring' : ['Aring'] |
|---|
| 217 |
etc. |
|---|
| 218 |
} |
|---|
| 219 |
""" |
|---|
| 220 |
|
|---|
| 221 |
|
|---|
| 222 |
|
|---|
| 223 |
|
|---|
| 224 |
|
|---|
| 225 |
|
|---|
| 226 |
|
|---|
| 227 |
|
|---|
| 228 |
|
|---|
| 229 |
|
|---|
| 230 |
|
|---|
| 231 |
|
|---|
| 232 |
|
|---|
| 233 |
|
|---|
| 234 |
|
|---|
| 235 |
import time |
|---|
| 236 |
import os |
|---|
| 237 |
import re |
|---|
| 238 |
componentSearch_RE = re.compile( |
|---|
| 239 |
"<component\s+" |
|---|
| 240 |
"[^>]*?" |
|---|
| 241 |
"base\s*=\s*[\"\']" |
|---|
| 242 |
"(.*?)" |
|---|
| 243 |
"[\"\']" |
|---|
| 244 |
) |
|---|
| 245 |
rightNow = time.time() |
|---|
| 246 |
libKey = "org.robofab.componentMapping" |
|---|
| 247 |
previousMap = None |
|---|
| 248 |
if self.lib.has_key(libKey): |
|---|
| 249 |
previousMap = self.lib[libKey] |
|---|
| 250 |
basicMap = {} |
|---|
| 251 |
reverseMap = {} |
|---|
| 252 |
for glyphName in self.keys(): |
|---|
| 253 |
componentsToMap = None |
|---|
| 254 |
modTime = None |
|---|
| 255 |
|
|---|
| 256 |
previousModTime = None |
|---|
| 257 |
previousList = None |
|---|
| 258 |
if previousMap is not None and previousMap.has_key(glyphName): |
|---|
| 259 |
previousModTime, previousList = previousMap[glyphName] |
|---|
| 260 |
|
|---|
| 261 |
|
|---|
| 262 |
if self._object.has_key(glyphName): |
|---|
| 263 |
componentsToMap = [component.baseGlyph for component in self._object[glyphName].components] |
|---|
| 264 |
|
|---|
| 265 |
else: |
|---|
| 266 |
glyphPath = os.path.join(self._glyphSet.dirName, self._glyphSet.contents[glyphName]) |
|---|
| 267 |
scanGlyph = True |
|---|
| 268 |
|
|---|
| 269 |
fileModTime = os.path.getmtime(glyphPath) |
|---|
| 270 |
if previousModTime is not None and fileModTime == previousModTime: |
|---|
| 271 |
|
|---|
| 272 |
|
|---|
| 273 |
|
|---|
| 274 |
|
|---|
| 275 |
scanGlyph = False |
|---|
| 276 |
componentsToMap = previousList |
|---|
| 277 |
modTime = previousModTime |
|---|
| 278 |
else: |
|---|
| 279 |
|
|---|
| 280 |
modTime = fileModTime |
|---|
| 281 |
if scanGlyph: |
|---|
| 282 |
|
|---|
| 283 |
|
|---|
| 284 |
f = open(glyphPath, 'rb') |
|---|
| 285 |
data = f.read() |
|---|
| 286 |
f.close() |
|---|
| 287 |
componentsToMap = componentSearch_RE.findall(data) |
|---|
| 288 |
if componentsToMap is not None: |
|---|
| 289 |
|
|---|
| 290 |
basicMap[glyphName] = (modTime, componentsToMap) |
|---|
| 291 |
|
|---|
| 292 |
if componentsToMap: |
|---|
| 293 |
for baseGlyphName in componentsToMap: |
|---|
| 294 |
if not reverseMap.has_key(baseGlyphName): |
|---|
| 295 |
reverseMap[baseGlyphName] = [] |
|---|
| 296 |
reverseMap[baseGlyphName].append(glyphName) |
|---|
| 297 |
|
|---|
| 298 |
|
|---|
| 299 |
|
|---|
| 300 |
if modTime is None: |
|---|
| 301 |
del basicMap[glyphName] |
|---|
| 302 |
|
|---|
| 303 |
self.lib[libKey] = basicMap |
|---|
| 304 |
return reverseMap |
|---|
| 305 |
|
|---|
| 306 |
|
|---|
| 307 |
def save(self, destDir=None, doProgress=False, saveNow=False): |
|---|
| 308 |
"""Save the Font in UFO format.""" |
|---|
| 309 |
|
|---|
| 310 |
|
|---|
| 311 |
|
|---|
| 312 |
|
|---|
| 313 |
|
|---|
| 314 |
from robofab.ufoLib import UFOWriter |
|---|
| 315 |
|
|---|
| 316 |
|
|---|
| 317 |
|
|---|
| 318 |
if destDir is None or destDir == self._path: |
|---|
| 319 |
saveAs = False |
|---|
| 320 |
destDir = self._path |
|---|
| 321 |
else: |
|---|
| 322 |
saveAs = True |
|---|
| 323 |
u = UFOWriter(destDir) |
|---|
| 324 |
nonGlyphCount = 5 |
|---|
| 325 |
bar = None |
|---|
| 326 |
if doProgress: |
|---|
| 327 |
from robofab.interface.all.dialogs import ProgressBar |
|---|
| 328 |
bar = ProgressBar('Exporting UFO', nonGlyphCount+len(self._object.keys())) |
|---|
| 329 |
try: |
|---|
| 330 |
|
|---|
| 331 |
if bar: |
|---|
| 332 |
bar.label('Saving info...') |
|---|
| 333 |
u.writeInfo(self.info) |
|---|
| 334 |
if bar: |
|---|
| 335 |
bar.tick() |
|---|
| 336 |
if self.kerning.changed or saveAs: |
|---|
| 337 |
if bar: |
|---|
| 338 |
bar.label('Saving kerning...') |
|---|
| 339 |
u.writeKerning(self.kerning.asDict()) |
|---|
| 340 |
self.kerning.setChanged(False) |
|---|
| 341 |
if bar: |
|---|
| 342 |
bar.tick() |
|---|
| 343 |
|
|---|
| 344 |
if bar: |
|---|
| 345 |
bar.label('Saving groups...') |
|---|
| 346 |
u.writeGroups(self.groups) |
|---|
| 347 |
if bar: |
|---|
| 348 |
bar.tick() |
|---|
| 349 |
|
|---|
| 350 |
if self._supportHints: |
|---|
| 351 |
|
|---|
| 352 |
self.lib[postScriptHintDataLibKey] = self.psHints.asDict() |
|---|
| 353 |
|
|---|
| 354 |
if bar: |
|---|
| 355 |
bar.label('Saving lib...') |
|---|
| 356 |
u.writeLib(self.lib) |
|---|
| 357 |
if bar: |
|---|
| 358 |
bar.tick() |
|---|
| 359 |
glyphNameToFileNameFunc = self.getGlyphNameToFileNameFunc() |
|---|
| 360 |
glyphSet = u.getGlyphSet(glyphNameToFileNameFunc) |
|---|
| 361 |
if len(self._scheduledForDeletion) != 0: |
|---|
| 362 |
if bar: |
|---|
| 363 |
bar.label('Removing deleted glyphs......') |
|---|
| 364 |
for glyphName in self._scheduledForDeletion: |
|---|
| 365 |
if glyphSet.has_key(glyphName): |
|---|
| 366 |
glyphSet.deleteGlyph(glyphName) |
|---|
| 367 |
if bar: |
|---|
| 368 |
bar.tick() |
|---|
| 369 |
if bar: |
|---|
| 370 |
bar.label('Saving glyphs...') |
|---|
| 371 |
count = nonGlyphCount |
|---|
| 372 |
if saveAs: |
|---|
| 373 |
glyphNames = self.keys() |
|---|
| 374 |
else: |
|---|
| 375 |
glyphNames = self._object.keys() |
|---|
| 376 |
for glyphName in glyphNames: |
|---|
| 377 |
glyph = self[glyphName] |
|---|
| 378 |
glyph._saveToGlyphSet(glyphSet, glyphName=glyphName, force=saveAs) |
|---|
| 379 |
if bar and not count % 10: |
|---|
| 380 |
bar.tick(count) |
|---|
| 381 |
count = count + 1 |
|---|
| 382 |
glyphSet.writeContents() |
|---|
| 383 |
self._glyphSet = glyphSet |
|---|
| 384 |
except KeyboardInterrupt: |
|---|
| 385 |
bar.close() |
|---|
| 386 |
bar = None |
|---|
| 387 |
if bar: |
|---|
| 388 |
bar.close() |
|---|
| 389 |
self._path = destDir |
|---|
| 390 |
self._scheduledForDeletion = [] |
|---|
| 391 |
self.setChanged(False) |
|---|
| 392 |
|
|---|
| 393 |
def newGlyph(self, glyphName, clear=True): |
|---|
| 394 |
"""Make a new glyph with glyphName |
|---|
| 395 |
if the glyph exists and clear=True clear the glyph""" |
|---|
| 396 |
if clear and glyphName in self: |
|---|
| 397 |
g = self[glyphName] |
|---|
| 398 |
g.clear() |
|---|
| 399 |
g.width = self.info.defaultWidth |
|---|
| 400 |
return g |
|---|
| 401 |
g = RGlyph() |
|---|
| 402 |
g.setParent(self) |
|---|
| 403 |
g.name = glyphName |
|---|
| 404 |
g.width = self.info.defaultWidth |
|---|
| 405 |
g._hasChanged() |
|---|
| 406 |
self._object[glyphName] = g |
|---|
| 407 |
|
|---|
| 408 |
|
|---|
| 409 |
if glyphName in self._scheduledForDeletion: |
|---|
| 410 |
self._scheduledForDeletion.remove(glyphName) |
|---|
| 411 |
return self.getGlyph(glyphName) |
|---|
| 412 |
|
|---|
| 413 |
def insertGlyph(self, glyph, as=None): |
|---|
| 414 |
"""returns a new glyph that has been inserted into the font""" |
|---|
| 415 |
if as is None: |
|---|
| 416 |
name = glyph.name |
|---|
| 417 |
else: |
|---|
| 418 |
name = as |
|---|
| 419 |
glyph = glyph.copy() |
|---|
| 420 |
glyph.name = name |
|---|
| 421 |
glyph.setParent(self) |
|---|
| 422 |
glyph._hasChanged() |
|---|
| 423 |
self._object[name] = glyph |
|---|
| 424 |
|
|---|
| 425 |
|
|---|
| 426 |
if name in self._scheduledForDeletion: |
|---|
| 427 |
self._scheduledForDeletion.remove(name) |
|---|
| 428 |
return self.getGlyph(name) |
|---|
| 429 |
|
|---|
| 430 |
def removeGlyph(self, glyphName): |
|---|
| 431 |
"""remove a glyph from the font""" |
|---|
| 432 |
|
|---|
| 433 |
|
|---|
| 434 |
|
|---|
| 435 |
|
|---|
| 436 |
|
|---|
| 437 |
|
|---|
| 438 |
|
|---|
| 439 |
|
|---|
| 440 |
|
|---|
| 441 |
if self.has_key(glyphName) and glyphName not in self._scheduledForDeletion: |
|---|
| 442 |
self._scheduledForDeletion.append(glyphName) |
|---|
| 443 |
|
|---|
| 444 |
if self._object.has_key(glyphName): |
|---|
| 445 |
del self._object[glyphName] |
|---|
| 446 |
self._hasChanged() |
|---|
| 447 |
|
|---|
| 448 |
def getGlyph(self, glyphName): |
|---|
| 449 |
|
|---|
| 450 |
|
|---|
| 451 |
n = None |
|---|
| 452 |
if self._object.has_key(glyphName): |
|---|
| 453 |
|
|---|
| 454 |
n = self._object[glyphName] |
|---|
| 455 |
else: |
|---|
| 456 |
|
|---|
| 457 |
if self._glyphSet is not None and glyphName in self._glyphSet: |
|---|
| 458 |
|
|---|
| 459 |
n = self._loadGlyph(glyphName) |
|---|
| 460 |
if n is None: |
|---|
| 461 |
raise KeyError, glyphName |
|---|
| 462 |
return n |
|---|
| 463 |
|
|---|
| 464 |
|
|---|
| 465 |
class RGlyph(BaseGlyph): |
|---|
| 466 |
|
|---|
| 467 |
_title = "RGlyph" |
|---|
| 468 |
|
|---|
| 469 |
def __init__(self): |
|---|
| 470 |
BaseGlyph.__init__(self) |
|---|
| 471 |
self.contours = [] |
|---|
| 472 |
self.components = [] |
|---|
| 473 |
self.anchors = [] |
|---|
| 474 |
self._unicodes = [] |
|---|
| 475 |
self.width = 0 |
|---|
| 476 |
self.note = None |
|---|
| 477 |
self._name = "Unnamed Glyph" |
|---|
| 478 |
self.selected = False |
|---|
| 479 |
self._properties = None |
|---|
| 480 |
self._lib = RLib() |
|---|
| 481 |
self._lib.setParent(self) |
|---|
| 482 |
|
|---|
| 483 |
|
|---|
| 484 |
|
|---|
| 485 |
def __len__(self): |
|---|
| 486 |
return len(self.contours) |
|---|
| 487 |
|
|---|
| 488 |
def __getitem__(self, index): |
|---|
| 489 |
if index < len(self.contours): |
|---|
| 490 |
return self.contours[index] |
|---|
| 491 |
raise IndexError |
|---|
| 492 |
|
|---|
| 493 |
def _hasNotChanged(self): |
|---|
| 494 |
for contour in self.contours: |
|---|
| 495 |
contour.setChanged(False) |
|---|
| 496 |
for segment in contour.segments: |
|---|
| 497 |
segment.setChanged(False) |
|---|
| 498 |
for point in segment.points: |
|---|
| 499 |
point.setChanged(False) |
|---|
| 500 |
for component in self.components: |
|---|
| 501 |
component.setChanged(False) |
|---|
| 502 |
for anchor in self.anchors: |
|---|
| 503 |
anchor.setChanged(False) |
|---|
| 504 |
self.setChanged(False) |
|---|
| 505 |
|
|---|
| 506 |
|
|---|
| 507 |
|
|---|
| 508 |
|
|---|
| 509 |
|
|---|
| 510 |
def _get_lib(self): |
|---|
| 511 |
return self._lib |
|---|
| 512 |
|
|---|
| 513 |
def _set_lib(self, obj): |
|---|
| 514 |
self._lib.clear() |
|---|
| 515 |
self._lib.update(obj) |
|---|
| 516 |
|
|---|
| 517 |
lib = property(_get_lib, _set_lib) |
|---|
| 518 |
|
|---|
| 519 |
def _get_name(self): |
|---|
| 520 |
return self._name |
|---|
| 521 |
|
|---|
| 522 |
def _set_name(self, value): |
|---|
| 523 |
prevName = self._name |
|---|
| 524 |
newName = value |
|---|
| 525 |
if newName == prevName: |
|---|
| 526 |
return |
|---|
| 527 |
self._name = newName |
|---|
| 528 |
self.setChanged(True) |
|---|
| 529 |
font = self.getParent() |
|---|
| 530 |
if font is not None: |
|---|
| 531 |
|
|---|
| 532 |
|
|---|
| 533 |
|
|---|
| 534 |
|
|---|
| 535 |
|
|---|
| 536 |
|
|---|
| 537 |
if isinstance(font, RFont): |
|---|
| 538 |
font._object[newName] = self |
|---|
| 539 |
|
|---|
| 540 |
|
|---|
| 541 |
if newName in font._scheduledForDeletion: |
|---|
| 542 |
font._scheduledForDeletion.remove(newName) |
|---|
| 543 |
font.removeGlyph(prevName) |
|---|
| 544 |
|
|---|
| 545 |
name = property(_get_name, _set_name) |
|---|
| 546 |
|
|---|
| 547 |
def _get_unicodes(self): |
|---|
| 548 |
return self._unicodes |
|---|
| 549 |
|
|---|
| 550 |
def _set_unicodes(self, value): |
|---|
| 551 |
if not isinstance(value, list): |
|---|
| 552 |
raise RoboFabError, "unicodes must be a list" |
|---|
| 553 |
self._unicodes = value |
|---|
| 554 |
self._hasChanged() |
|---|
| 555 |
|
|---|
| 556 |
unicodes = property(_get_unicodes, _set_unicodes, doc="all unicode values for the glyph") |
|---|
| 557 |
|
|---|
| 558 |
def _get_unicode(self): |
|---|
| 559 |
if len(self._unicodes) == 0: |
|---|
| 560 |
return None |
|---|
| 561 |
return self._unicodes[0] |
|---|
| 562 |
|
|---|
| 563 |
def _set_unicode(self, value): |
|---|
| 564 |
uni = self._unicodes |
|---|
| 565 |
if value is not None: |
|---|
| 566 |
if value not in uni: |
|---|
| 567 |
self.unicodes.insert(0, value) |
|---|
| 568 |
elif uni.index(value) != 0: |
|---|
| 569 |
uni.insert(0, uni.pop(uni.index(value))) |
|---|
| 570 |
self.unicodes = uni |
|---|
| 571 |
|
|---|
| 572 |
unicode = property(_get_unicode, _set_unicode, doc="first unicode value for the glyph") |
|---|
| 573 |
|
|---|
| 574 |
def getPointPen(self): |
|---|
| 575 |
from robofab.pens.rfUFOPen import RFUFOPointPen |
|---|
| 576 |
return RFUFOPointPen(self) |
|---|
| 577 |
|
|---|
| 578 |
def appendComponent(self, baseGlyph, offset=(0, 0), scale=(1, 1)): |
|---|
| 579 |
"""append a component to the glyph""" |
|---|
| 580 |
new = RComponent(baseGlyph, offset, scale) |
|---|
| 581 |
new.setParent(self) |
|---|
| 582 |
self.components.append(new) |
|---|
| 583 |
self._hasChanged() |
|---|
| 584 |
|
|---|
| 585 |
def appendAnchor(self, name, position, mark=None): |
|---|
| 586 |
"""append an anchor to the glyph""" |
|---|
| 587 |
new = RAnchor(name, position, mark) |
|---|
| 588 |
new.setParent(self) |
|---|
| 589 |
self.anchors.append(new) |
|---|
| 590 |
self._hasChanged() |
|---|
| 591 |
|
|---|
| 592 |
def removeContour(self, index): |
|---|
| 593 |
"""remove a specific contour from the glyph""" |
|---|
| 594 |
del self.contours[index] |
|---|
| 595 |
self._hasChanged() |
|---|
| 596 |
|
|---|
| 597 |
def removeAnchor(self, anchor): |
|---|
| 598 |
"""remove a specific anchor from the glyph""" |
|---|
| 599 |
del self.anchors[anchor.index] |
|---|
| 600 |
self._hasChanged() |
|---|
| 601 |
|
|---|
| 602 |
def removeComponent(self, component): |
|---|
| 603 |
"""remove a specific component from the glyph""" |
|---|
| 604 |
del self.components[component.index] |
|---|
| 605 |
self._hasChanged() |
|---|
| 606 |
|
|---|
| 607 |
def center(self, padding=None): |
|---|
| 608 |
"""Equalise sidebearings, set to padding if wanted.""" |
|---|
| 609 |
left = self.leftMargin |
|---|
| 610 |
right = self.rightMargin |
|---|
| 611 |
if padding: |
|---|
| 612 |
e_left = e_right = padding |
|---|
| 613 |
else: |
|---|
| 614 |
e_left = (left + right)/2 |
|---|
| 615 |
e_right = (left + right) - e_left |
|---|
| 616 |
self.leftMargin = e_left |
|---|
| 617 |
self.rightMargin = e_right |
|---|
| 618 |
|
|---|
| 619 |
def decompose(self): |
|---|
| 620 |
"""Decompose all components""" |
|---|
| 621 |
for i in range(len(self.components)): |
|---|
| 622 |
self.components[-1].decompose() |
|---|
| 623 |
self._hasChanged() |
|---|
| 624 |
|
|---|
| 625 |
def clear(self, contours=True, components=True, anchors=True, guides=True): |
|---|
| 626 |
"""Clear all items marked as True from the glyph""" |
|---|
| 627 |
if contours: |
|---|
| 628 |
self.clearContours() |
|---|
| 629 |
if components: |
|---|
| 630 |
self.clearComponents() |
|---|
| 631 |
if anchors: |
|---|
| 632 |
self.clearAnchors() |
|---|
| 633 |
if guides: |
|---|
| 634 |
self.clearHGuides() |
|---|
| 635 |
self.clearVGuides() |
|---|
| 636 |
|
|---|
| 637 |
def clearContours(self): |
|---|
| 638 |
"""clear all contours""" |
|---|
| 639 |
self.contours = [] |
|---|
| 640 |
self._hasChanged() |
|---|
| 641 |
|
|---|
| 642 |
def clearComponents(self): |
|---|
| 643 |
"""clear all components""" |
|---|
| 644 |
self.components = [] |
|---|
| 645 |
self._hasChanged() |
|---|
| 646 |
|
|---|
| 647 |
def clearAnchors(self): |
|---|
| 648 |
"""clear all anchors""" |
|---|
| 649 |
self.anchors = [] |
|---|
| 650 |
self._hasChanged() |
|---|
| 651 |
|
|---|
| 652 |
def clearHGuides(self): |
|---|
| 653 |
"""clear all horizontal guides""" |
|---|
| 654 |
self.hGuides = [] |
|---|
| 655 |
self._hasChanged() |
|---|
| 656 |
|
|---|
| 657 |
def clearVGuides(self): |
|---|
| 658 |
"""clear all vertical guides""" |
|---|
| 659 |
self.vGuides = [] |
|---|
| 660 |
self._hasChanged() |
|---|
| 661 |
|
|---|
| 662 |
def getAnchors(self): |
|---|
| 663 |
return self.anchors |
|---|
| 664 |
|
|---|
| 665 |
def getComponents(self): |
|---|
| 666 |
return self.components |
|---|
| 667 |
|
|---|
| 668 |
|
|---|
| 669 |
|
|---|
| 670 |
|
|---|
| 671 |
|
|---|
| 672 |
|
|---|
| 673 |
|
|---|
| 674 |
class RContour(BaseContour): |
|---|
| 675 |
|
|---|
| 676 |
_title = "RoboFabContour" |
|---|
| 677 |
|
|---|
| 678 |
def __init__(self, object=None): |
|---|
| 679 |
|
|---|
| 680 |
self.segments = [] |
|---|
| 681 |
self.selected = False |
|---|
| 682 |
|
|---|
| 683 |
def __len__(self): |
|---|
| 684 |
return len(self.segments) |
|---|
| 685 |
|
|---|
| 686 |
def __getitem__(self, index): |
|---|
| 687 |
if index < len(self.segments): |
|---|
| 688 |
return self.segments[index] |
|---|
| 689 |
raise IndexError |
|---|
| 690 |
|
|---|
| 691 |
def _get_index(self): |
|---|
| 692 |
return self.getParent().contours.index(self) |
|---|
| 693 |
|
|---|
| 694 |
def _set_index(self, index): |
|---|
| 695 |
ogIndex = self.index |
|---|
| 696 |
if index != ogIndex: |
|---|
| 697 |
contourList = self.getParent().contours |
|---|
| 698 |
contourList.insert(index, contourList.pop(ogIndex)) |
|---|
| 699 |
|
|---|
| 700 |
|
|---|
| 701 |
index = property(_get_index, _set_index, doc="index of the contour") |
|---|
| 702 |
|
|---|
| 703 |
def _get_points(self): |
|---|
| 704 |
points = [] |
|---|
| 705 |
for segment in self.segments: |
|---|
| 706 |
for point in segment.points: |
|---|
| 707 |
points.append(point) |
|---|
| 708 |
return points |
|---|
| 709 |
|
|---|
| 710 |
points = property(_get_points, doc="view the contour as a list of points") |
|---|
| 711 |
|
|---|
| 712 |
def _get_bPoints(self): |
|---|
| 713 |
bPoints = [] |
|---|
| 714 |
for segment in self.segments: |
|---|
| 715 |
segType = segment.type |
|---|
| 716 |
if segType == MOVE: |
|---|
| 717 |
bType = CORNER |
|---|
| 718 |
elif segType == LINE: |
|---|
| 719 |
bType = CORNER |
|---|
| 720 |
elif segType == CURVE: |
|---|
| 721 |
if segment.smooth: |
|---|
| 722 |
bType = CURVE |
|---|
| 723 |
else: |
|---|
| 724 |
bType = CORNER |
|---|
| 725 |
else: |
|---|
| 726 |
raise RoboFabError, "encountered unknown segment type" |
|---|
| 727 |
b = RBPoint() |
|---|
| 728 |
b.setParent(segment) |
|---|
| 729 |
bPoints.append(b) |
|---|
| 730 |
return bPoints |
|---|
| 731 |
|
|---|
| 732 |
bPoints = property(_get_bPoints, doc="view the contour as a list of bPoints") |
|---|
| 733 |
|
|---|
| 734 |
def appendSegment(self, segmentType, points, smooth=False): |
|---|
| 735 |
"""append a segment to the contour""" |
|---|
| 736 |
segment = self.insertSegment(index=len(self.segments), segmentType=segmentType, points=points, smooth=smooth) |
|---|
| 737 |
return segment |
|---|
| 738 |
|
|---|
| 739 |
def insertSegment(self, index, segmentType, points, smooth=False): |
|---|
| 740 |
"""insert a segment into the contour""" |
|---|
| 741 |
segment = RSegment(segmentType, points, smooth) |
|---|
| 742 |
segment.setParent(self) |
|---|
| 743 |
self.segments.insert(index, segment) |
|---|
| 744 |
self._hasChanged() |
|---|
| 745 |
return segment |
|---|
| 746 |
|
|---|
| 747 |
def removeSegment(self, index): |
|---|
| 748 |
"""remove a segment from the contour""" |
|---|
| 749 |
del self.segments[index] |
|---|
| 750 |
self._hasChanged() |
|---|
| 751 |
|
|---|
| 752 |
def reverseContour(self): |
|---|
| 753 |
"""reverse the contour""" |
|---|
| 754 |
from robofab.pens.reverseContourPointPen import ReverseContourPointPen |
|---|
| 755 |
index = self.index |
|---|
| 756 |
glyph = self.getParent() |
|---|
| 757 |
pen = glyph.getPointPen() |
|---|
| 758 |
reversePen = ReverseContourPointPen(pen) |
|---|
| 759 |
self.drawPoints(reversePen) |
|---|
| 760 |
|
|---|
| 761 |
|
|---|
| 762 |
newContour = glyph.contours.pop(-1) |
|---|
| 763 |
for segment in newContour.segments: |
|---|
| 764 |
segment.setParent(self) |
|---|
| 765 |
self.segments = newContour.segments |
|---|
| 766 |
self._hasChanged() |
|---|
| 767 |
|
|---|
| 768 |
def setStartSegment(self, segmentIndex): |
|---|
| 769 |
"""set the first segment on the contour""" |
|---|
| 770 |
|
|---|
| 771 |
if len(self.segments) < 2: |
|---|
| 772 |
return |
|---|
| 773 |
if segmentIndex == 0: |
|---|
| 774 |
return |
|---|
| 775 |
if segmentIndex > len(self.segments)-1: |
|---|
| 776 |
raise IndexError, 'segment index not in segments list' |
|---|
| 777 |
oldStart = self.segments[0] |
|---|
| 778 |
oldLast = self.segments[-1] |
|---|
| 779 |
|
|---|
| 780 |
|
|---|
| 781 |
if oldLast.type == CURVE or oldLast.type == QCURVE: |
|---|
| 782 |
startOn = oldStart.onCurve |
|---|
| 783 |
lastOn = oldLast.onCurve |
|---|
| 784 |
if startOn.x == lastOn.x and startOn.y == lastOn.y: |
|---|
| 785 |
del self.segments[0] |
|---|
| 786 |
|
|---|
| 787 |
segmentIndex = segmentIndex - 1 |
|---|
| 788 |
|
|---|
| 789 |
if self.segments[0].type == MOVE: |
|---|
| 790 |
self.segments[0].type = LINE |
|---|
| 791 |
|
|---|
| 792 |
segments = self.segments[segmentIndex:] |
|---|
| 793 |
self.segments = segments + self.segments[:segmentIndex] |
|---|
| 794 |
|
|---|
| 795 |
glyph = self.getParent() |
|---|
| 796 |
pen = glyph.getPointPen() |
|---|
| 797 |
self.drawPoints(pen) |
|---|
| 798 |
|
|---|
| 799 |
|
|---|
| 800 |
newContour = glyph.contours.pop(-1) |
|---|
| 801 |
for segment in newContour.segments: |
|---|
| 802 |
segment.setParent(self) |
|---|
| 803 |
self.segments = newContour.segments |
|---|
| 804 |
self._hasChanged() |
|---|
| 805 |
|
|---|
| 806 |
|
|---|
| 807 |
class RSegment(BaseSegment): |
|---|
| 808 |
|
|---|
| 809 |
_title = "RoboFabSegment" |
|---|
| 810 |
|
|---|
| 811 |
def __init__(self, segmentType=None, points=[], smooth=False): |
|---|
| 812 |
BaseSegment.__init__(self) |
|---|
| 813 |
self.selected = False |
|---|
| 814 |
self.points = [] |
|---|
| 815 |
self.smooth = smooth |
|---|
| 816 |
if points: |
|---|
| 817 |
|
|---|
| 818 |
for point in points[:-1]: |
|---|
| 819 |
x, y = point |
|---|
| 820 |
p = RPoint(x, y, pointType=OFFCURVE) |
|---|
| 821 |
p.setParent(self) |
|---|
| 822 |
self.points.append(p) |
|---|
| 823 |
aX, aY = points[-1] |
|---|
| 824 |
p = RPoint(aX, aY, segmentType) |
|---|
| 825 |
p.setParent(self) |
|---|
| 826 |
self.points.append(p) |
|---|
| 827 |
|
|---|
| 828 |
def _get_type(self): |
|---|
| 829 |
return self.points[-1].type |
|---|
| 830 |
|
|---|
| 831 |
def _set_type(self, pointType): |
|---|
| 832 |
onCurve = self.points[-1] |
|---|
| 833 |
ocType = onCurve.type |
|---|
| 834 |
if ocType == pointType: |
|---|
| 835 |
return |
|---|
| 836 |
|
|---|
| 837 |
if pointType == CURVE and ocType == LINE: |
|---|
| 838 |
onCurve.type = pointType |
|---|
| 839 |
parent = self.getParent() |
|---|
| 840 |
prev = parent._prevSegment(self.index) |
|---|
| 841 |
p1 = RPoint(prev.onCurve.x, prev.onCurve.y, pointType=OFFCURVE) |
|---|
| 842 |
p1.setParent(self) |
|---|
| 843 |
p2 = RPoint(onCurve.x, onCurve.y, pointType=OFFCURVE) |
|---|
| 844 |
p2.setParent(self) |
|---|
| 845 |
self.points.insert(0, p2) |
|---|
| 846 |
self.points.insert(0, p1) |
|---|
| 847 |
|
|---|
| 848 |
elif pointType == CURVE and ocType == MOVE: |
|---|
| 849 |
onCurve.type = pointType |
|---|
| 850 |
parent = self.getParent() |
|---|
| 851 |
prev = parent._prevSegment(self.index) |
|---|
| 852 |
p1 = RPoint(prev.onCurve.x, prev.onCurve.y, pointType=OFFCURVE) |
|---|
| 853 |
p1.setParent(self) |
|---|
| 854 |
p2 = RPoint(onCurve.x, onCurve.y, pointType=OFFCURVE) |
|---|
| 855 |
p2.setParent(self) |
|---|
| 856 |
self.points.insert(0, p2) |
|---|
| 857 |
self.points.insert(0, p1) |
|---|
| 858 |
|
|---|
| 859 |
elif pointType == CURVE and ocType == QCURVE: |
|---|
| 860 |
onCurve.type == CURVE |
|---|
| 861 |
|
|---|
| 862 |
elif pointType == LINE and ocType == CURVE: |
|---|
| 863 |
p = self.points.pop(-1) |
|---|
| 864 |
self.points = [p] |
|---|
| 865 |
onCurve.type = pointType |
|---|
| 866 |
self.smooth = False |
|---|
| 867 |
|
|---|
| 868 |
elif pointType == LINE and ocType == MOVE: |
|---|
| 869 |
onCurve.type = pointType |
|---|
| 870 |
|
|---|
| 871 |
elif pointType == LINE and ocType == QCURVE: |
|---|
| 872 |
p = self.points.pop(-1) |
|---|
| 873 |
self.points = [p] |
|---|
| 874 |
onCurve.type = pointType |
|---|
| 875 |
self.smooth = False |
|---|
| 876 |
|
|---|
| 877 |
elif pointType == QCURVE: |
|---|
| 878 |
onCurve.type = pointType |
|---|
| 879 |
else: |
|---|
| 880 |
raise RoboFabError, 'unknown segment type' |
|---|
| 881 |
|
|---|
| 882 |
type = property(_get_type, _set_type, doc="type of the segment") |
|---|
| 883 |
|
|---|
| 884 |
def _get_index(self): |
|---|
| 885 |
return self.getParent().segments.index(self) |
|---|
| 886 |
|
|---|
| 887 |
index = property(_get_index, doc="index of the segment") |
|---|
| 888 |
|
|---|
| 889 |
def insertPoint(self, index, pointType, point): |
|---|
| 890 |
x, y = point |
|---|
| 891 |
p = RPoint(x, y, pointType=pointType) |
|---|
| 892 |
p.setParent(self) |
|---|
| 893 |
self.points.insert(index, p) |
|---|
| 894 |
self._hasChanged() |
|---|
| 895 |
|
|---|
| 896 |
def removePoint(self, index): |
|---|
| 897 |
del self.points[index] |
|---|
| 898 |
self._hasChanged() |
|---|
| 899 |
|
|---|
| 900 |
|
|---|
| 901 |
class RBPoint(BaseBPoint): |
|---|
| 902 |
|
|---|
| 903 |
_title = "RoboFabBPoint" |
|---|
| 904 |
|
|---|
| 905 |
def _setAnchorChanged(self, value): |
|---|
| 906 |
self._anchorPoint.setChanged(value) |
|---|
| 907 |
|
|---|
| 908 |
def _setNextChanged(self, value): |
|---|
| 909 |
self._nextOnCurve.setChanged(value) |
|---|
| 910 |
|
|---|
| 911 |
def _get__parentSegment(self): |
|---|
| 912 |
return self.getParent() |
|---|
| 913 |
|
|---|
| 914 |
_parentSegment = property(_get__parentSegment, doc="") |
|---|
| 915 |
|
|---|
| 916 |
def _get__nextOnCurve(self): |
|---|
| 917 |
pSeg = self._parentSegment |
|---|
| 918 |
contour = pSeg.getParent() |
|---|
| 919 |
|
|---|
| 920 |
return contour.segments[(contour.segments.index(pSeg) + 1) % len(contour.segments)] |
|---|
| 921 |
|
|---|
| 922 |
_nextOnCurve = property(_get__nextOnCurve, doc="") |
|---|
| 923 |
|
|---|
| 924 |
def _get_index(self): |
|---|
| 925 |
return self._parentSegment.index |
|---|
| 926 |
|
|---|
| 927 |
index = property(_get_index, doc="index of the bPoint on the contour") |
|---|
| 928 |
|
|---|
| 929 |
|
|---|
| 930 |
class RPoint(BasePoint): |
|---|
| 931 |
|
|---|
| 932 |
_title = "RoboFabPoint" |
|---|
| 933 |
|
|---|
| 934 |
def __init__(self, x=0, y=0, pointType=None, name=None): |
|---|
| 935 |
self.selected = False |
|---|
| 936 |
self._type = pointType |
|---|
| 937 |
self._x = x |
|---|
| 938 |
self._y = y |
|---|
| 939 |
self._name = None |
|---|
| 940 |
|
|---|
| 941 |
def _get_x(self): |
|---|
| 942 |
return self._x |
|---|
| 943 |
|
|---|
| 944 |
def _set_x(self, value): |
|---|
| 945 |
self._x = value |
|---|
| 946 |
self._hasChanged() |
|---|
| 947 |
|
|---|
| 948 |
x = property(_get_x, _set_x, doc="") |
|---|
| 949 |
|
|---|
| 950 |
def _get_y(self): |
|---|
| 951 |
return self._y |
|---|
| 952 |
|
|---|
| 953 |
def _set_y(self, value): |
|---|
| 954 |
self._y = value |
|---|
| 955 |
self._hasChanged() |
|---|
| 956 |
|
|---|
| 957 |
y = property(_get_y, _set_y, doc="") |
|---|
| 958 |
|
|---|
| 959 |
def _get_type(self): |
|---|
| 960 |
return self._type |
|---|
| 961 |
|
|---|
| 962 |
def _set_type(self, value): |
|---|
| 963 |
self._type = value |
|---|
| 964 |
self._hasChanged() |
|---|
| 965 |
|
|---|
| 966 |
type = property(_get_type, _set_type, doc="") |
|---|
| 967 |
|
|---|
| 968 |
def _get_name(self): |
|---|
| 969 |
return self._name |
|---|
| 970 |
|
|---|
| 971 |
def _set_name(self, value): |
|---|
| 972 |
self._name = value |
|---|
| 973 |
self._hasChanged() |
|---|
| 974 |
|
|---|
| 975 |
name = property(_get_name, _set_name, doc="") |
|---|
| 976 |
|
|---|
| 977 |
|
|---|
| 978 |
class RAnchor(BaseAnchor): |
|---|
| 979 |
|
|---|
| 980 |
_title = "RoboFabAnchor" |
|---|
| 981 |
|
|---|
| 982 |
def __init__(self, name=None, position=None, mark=None): |
|---|
| 983 |
BaseAnchor.__init__(self) |
|---|
| 984 |
self.selected = False |
|---|
| 985 |
self.name = name |
|---|
| 986 |
if position is None: |
|---|
| 987 |
self.x = self.y = None |
|---|
| 988 |
else: |
|---|
| 989 |
self.x, self.y = position |
|---|
| 990 |
self.mark = mark |
|---|
| 991 |
|
|---|
| 992 |
def _get_index(self): |
|---|
| 993 |
if self.getParent() is None: return None |
|---|
| 994 |
return self.getParent().anchors.index(self) |
|---|
| 995 |
|
|---|
| 996 |
index = property(_get_index, doc="index of the anchor") |
|---|
| 997 |
|
|---|
| 998 |
def _get_position(self): |
|---|
| 999 |
return (self.x, self.y) |
|---|
| 1000 |
|
|---|
| 1001 |
def _set_position(self, value): |
|---|
| 1002 |
self.x = value[0] |
|---|
| 1003 |
self.y = value[1] |
|---|
| 1004 |
self._hasChanged() |
|---|
| 1005 |
|
|---|
| 1006 |
position = property(_get_position, _set_position, doc="position of the anchor") |
|---|
| 1007 |
|
|---|
| 1008 |
def move(self, (x, y)): |
|---|
| 1009 |
"""Move the anchor""" |
|---|
| 1010 |
self.x = self.x + x |
|---|
| 1011 |
self.y = self.y + y |
|---|
| 1012 |
self._hasChanged() |
|---|
| 1013 |
|
|---|
| 1014 |
|
|---|
| 1015 |
class RComponent(BaseComponent): |
|---|
| 1016 |
|
|---|
| 1017 |
_title = "RoboFabComponent" |
|---|
| 1018 |
|
|---|
| 1019 |
def __init__(self, baseGlyphName=None, offset=(0,0), scale=(1,1)): |
|---|
| 1020 |
BaseComponent.__init__(self) |
|---|
| 1021 |
self.selected = False |
|---|
| 1022 |
self._baseGlyph = baseGlyphName |
|---|
| 1023 |
self._offset = offset |
|---|
| 1024 |
self._scale = scale |
|---|
| 1025 |
|
|---|
| 1026 |
def _get_index(self): |
|---|
| 1027 |
if self.getParent() is None: return None |
|---|
| 1028 |
return self.getParent().components.index(self) |
|---|
| 1029 |
|
|---|
| 1030 |
index = property(_get_index, doc="index of the component") |
|---|
| 1031 |
|
|---|
| 1032 |
def _get_baseGlyph(self): |
|---|
| 1033 |
return self._baseGlyph |
|---|
| 1034 |
|
|---|
| 1035 |
def _set_baseGlyph(self, glyphName): |
|---|
| 1036 |
|
|---|
| 1037 |
self._baseGlyph = glyphName |
|---|
| 1038 |
self._hasChanged() |
|---|
| 1039 |
|
|---|
| 1040 |
baseGlyph = property(_get_baseGlyph, _set_baseGlyph, doc="") |
|---|
| 1041 |
|
|---|
| 1042 |
def _get_offset(self): |
|---|
| 1043 |
return self._offset |
|---|
| 1044 |
|
|---|
| 1045 |
def _set_offset(self, value): |
|---|
| 1046 |
self._offset = value |
|---|
| 1047 |
self._hasChanged() |
|---|
| 1048 |
|
|---|
| 1049 |
offset = property(_get_offset, _set_offset, doc="the offset of the component") |
|---|
| 1050 |
|
|---|
| 1051 |
def _get_scale(self): |
|---|
| 1052 |
return self._scale |
|---|
| 1053 |
|
|---|
| 1054 |
def _set_scale(self, (x, y)): |
|---|
| 1055 |
self._scale = (x, y) |
|---|
| 1056 |
self._hasChanged() |
|---|
| 1057 |
|
|---|
| 1058 |
scale = property(_get_scale, _set_scale, doc="the scale of the component") |
|---|
| 1059 |
|
|---|
| 1060 |
def move(self, (x, y)): |
|---|
| 1061 |
"""Move the component""" |
|---|
| 1062 |
self.offset = (self.offset[0] + x, self.offset[1] + y) |
|---|
| 1063 |
|
|---|
| 1064 |
def decompose(self): |
|---|
| 1065 |
"""Decompose the component""" |
|---|
| 1066 |
baseGlyphName = self.baseGlyph |
|---|
| 1067 |
parentGlyph = self.getParent() |
|---|
| 1068 |
|
|---|
| 1069 |
if baseGlyphName is not None and parentGlyph is not None: |
|---|
| 1070 |
parentFont = parentGlyph.getParent() |
|---|
| 1071 |
|
|---|
| 1072 |
|
|---|
| 1073 |
|
|---|
| 1074 |
|
|---|
| 1075 |
if parentFont is not None and parentFont.has_key(baseGlyphName): |
|---|
| 1076 |
from robofab.pens.adapterPens import TransformPointPen |
|---|
| 1077 |
oX, oY = self.offset |
|---|
| 1078 |
sX, sY = self.scale |
|---|
| 1079 |
baseGlyph = parentFont[baseGlyphName] |
|---|
| 1080 |
for contour in baseGlyph.contours: |
|---|
| 1081 |
pointPen = parentGlyph.getPointPen() |
|---|
| 1082 |
transPen = TransformPointPen(pointPen, (sX, 0, 0, sY, oX, oY)) |
|---|
| 1083 |
contour.drawPoints(transPen) |
|---|
| 1084 |
parentGlyph.components.remove(self) |
|---|
| 1085 |
|
|---|
| 1086 |
|
|---|
| 1087 |
class RKerning(BaseKerning): |
|---|
| 1088 |
|
|---|
| 1089 |
_title = "RoboFabKerning" |
|---|
| 1090 |
|
|---|
| 1091 |
|
|---|
| 1092 |
class RGroups(BaseGroups): |
|---|
| 1093 |
|
|---|
| 1094 |
_title = "RoboFabGroups" |
|---|
| 1095 |
|
|---|
| 1096 |
class RLib(BaseLib): |
|---|
| 1097 |
|
|---|
| 1098 |
_title = "RoboFabLib" |
|---|
| 1099 |
|
|---|
| 1100 |
|
|---|
| 1101 |
class RInfo(BaseInfo): |
|---|
| 1102 |
|
|---|
| 1103 |
_title = "RoboFabFonInfo" |
|---|
| 1104 |
|
|---|
| 1105 |
def __init__(self): |
|---|
| 1106 |
BaseInfo.__init__(self) |
|---|
| 1107 |
self.selected = False |
|---|
| 1108 |
|
|---|
| 1109 |
self._familyName = None |
|---|
| 1110 |
self._styleName = None |
|---|
| 1111 |
self._fullName = None |
|---|
| 1112 |
self._fontName = None |
|---|
| 1113 |
self._menuName = None |
|---|
| 1114 |
self._fondName = None |
|---|
| 1115 |
self._otFamilyName = None |
|---|
| 1116 |
self._otStyleName = None |
|---|
| 1117 |
self._otMacName = None |
|---|
| 1118 |
self._weightValue = None |
|---|
| 1119 |
self._weightName = None |
|---|
| 1120 |
self._widthName = None |
|---|
| 1121 |
self._fontStyle = None |
|---|
| 1122 |
self._msCharSet = None |
|---|
| 1123 |
self._note = None |
|---|
| 1124 |
self._fondID = None |
|---|
| 1125 |
self._uniqueID = None |
|---|
| 1126 |
self._versionMajor = None |
|---|
| 1127 |
self._versionMinor = None |
|---|
| 1128 |
self._year = None |
|---|
| 1129 |
self._copyright = None |
|---|
| 1130 |
self._notice = None |
|---|
| 1131 |
self._trademark = None |
|---|
| 1132 |
self._license = None |
|---|
| 1133 |
self._licenseURL = None |
|---|
| 1134 |
self._designer = None |
|---|
| 1135 |
self._designerURL = None |
|---|
| 1136 |
self._vendorURL = None |
|---|
| 1137 |
self._ttVendor = None |
|---|
| 1138 |
self._ttUniqueID = None |
|---|
| 1139 |
self._ttVersion = None |
|---|
| 1140 |
self._unitsPerEm = None |
|---|
| 1141 |
self._ascender = None |
|---|
| 1142 |
self._descender = None |
|---|
| 1143 |
self._capHeight = None |
|---|
| 1144 |
self._xHeight = None |
|---|
| 1145 |
self._defaultWidth = None |
|---|
| 1146 |
self._italicAngle = None |
|---|
| 1147 |
self._slantAngle = None |
|---|
| 1148 |
|
|---|
| 1149 |
def _get_familyName(self): |
|---|
| 1150 |
return self._familyName |
|---|
| 1151 |
|
|---|
| 1152 |
def _set_familyName(self, value): |
|---|
| 1153 |
self._familyName = value |
|---|
| 1154 |
|
|---|
| 1155 |
familyName = property(_get_familyName, _set_familyName, doc="family_name") |
|---|
| 1156 |
|
|---|
| 1157 |
def _get_styleName(self): |
|---|
| 1158 |
return self._styleName |
|---|
| 1159 |
|
|---|
| 1160 |
def _set_styleName(self, value): |
|---|
| 1161 |
self._styleName = value |
|---|
| 1162 |
|
|---|
| 1163 |
styleName = property(_get_styleName, _set_styleName, doc="style_name") |
|---|
| 1164 |
|
|---|
| 1165 |
def _get_fullName(self): |
|---|
| 1166 |
return self._fullName |
|---|
| 1167 |
|
|---|
| 1168 |
def _set_fullName(self, value): |
|---|
| 1169 |
self._fullName = value |
|---|
| 1170 |
|
|---|
| 1171 |
fullName = property(_get_fullName, _set_fullName, doc="full_name") |
|---|
| 1172 |
|
|---|
| 1173 |
def _get_fontName(self): |
|---|
| 1174 |
return self._fontName |
|---|
| 1175 |
|
|---|
| 1176 |
def _set_fontName(self, value): |
|---|
| 1177 |
self._fontName = value |
|---|
| 1178 |
|
|---|
| 1179 |
fontName = property(_get_fontName, _set_fontName, doc="font_name") |
|---|
| 1180 |
|
|---|
| 1181 |
def _get_menuName(self): |
|---|
| 1182 |
return self._menuName |
|---|
| 1183 |
|
|---|
| 1184 |
def _set_menuName(self, value): |
|---|
| 1185 |
self._menuName = value |
|---|
| 1186 |
|
|---|
| 1187 |
menuName = property(_get_menuName, _set_menuName, doc="menu_name") |
|---|
| 1188 |
|
|---|
| 1189 |
def _get_fondName(self): |
|---|
| 1190 |
return self._fondName |
|---|
| 1191 |
|
|---|
| 1192 |
def _set_fondName(self, value): |
|---|
| 1193 |
self._fondName = value |
|---|
| 1194 |
|
|---|
| 1195 |
fondName = property(_get_fondName, _set_fondName, doc="apple_name") |
|---|
| 1196 |
|
|---|
| 1197 |
def _get_otFamilyName(self): |
|---|
| 1198 |
return self._otFamilyName |
|---|
| 1199 |
|
|---|
| 1200 |
def _set_otFamilyName(self, value): |
|---|
| 1201 |
self._otFamilyName = value |
|---|
| 1202 |
|
|---|
| 1203 |
otFamilyName = property(_get_otFamilyName, _set_otFamilyName, doc="pref_family_name") |
|---|
| 1204 |
|
|---|
| 1205 |
def _get_otStyleName(self): |
|---|
| 1206 |
return self._otStyleName |
|---|
| 1207 |
|
|---|
| 1208 |
def _set_otStyleName(self, value): |
|---|
| 1209 |
self._otStyleName = value |
|---|
| 1210 |
|
|---|
| 1211 |
otStyleName = property(_get_otStyleName, _set_otStyleName, doc="pref_style_name") |
|---|
| 1212 |
|
|---|
| 1213 |
def _get_otMacName(self): |
|---|
| 1214 |
return self._otMacName |
|---|
| 1215 |
|
|---|
| 1216 |
def _set_otMacName(self, value): |
|---|
| 1217 |
self._otMacName = value |
|---|
| 1218 |
|
|---|
| 1219 |
otMacName = property(_get_otMacName, _set_otMacName, doc="mac_compatible") |
|---|
| 1220 |
|
|---|
| 1221 |
def _get_weightValue(self): |
|---|
| 1222 |
return self._weightValue |
|---|
| 1223 |
|
|---|
| 1224 |
def _set_weightValue(self, value): |
|---|
| 1225 |
self._weightValue = value |
|---|
| 1226 |
|
|---|
| 1227 |
weightValue = property(_get_weightValue, _set_weightValue, doc="weight value") |
|---|
| 1228 |
|
|---|
| 1229 |
def _get_weightName(self): |
|---|
| 1230 |
return self._weightName |
|---|
| 1231 |
|
|---|
| 1232 |
def _set_weightName(self, value): |
|---|
| 1233 |
self._weightName = value |
|---|
| 1234 |
|
|---|
| 1235 |
weightName = property(_get_weightName, _set_weightName, doc="weight name") |
|---|
| 1236 |
|
|---|
| 1237 |
def _get_widthName(self): |
|---|
| 1238 |
return self._widthName |
|---|
| 1239 |
|
|---|
| 1240 |
def _set_widthName(self, value): |
|---|
| 1241 |
self._widthName = value |
|---|
| 1242 |
|
|---|
| 1243 |
widthName = property(_get_widthName, _set_widthName, doc="width name") |
|---|
| 1244 |
|
|---|
| 1245 |
def _get_fontStyle(self): |
|---|
| 1246 |
return self._fontStyle |
|---|
| 1247 |
|
|---|
| 1248 |
def _set_fontStyle(self, value): |
|---|
| 1249 |
self._fontStyle = value |
|---|
| 1250 |
|
|---|
| 1251 |
fontStyle = property(_get_fontStyle, _set_fontStyle, doc="font_style") |
|---|
| 1252 |
|
|---|
| 1253 |
def _get_msCharSet(self): |
|---|
| 1254 |
return self._msCharSet |
|---|
| 1255 |
|
|---|
| 1256 |
def _set_msCharSet(self, value): |
|---|
| 1257 |
self._msCharSet = value |
|---|
| 1258 |
|
|---|
| 1259 |
msCharSet = property(_get_msCharSet, _set_msCharSet, doc="ms_charset") |
|---|
| 1260 |
|
|---|
| 1261 |
def _get_note(self): |
|---|
| 1262 |
return self._note |
|---|
| 1263 |
|
|---|
| 1264 |
def _set_note(self, value): |
|---|
| 1265 |
self._note = value |
|---|
| 1266 |
|
|---|
| 1267 |
note = property(_get_note, _set_note, doc="note") |
|---|
| 1268 |
|
|---|
| 1269 |
def _get_fondID(self): |
|---|
| 1270 |
return self._fondID |
|---|
| 1271 |
|
|---|
| 1272 |
def _set_fondID(self, value): |
|---|
| 1273 |
self._fondID = value |
|---|
| 1274 |
|
|---|
| 1275 |
fondID = property(_get_fondID, _set_fondID, doc="fond_id") |
|---|
| 1276 |
|
|---|
| 1277 |
def _get_uniqueID(self): |
|---|
| 1278 |
return self._uniqueID |
|---|
| 1279 |
|
|---|
| 1280 |
def _set_uniqueID(self, value): |
|---|
| 1281 |
self._uniqueID = value |
|---|
| 1282 |
|
|---|
| 1283 |
uniqueID = property(_get_uniqueID, _set_uniqueID, doc="unique_id") |
|---|
| 1284 |
|
|---|
| 1285 |
def _get_versionMajor(self): |
|---|
| 1286 |
return self._versionMajor |
|---|
| 1287 |
|
|---|
| 1288 |
def _set_versionMajor(self, value): |
|---|
| 1289 |
self._versionMajor = value |
|---|
| 1290 |
|
|---|
| 1291 |
versionMajor = property(_get_versionMajor, _set_versionMajor, doc="version_major") |
|---|
| 1292 |
|
|---|
| 1293 |
def _get_versionMinor(self): |
|---|
| 1294 |
return self._versionMinor |
|---|
| 1295 |
|
|---|
| 1296 |
def _set_versionMinor(self, value): |
|---|
| 1297 |
self._versionMinor = value |
|---|
| 1298 |
|
|---|
| 1299 |
versionMinor = property(_get_versionMinor, _set_versionMinor, doc="version_minor") |
|---|
| 1300 |
|
|---|
| 1301 |
def _get_year(self): |
|---|
| 1302 |
return self._year |
|---|
| 1303 |
|
|---|
| 1304 |
def _set_year(self, value): |
|---|
| 1305 |
self._year = value |
|---|
| 1306 |
|
|---|
| 1307 |
year = property(_get_year, _set_year, doc="year") |
|---|
| 1308 |
|
|---|
| 1309 |
def _get_copyright(self): |
|---|
| 1310 |
return self._copyright |
|---|
| 1311 |
|
|---|
| 1312 |
def _set_copyright(self, value): |
|---|
| 1313 |
self._copyright = value |
|---|
| 1314 |
|
|---|
| 1315 |
copyright = property(_get_copyright, _set_copyright, doc="copyright") |
|---|
| 1316 |
|
|---|
| 1317 |
def _get_notice(self): |
|---|
| 1318 |
return self._notice |
|---|
| 1319 |
|
|---|
| 1320 |
def _set_notice(self, value): |
|---|
| 1321 |
self._notice = value |
|---|
| 1322 |
|
|---|
| 1323 |
notice = property(_get_notice, _set_notice, doc="notice") |
|---|
| 1324 |
|
|---|
| 1325 |
def _get_trademark(self): |
|---|
| 1326 |
return self._trademark |
|---|
| 1327 |
|
|---|
| 1328 |
def _set_trademark(self, value): |
|---|
| 1329 |
self._trademark = value |
|---|
| 1330 |
|
|---|
| 1331 |
trademark = property(_get_trademark, _set_trademark, doc="trademark") |
|---|
| 1332 |
|
|---|
| 1333 |
def _get_license(self): |
|---|
| 1334 |
return self._license |
|---|
| 1335 |
|
|---|
| 1336 |
def _set_license(self, value): |
|---|
| 1337 |
self._license = value |
|---|
| 1338 |
|
|---|
| 1339 |
license = property(_get_license, _set_license, doc="license") |
|---|
| 1340 |
|
|---|
| 1341 |
def _get_licenseURL(self): |
|---|
| 1342 |
return self._licenseURL |
|---|
| 1343 |
|
|---|
| 1344 |
def _set_licenseURL(self, value): |
|---|
| 1345 |
self._licenseURL = value |
|---|
| 1346 |
|
|---|
| 1347 |
licenseURL = property(_get_licenseURL, _set_licenseURL, doc="license_url") |
|---|
| 1348 |
|
|---|
| 1349 |
def _get_designer(self): |
|---|
| 1350 |
return self._designer |
|---|
| 1351 |
|
|---|
| 1352 |
def _set_designer(self, value): |
|---|
| 1353 |
self._designer = value |
|---|
| 1354 |
|
|---|
| 1355 |
designer = property(_get_designer, _set_designer, doc="designer") |
|---|
| 1356 |
|
|---|
| 1357 |
def _get_createdBy(self): |
|---|
| 1358 |
return self._createdBy |
|---|
| 1359 |
|
|---|
| 1360 |
def _set_createdBy(self, value): |
|---|
| 1361 |
self._createdBy = value |
|---|
| 1362 |
|
|---|
| 1363 |
createdBy = property(_get_createdBy, _set_createdBy, doc="source") |
|---|
| 1364 |
|
|---|
| 1365 |
def _get_designerURL(self): |
|---|
| 1366 |
return self._designerURL |
|---|
| 1367 |
|
|---|
| 1368 |
def _set_designerURL(self, value): |
|---|
| 1369 |
self._designerURL = value |
|---|
| 1370 |
|
|---|
| 1371 |
designerURL = property(_get_designerURL, _set_designerURL, doc="designer_url") |
|---|
| 1372 |
|
|---|
| 1373 |
def _get_vendorURL(self): |
|---|
| 1374 |
return self._vendorURL |
|---|
| 1375 |
|
|---|
| 1376 |
def _set_vendorURL(self, value): |
|---|
| 1377 |
self._vendorURL = value |
|---|
| 1378 |
|
|---|
| 1379 |
vendorURL = property(_get_vendorURL, _set_vendorURL, doc="vendor_url") |
|---|
| 1380 |
|
|---|
| 1381 |
def _get_ttVendor(self): |
|---|
| 1382 |
return self._ttVendor |
|---|
| 1383 |
|
|---|
| 1384 |
def _set_ttVendor(self, value): |
|---|
| 1385 |
self._ttVendor = value |
|---|
| 1386 |
|
|---|
| 1387 |
ttVendor = property(_get_ttVendor, _set_ttVendor, doc="vendor") |
|---|
| 1388 |
|
|---|
| 1389 |
def _get_ttUniqueID(self): |
|---|
| 1390 |
return self._ttUniqueID |
|---|
| 1391 |
|
|---|
| 1392 |
def _set_ttUniqueID(self, value): |
|---|
| 1393 |
self._ttUniqueID = value |
|---|
| 1394 |
|
|---|
| 1395 |
ttUniqueID = property(_get_ttUniqueID, _set_ttUniqueID, doc="tt_u_id") |
|---|
| 1396 |
|
|---|
| 1397 |
def _get_ttVersion(self): |
|---|
| 1398 |
return self._ttVersion |
|---|
| 1399 |
|
|---|
| 1400 |
def _set_ttVersion(self, value): |
|---|
| 1401 |
self._ttVersion = value |
|---|
| 1402 |
|
|---|
| 1403 |
ttVersion = property(_get_ttVersion, _set_ttVersion, doc="tt_version") |
|---|
| 1404 |
|
|---|
| 1405 |
def _get_unitsPerEm(self): |
|---|
| 1406 |
return self._unitsPerEm |
|---|
| 1407 |
|
|---|
| 1408 |
def _set_unitsPerEm(self, value): |
|---|
| 1409 |
self._unitsPerEm = value |
|---|
| 1410 |
|
|---|
| 1411 |
unitsPerEm = property(_get_unitsPerEm, _set_unitsPerEm, doc="") |
|---|
| 1412 |
|
|---|
| 1413 |
def _get_ascender(self): |
|---|
| 1414 |
return self._ascender |
|---|
| 1415 |
|
|---|
| 1416 |
def _set_ascender(self, value): |
|---|
| 1417 |
self._ascender = value |
|---|
| 1418 |
|
|---|
| 1419 |
ascender = property(_get_ascender, _set_ascender, doc="ascender value") |
|---|
| 1420 |
|
|---|
| 1421 |
def _get_descender(self): |
|---|
| 1422 |
return self._descender |
|---|
| 1423 |
|
|---|
| 1424 |
def _set_descender(self, value): |
|---|
| 1425 |
self._descender = value |
|---|
| 1426 |
|
|---|
| 1427 |
descender = property(_get_descender, _set_descender, doc="descender value") |
|---|
| 1428 |
|
|---|
| 1429 |
def _get_capHeight(self): |
|---|
| 1430 |
return self._capHeight |
|---|
| 1431 |
|
|---|
| 1432 |
def _set_capHeight(self, value): |
|---|
| 1433 |
self._capHeight = value |
|---|
| 1434 |
|
|---|
| 1435 |
capHeight = property(_get_capHeight, _set_capHeight, doc="cap height value") |
|---|
| 1436 |
|
|---|
| 1437 |
def _get_xHeight(self): |
|---|
| 1438 |
return self._xHeight |
|---|
| 1439 |
|
|---|
| 1440 |
def _set_xHeight(self, value): |
|---|
| 1441 |
self._xHeight = value |
|---|
| 1442 |
|
|---|
| 1443 |
xHeight = property(_get_xHeight, _set_xHeight, doc="x height value") |
|---|
| 1444 |
|
|---|
| 1445 |
def _get_defaultWidth(self): |
|---|
| 1446 |
return self._defaultWidth |
|---|
| 1447 |
|
|---|
| 1448 |
def _set_defaultWidth(self, value): |
|---|
| 1449 |
self._defaultWidth = value |
|---|
| 1450 |
|
|---|
| 1451 |
defaultWidth = property(_get_defaultWidth, _set_defaultWidth, doc="default width value") |
|---|
| 1452 |
|
|---|
| 1453 |
def _get_italicAngle(self): |
|---|
| 1454 |
return self._italicAngle |
|---|
| 1455 |
|
|---|
| 1456 |
def _set_italicAngle(self, value): |
|---|
| 1457 |
self._italicAngle = value |
|---|
| 1458 |
|
|---|
| 1459 |
italicAngle = property(_get_italicAngle, _set_italicAngle, doc="italic_angle") |
|---|
| 1460 |
|
|---|
| 1461 |
def _get_slantAngle(self): |
|---|
| 1462 |
return self._slantAngle |
|---|
| 1463 |
|
|---|
| 1464 |
def _set_slantAngle(self, value): |
|---|
| 1465 |
self._slantAngle = value |
|---|
| 1466 |
|
|---|
| 1467 |
slantAngle = property(_get_slantAngle, _set_slantAngle, doc="slant_angle") |
|---|
| 1468 |
|
|---|