├── Clone Glyph.py ├── ExportSelectedGlyphsToFL.py ├── GetAllGlyphsMarkedLikeAsSelected.py ├── GetSelectedGlyphsAsArray.py ├── GetSelectedGlyphsAsString.py ├── Import Marks and Masks from Fontlab.py ├── Interpolation Tool └── Interpolation Tool (beta).roboFontExt │ ├── html │ ├── index.html │ ├── inttoolmain.jpg │ └── inttoolshortview.jpg │ ├── info.plist │ └── lib │ ├── InterpolationLib.py │ ├── InterpolationTool.py │ ├── ReportWindow.py │ └── tempfont.ufo │ ├── fontinfo.plist │ ├── glyphs │ ├── DDbracketleft_.glif │ ├── DDbracketright_.glif │ ├── DDeight_.glif │ ├── DDfive_.glif │ ├── DDfour_.glif │ ├── DDminus_.glif │ ├── DDnine_.glif │ ├── DDone_.glif │ ├── DDseven_.glif │ ├── DDsix_.glif │ ├── DDthree_.glif │ ├── DDtwo_.glif │ ├── DDzero_.glif │ └── contents.plist │ ├── lib.plist │ └── metainfo.plist ├── LatCyrl-CharacterSet-RF.txt ├── README.md ├── Show all glyphs.py ├── TestInstallAdvanced.py ├── Version Control ├── README.md ├── VersionControl.roboFontExt │ ├── html │ │ └── index.html │ ├── info.plist │ └── lib │ │ └── VersionControl.py └── doc │ └── VersionControl-RobofontExtension.pdf ├── checkOverlaping.py ├── drawReferenceGlyph.py ├── dump All-to-All to SpaceCenter.py ├── getInterpolationFactorByStems.py ├── makeGroupsFromFeature.py ├── makeTableAlltoAll.py ├── make_ALT_fea.py ├── polygon selection tool ├── polygon-select.png └── polygonSelectionTool.py ├── removeAllGuides.py ├── renameGroupsOBSR.py └── resortGlyphOrder.py /Clone Glyph.py: -------------------------------------------------------------------------------- 1 | # RoboFont Script 2 | # Dublicate selected glyphs and rename them to NameGlyph.ver.XXX 3 | # XXX ( XXX - 001, 002 ... 999 ) 4 | # Alexander Lubovenko 5 | # http://github.com/typedev 6 | 7 | from robofab.world import CurrentFont, CurrentGlyph 8 | from mojo.UI import * 9 | from time import asctime 10 | 11 | font = CurrentFont() 12 | glyphslist = font.selection 13 | 14 | def cloneGlyph(glyph,name=''): 15 | if name == '': 16 | oldname = glyph.name 17 | else: 18 | oldname = name 19 | for i in range(1,1000): 20 | oldname = oldname.replace('.ver','') 21 | newName = '%s.ver.%03d' % (oldname, i) 22 | if newName not in font.keys(): 23 | font.insertGlyph(glyph,newName) 24 | font.update() 25 | font[newName].note = asctime() 26 | break 27 | 28 | for i in glyphslist: 29 | glyph = font[i] 30 | lname = glyph.name.split('.') 31 | if len(lname) == 1: 32 | cloneGlyph(glyph) 33 | else: 34 | gnumber = lname[-1] 35 | if gnumber.isdigit(): 36 | lname.pop() 37 | sname='.'.join(lname) 38 | cloneGlyph(glyph,sname) 39 | 40 | font.update() -------------------------------------------------------------------------------- /ExportSelectedGlyphsToFL.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.path.append( '/Users/alexander/PycharmProjects/CustomControls' ) 4 | 5 | import tdReport 6 | from robofab.world import CurrentFont, CurrentGlyph 7 | font = CurrentFont() 8 | gselected = CurrentGlyph() 9 | 10 | TOFL_MARK = (0.4, 1.0, 0.4, 1.0) 11 | EXPORTED = (0.4, 1.0, 0.4, 0.1) 12 | EXCEPT_MARK = (1.0, 0.8, 0.4, 1.0) 13 | 14 | file_ext = 'toFl' 15 | path_exp = font.path.replace('.ufo','') 16 | # filename = font.filename 17 | report = tdReport.Report(file = path_exp, ext = 'toFL', process= 'Export selected glyphs to FontLab' ) 18 | print 'Selected glyph: ', gselected.name, 'marked as', gselected.mark 19 | names = [] 20 | for gf in CurrentFont(): 21 | if gf.mark == gselected.mark: 22 | names.append(gf.name) 23 | report.add(gf.name) 24 | print names 25 | print 'Glyph list saved as: ' + path_exp + '.' + file_ext 26 | report.save() 27 | 28 | 29 | -------------------------------------------------------------------------------- /GetAllGlyphsMarkedLikeAsSelected.py: -------------------------------------------------------------------------------- 1 | gselected = CurrentGlyph() 2 | 3 | print 'Selected glyph: ', gselected.name, 'marked as', gselected.mark 4 | names = [] 5 | for gf in CurrentFont(): 6 | if gf.mark == gselected.mark: 7 | names.append(gf.name) 8 | print names 9 | namesstr = '' 10 | for n in names: 11 | namesstr = namesstr + n +' ' 12 | print namesstr 13 | -------------------------------------------------------------------------------- /GetSelectedGlyphsAsArray.py: -------------------------------------------------------------------------------- 1 | __author__ = 'alexander' 2 | 3 | stroke = '["' 4 | font = CurrentFont() 5 | 6 | for g in font.selection: 7 | stroke = stroke + g + '","' 8 | print stroke + '"]' 9 | -------------------------------------------------------------------------------- /GetSelectedGlyphsAsString.py: -------------------------------------------------------------------------------- 1 | __author__ = 'alexander' 2 | 3 | stroke = '' 4 | font = CurrentFont() 5 | 6 | for g in font.selection: 7 | g = g.replace('\n','') 8 | stroke = stroke + g + ' ' 9 | print stroke 10 | -------------------------------------------------------------------------------- /Import Marks and Masks from Fontlab.py: -------------------------------------------------------------------------------- 1 | import colorsys f = CurrentFont() MASK_LIB_KEY = "org.robofab.fontlab.maskData" MARK_LIB_KEY = "org.robofab.fontlab.mark" def portFLmark(glyph): fontLabMarkColor = 0 fontLabMarkColor = glyph.lib.get("org.robofab.fontlab.mark") if fontLabMarkColor != 0: r, g, b = colorsys.hsv_to_rgb(fontLabMarkColor/256., 1., 1.) glyph.mark = (r, g, b, .5) def portFLmaskData(glyph): #get pendata # filter out any single point contours (anchors) instructions = [] pointStack = [] lib = glyph.lib if lib.has_key(MASK_LIB_KEY): instructions = lib[MASK_LIB_KEY] pen = glyph.getPointPen() instructionsDrawPoints(instructions, pen) # clear the mask data from the glyph lib del lib[MASK_LIB_KEY] glyph.update() def instructionsDrawPoints(instructions, pointPen): """draw instructions created by InstructionPointPen""" # filter out single point contours (anchors) pointStack = [] for instruction in instructions: pointStack.append(instruction) meth = instruction["method"] if meth == "endPath": if len(pointStack) > 3: _drawPointStack(pointStack, pointPen) pointStack = [] def _drawPointStack(stack, pointPen): for instruction in stack: meth = instruction["method"] if meth == "beginPath": pointPen.beginPath() elif meth == "endPath": pointPen.endPath() elif meth == "addPoint": pt = instruction["pt"] smooth = instruction.get("smooth") segmentType = instruction.get("segmentType") name = instruction.get("name") pointPen.addPoint(pt, segmentType, smooth, name) elif meth == "addComponent": baseGlyphName = instruction["baseGlyphName"] transformation = instruction["transformation"] pointPen.addComponent(baseGlyphName, transformation) else: raise NotImplementedError, meth for glyph in f: #port the colour marks portFLmark(glyph) #create/get the layer for the mask data glyph.getLayer("FontLab Mask") #flip it so we draw on a clean layer glyph.flipLayers("FontLab Mask", "foreground") portFLmaskData(glyph) #flip back we’re done glyph.flipLayers("FontLab Mask", "foreground") print "Done" -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | documentation-eng2 7 | 8 | 20 | 21 | 22 | 23 |
24 |

Interpolation Tool

25 | 26 |

Interpolation Tool is an extension for Robofont which allows you to model interpolation and extrapolation of any number of instances between two masters. Two compatible fonts should be used as masters for interpolation. There are three methods for interpolation modeling: “Luc(as) de Groot”, “Pablo Impallari” and “Linear” method. However, each instance in the line can be adjusted with the Tuner.

27 | 28 |
29 |

Interpolation Tool may also be useful for basic masters correction, as any changes in contours of basic glyphs are displayed in Interpolation line immediately.

30 |
31 | 32 |

User interface

33 | 34 |
35 | Main Window 36 |
Main Window
37 | 38 | 39 | 40 |
    41 |
  1. Choose Interpolation Method

  2. 42 |
  3. Increasing/ decreasing the number of instances between masters

  4. 43 |
  5. The first master

  6. 44 |
  7. The second master

  8. 45 |
  9. Add extrapolation –100

  10. 46 |
  11. Add extrapolation +500

  12. 47 |
  13. View window of Instance line

  14. 48 |
  15. Instance weight

  16. 49 |
  17. Tuner instance

  18. 50 |
  19. Button to display the preview of the selected glyph or open master`s glyph edit window

  20. 51 |
  21. Button to remove the selected instance

  22. 52 |
  23. Button to generate the selected instance (currently not working)

  24. 53 |
  25. Button to generate all instances (currently not working)

  26. 54 |
55 | 56 |

View mode

57 | 58 |

A. Full View Mode (by default) – all tools are visible

59 | 60 |

B. Short View Mode – a part of tools are visible. 61 | This mode can be useful for making adjustments to glyphs` masters.

62 | 63 |

