blob: 5add6bb0df091a8da36319172a397c214687eb04 [file] [log] [blame]
"""Mac-OS9-only TrueType browser window, deprecated and no longer maintained."""
from fontTools import ttLib
from fontTools.ttLib import macUtils
import macfs
import PyBrowser
import W, Lists
import os
import ATM
import numpy
import Qd
from rf.views.wGlyphList import GlyphList
class TableBrowser:
def __init__(self, path=None, ttFont=None, res_index=None):
W.SetCursor('watch')
if path is None:
self.ttFont = ttFont
self.filename = "????"
else:
self.ttFont = ttLib.TTFont(path, res_index)
if res_index is None:
self.filename = os.path.basename(path)
else:
self.filename = os.path.basename(path) + " - " + str(res_index)
self.currentglyph = None
self.glyphs = {}
self.buildinterface()
def buildinterface(self):
buttonwidth = 120
glyphlistwidth = 150
hmargin = 10
vmargin = 8
title = self.filename
tables = self.ttFont.keys()
tables.sort()
self.w = w = W.Window((500, 300), title, minsize = (400, 200))
w.browsetablebutton = W.Button((hmargin, 32, buttonwidth, 16), "Browse tableŠ",
self.browsetable)
w.browsefontbutton = W.Button((hmargin, vmargin, buttonwidth, 16), "Browse fontŠ",
self.browsefont)
w.tablelist = W.List((hmargin, 56, buttonwidth, -128), tables, self.tablelisthit)
w.divline1 = W.VerticalLine((buttonwidth + 2 * hmargin, vmargin, 1, -vmargin))
gleft = buttonwidth + 3 * hmargin + 1
hasGlyfTable = self.ttFont.has_key('glyf')
glyphnames = self.ttFont.getGlyphNames2() # caselessly sorted glyph names
if hasGlyfTable:
w.glyphlist = GlyphList((gleft, 56, glyphlistwidth, -vmargin),
glyphnames, self.glyphlisthit)
w.divline2 = W.VerticalLine((buttonwidth + glyphlistwidth + 4 * hmargin + 2,
vmargin, 1, -vmargin))
yMin = self.ttFont['head'].yMin
yMax = self.ttFont['head'].yMax
w.gviewer = GlyphViewer((buttonwidth + glyphlistwidth + 5 * hmargin + 3,
vmargin, -hmargin, -vmargin), yMin, yMax)
w.showpoints = W.CheckBox((gleft, vmargin, glyphlistwidth, 16), "Show points",
self.w.gviewer.toggleshowpoints)
w.showpoints.set(self.w.gviewer.showpoints)
w.showlines = W.CheckBox((gleft, vmargin + 24, glyphlistwidth, 16), "Show lines",
self.w.gviewer.toggleshowlines)
w.showlines.set(self.w.gviewer.showlines)
else:
w.glyphlist = GlyphList((gleft, 56, glyphlistwidth, -vmargin),
glyphnames)
w.noGlyphTable = W.TextBox((gleft, vmargin, -20, 20), "no 'glyf' table found")
w.setdefaultbutton(w.browsetablebutton)
w.tocurrentfont = W.Button((hmargin, -120, buttonwidth, 16), "Copy to current font", self.copytocurrentfont)
w.fromcurrentfont = W.Button((hmargin, -96, buttonwidth, 16), "Copy from current font", self.copyfromcurrentfont)
w.saveflat = W.Button((hmargin, -72, buttonwidth, 16), "Save as flat fileŠ", self.saveflat)
w.savesuitcasebutton = W.Button((hmargin, -48, buttonwidth, 16), "Save as suitcaseŠ", self.savesuitcase)
w.savexmlbutton = W.Button((hmargin, -24, buttonwidth, 16), "Save as XMLŠ", self.saveXML)
w.open()
w.browsetablebutton.enable(0)
def browsetable(self):
self.tablelisthit(1)
def browsefont(self):
PyBrowser.Browser(self.ttFont)
def copytocurrentfont(self):
pass
def copyfromcurrentfont(self):
pass
def saveflat(self):
path = putfile("Save font as flat file:", self.filename, ".TTF")
if path:
W.SetCursor('watch')
self.ttFont.save(path)
def savesuitcase(self):
path = putfile("Save font as suitcase:", self.filename, ".suit")
if path:
W.SetCursor('watch')
self.ttFont.save(path, 1)
def saveXML(self):
path = putfile("Save font as XML text file:", self.filename, ".ttx")
if path:
W.SetCursor('watch')
pb = macUtils.ProgressBar("Saving %s as XMLŠ" % self.filename)
try:
self.ttFont.saveXML(path, pb)
finally:
pb.close()
def glyphlisthit(self, isDbl):
sel = self.w.glyphlist.getselectedobjects()
if not sel or sel[0] == self.currentglyph:
return
self.currentglyph = sel[0]
if self.glyphs.has_key(self.currentglyph):
g = self.glyphs[self.currentglyph]
else:
g = Glyph(self.ttFont, self.currentglyph)
self.glyphs[self.currentglyph] = g
self.w.gviewer.setglyph(g)
def tablelisthit(self, isdbl):
if isdbl:
for tag in self.w.tablelist.getselectedobjects():
table = self.ttFont[tag]
if tag == 'glyf':
W.SetCursor('watch')
for glyphname in self.ttFont.getGlyphOrder():
try:
glyph = table[glyphname]
except KeyError:
pass # incomplete font, oh well.
PyBrowser.Browser(table)
else:
sel = self.w.tablelist.getselection()
if sel:
self.w.browsetablebutton.enable(1)
else:
self.w.browsetablebutton.enable(0)
class Glyph:
def __init__(self, ttFont, glyphName):
ttglyph = ttFont['glyf'][glyphName]
self.iscomposite = ttglyph.numberOfContours == -1
self.width, self.lsb = ttFont['hmtx'][glyphName]
if ttglyph.numberOfContours == 0:
self.xMin = 0
self.contours = []
return
self.xMin = ttglyph.xMin
coordinates, endPts, flags = ttglyph.getCoordinates(ttFont['glyf'])
self.contours = []
self.flags = []
startpt = 0
for endpt in endPts:
self.contours.append(numpy.array(coordinates[startpt:endpt+1]))
self.flags.append(flags[startpt:endpt+1])
startpt = endpt + 1
def getcontours(self, scale, move):
contours = []
for i in range(len(self.contours)):
contours.append(((self.contours[i] * numpy.array(scale) + move), self.flags[i]))
return contours
class GlyphViewer(W.Widget):
def __init__(self, possize, yMin, yMax):
W.Widget.__init__(self, possize)
self.glyph = None
extra = 0.02 * (yMax-yMin)
self.yMin, self.yMax = yMin - extra, yMax + extra
self.showpoints = 1
self.showlines = 1
def toggleshowpoints(self, onoff):
self.showpoints = onoff
self.SetPort()
self.draw()
def toggleshowlines(self, onoff):
self.showlines = onoff
self.SetPort()
self.draw()
def setglyph(self, glyph):
self.glyph = glyph
self.SetPort()
self.draw()
def draw(self, visRgn=None):
# This a HELL of a routine, but it's pretty damn fast...
import Qd
if not self._visible:
return
Qd.EraseRect(Qd.InsetRect(self._bounds, 1, 1))
cliprgn = Qd.NewRgn()
savergn = Qd.NewRgn()
Qd.RectRgn(cliprgn, self._bounds)
Qd.GetClip(savergn)
Qd.SetClip(cliprgn)
try:
if self.glyph:
l, t, r, b = Qd.InsetRect(self._bounds, 1, 1)
height = b - t
scale = float(height) / (self.yMax - self.yMin)
topoffset = t + scale * self.yMax
width = scale * self.glyph.width
lsb = scale * self.glyph.lsb
xMin = scale * self.glyph.xMin
# XXXX this is not correct when USE_MY_METRICS is set in component!
leftoffset = l + 0.5 * (r - l - width)
gleftoffset = leftoffset - xMin + lsb
if self.showlines:
Qd.RGBForeColor((0xafff, 0xafff, 0xafff))
# left sidebearing
Qd.MoveTo(leftoffset, t)
Qd.LineTo(leftoffset, b - 1)
# right sidebearing
Qd.MoveTo(leftoffset + width, t)
Qd.LineTo(leftoffset + width, b - 1)
# baseline
Qd.MoveTo(l, topoffset)
Qd.LineTo(r - 1, topoffset)
# origin
Qd.RGBForeColor((0x5fff, 0, 0))
Qd.MoveTo(gleftoffset, topoffset - 16)
Qd.LineTo(gleftoffset, topoffset + 16)
# reset color
Qd.RGBForeColor((0, 0, 0))
if self.glyph.iscomposite:
Qd.RGBForeColor((0x7fff, 0x7fff, 0x7fff))
ATM.startFillATM()
contours = self.glyph.getcontours((scale, -scale), (gleftoffset, topoffset))
for contour, flags in contours:
currentpoint = None
done_moveto = 0
i = 0
nPoints = len(contour)
while i < nPoints:
pt = contour[i]
if flags[i]:
# onCurve
currentpoint = lineto(pt, done_moveto)
else:
if not currentpoint:
if not flags[i-1]:
currentpoint = 0.5 * (contour[i-1] + pt)
else:
currentpoint = contour[i-1]
if not flags[(i+1) % nPoints]:
endPt = 0.5 * (pt + contour[(i+1) % nPoints])
else:
endPt = contour[(i+1) % nPoints]
i = i + 1
# offCurve
currentpoint = qcurveto(currentpoint,
pt, endPt, done_moveto)
done_moveto = 1
i = i + 1
ATM.fillClosePathATM()
ATM.endFillATM()
# draw point markers
if self.showpoints:
for contour, flags in contours:
Qd.RGBForeColor((0, 0xffff, 0))
for i in range(len(contour)):
(x, y) = contour[i]
onCurve = flags[i] & 0x1
if onCurve:
Qd.PaintRect(Qd.InsetRect((x, y, x, y), -2, -2))
else:
Qd.PaintOval(Qd.InsetRect((x, y, x, y), -2, -2))
Qd.RGBForeColor((0xffff, 0, 0))
Qd.RGBForeColor((0, 0, 0))
Qd.FrameRect(self._bounds)
finally:
Qd.SetClip(savergn)
Qd.DisposeRgn(cliprgn)
Qd.DisposeRgn(savergn)
extensions = [".suit", ".xml", ".ttx", ".TTF", ".ttf"]
def putfile(prompt, filename, newextension):
for ext in extensions:
if filename[-len(ext):] == ext:
filename = filename[:-len(ext)] + newextension
break
else:
filename = filename + newextension
fss, ok = macfs.StandardPutFile(prompt, filename)
if ok:
return fss.as_pathname()
def lineto(pt, done_moveto):
x, y = pt
if done_moveto:
ATM.fillLineToATM((x, y))
else:
ATM.fillMoveToATM((x, y))
return pt
def qcurveto(pt0, pt1, pt2, done_moveto):
if not done_moveto:
x0, y0 = pt0
ATM.fillMoveToATM((x0, y0))
x1a, y1a = pt0 + 0.6666666666667 * (pt1 - pt0)
x1b, y1b = pt2 + 0.6666666666667 * (pt1 - pt2)
x2, y2 = pt2
ATM.fillCurveToATM((x1a, y1a), (x1b, y1b), (x2, y2))
return pt2
def browseTTFont():
fss, ok = macfs.StandardGetFile()
if not ok:
return
path = fss.as_pathname()
indices = macUtils.getSFNTResIndices(path)
if indices:
for i in indices:
TableBrowser(path, res_index=i)
else:
TableBrowser(path)
if __name__ == "__main__":
browseTTFont()