from vanilla import FloatingWindow, CheckBox from defconAppKit.windows.baseWindow import BaseWindowController from mojo.events import addObserver, removeObserver from mojo.UI import CurrentSpaceCenter from defcon import Glyph, registerRepresentationFactory, unregisterRepresentationFactory import mojo.drawingTools as ctx from fontTools.pens.cocoaPen import CocoaPen def BoundsRectFactory(glyph): '''A factory function which creates a representation for a given glyph.''' pen = CocoaPen(glyph.layer) if not glyph.bounds: return x, y, w, h = glyph.bounds pen.moveTo((x, y)) pen.lineTo((w, y)) pen.lineTo((w, h)) pen.lineTo((x, h)) pen.closePath() return pen.path class BoundsRectViewer(BaseWindowController): '''A simple floating window to toggle the preview on/off.''' def __init__(self): self.w = FloatingWindow((123, 40)) self.w.preview = CheckBox((10, 10, -10, 20), 'preview', value=True, callback=self.updatePreviewCallback) self.setUpBaseWindowBehavior() # register the representation factory in the defcon Glyph object registerRepresentationFactory(Glyph, "BoundsRectPreview", BoundsRectFactory) # add an observer for drawing in the Space Center addObserver(self, "drawBoundsRect", "spaceCenterDraw") self.w.open() def windowCloseCallback(self, sender): '''Clear observer & representation factory when window is closed.''' super().windowCloseCallback(sender) removeObserver(self, "spaceCenterDraw") unregisterRepresentationFactory(Glyph, "BoundsRectPreview") def updatePreviewCallback(self, sender): S = CurrentSpaceCenter() if not S: return S.updateGlyphLineView() def drawBoundsRect(self, notification): '''Drawing the bounding box around each glyph.''' S = CurrentSpaceCenter() if not S or not self.w.preview.get(): return # get the current glyph glyph = notification['glyph'] # get representation for glyph boundsRect = glyph.getRepresentation("BoundsRectPreview") if not boundsRect: return # draw representation scale = notification['scale'] ctx.save() ctx.fill(None) ctx.strokeWidth(3 * scale) ctx.stroke(0, 1, 0, 0.5) ctx.drawPath(boundsRect) ctx.restore() BoundsRectViewer()