C. Controlling Instance`s Line Preview Size

64 | 65 |
66 | Short View Mode 67 |
Short View Mode
68 | 69 |
70 | 71 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/html/inttoolmain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typedev/RoboFont/d74e13781b1685a28b1e6fe59f24a42f75d74432/Interpolation Tool/Interpolation Tool (beta).roboFontExt/html/inttoolmain.jpg -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/html/inttoolshortview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typedev/RoboFont/d74e13781b1685a28b1e6fe59f24a42f75d74432/Interpolation Tool/Interpolation Tool (beta).roboFontExt/html/inttoolshortview.jpg -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | addToMenu 6 | 7 | 8 | path 9 | InterpolationTool.py 10 | preferredName 11 | InterpolationTool 12 | shortKey 13 | 14 | 15 | 16 | developer 17 | Alexander Lubovenko 18 | developerURL 19 | https://github.com/typedev 20 | html 21 | 22 | launchAtStartUp 23 | 0 24 | mainScript 25 | 26 | name 27 | Interpolation Tool (beta) 28 | requiresVersionMajor 29 | 1 30 | requiresVersionMinor 31 | 5 32 | timeStamp 33 | 1382679499.7877497 34 | version 35 | 0.8.72 36 | repository 37 | typedev/RoboFont 38 | extensionPath 39 | Interpolation Tool/Interpolation Tool (beta).roboFontExt 40 | 41 | 42 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/InterpolationLib.py: -------------------------------------------------------------------------------- 1 | from mojo.roboFont import * 2 | from time import asctime 3 | from math import * 4 | # import ReportWindow 5 | # reload(ReportWindow) 6 | 7 | redMark = (1,0,0,1) 8 | greyMark = (.2, .2, .2, .5) 9 | 10 | 11 | from vanilla import * 12 | 13 | # InterpolationReport = ReportWindow.ReportWindow('Interpolation Report') 14 | 15 | def mathVM(minVM,maxVM,factor): 16 | delta = maxVM - minVM 17 | return int(round(minVM+factor*delta,0)) 18 | 19 | class ProgressBarWindow(object): 20 | 21 | def __init__(self, Count = 0, nameOfProcess = ''): 22 | self.w = FloatingWindow((280, 65)) 23 | self.w.label = TextBox((10, 12, -10, 24), nameOfProcess) 24 | self.w.bar = ProgressBar((10, 40, -10, 16),minValue=0, maxValue = Count) 25 | self.w.center() 26 | self.w.open() 27 | 28 | def increment(self): 29 | self.w.bar.increment() 30 | 31 | def closeProgress(self): 32 | self.w.close() 33 | 34 | 35 | def decomposeGlyph(glyph): 36 | if glyph.components != None: 37 | for c in glyph.components: 38 | c.decompose() 39 | return glyph 40 | 41 | def getListOfCompatibleGlyphs(bFont,dFont, mark = True): 42 | bGlyphCount = len(bFont) 43 | dGlyphCount = len(dFont) 44 | okGlyphs = [] 45 | wrongGlyphs = [] 46 | missingGlyphs = [] 47 | Progress = ProgressBarWindow((bGlyphCount+dGlyphCount),'Checking glyphs...') 48 | copyBfont = bFont.copy() 49 | copyDfont = dFont.copy() 50 | for glyph in bFont: 51 | Progress.increment() 52 | if dFont.has_key( glyph.name ): 53 | # print "++++++++++++++++", glyph.name 54 | # aGlyph = bFont[glyph.name] 55 | # bGlyph = dFont[glyph.name] 56 | aGlyph = decomposeGlyph(copyBfont[glyph.name]) 57 | bGlyph = decomposeGlyph(copyDfont[glyph.name]) 58 | isComp = aGlyph.isCompatible (bGlyph, True) 59 | if isComp[0]: 60 | okGlyphs.append(glyph.name) 61 | else: 62 | a = ' '.join(isComp[1]) 63 | a = a.replace('Fatal error: ','') 64 | wrongGlyphs.append([glyph.name, a]) 65 | if mark: 66 | glyph.mark = redMark 67 | dFont[ glyph.name ].mark = redMark 68 | else: 69 | missingGlyphs.append([bFont.info.familyName, bFont.info.styleName, glyph.name]) 70 | if mark: 71 | glyph.mark = greyMark 72 | for glyph in dFont: 73 | Progress.increment() 74 | 75 | if bFont.has_key( glyph.name ): 76 | pass 77 | else: 78 | missingGlyphs.append([dFont.info.familyName, dFont.info.styleName, glyph.name]) 79 | if mark: 80 | glyph.mark = greyMark 81 | # bFont.update() 82 | # dFont.update() 83 | Progress.closeProgress() 84 | return okGlyphs, wrongGlyphs, missingGlyphs 85 | 86 | def getRightFontOrder(bFont,dFont): 87 | bGlyphCount = len(bFont) 88 | dGlyphCount = len(dFont) 89 | if bGlyphCount == dGlyphCount: 90 | return bFont, dFont 91 | else: 92 | if bGlyphCount > dGlyphCount: 93 | return bFont, dFont 94 | if bGlyphCount < dGlyphCount: 95 | return dFont, bFont 96 | 97 | 98 | def checkCompatibilityConsole(bFont,dFont, mark = True, report = True): 99 | # InterpolationReport.addToReport( "Interpolation Tool report" ) 100 | # InterpolationReport.addToReport( "Checking glyphs... " + asctime() ) 101 | print "Interpolation Tool report" 102 | print "Checking glyphs... ", asctime() 103 | okGlyphs = [] 104 | wrongGlyphs = [] 105 | missingGlyphs = [] 106 | 107 | 108 | aFont, bFont = getRightFontOrder(bFont,dFont) 109 | okGlyphs, wrongGlyphs, missingGlyphs = getListOfCompatibleGlyphs( aFont, bFont, mark ) 110 | 111 | 112 | if report: 113 | Progress = ProgressBarWindow(len(wrongGlyphs)+len(missingGlyphs),'Making report...') 114 | for glyph in wrongGlyphs: 115 | gname, gerror = glyph 116 | print "Incompatible:", glyph[0] ,"Reason:", gerror, "Marked RED label" 117 | Progress.increment() 118 | 119 | for glyph in missingGlyphs: 120 | print "Missing Glyph:", glyph[0], glyph[1], glyph[2], "Marked GREY label" 121 | Progress.increment() 122 | Progress.closeProgress() 123 | 124 | # for glyph in wrongGlyphs: 125 | # gname, gerror = glyph 126 | # InterpolationReport.addToReport( "Incompatible: " + glyph[0] + " Reason: " + gerror + " Marked RED label." ) 127 | # Progress.increment() 128 | 129 | # for glyph in missingGlyphs: 130 | # InterpolationReport.addToReport( "Missing Glyph: " + glyph[0] +' '+ glyph[1] +' '+ glyph[2] + " Marked GREY label." ) 131 | # Progress.increment() 132 | return okGlyphs 133 | 134 | 135 | def InterpolateFonts(minFont,maxFont, 136 | compatibleGlyphs = [], 137 | intrepolateScale = [], 138 | kerning = True, 139 | deletesmallpairs = True, 140 | lowpair = -5, 141 | highpair = 5): 142 | # InterpolationReport.addToReport( "Interpolate..." ) 143 | print "Interpolate..." 144 | 145 | aFont, bFont = getRightFontOrder(minFont, maxFont) 146 | 147 | 148 | 149 | for factor in intrepolateScale: 150 | 151 | ffactor = int(factor * 1000) 152 | if (ffactor != 0) and (ffactor != 1000): 153 | fontNewWeightName = str(ffactor) 154 | 155 | # InterpolationReport.addToReport( "Generate instance: " + fontNewWeightName + ' -- ' + asctime() ) 156 | print "Generate instance: ", fontNewWeightName, ' -- ', asctime() 157 | 158 | resultFont = NewFont(aFont.info.familyName, fontNewWeightName ) 159 | 160 | print "Dimensions:" 161 | 162 | 163 | A = minFont.info.ascender 164 | B = maxFont.info.ascender 165 | resultFont.info.ascender = mathVM(A,B,factor) 166 | 167 | print '\tAscender:', resultFont.info.ascender 168 | 169 | A = minFont.info.capHeight 170 | B = maxFont.info.capHeight 171 | resultFont.info.capHeight = mathVM(A,B,factor) 172 | 173 | print '\tCap-height', resultFont.info.capHeight 174 | 175 | A = minFont.info.xHeight 176 | B = maxFont.info.xHeight 177 | resultFont.info.xHeight = mathVM(A,B,factor) 178 | 179 | print '\tx-height', resultFont.info.xHeight 180 | 181 | A = minFont.info.descender 182 | B = maxFont.info.descender 183 | resultFont.info.descender = mathVM(A,B,factor) 184 | 185 | print '\tDescender:', resultFont.info.descender 186 | 187 | 188 | 189 | 190 | 191 | # Copy groups 192 | Progress = ProgressBarWindow(len(aFont.groups.items()),'['+fontNewWeightName+'] Copying groups...') 193 | # InterpolationReport.addToReport('Groups: ' + str(len(aFont.groups.items())) ) 194 | print 'Groups: ', str(len(aFont.groups.items())) 195 | for group, value in aFont.groups.items(): 196 | resultFont.groups[group] = value 197 | Progress.increment() 198 | Progress.closeProgress() 199 | 200 | # Interpolate kerning 201 | if kerning: 202 | resultFont.kerning.interpolate(minFont.kerning, maxFont.kerning, factor ) 203 | if deletesmallpairs: 204 | dic = {} 205 | totalPairs = len(resultFont.kerning.items()) 206 | Progress = ProgressBarWindow( totalPairs ,'['+fontNewWeightName+'] Interpolate kerning...') 207 | # InterpolationReport.addToReport('Interpolate kerning: ') 208 | # InterpolationReport.addToReport('total pairs ' + str(totalPairs) ) 209 | # InterpolationReport.addToReport('removing pairs between -5 and 5 ' ) 210 | for i in resultFont.kerning.items(): 211 | # InterpolationReport.addToReport(str(i[1]) +' '+ str(i[0])) 212 | Progress.increment() 213 | if i[1] != 0: 214 | if i[1] > highpair: 215 | dic[i[0]] = int(round(i[1])) 216 | else: 217 | if i[1] < lowpair: 218 | dic[i[0]] = int(round(i[1])) 219 | 220 | resultFont.kerning.clear() 221 | resultFont.kerning.update(dic) 222 | # InterpolationReport.addToReport('total pairs ' + str(len(resultFont.kerning.items())) ) 223 | Progress.closeProgress() 224 | 225 | # Interpolate glyphs 226 | Progress = ProgressBarWindow(len(compatibleGlyphs),'['+fontNewWeightName+'] Interpolate glyphs...') 227 | 228 | for glyphname in compatibleGlyphs: 229 | newglyph = resultFont.newGlyph( glyphname ) 230 | newglyph.interpolate (factor, minFont[ glyphname ], maxFont[ glyphname ]) 231 | newglyph.unicode = aFont[ glyphname ].unicode 232 | newglyph.update() 233 | Progress.increment() 234 | 235 | resultFont.round() 236 | 237 | Progress.closeProgress() 238 | 239 | 240 | # resultFont.glyphOrder = aFont.glyphOrder 241 | # InterpolationReport.addToReport( "Instance: " + fontNewWeightName + " done" ) 242 | print "Instance: ", fontNewWeightName, " done" 243 | 244 | minFont.update() 245 | maxFont.update() 246 | # InterpolationReport.addToReport( "All done. =)" ) 247 | # InterpolationReport.showReport() 248 | print "All done. =)" 249 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/InterpolationTool.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | RoboFont Script 4 | InterpolationTool.py 5 | 6 | Created by Alexander Lubovenko on 2013-08-26. 7 | http://github.com/typedev 8 | """ 9 | #from __future__ import division 10 | 11 | import sys 12 | from math import * 13 | from vanilla import * 14 | from mojo.UI import * 15 | from mojo.glyphPreview import GlyphPreview 16 | from mojo.events import addObserver, removeObserver 17 | from mojo.roboFont import OpenWindow 18 | from defconAppKit.windows.baseWindow import BaseWindowController 19 | from defconAppKit.controls.glyphLineView import GlyphLineView 20 | from mojo import events 21 | from mojo.drawingTools import * 22 | from mojo.canvas import Canvas 23 | import InterpolationLib #import * 24 | #import mojo.extensions 25 | # from lib.settings import applicationPluginRootPath, applicationPluginPreferencesPath, appName 26 | 27 | # print applicationPluginRootPath 28 | # print sys.path[0] 29 | # print applicationPluginPreferencesPath 30 | 31 | #reload(InterpolationLib) 32 | 33 | minStem = 1 34 | maxStem = 10 35 | 36 | intLucas = 0 37 | intImpallari = 1 38 | intLinear = 2 39 | intManual = 3 40 | 41 | viewFull = 0 42 | viewShort = 1 43 | 44 | #=================================================================================== 45 | redMark = (1, 0, 0, 1) 46 | greyMark = (.2, .2, .2, .5) 47 | 48 | previewOptions = {'Inverse': False, 'xHeight Cut': False, 'Show Kerning': True, 49 | 'Left to Right': True, 'Show Metrics': False, 'Show Space Matrix': True, 50 | 'Upside Down': False, 'Right to Left': False, 'Stroke': False, 'Beam': False, 51 | 'Water Fall': False, 'Multi Line': True, 'Single Line': False, 52 | 'Show Control glyphs': False, 'Fill': True} 53 | 54 | DDlist = {'DDzero': 0, 'DDone': 1, 55 | 'DDtwo': 2, 'DDthree': 3, 56 | 'DDfour': 4, 'DDfive': 5, 57 | 'DDsix': 6, 'DDseven': 7, 58 | 'DDeight': 8, 'DDnine': 9} 59 | 60 | DDfontPath = sys.path[0] + '/tempfont.ufo' 61 | listfonts = AllFonts() 62 | 63 | ListManualStems = '48=0 74 94 128 165 192 218=1' 64 | 65 | 66 | def getListOfOpenFonts (): 67 | lfonts = [] 68 | for n in listfonts: 69 | fontFamilyName = '' 70 | fontStyleName = '' 71 | if n.info.familyName != None: 72 | fontFamilyName = n.info.familyName 73 | if n.info.styleName != None: 74 | fontStyleName = n.info.styleName 75 | lfonts.append(fontFamilyName + '/' + fontStyleName) 76 | lfonts.sort() 77 | return lfonts 78 | 79 | 80 | def getGlyphNameString (number): 81 | st = [] 82 | if number[0] != '-': 83 | for a in number: 84 | for n, d in DDlist.items(): 85 | if d == int(a): 86 | st.append(n) 87 | else: 88 | st.append('DDminus') 89 | for a in number[1:]: 90 | for n, d in DDlist.items(): 91 | if d == int(a): 92 | st.append(n) 93 | return st 94 | 95 | 96 | def getLucasFactor (a, b, n): 97 | d = (log(b) - log(a)) / (n + 1) 98 | factor = [] 99 | for i in range(n + 2): 100 | dd = exp(log(a) + i * d) 101 | factor = factor + [round((dd - a) / (b - a), 3)] 102 | return factor 103 | 104 | 105 | def getLinearFactor (a, b, n): 106 | factor = [] 107 | c = float((b - (a - 1))) / (n + 1) 108 | for i in range(n + 2): 109 | factor = factor + [round(((a - 1) + c * i) / 10, 3)] 110 | return factor 111 | 112 | 113 | def getImpallariFactor (min, max, n): 114 | es = getLinearFactor(min, max, n) 115 | ls = getLucasFactor(min, max, n) 116 | return [round(l * (1 - i / (n + 1)) + e * (i / (n + 1)), 3) for (i, e, l) in zip(range(n + 2), es, ls)] 117 | 118 | 119 | def getFactorByStem (minStem, maxStem, midStem): 120 | if (midStem != 0) and (midStem != 1000): 121 | return 1000 * (midStem - minStem) / (maxStem - minStem) 122 | else: 123 | return midStem 124 | 125 | 126 | def getFactorListByStems (listStems): # listStems string: 10 20 30 40=0 50 60 70 80 90 100=1 110 120 127 | ld = listStems.split(' ') 128 | ls = [] 129 | lf = [] 130 | for i in ld: 131 | if '=' in i: 132 | lm = i.split('=') 133 | if lm[1] == '0': 134 | minStem = int(lm[0]) 135 | ls.append(0) 136 | if lm[1] == '1': 137 | maxStem = int(lm[0]) 138 | ls.append(1000) 139 | else: 140 | ls.append(int(i)) 141 | for i in ls: 142 | lf.append(getFactorByStem(minStem, maxStem, i) / 1000.0) 143 | return lf 144 | 145 | 146 | def decomposeGlyph (glyph): 147 | if glyph.components != None: 148 | for c in glyph.components: 149 | c.decompose() 150 | return glyph 151 | 152 | # def interpolateFonts(factor, minFont, maxFont, kerning = False): 153 | # pass 154 | 155 | #=================================================================================== 156 | 157 | def is_number (s): 158 | try: 159 | float(s) 160 | # print 'NUMBER' 161 | return True 162 | except ValueError: 163 | # print 'NOT NUMBER' 164 | return False 165 | 166 | 167 | class InterpolationWindow(BaseWindowController): 168 | class InstancesSelector(BaseWindowController): 169 | def __init__ (self, interpolationScales=[], selected=0, operation='Generate', minF=None, maxF=None): 170 | self.w = FloatingWindow((150, 300), minSize = (150, 150), maxSize = (150, 900)) 171 | # self.w.lblLabel = TextBox((10, 5, 70, 47), 'Generate selected instances:') 172 | lwBorder = -120 173 | self.w.InstancesList = List((5, 5, -5, lwBorder), [], 174 | selectionCallback = self.selectionInstanceCallback) 175 | self.w.InstancesList.setSelection([selected]) 176 | 177 | self.w.btnAction = Button((10, -32, -10, 22), operation, callback = self.btnActionCallback) 178 | 179 | self.w.chkKerning = CheckBox((10, lwBorder + 5, -10, 10), "Interpolate Kerning", value = True, 180 | sizeStyle = 'mini', callback = self.chkKerningCallback) 181 | self.w.chkDelSmallPairs = CheckBox((25, lwBorder + 20, -10, 10), "Delete small pairs", value = True, 182 | sizeStyle = 'mini', callback = self.chkDelSmallPairsCallback) 183 | 184 | self.w.lbl1 = TextBox((37, lwBorder + 37, 40, 15), 'from:', sizeStyle = 'mini') 185 | self.w.txtFrom = EditText((67, lwBorder + 35, 25, 15), '-5', sizeStyle = 'mini') 186 | self.w.lbl2 = TextBox((98, lwBorder + 37, 40, 15), 'to:', sizeStyle = 'mini') 187 | self.w.txtTo = EditText((115, lwBorder + 35, 25, 15), '5', sizeStyle = 'mini') 188 | 189 | self.w.chkReport = CheckBox((10, lwBorder + 53, -10, 10), "Make Report (slowly)", value = True, 190 | sizeStyle = 'mini') 191 | self.w.chkColorMark = CheckBox((10, lwBorder + 68, -10, 10), "Marks problem glyphs", value = True, 192 | sizeStyle = 'mini') 193 | 194 | # self.w.chkReport = CheckBox((10, 10, -10, 10), "Report", value=True, sizeStyle='mini') 195 | 196 | 197 | self.setListInstances(interpolationScales, selected) 198 | self.minFontName = minF 199 | self.maxFontName = maxF 200 | 201 | self.setUpBaseWindowBehavior() 202 | self.w.center() 203 | self.w.show() 204 | 205 | def setDelSmallPairs (self, value=True): 206 | if value: 207 | self.w.txtFrom.enable(True) 208 | self.w.lbl1.enable(True) 209 | self.w.lbl2.enable(True) 210 | self.w.txtTo.enable(True) 211 | self.w.txtFrom.set('-5') 212 | self.w.txtTo.set('5') 213 | else: 214 | self.w.txtFrom.enable(False) 215 | self.w.lbl1.enable(False) 216 | self.w.lbl2.enable(False) 217 | self.w.txtTo.enable(False) 218 | self.w.txtFrom.set('-5') 219 | self.w.txtTo.set('5') 220 | 221 | def chkDelSmallPairsCallback (self, sender): 222 | if self.w.chkDelSmallPairs.get(): 223 | self.setDelSmallPairs(True) 224 | else: 225 | self.setDelSmallPairs(False) 226 | 227 | def chkKerningCallback (self, sender): 228 | if self.w.chkKerning.get(): 229 | self.w.chkDelSmallPairs.enable(True) 230 | self.w.chkDelSmallPairs.set(True) 231 | self.setDelSmallPairs(True) 232 | else: 233 | self.w.chkDelSmallPairs.enable(False) 234 | self.w.chkDelSmallPairs.set(False) 235 | self.setDelSmallPairs(False) 236 | 237 | 238 | def InterpolateInstances (self, scale): 239 | glyphlist = [] 240 | minFamily, minStyle = self.minFontName 241 | maxFamily, maxStyle = self.maxFontName 242 | 243 | _report = self.w.chkReport.get() 244 | _kerning = self.w.chkKerning.get() 245 | _deletesmallpairs = self.w.chkDelSmallPairs.get() 246 | _mark = self.w.chkColorMark.get() 247 | 248 | if is_number(self.w.txtFrom.get()): 249 | _lowpair = int(self.w.txtFrom.get()) 250 | else: 251 | _deletesmallpairs = False 252 | print 'Wrong number!', _lowpair 253 | if is_number(self.w.txtTo.get()): 254 | _highpair = int(self.w.txtTo.get()) 255 | else: 256 | _deletesmallpairs = False 257 | print 'Wrong number!', _highpair 258 | 259 | glyphlist = InterpolationLib.checkCompatibilityConsole( 260 | listfonts.getFontsByFamilyNameStyleName(minFamily, minStyle), 261 | listfonts.getFontsByFamilyNameStyleName(maxFamily, maxStyle), 262 | mark = _mark, 263 | report = _report) 264 | 265 | InterpolationLib.InterpolateFonts(listfonts.getFontsByFamilyNameStyleName(minFamily, minStyle), 266 | listfonts.getFontsByFamilyNameStyleName(maxFamily, maxStyle), 267 | compatibleGlyphs = glyphlist, 268 | intrepolateScale = scale, 269 | kerning = _kerning, 270 | deletesmallpairs = _deletesmallpairs, 271 | lowpair = _lowpair, 272 | highpair = _highpair) 273 | 274 | 275 | def selectionInstanceCallback (self, sender): 276 | pass 277 | 278 | def setListInstances (self, interpolationScales=[], selected=0): 279 | self.w.InstancesList.set([]) 280 | for i in interpolationScales: 281 | ins = str(int(i * 1000)) 282 | self.w.InstancesList.append(ins) 283 | self.w.InstancesList.setSelection([selected]) 284 | self.w.InstancesList.scrollToSelection() 285 | self.w.InstancesList.remove('0') 286 | self.w.InstancesList.remove('1000') 287 | 288 | def getSelectedInstances (self): 289 | selectedInstances = [] 290 | sellist = self.w.InstancesList.getSelection() 291 | for i in sellist: 292 | selectedInstances.append(round(float(self.w.InstancesList[i]) / 1000, 3)) 293 | return selectedInstances 294 | 295 | def windowCloseCallback (self, sender): 296 | super(InstancesSelector, self).windowCloseCallback(sender) 297 | 298 | def btnActionCallback (self, sender): 299 | scale = [] 300 | scale = self.getSelectedInstances() 301 | self.w.hide() 302 | self.InterpolateInstances(scale) 303 | 304 | 305 | def __init__ (self, font): 306 | self.interpolatingSteps = 5 307 | self.pointSize = 150 308 | self.viewMode = viewFull 309 | self.resizeInProgress = False 310 | 311 | self.w = Window((1000, 450), minSize = (400, 150), title = 'Interpolation Tool (beta 0.8.72)') 312 | 313 | # Upper panel 314 | 315 | self.w.p1 = Group((0, 0, -0, 100)) 316 | self.w.p1.lblMethod = TextBox((10, 23, 70, 17), 'Method') 317 | self.w.p1.radioSelectMethod = RadioGroup((70, 5, 160, 55), #(70, 1, 160, 65) 318 | ["Luc(as) de Groot", "Pablo Impallari", "Linear"], #,"Manual"], 319 | sizeStyle = 'small', 320 | callback = self.radioSelectMethodCallback) 321 | 322 | # self.w.p1.txtStemsLine = 323 | 324 | self.w.p1.radioSelectMethod.set(0) 325 | self.w.p1.vline = VerticalLine((210, 6, 1, 53)) 326 | 327 | self.w.p1.hline = HorizontalLine((10, 65, -10, 1)) 328 | self.w.p1.lblAxis0001 = TextBox((230, 12, 100, 17), "Axis 00/01") 329 | 330 | self.w.p1.lblMinFont = TextBox((10, 75, 60, 17), "Axis 00") 331 | self.w.p1.cbMinFont = ComboBox((70, 72, 200, 21), 332 | getListOfOpenFonts(), 333 | callback = self.cbSelectFontCallback) 334 | self.w.p1.lblMaxFont = TextBox((-270, 75, 60, 17), "Axis 01") 335 | self.w.p1.cbMaxFont = ComboBox((-210, 72, 200, 21), 336 | getListOfOpenFonts(), 337 | callback = self.cbSelectFontCallback) 338 | self.w.p1.btnAddLowExtra = Button((280, 73, 100, 20), "- 100 Extra", #48 339 | callback = self.btnAddLowExtraCallback) 340 | self.w.p1.btnAddHighExtra = Button((-380, 73, 100, 20), "+ 500 Extra", #48 341 | callback = self.btnAddHighExtraCallback) 342 | 343 | self.w.p1.btnAddStep = Button((300, 35, 60, 20), "+ step", #48 344 | callback = self.btnAddStepCallback) 345 | self.w.p1.btnDelStep = Button((230, 35, 60, 20), "- step", 346 | callback = self.btnDelStepCallback) 347 | self.w.p1.vline2 = VerticalLine((380, 6, 1, 53)) 348 | 349 | # Glyphs lineview 350 | 351 | self.w.lineView = MultiLineView((0, 100, -0, -80), 352 | pointSize = self.pointSize, 353 | lineHeight = self.pointSize * 1.75, 354 | bordered = True, 355 | hasVerticalScroller = True, 356 | # displayOptions = dict(previewOptions), 357 | selectionCallback = self.lineViewSelectionCallback) 358 | 359 | self.w.lblStatus = TextBox((15, -105, -20, 17), 'Status bar') 360 | self.w.lineView.setFont(font) 361 | 362 | # View panel 363 | 364 | self.w.pV = Group((-270, 12, 250, 100)) 365 | segments = [{'width': 40, 'title': 'Full'}, {'width': 40, 'title': 'Short'}] 366 | yPosV = 10 367 | xPosV = 0 368 | self.w.pV.btnPreviwGlyphSmall = Button((0, yPosV + 3, 65, 14), 'Preview...', 369 | sizeStyle = 'mini', 370 | callback = self.btnPreviwButtonCallback) 371 | self.w.pV.btnSwitchViewMode = SegmentedButton((70, yPosV, 90, 20), 372 | segmentDescriptions = segments, 373 | selectionStyle = 'one', sizeStyle = 'mini', #48 374 | callback = self.btnSwitchViewMode) 375 | self.w.pV.btnSwitchViewMode.set(0) 376 | self.w.pV.lblGlyphBtnHint = TextBox((15, 0, 100, 12), "Glyph", sizeStyle = 'mini') 377 | 378 | self.w.pV.lblViewMode = TextBox((85, 0, 100, 12), "View mode", sizeStyle = 'mini') 379 | self.w.pV.lblPointSize = TextBox((175, 0, 100, 12), "Preview size", sizeStyle = 'mini') 380 | self.w.pV.sliderPointSize = Slider((165, yPosV + 3, 80, 17), 381 | stopOnTickMarks = False, 382 | callback = self.sliderPointSizeCallback, 383 | sizeStyle = 'mini') 384 | self.w.pV.sliderPointSize.enable(True) 385 | self.w.pV.sliderPointSize.setMinValue(72) 386 | self.w.pV.sliderPointSize.setMaxValue(512) 387 | self.w.pV.sliderPointSize.set(self.pointSize) 388 | self.w.pV.lblGlyphBtnHint.show(False) 389 | self.w.pV.btnPreviwGlyphSmall.show(False) 390 | 391 | # Bottom panel 392 | 393 | self.w.p2 = Group((0, -80, -0, -0)) 394 | self.w.p2.lblTuner0001 = TextBox((10, -68, 100, 17), "Tuner 00/01") 395 | self.w.p2.sliderFactor = Slider((110, -65, 210, 23), 396 | tickMarkCount = 2, 397 | stopOnTickMarks = False, 398 | callback = self.sliderFactorCallback) 399 | self.w.p2.sliderFactor.enable(False) 400 | self.w.p2.sliderFactor.setMinValue(0) 401 | self.w.p2.sliderFactor.setMaxValue(1000) 402 | self.w.p2.sliderFactor.set(500) 403 | self.w.p2.lblMin = TextBox((110, -38, 70, 17), '0', alignment = 'left') 404 | self.w.p2.lblMax = TextBox((250, -38, 70, 17), '1000', alignment = 'right') 405 | self.w.p2.lblCurrent = TextBox((185, -38, 60, 17), '500', alignment = 'center') 406 | self.w.p2.lblMin.show(False) 407 | self.w.p2.lblMax.show(False) 408 | self.w.p2.lblCurrent.show(False) 409 | 410 | self.w.p2.vline3 = VerticalLine((340, -73, 1, -10)) 411 | 412 | self.w.p2.btnPreviwGlyph = Button((360, -70, 130, 20), "Preview glyph...", 413 | callback = self.btnPreviwButtonCallback) 414 | self.w.p2.btnDeleteInstance = Button((360, -40, 130, 20), "Delete Instance", 415 | callback = self.btnDeleteInstanceCallback) 416 | self.w.p2.spinner = ProgressSpinner((503, 20, 32, 32), 417 | displayWhenStopped = False) 418 | # self.w.p2.btnGenerateSeleced = Button((-220, -70, -10, 20), "Generate Selected Instance...", 419 | # callback=self.btnGenerateSelectedCallback) 420 | self.w.p2.btnGenerateAll = Button((-220, -40, -10, 20), "Generate Instances...", 421 | callback = self.btnGenerateAllCallback) 422 | # self.w.p2.btnGenerateSeleced.enable(False) 423 | self.w.p2.btnGenerateAll.enable(False) 424 | self.w.p2.btnDeleteInstance.enable(False) 425 | 426 | # Init section 427 | 428 | self.minFont = None 429 | self.minFontName = [] 430 | self.maxFont = None 431 | self.minFontName = [] 432 | self.DDfont = OpenFont(DDfontPath, showUI = False) 433 | 434 | self.indexSelectedGlyph = None 435 | self.interpolateMethod = intLucas 436 | self.setInterpolateScale() 437 | self.drawGlyphsLine(dict(glyph = None)) 438 | 439 | self.w.bind('resize', self.windowResize) 440 | events.addObserver(self, "drawMessagePreviewOnly", 'draw') 441 | events.addObserver(self, "drawGlyphsLine", "currentGlyphChanged") 442 | events.addObserver(self, "drawGlyphsLine", "draw") 443 | 444 | self.setUpBaseWindowBehavior() 445 | self.w.center() 446 | self.w.open() 447 | 448 | def changeViewMode (self): 449 | wS = self.w.getPosSize() 450 | lS = self.w.lineView.getPosSize() 451 | self.resizeInProgress = True 452 | if self.viewMode == viewShort: 453 | self.w.pV.setPosSize((-270, 2, 250, 100)) 454 | self.w.p1.show(False) 455 | self.w.pV.lblGlyphBtnHint.show(True) 456 | self.w.pV.btnPreviwGlyphSmall.show(True) 457 | self.w.lineView.setPosSize((0, 0, -0, -0)) 458 | self.w.p2.show(False) 459 | hW = wS[3] + lS[3] - lS[1] 460 | self.w.resize(wS[2], hW) 461 | else: 462 | self.w.pV.setPosSize((-270, 12, 250, 100)) 463 | self.w.p1.show(True) 464 | self.w.p2.show(True) 465 | self.w.pV.lblGlyphBtnHint.show(False) 466 | self.w.pV.btnPreviwGlyphSmall.show(False) 467 | if wS[2] < 770: 468 | hW = 770 469 | else: 470 | hW = wS[2] 471 | self.w.resize(hW, wS[3] + 180) 472 | self.w.lineView.setPosSize((0, 100, -0, -80)) 473 | self.resizeInProgress = False 474 | 475 | def btnSwitchViewMode (self, sender): 476 | if sender.get() != self.viewMode: 477 | self.viewMode = sender.get() 478 | self.changeViewMode() 479 | 480 | def windowResize (self, sender): 481 | wS = self.w.getPosSize() 482 | if (wS[3] < 313) or (wS[2] < 770): 483 | if not self.resizeInProgress: 484 | self.viewMode = viewShort 485 | self.w.pV.btnSwitchViewMode.set(1) 486 | self.changeViewMode() 487 | 488 | def windowCloseCallback (self, sender): 489 | events.removeObserver(self, "draw") 490 | events.removeObserver(self, "currentGlyphChanged") 491 | super(InterpolationWindow, self).windowCloseCallback(sender) 492 | 493 | def drawMessagePreviewOnly (self, info): 494 | glyph = info["glyph"] 495 | if self.minFont.has_key(glyph.name) and self.maxFont.has_key(glyph.name): pass 496 | else: 497 | r = 0 498 | g = 0 499 | b = 0 500 | a = .5 501 | font("Menlo", 20) 502 | stroke(None) 503 | fill(r, g, b, a) 504 | text('Preview ONLY. Any changes will be lost.', (20, -40)) 505 | 506 | def sliderPointSizeCallback (self, sender): 507 | self.pointSize = sender.get() 508 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 509 | 510 | def btnAddLowExtraCallback (self, sender): 511 | minf = self.interpolateScale[0] 512 | self.interpolateScale.insert(0, minf - .1) 513 | self.indexSelectedGlyph = None 514 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 515 | 516 | def btnAddHighExtraCallback (self, sender): 517 | maxf = self.interpolateScale[-1] 518 | self.interpolateScale.append(maxf + .5) 519 | self.indexSelectedGlyph = None 520 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 521 | 522 | def btnDeleteInstanceCallback (self, sender): 523 | self.interpolateScale.pop(self.indexSelectedGlyph) 524 | self.indexSelectedGlyph = None 525 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 526 | 527 | def sliderFactorCallback (self, sender): 528 | if self.indexSelectedGlyph != None: 529 | factor = round(float(sender.get()) / 1000, 3) 530 | # if factor != 1000: 531 | self.interpolateScale[self.indexSelectedGlyph] = factor 532 | # else: 533 | # self.interpolateScale[self.indexSelectedGlyph] = factor + 1 534 | self.w.p2.lblCurrent.set(str(int(factor * 1000))) 535 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 536 | 537 | def blockSlider (self, showFactor=0): 538 | self.w.p2.lblMin.set(0) 539 | self.w.p2.lblMax.set(10) 540 | self.w.p2.sliderFactor.set(5) 541 | self.w.p2.lblMin.show(False) 542 | self.w.p2.lblMax.show(False) 543 | self.w.p2.sliderFactor.enable(False) 544 | self.w.p2.lblCurrent.show(True) 545 | self.w.p2.lblCurrent.set(str(showFactor)) 546 | 547 | # self.w.p2.btnGenerateSeleced.enable(False) 548 | 549 | 550 | def openSelectedGlyph (self): 551 | cg = CurrentGlyph() 552 | minFamily, minStyle = self.minFontName 553 | maxFamily, maxStyle = self.maxFontName 554 | lineGlyphs = self.w.lineView.get() 555 | selectedname = lineGlyphs[self.indexSelectedGlyph].name 556 | if selectedname != '0' and selectedname != '1000': 557 | tempname = cg.name + '.' + selectedname + '.Preview.' 558 | self.DDfont.newGlyph(tempname, clear = True) 559 | self.DDfont[tempname] = self.DDfont[selectedname].copy() 560 | for c in self.DDfont[tempname].components: 561 | self.DDfont[tempname].removeComponent(c) 562 | self.DDfont.round() 563 | OpenGlyphWindow(self.DDfont[tempname]) 564 | elif selectedname == '0': 565 | OpenGlyphWindow(listfonts.getFontsByFamilyNameStyleName(minFamily, minStyle)[cg.name]) 566 | elif selectedname == '1000': 567 | OpenGlyphWindow(listfonts.getFontsByFamilyNameStyleName(maxFamily, maxStyle)[cg.name]) 568 | 569 | def btnPreviwButtonCallback (self, sender): 570 | self.openSelectedGlyph() 571 | 572 | def radioSelectMethodCallback (self, sender): 573 | self.interpolateMethod = sender.get() 574 | self.setInterpolateScale() 575 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 576 | 577 | def btnAddStepCallback (self, sender): 578 | self.interpolatingSteps = self.interpolatingSteps + 1 579 | self.setInterpolateScale() 580 | self.indexSelectedGlyph = None 581 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 582 | 583 | def btnDelStepCallback (self, sender): 584 | if self.interpolatingSteps != 1: 585 | self.interpolatingSteps = self.interpolatingSteps - 1 586 | self.indexSelectedGlyph = None 587 | self.setInterpolateScale() 588 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 589 | 590 | 591 | def interpolateFonts (self, scale=[]): 592 | pass 593 | 594 | 595 | # def btnGenerateSelectedCallback(self,sender): 596 | # self.interpolateFonts(selectedOnly = True) 597 | 598 | def btnGenerateAllCallback (self, sender): 599 | Selector = self.InstancesSelector(interpolationScales = self.interpolateScale, 600 | selected = self.indexSelectedGlyph, 601 | operation = "Generate", 602 | minF = self.minFontName, 603 | maxF = self.maxFontName) 604 | 605 | # print Selector.getSelectedInstances() 606 | 607 | # self.interpolateFonts(selectedOnly = False) 608 | 609 | def cbSelectFontCallback (self, sender): 610 | self.w.p2.spinner.start() 611 | lfonts = getListOfOpenFonts() 612 | if sender.get() in lfonts: 613 | l2 = [] 614 | l1 = sender.get() 615 | l2 = l1.split('/') 616 | if sender == self.w.p1.cbMinFont: 617 | self.minFontName = l2 618 | self.minFont = listfonts.getFontsByFamilyNameStyleName(l2[0], l2[1]).copy() 619 | if sender == self.w.p1.cbMaxFont: 620 | self.maxFontName = l2 621 | self.maxFont = listfonts.getFontsByFamilyNameStyleName(l2[0], l2[1]).copy() 622 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 623 | self.w.p2.spinner.stop() 624 | 625 | # def lineViewDoubleSelectionCallback (self, sender): 626 | # self.openSelectedGlyph() 627 | 628 | def lineViewSelectionCallback (self, sender): 629 | lineGlyphs = self.w.lineView.get() 630 | selGlyph = self.w.lineView.getSelectedGlyph() 631 | # self.nameOfSelectedGlyph = selGlyph.name 632 | if selGlyph != None: 633 | i = 0 634 | for g in lineGlyphs: 635 | if selGlyph.name == g.name: 636 | self.indexSelectedGlyph = i 637 | break 638 | i = i + 1 639 | 640 | factor = int(selGlyph.name) 641 | if (factor != 0) and (factor != 1000): 642 | self.w.p2.sliderFactor.enable(True) 643 | 644 | if factor > 1000: 645 | minf = int(lineGlyphs[self.indexSelectedGlyph - 1].name) + 10 646 | else: 647 | minf = int(lineGlyphs[self.indexSelectedGlyph - 1].name) + 1 648 | 649 | if factor < 1000: 650 | maxf = int(lineGlyphs[self.indexSelectedGlyph + 1].name) - 1 651 | else: 652 | if factor == int(lineGlyphs[-1].name): 653 | maxf = factor + 500 654 | else: 655 | maxf = int(lineGlyphs[self.indexSelectedGlyph + 1].name) - 1 656 | 657 | if factor < 0: 658 | maxf = int(lineGlyphs[self.indexSelectedGlyph + 1].name) - 1 659 | if factor == int(lineGlyphs[0].name): 660 | minf = factor - 100 661 | else: 662 | minf = int(lineGlyphs[self.indexSelectedGlyph - 1].name) + 1 663 | 664 | self.w.p2.sliderFactor.setMaxValue(maxf) 665 | self.w.p2.lblMax.set(str(maxf)) 666 | self.w.p2.lblMax.show(True) 667 | 668 | self.w.p2.sliderFactor.setMinValue(minf) 669 | self.w.p2.lblMin.show(True) 670 | self.w.p2.lblMin.set(str(minf)) 671 | 672 | self.w.p2.sliderFactor.set(factor) 673 | self.w.p2.lblCurrent.set(str(factor)) 674 | self.w.p2.lblCurrent.show(True) 675 | self.w.pV.btnPreviwGlyphSmall.setTitle('Preview...') 676 | self.w.p2.btnPreviwGlyph.setTitle('Preview glyph...') 677 | self.w.p2.btnDeleteInstance.enable(True) 678 | # self.w.p2.btnGenerateSeleced.enable(True) 679 | else: 680 | self.w.p2.btnPreviwGlyph.setTitle('Edit glyph...') 681 | self.w.pV.btnPreviwGlyphSmall.setTitle('Edit...') 682 | self.w.p2.btnDeleteInstance.enable(False) 683 | self.blockSlider(factor) 684 | 685 | self.drawGlyphsLine(dict(glyph = CurrentGlyph())) 686 | 687 | 688 | def setInterpolateScale (self): 689 | if self.interpolateMethod == intLucas: 690 | self.interpolateScale = getLucasFactor(minStem, maxStem, self.interpolatingSteps) 691 | if self.interpolateMethod == intImpallari: 692 | self.interpolateScale = getImpallariFactor(minStem, maxStem, self.interpolatingSteps) 693 | if self.interpolateMethod == intLinear: 694 | self.interpolateScale = getLinearFactor(minStem, maxStem, self.interpolatingSteps) 695 | if self.interpolateMethod == intManual: 696 | self.interpolateScale = getFactorListByStems(ListManualStems) 697 | 698 | def drawGlyphsLine (self, info): 699 | self.w.lblStatus.set('') 700 | if self.minFont and self.maxFont: 701 | self.w.p2.btnGenerateAll.enable(True) 702 | if self.indexSelectedGlyph == None: 703 | self.blockSlider() 704 | 705 | glyph = CurrentGlyph() 706 | glyphs = [] 707 | 708 | if glyph is not None: 709 | glyphName = glyph.name 710 | idx = 0 711 | if self.minFont.has_key(glyphName) and self.maxFont.has_key(glyphName): 712 | minFamily, minStyle = self.minFontName 713 | maxFamily, maxStyle = self.maxFontName 714 | self.minFont.removeGlyph(glyphName) 715 | self.maxFont.removeGlyph(glyphName) 716 | self.minFont.insertGlyph(listfonts.getFontsByFamilyNameStyleName(minFamily, minStyle)[glyphName], 717 | name = glyphName) 718 | self.maxFont.insertGlyph(listfonts.getFontsByFamilyNameStyleName(maxFamily, maxStyle)[glyphName], 719 | name = glyphName) 720 | sg = decomposeGlyph(self.minFont[glyphName]) 721 | dg = decomposeGlyph(self.maxFont[glyphName]) 722 | 723 | ### 724 | # sg.leftMargin = 50 725 | # sg.rightMargin = 50 726 | # dg.leftMargin = 50 727 | # sg.rightMargin = 50 728 | ### 729 | 730 | for i in self.interpolateScale: 731 | gname = str(int(i * 1000)) 732 | g = self.DDfont.newGlyph(gname, clear = True) 733 | 734 | isComp = sg.isCompatible(dg, True) 735 | if isComp[0]: 736 | g.interpolate(i, sg, dg) 737 | stname = getGlyphNameString(gname) 738 | ddXpos = 0 739 | ddYpos = -310 740 | if idx == self.indexSelectedGlyph: 741 | g.appendComponent('DDbracketleft', (ddXpos, ddYpos + 4 ), (.08, .08)) 742 | ddXpos = ddXpos + 70 743 | 744 | for a in stname: 745 | g.appendComponent(a, (ddXpos, ddYpos), (.08, .08)) 746 | ddXpos = ddXpos + 70 747 | 748 | if idx == self.indexSelectedGlyph: 749 | g.appendComponent('DDbracketright', (ddXpos, ddYpos + 4 ), (.08, .08)) 750 | 751 | idx = idx + 1 752 | g.update() 753 | glyphs.append(g) 754 | else: 755 | # pass 756 | self.w.lblStatus.set(' '.join(isComp[1])) 757 | 758 | # self.w.lineView.setDisplayStates(previewOptions) 759 | self.w.lineView.setPointSize(self.pointSize) 760 | self.w.lineView.set(glyphs) 761 | 762 | 763 | InterpolationWindow(CurrentFont()) 764 | 765 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/ReportWindow.py: -------------------------------------------------------------------------------- 1 | #Embedded file name: /Users/alexander/Documents/WORKS/typedev/RoboFont/dev/OutputWindow.py 2 | """ 3 | RoboFont Script 4 | ReportWindow.py 5 | 6 | Created by Alexander Lubovenko on 2013-10-24. 7 | http://github.com/typedev 8 | """ 9 | from vanilla import * 10 | from AppKit import * 11 | # import codecs 12 | from time import asctime 13 | import sys, subprocess 14 | 15 | class ReportWindow(object): 16 | 17 | def __init__(self, titleReport = 'Report'): 18 | global _bufferTxT 19 | self.w = FloatingWindow((900, 500), title = titleReport, minSize=(360, 270)) 20 | self.w.textBox = TextEditor((0, 0, 0, -50), '') 21 | self.w.textBox.getNSTextView().setRichText_(False) 22 | self.w.textBox.getNSTextView().setUsesFontPanel_(False) 23 | color = NSColor.colorWithCalibratedRed_green_blue_alpha_(20.0 / 255.0, 20.0 / 255.0, 20.0 / 255.0, 1) 24 | self.w.textBox.getNSTextView().setBackgroundColor_(color) 25 | self.w.textBox.getNSTextView().setTextColor_(NSColor.whiteColor()) 26 | self.w.textBox.getNSTextView().setFont_(NSFont.fontWithName_size_('Menlo', 14)) 27 | self.w.btnClose = Button((-80, -40, 65, 22), 'Close', callback=self.btnCloseCallback) 28 | self.w.center() 29 | self.report = [] 30 | 31 | def btnCloseCallback(self, sender): 32 | self.w.hide() 33 | 34 | def showReport(self): 35 | text = '\n'.join(self.report) 36 | self.w.textBox.set(text) 37 | self.w.textBox.getNSTextView().scrollRangeToVisible_((len(text), 0)) 38 | self.w.center() 39 | self.w.show() 40 | 41 | def addToReport(self, txt = ''): 42 | self.report.append(txt) 43 | 44 | 45 | if __name__ == '__main__': 46 | report = ReportWindow(titleReport = 'Test ReportWindow') 47 | for i in range(10): 48 | report.addToReport(str(i) +'. Test Report Window. '+asctime()) 49 | # report.addToReport('Test Report Window 2'+asctime()) 50 | report.showReport() -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 770 7 | capHeight 8 | 700 9 | descender 10 | -230 11 | familyName 12 | Temporary Font 13 | italicAngle 14 | 0.0 15 | macintoshFONDFamilyID 16 | 128 17 | openTypeHeadLowestRecPPEM 18 | 9 19 | openTypeHheaAscender 20 | 885 21 | openTypeHheaDescender 22 | -235 23 | openTypeHheaLineGap 24 | 0 25 | openTypeNameLicenseURL 26 | 27 | openTypeOS2CodePageRanges 28 | 29 | 30 | openTypeOS2FamilyClass 31 | 32 | 0 33 | 0 34 | 35 | openTypeOS2Panose 36 | 37 | 2 38 | 6 39 | 5 40 | 9 41 | 2 42 | 2 43 | 5 44 | 2 45 | 2 46 | 4 47 | 48 | openTypeOS2StrikeoutPosition 49 | 250 50 | openTypeOS2StrikeoutSize 51 | 50 52 | openTypeOS2SubscriptXOffset 53 | 0 54 | openTypeOS2SubscriptXSize 55 | 650 56 | openTypeOS2SubscriptYOffset 57 | 75 58 | openTypeOS2SubscriptYSize 59 | 600 60 | openTypeOS2SuperscriptXOffset 61 | 0 62 | openTypeOS2SuperscriptXSize 63 | 650 64 | openTypeOS2SuperscriptYOffset 65 | 350 66 | openTypeOS2SuperscriptYSize 67 | 600 68 | openTypeOS2Type 69 | 70 | 71 | openTypeOS2TypoAscender 72 | 770 73 | openTypeOS2TypoDescender 74 | -230 75 | openTypeOS2TypoLineGap 76 | 120 77 | openTypeOS2UnicodeRanges 78 | 79 | 0 80 | 1 81 | 2 82 | 3 83 | 5 84 | 6 85 | 7 86 | 10 87 | 32 88 | 33 89 | 34 90 | 35 91 | 37 92 | 38 93 | 39 94 | 44 95 | 45 96 | 46 97 | 47 98 | 63 99 | 65 100 | 101 | openTypeOS2VendorID 102 | type 103 | openTypeOS2WeightClass 104 | 400 105 | openTypeOS2WidthClass 106 | 5 107 | openTypeOS2WinAscent 108 | 885 109 | openTypeOS2WinDescent 110 | 235 111 | postscriptBlueFuzz 112 | 1 113 | postscriptBlueScale 114 | 0.039625 115 | postscriptBlueShift 116 | 7 117 | postscriptBlueValues 118 | 119 | 120 | postscriptDefaultWidthX 121 | 500 122 | postscriptFamilyBlues 123 | 124 | 125 | postscriptFamilyOtherBlues 126 | 127 | 128 | postscriptForceBold 129 | 130 | postscriptIsFixedPitch 131 | 132 | postscriptOtherBlues 133 | 134 | 135 | postscriptSlantAngle 136 | 0.0 137 | postscriptStemSnapH 138 | 139 | 140 | postscriptStemSnapV 141 | 142 | 143 | postscriptUnderlinePosition 144 | -75 145 | postscriptUnderlineThickness 146 | 50 147 | postscriptUniqueID 148 | -1 149 | postscriptWindowsCharacterSet 150 | 1 151 | styleMapFamilyName 152 | Temporary Font Regular 153 | styleMapStyleName 154 | regular 155 | styleName 156 | Regular 157 | unitsPerEm 158 | 1000 159 | versionMajor 160 | 1 161 | versionMinor 162 | 3 163 | xHeight 164 | 500 165 | year 166 | 0 167 | 168 | 169 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDbracketleft_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | com.typemytype.robofont.layerData 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDbracketright_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | com.typemytype.robofont.layerData 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDeight_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | com.typemytype.robofont.layerData 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDfive_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | com.typemytype.robofont.layerData 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDfour_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | com.typemytype.robofont.layerData 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDminus_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | com.typemytype.robofont.layerData 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDnine_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | com.typemytype.robofont.layerData 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDone_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | com.typemytype.robofont.layerData 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDseven_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | com.typemytype.robofont.layerData 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDsix_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | com.typemytype.robofont.layerData 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDthree_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | com.typemytype.robofont.layerData 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDtwo_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | com.typemytype.robofont.layerData 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/DDzero_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | com.typemytype.robofont.layerData 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DDbracketleft 6 | DDbracketleft_.glif 7 | DDbracketright 8 | DDbracketright_.glif 9 | DDeight 10 | DDeight_.glif 11 | DDfive 12 | DDfive_.glif 13 | DDfour 14 | DDfour_.glif 15 | DDminus 16 | DDminus_.glif 17 | DDnine 18 | DDnine_.glif 19 | DDone 20 | DDone_.glif 21 | DDseven 22 | DDseven_.glif 23 | DDsix 24 | DDsix_.glif 25 | DDthree 26 | DDthree_.glif 27 | DDtwo 28 | DDtwo_.glif 29 | DDzero 30 | DDzero_.glif 31 | 32 | 33 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/lib.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.typedev.markers.groupsclear 6 | Cleared 7 | com.typemytype.robofont.compileSettings.autohint 8 | 9 | com.typemytype.robofont.compileSettings.checkOutlines 10 | 11 | com.typemytype.robofont.compileSettings.decompose 12 | 13 | com.typemytype.robofont.compileSettings.generateFormat 14 | 0 15 | com.typemytype.robofont.compileSettings.releaseMode 16 | 17 | com.typemytype.robofont.foreground.layerStrokeColor 18 | 19 | 0.5 20 | 0.0 21 | 0.5 22 | 0.7 23 | 24 | com.typemytype.robofont.italicSlantOffset 25 | 0 26 | com.typemytype.robofont.layerOrder 27 | 28 | 29 | com.typemytype.robofont.segmentType 30 | curve 31 | com.typemytype.robofont.shouldAddPointsInSplineConversion 32 | 33 | com.typemytype.robofont.sort 34 | 35 | 36 | ascending 37 | 38 | zero 39 | one 40 | two 41 | three 42 | four 43 | five 44 | six 45 | seven 46 | eight 47 | nine 48 | bracketleft 49 | bracketright 50 | minus 51 | 52 | type 53 | glyphList 54 | 55 | 56 | org.robofab.glyphOrder 57 | 58 | bracketleft 59 | bracketright 60 | eight 61 | five 62 | four 63 | nine 64 | one 65 | seven 66 | six 67 | three 68 | two 69 | zero 70 | 71 | public.glyphOrder 72 | 73 | zero 74 | one 75 | two 76 | three 77 | four 78 | five 79 | six 80 | seven 81 | eight 82 | nine 83 | bracketleft 84 | bracketright 85 | minus 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Interpolation Tool/Interpolation Tool (beta).roboFontExt/lib/tempfont.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /LatCyrl-CharacterSet-RF.txt: -------------------------------------------------------------------------------- 1 | space exclam quotesingle quotedbl numbersign dollar percent ampersand parenleft parenright asterisk plus comma hyphen period slash zero one two three four five six seven eight nine colon semicolon less equal greater question at A B C D E F G H I J K L M N O P Q R S T U V W X Y Z bracketleft backslash bracketright asciicircum underscore grave a b c d e f g h i j k l m n o p q r s t u v w x y z braceleft bar braceright asciitilde exclamdown cent sterling currency yen brokenbar section dieresis copyright ordfeminine guillemotleft logicalnot registered macron degree plusminus twosuperior threesuperior acute mu paragraph periodcentered cedilla onesuperior ordmasculine guillemotright onequarter onehalf threequarters questiondown Agrave Aacute Acircumflex Atilde Adieresis Aring AE Ccedilla Egrave Eacute Ecircumflex Edieresis Igrave Iacute Icircumflex Idieresis Eth Ntilde Ograve Oacute Ocircumflex Otilde Odieresis multiply Oslash Ugrave Uacute Ucircumflex Udieresis Yacute Thorn germandbls agrave aacute acircumflex atilde adieresis aring ae ccedilla egrave eacute ecircumflex edieresis igrave iacute icircumflex idieresis eth ntilde ograve oacute ocircumflex otilde odieresis divide oslash ugrave uacute ucircumflex udieresis yacute thorn ydieresis dotlessi circumflex caron breve dotaccent ring ogonek tilde hungarumlaut quoteleft quoteright minus u00A0|00A0 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10023 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10071 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097 afii10051 afii10099 afii10050 afii10055 afii10052 afii10100 afii10103 afii10098 afii10057 afii10053 afii10101 afii10056 afii10104 afii10058 afii10106 afii10059 afii10107 afii10105 afii10054 afii10060 afii10108 afii10061 afii10109 afii10102 afii10062 afii10110 afii10145 afii10193 afii10146 afii10194 afii10147 afii10195 afii10148 afii10196 afii61352 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | typedev RoboFont scripts and Extensions 2 | ======== 3 | 4 | A collection of free and open-source RoboFont extensions and scripts. 5 | -------- 6 | 7 | 8 | 9 | ## MIT License 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | -------------------------------------------------------------------------------- /Show all glyphs.py: -------------------------------------------------------------------------------- 1 | # RoboFont Script 2 | # Just one click to show all ready glyphs in SpaceCenter 3 | # Alexander Lubovenko 4 | # http://github.com/typedev 5 | 6 | from mojo.UI import * 7 | 8 | font = CurrentFont() 9 | 10 | a=[] 11 | for i in font: 12 | if i: 13 | a.append(i.name) 14 | 15 | OpenSpaceCenter(font) 16 | SC = CurrentSpaceCenter() 17 | SC.set(a) 18 | -------------------------------------------------------------------------------- /TestInstallAdvanced.py: -------------------------------------------------------------------------------- 1 | # RoboFont Script 2 | # Install current font with empty glyphs. It is useful when you are testing font in InDesign 3 | # Alexander Lubovenko 4 | # http://github.com/typedev 5 | 6 | from robofab.world import CurrentFont 7 | 8 | 9 | s = 'space exclam quotesingle quotedbl numbersign dollar percent ampersand parenleft parenright asterisk plus comma hyphen period slash zero one two three four five six seven eight nine colon semicolon less equal greater question at A B C D E F G H I J K L M N O P Q R S T U V W X Y Z bracketleft backslash bracketright asciicircum underscore grave a b c d e f g h i j k l m n o p q r s t u v w x y z braceleft bar braceright asciitilde exclamdown cent sterling currency yen brokenbar section dieresis copyright ordfeminine guillemotleft logicalnot registered macron degree plusminus twosuperior threesuperior acute mu paragraph periodcentered cedilla onesuperior ordmasculine guillemotright onequarter onehalf threequarters questiondown Agrave Aacute Acircumflex Atilde Adieresis Aring AE Ccedilla Egrave Eacute Ecircumflex Edieresis Igrave Iacute Icircumflex Idieresis Eth Ntilde Ograve Oacute Ocircumflex Otilde Odieresis multiply Oslash Ugrave Uacute Ucircumflex Udieresis Yacute Thorn germandbls agrave aacute acircumflex atilde adieresis aring ae ccedilla egrave eacute ecircumflex edieresis igrave iacute icircumflex idieresis eth ntilde ograve oacute ocircumflex otilde odieresis divide oslash ugrave uacute ucircumflex udieresis yacute thorn ydieresis dotlessi circumflex caron breve dotaccent ring ogonek tilde hungarumlaut quoteleft quoteright minus u00A0|00A0 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10023 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10071 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097 afii10051 afii10099 afii10050 afii10055 afii10052 afii10100 afii10103 afii10098 afii10057 afii10053 afii10101 afii10056 afii10104 afii10058 afii10106 afii10059 afii10107 afii10105 afii10054 afii10060 afii10108 afii10061 afii10109 afii10102 afii10062 afii10110 afii10145 afii10193 afii61352' 10 | 11 | ng = s.split(' ') 12 | 13 | font = CurrentFont() 14 | 15 | for gname in ng: 16 | if gname not in font.keys(): 17 | d = RGlyph() 18 | font[gname] = d 19 | missglyph = font[gname] 20 | missglyph.width = 0 21 | missglyph.update() 22 | 23 | font.update() 24 | 25 | font.testInstall() 26 | 27 | glyphOrder = font.glyphOrder 28 | 29 | for gname in ng: 30 | if font[gname].width == 0: 31 | font.removeGlyph(gname) 32 | 33 | font.glyphOrder = glyphOrder 34 | font.update() 35 | -------------------------------------------------------------------------------- /Version Control/README.md: -------------------------------------------------------------------------------- 1 | # Version Control RoboFont Extension 2 | 3 | Version Control allows saving the current glyph as version and managing these versions. For example, if you draw a glyph and doubt in correctness of current position you can save it as the version and continue drawing. Then, if necessary, return to any previous versions, manage them, compare with current or view all glyph revisions in SpaceCenter, replace the drawing of current glyph with version\`s drawing or delete it. 4 | 5 | > The number of versions for each glyph is to 999. Versions of the glyphs are stored in the glyph general table with names GlyphName.ver.XXX - where XXX is the version number from 001 to 999. If necessary, they can be manually removed, as usual glyphs. 6 | 7 | ![Version Control window](https://dl.dropboxusercontent.com/u/2432828/RoboFont/VersionControl/vcwindow.png) 8 | 9 | 1. Preview of the selected version 10 | 11 | 2. Versions list of the current glyph. 12 | Edit window of glyph version is opened by double-click 13 | 14 | 3. Note field 15 | 16 | 4. Save the current glyph as version 17 | 18 | 5. Remove the selected glyph version 19 | 20 | 6. Replace the current glyph`s drawing with the selected version. The current glyph will be saved instead of the selected version. 21 | 7. View all glyph versions in SpaceCenter 22 | 23 | ## Installation 24 | Double click VersionControl.roboFontExt ## MIT License 25 | 26 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 29 | 30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Version Control/VersionControl.roboFontExt/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | README 7 | 8 | 20 | 21 | 22 | 23 |
24 |

Version Control RoboFont Extension

25 | 26 |

Version Control allows saving the current glyph as version and managing these versions. 27 | For example, if you draw a glyph and doubt in correctness of current position you can save it as the version and continue drawing. Then, if necessary, return to any previous versions, manage them, compare with current or view all glyph revisions in SpaceCenter, replace the drawing of current glyph with version`s drawing or delete it.

28 | 29 |
30 |

The number of versions for each glyph is to 999. Versions of the glyphs are stored in the glyph general table with names GlyphName.ver.XXX - where XXX is the version number from 001 to 999. If necessary, they can be manually removed, as usual glyphs.

31 |
32 | 33 |
34 | Version Control window 35 |
Version Control window
36 | 37 | 38 | 39 |
    40 |
  1. Preview of the selected version

  2. 41 |
  3. Versions list of the current glyph. 42 | Edit window of glyph version is opened by double-click

  4. 43 |
  5. Note field

  6. 44 |
  7. Save the current glyph as version

  8. 45 |
  9. Remove the selected glyph version

  10. 46 |
  11. Replace the current glyph`s drawing with the selected version. The current glyph will be saved instead of the selected version.

  12. 47 |
  13. View all glyph versions in SpaceCenter

  14. 48 |
49 | 50 |

Installation

51 | 52 |

Double click VersionControl.roboFontExt

53 | 54 |

MIT License

55 | 56 |

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

57 | 58 |

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

59 | 60 |

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

61 |
62 | 63 | -------------------------------------------------------------------------------- /Version Control/VersionControl.roboFontExt/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | addToMenu 6 | 7 | 8 | path 9 | VersionControl.py 10 | preferredName 11 | Version Control 12 | shortKey 13 | 14 | 15 | 16 | developer 17 | Alexander Lubovenko 18 | developerURL 19 | https://github.com/typedev 20 | html 21 | 22 | launchAtStartUp 23 | 0 24 | mainScript 25 | 26 | name 27 | VersionControl 28 | requiresVersionMajor 29 | 1 30 | requiresVersionMinor 31 | 4 32 | timeStamp 33 | 1377714391.681957 34 | version 35 | 1.2 36 | repository 37 | typedev/RoboFont 38 | extensionPath 39 | Version Control/VersionControl.roboFontExt 40 | 41 | 42 | -------------------------------------------------------------------------------- /Version Control/VersionControl.roboFontExt/lib/VersionControl.py: -------------------------------------------------------------------------------- 1 | # RoboFont Script 2 | # Version Control 3 | # Alexander Lubovenko 4 | # http://github.com/typedev 5 | 6 | from mojo.UI import * 7 | from vanilla import * 8 | from mojo.glyphPreview import GlyphPreview 9 | from mojo.events import addObserver, removeObserver 10 | from mojo.roboFont import OpenWindow 11 | from time import asctime 12 | 13 | 14 | libVC = 'com.typedev.version_control.' 15 | font = CurrentFont() 16 | 17 | def getVersionNumber(glyphName): 18 | libKey = libVC + glyphName 19 | if font.lib.has_key(libKey): 20 | font.lib[libKey] = font.lib[libKey] + 1 21 | else: 22 | font.lib[libKey] = 1 23 | return font.lib[libKey] 24 | 25 | 26 | def setVersionNumber(glyphName, versionNumber = 0): 27 | libKey = libVC + glyphName 28 | font.lib[libKey] = versionNumber 29 | 30 | 31 | def checkVersionNumbers(): 32 | gversions = [] 33 | for g in font: 34 | if '.ver.' not in g.name: 35 | gversions = GetListVersions(g.name) 36 | if gversions != []: 37 | gname = gversions[-1] 38 | a = gname.split('.') 39 | lastnumber = int(a[-1]) 40 | setVersionNumber( g.name, lastnumber ) 41 | else: 42 | setVersionNumber( g.name ) 43 | 44 | 45 | def cloneGlyph(glyph,name=''): 46 | if name == '': 47 | oldname = glyph.name 48 | else: 49 | oldname = name 50 | i = getVersionNumber(oldname) 51 | newName = oldname+'.ver.'+'%03d' % i 52 | font.insertGlyph(glyph,newName) 53 | font.update() 54 | font[newName].note = 'Version created ' + asctime() 55 | font[newName].update() 56 | font.update() 57 | 58 | def GetListVersions(glyphName): 59 | gversions = [] 60 | if '.ver.' in glyphName: 61 | selname = glyphName.split('.') 62 | if 'ver' == selname[-2]: 63 | selname.pop() 64 | selname.pop() 65 | glyphName='.'.join(selname) 66 | gversions.append(glyphName) 67 | for g in font: 68 | if (glyphName + '.ver.') in g.name: 69 | gversions.append(g.name) 70 | gversions.sort() 71 | return gversions 72 | 73 | 74 | class VersionControl: 75 | 76 | def __init__(self): 77 | 78 | self.w = FloatingWindow((250, 530),minSize=(200, 400),title = 'Version Control') 79 | 80 | self.PreviewPanel = Group((0, 0, -0, -0)) 81 | self.PreviewPanel.Preview = GlyphPreview((0, 0, -15, 0)) 82 | self.PreviewPanel.GlyphInfo = TextBox((5, -13, 0, 12), '', alignment='left', selectable=False, sizeStyle='mini') 83 | self.PreviewPanel.hline = HorizontalLine((5, -1, -5, 1)) 84 | self.Control = Group((0, 0, -0, -0)) 85 | 86 | self.Control.VersionsList = List((0, 30, -0, -0), [], allowsMultipleSelection = False, 87 | selectionCallback=self.selectionVersionCallback, 88 | doubleClickCallback=self.selectionDoubleVersionCallback) 89 | 90 | self.Control.btnAdd = Button((5,5,30,20), '+', callback=self.btnAddCallback) 91 | self.Control.btnDel = Button((40,5,30,20), '-', callback=self.btnDelCallback) 92 | self.Control.btnSwap = Button((75,5,40,20), '<>', callback=self.btnSwapCallback) 93 | self.Control.btnShow = Button((120,5,40,20), 'Sc', callback=self.btnShowCallback) 94 | 95 | self.Note = TextEditor((5, 5, -5, -5)) 96 | 97 | descriptions = [ 98 | dict(label="Preview", view=self.PreviewPanel, size=320, collapsed=False, canResize=True), 99 | dict(label="Control", view=self.Control, minSize=100, size=140, collapsed=False, canResize=True), 100 | dict(label="Note", view=self.Note, minSize=100, size=140, collapsed=True, canResize=True), 101 | ] 102 | 103 | 104 | 105 | addObserver(self, "_currentGlyphChanged", "currentGlyphChanged") 106 | self.w.bind("close", self.windowClose) 107 | self.w.accordionView = AccordionView((0, 0, -0, -0), descriptions ) 108 | checkVersionNumbers() 109 | self.updateVersionsList() 110 | self.w.open() 111 | 112 | def selectionVersionCallback(self, sender): 113 | idx = sender.getSelection() 114 | if idx != []: 115 | self.setGlyph( font[ self.Control.VersionsList[ idx[0] ] ] ) 116 | 117 | def selectionDoubleVersionCallback(self, sender): 118 | idx = sender.getSelection() 119 | if idx != []: 120 | name = self.Control.VersionsList[idx [0]] 121 | SetCurrentGlyphByName(name) 122 | self.setGlyph( font[ name ] ) 123 | OpenGlyphWindow( font[ name ] ) 124 | 125 | def updateVersionsList(self): 126 | if CurrentGlyph() != None: 127 | self.setGlyph(CurrentGlyph()) 128 | self.Control.VersionsList.set([]) 129 | self.Control.VersionsList.set( GetListVersions( CurrentGlyph().name ) ) 130 | if CurrentGlyph().name in self.Control.VersionsList: 131 | self.Control.VersionsList.setSelection([ self.Control.VersionsList.index(CurrentGlyph().name) ]) 132 | 133 | def _currentGlyphChanged(self, info): 134 | self.updateVersionsList() 135 | 136 | def btnAddCallback(self, sender): 137 | glyph = CurrentGlyph() 138 | if '.ver.' in glyph.name: 139 | lname = glyph.name.split('.') 140 | if 'ver' == lname[-2]: 141 | lname.pop() 142 | lname.pop() 143 | sname='.'.join(lname) 144 | cloneGlyph(glyph,sname) 145 | else: 146 | cloneGlyph(glyph) 147 | font.update() 148 | self.updateVersionsList() 149 | 150 | def btnDelCallback(self, sender): 151 | idx = self.Control.VersionsList.getSelection() 152 | if idx != []: 153 | name = self.Control.VersionsList[idx [0]] 154 | if '.ver.' in name: 155 | 156 | aa = font.lib[ 'public.glyphOrder' ] 157 | if name in aa: 158 | aa.remove(name) 159 | font.lib[ 'public.glyphOrder' ] = aa 160 | font.removeGlyph (name) 161 | font.update() 162 | 163 | self.Control.VersionsList.remove(name) 164 | self.updateVersionsList() 165 | 166 | def btnSwapCallback(self, sender): 167 | idx = self.Control.VersionsList.getSelection() 168 | if idx != []: 169 | vName = self.Control.VersionsList[idx [0]] 170 | vGlyph = font[vName] 171 | vUcode = font[vName].unicode 172 | 173 | cGlyph = CurrentGlyph() 174 | cName = cGlyph.name 175 | cUcode = cGlyph.unicode 176 | 177 | if (vName != cName) and ('.ver.' not in cName): 178 | font.removeGlyph(cName) 179 | font.insertGlyph(vGlyph,cName) 180 | font[cName].unicode = cUcode 181 | font[cName].update() 182 | font.removeGlyph(vName) 183 | font.insertGlyph(cGlyph,vName) 184 | font[vName].update() 185 | font.glyphOrder = font.lib['public.glyphOrder'] 186 | font.update() 187 | self.updateVersionsList() 188 | OpenGlyphWindow( font[ cName ] ) 189 | 190 | def btnShowCallback(self, sender): 191 | cGlyph = CurrentGlyph().name 192 | gversions = GetListVersions(cGlyph) 193 | if gversions != []: 194 | OpenSpaceCenter(font) 195 | SC = CurrentSpaceCenter() 196 | if '.ver.' not in cGlyph: 197 | gversions.insert(0,cGlyph) 198 | SC.set(gversions) 199 | 200 | 201 | def setGlyph(self, glyph): 202 | self.PreviewPanel.GlyphInfo.set('') 203 | self.PreviewPanel.Preview.setGlyph(glyph) 204 | ucode = '-' 205 | if glyph.unicode != None: 206 | ucode = "%04X" % (glyph.unicode) 207 | gInfo = 'Glyph: ' + glyph.name + ' | U: '+ ucode + ' | Left: ' + str(int(round(glyph.leftMargin,0))) + ' | Right: ' + str(int(round(glyph.rightMargin))) 208 | self.PreviewPanel.GlyphInfo.set(gInfo) 209 | self.Note.set('') 210 | if glyph.note != None: 211 | self.Note.set(glyph.note) 212 | 213 | def windowClose(self, sender): 214 | removeObserver(self, "_currentGlyphChanged") 215 | 216 | VersionControl() -------------------------------------------------------------------------------- /Version Control/doc/VersionControl-RobofontExtension.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typedev/RoboFont/d74e13781b1685a28b1e6fe59f24a42f75d74432/Version Control/doc/VersionControl-RobofontExtension.pdf -------------------------------------------------------------------------------- /checkOverlaping.py: -------------------------------------------------------------------------------- 1 | font = CurrentFont() 2 | total = len(font) 3 | count = total 4 | for glyph in font: 5 | print '%i/%i %s' % (count, total, glyph.name) 6 | glyph.removeOverlap() 7 | glyph.update() 8 | count -= 1 9 | print 'Done..' -------------------------------------------------------------------------------- /drawReferenceGlyph.py: -------------------------------------------------------------------------------- 1 | """ 2 | An example script of adding an observers and do *something* 3 | 4 | It draws a simple unicode reference of an existing installed font. 5 | """ 6 | 7 | from mojo.events import addObserver 8 | from mojo.drawingTools import * 9 | 10 | class DrawReferenceGlyph(object): 11 | 12 | def __init__(self): 13 | addObserver(self, "drawReferenceGlyph", "draw") 14 | 15 | def drawReferenceGlyph(self, info): 16 | 17 | glyph = info["glyph"] 18 | 19 | r = 0 20 | g = 0 21 | b = 0 22 | a = .5 23 | 24 | if glyph is not None and glyph.unicode is not None: 25 | # if glyph.unicode is not None: 26 | t = unichr(glyph.unicode) 27 | font("Brill Roman", 100) 28 | stroke(None) 29 | fill(r, g, b, a) 30 | text(t, (glyph.width + 25, -120)) 31 | 32 | 33 | DrawReferenceGlyph() -------------------------------------------------------------------------------- /dump All-to-All to SpaceCenter.py: -------------------------------------------------------------------------------- 1 | # RoboFont Script 2 | # Generate dump text from the selected glyphs to SpaceCenter 3 | # Alexander Lubovenko 4 | # http://github.com/typedev 5 | 6 | from robofab.world import CurrentFont 7 | from mojo.UI import * 8 | 9 | font = CurrentFont() 10 | 11 | listglyphs = font.selection 12 | 13 | result = [] 14 | 15 | for b in listglyphs: 16 | for i in listglyphs: 17 | result.append(i) 18 | result.append(b) 19 | 20 | OpenSpaceCenter(font) 21 | SC = CurrentSpaceCenter() 22 | SC.set(result) 23 | 24 | -------------------------------------------------------------------------------- /getInterpolationFactorByStems.py: -------------------------------------------------------------------------------- 1 | 2 | # listStems string: 10 20 30 40=0 50 60 70 80 90 100=1 110 120 3 | 4 | ListManualStems = '48=0 74 94 128 165 192 218=1' 5 | 6 | def getFactorByStem (minStem, maxStem, midStem): 7 | if (midStem != 0) and (midStem != 1000): 8 | return 1000 * (midStem - minStem) / (maxStem - minStem) 9 | else: 10 | return midStem 11 | 12 | 13 | def getFactorListByStems (listStems): 14 | ld = listStems.split(' ') 15 | ls = [] 16 | lf = [] 17 | for i in ld: 18 | if '=' in i: 19 | lm = i.split('=') 20 | if lm[1] == '0': 21 | minStem = int(lm[0]) 22 | ls.append(0) 23 | if lm[1] == '1': 24 | maxStem = int(lm[0]) 25 | ls.append(1000) 26 | else: 27 | ls.append(int(i)) 28 | for i in ls: 29 | lf.append(getFactorByStem(minStem, maxStem, i) / 1000.0) 30 | return lf 31 | 32 | stemslist = ListManualStems.split(' ') 33 | for idx, value in enumerate(stemslist): 34 | print 'stem\t', value 35 | print 'factor\t',getFactorListByStems(ListManualStems)[idx] 36 | # print ListManualStems.split(' ') 37 | # print getFactorListByStems(ListManualStems) -------------------------------------------------------------------------------- /makeGroupsFromFeature.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from robofab.world import CurrentFont 4 | 5 | font = CurrentFont() 6 | 7 | featxt = font.features.text 8 | featxt = ' '.join(featxt.split()).split(';') 9 | for id, line in enumerate(featxt): 10 | line = line.strip() 11 | if line.startswith('@'): 12 | a = line.split(' ') 13 | groupname = a[0].replace('@','') 14 | a.remove('=') 15 | a.remove('[') 16 | a.remove(']') 17 | content = a[1:] 18 | # print groupname, '>', content 19 | 20 | print 'New group created: ' + groupname 21 | font.groups[groupname] = content 22 | -------------------------------------------------------------------------------- /makeTableAlltoAll.py: -------------------------------------------------------------------------------- 1 | font = CurrentFont() 2 | 3 | listglyphs = font.selection 4 | 5 | result = '' 6 | 7 | for b in listglyphs: 8 | gb = font[b].unicode 9 | for i in listglyphs: 10 | gi = font[i].unicode 11 | result = result + unichr(gb) + unichr(gi) 12 | result = result + '\n' 13 | 14 | print result 15 | -------------------------------------------------------------------------------- /make_ALT_fea.py: -------------------------------------------------------------------------------- 1 | # Make AALT feature 2 | from robofab.world import CurrentFont 3 | 4 | font = CurrentFont() 5 | 6 | sfx_names = [] 7 | print 'Available Suffixes in:', font 8 | for glyph in font: 9 | name = glyph.name 10 | if ('.' in name) and (name != '.notdef'): 11 | a = name.split('.') 12 | gname = a[0] 13 | sfx = a[1] 14 | if '.' + sfx not in sfx_names: 15 | sfx_names.append('.' + sfx) 16 | print sfx_names 17 | 18 | aaltdic = {} 19 | for glyph in font: 20 | if ('.' in glyph.name) and (glyph.name != '.notdef'): 21 | a = glyph.name.split('.') 22 | gname = a[0] 23 | if gname not in aaltdic: 24 | aaltdic[gname] = ['%s.' % gname + '.'.join(a[1:])] 25 | else: 26 | aaltdic[gname].append('%s.' % gname + '.'.join(a[1:])) 27 | 28 | print 'feature aalt {' 29 | for name, alts in sorted(aaltdic.items()): 30 | print '\tsub %s from [ %s ];' % (name, ' '.join(alts)) 31 | print '} aalt;' 32 | -------------------------------------------------------------------------------- /polygon selection tool/polygon-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typedev/RoboFont/d74e13781b1685a28b1e6fe59f24a42f75d74432/polygon selection tool/polygon-select.png -------------------------------------------------------------------------------- /polygon selection tool/polygonSelectionTool.py: -------------------------------------------------------------------------------- 1 | from mojo.events import EditingTool, installTool 2 | from mojo.drawingTools import * 3 | from AppKit import NSImage 4 | from fontTools.pens.cocoaPen import CocoaPen 5 | 6 | class PolygonSelectionTool(EditingTool): 7 | 8 | def setup(self): 9 | self.pen = None 10 | self._oldPen = None 11 | 12 | def mouseDown(self, point, clickCount): 13 | if self.selection.hasSelection(): 14 | return 15 | if not self.optionDown: 16 | self.pen = CocoaPen(None) 17 | else: 18 | self.pen = self._oldPen 19 | self.pen.moveTo((point.x, point.y)) 20 | 21 | def mouseDragged(self, point, delta): 22 | if self.pen is None: 23 | return 24 | self.pen.lineTo((point.x, point.y)) 25 | 26 | def mouseUp(self, point): 27 | if self.pen is None: 28 | return 29 | self.pen.closePath() 30 | 31 | glyph = self.getGlyph() 32 | path = self.pen.path 33 | for contour in glyph: 34 | for point in contour.points: 35 | result = path.containsPoint_((point.x, point.y)) 36 | if self.controlDown: 37 | point.selected = not result 38 | else: 39 | point.selected = result 40 | 41 | self._oldPen = self.pen 42 | self.pen = None 43 | 44 | def draw(self, scale): 45 | if self.pen is None: 46 | return 47 | fill( 1 , 0 , 0 , .2 ) 48 | #stroke(0, .6) 49 | #strokeWidth(scale) 50 | drawPath(self.pen.path) 51 | 52 | def canSelectWithMarque(self): 53 | return False 54 | 55 | def getToolbarTip(self): 56 | return "Polygon Selection Tool" 57 | 58 | def getToolbarIcon(self): 59 | icon = NSImage.alloc().initWithContentsOfFile_("polygon-select.pdf") 60 | if icon : 61 | return icon 62 | 63 | 64 | installTool(PolygonSelectionTool()) -------------------------------------------------------------------------------- /removeAllGuides.py: -------------------------------------------------------------------------------- 1 | font = CurrentFont() 2 | for guide in font.guides: 3 | font.removeGuide(guide) 4 | for glyph in font: 5 | for guide in glyph.guides: 6 | glyph.removeGuide(guide) -------------------------------------------------------------------------------- /renameGroupsOBSR.py: -------------------------------------------------------------------------------- 1 | from mojo.events import addObserver 2 | from afiiTabl import * 3 | 4 | 5 | def renameToAfiiCyrl(glyphName): 6 | if 'uni' in glyphName: 7 | n = getCyrlLetter(uName=glyphName) 8 | if n: 9 | print 'Glyph', n[uniN], 'renamed to', n[afiiN], '-Note:', n[noteCyrl] 10 | glyphName = n[afiiN] 11 | return glyphName 12 | 13 | def checkGlyphNames(font): 14 | print "=== Rename glyphs from uniXXXX to afiiXXXXX ===" 15 | glyphChanged = False 16 | for glyph in font: 17 | oldGlyphName = glyph.name 18 | newGlyphName = renameToAfiiCyrl(glyph.name) 19 | if oldGlyphName != newGlyphName: 20 | font.renameGlyph(oldGlyphName, newGlyphName) 21 | font[newGlyphName].update() 22 | glyphChanged = True 23 | #font.update() 24 | print "=== done renaming glyph names ===" 25 | if glyphChanged: 26 | print "=== Clearing GlyphOrder ===" 27 | font.glyphOrder = [] 28 | print "===DONE===" 29 | 30 | def checkGroupNames(font): 31 | print "=== Checking Group Names for Single Quotes ===" 32 | for groupName, items in font.groups.items(): 33 | newItems = [] 34 | for glyphName in items: 35 | if "'" in glyphName: 36 | glyphName = glyphName.replace("'", "") 37 | print glyphName,' changed' 38 | #glyphName = renameToAfiiCyrl(glyphName) 39 | newItems.append(glyphName) 40 | 41 | if newItems != items: 42 | ## something changed 43 | font.groups[groupName] = newItems 44 | font.lib['com.typedev.markers.groupsclear'] = 'Cleared' 45 | print "=== done checking group names ===" 46 | 47 | 48 | 49 | class RenameGroupsObserver(object): 50 | 51 | def __init__(self): 52 | addObserver(self, "checkFontNames", "fontDidOpen") 53 | 54 | def checkFontNames(self, info): 55 | font = info["font"] 56 | # print font.lib['com.typedev.markers.groupsok'] 57 | if font.lib.has_key('com.typedev.markers.groupsclear'): 58 | print "=== Groups OK ===" 59 | else: 60 | checkGroupNames(font) 61 | font.update() 62 | #checkGlyphNames(font) 63 | #font.glyphOrder = glyphOrder 64 | 65 | 66 | 67 | 68 | 69 | RenameGroupsObserver() -------------------------------------------------------------------------------- /resortGlyphOrder.py: -------------------------------------------------------------------------------- 1 | font = CurrentFont() 2 | 3 | sortedlist = sorted(font.selection) 4 | 5 | glyphOrder = font.lib[ 'public.glyphOrder' ] 6 | 7 | indexes = [] 8 | start = None 9 | 10 | for name in font.selection: 11 | for id, fglyph in enumerate(glyphOrder): 12 | if fglyph == name: 13 | indexes.append(id) 14 | 15 | for id, index in enumerate(indexes): 16 | print glyphOrder[index], ' << ', sortedlist[id] 17 | glyphOrder[index]= sortedlist[id] 18 | font[sortedlist[id]].update() 19 | 20 | font.lib['public.glyphOrder'] = glyphOrder 21 | font.glyphOrder = font.lib['public.glyphOrder'] 22 | font.update() --------------------------------------------------------------------------------