def __init__(self, posSize, glyphNamesToDisplay, verticalMode, fontsOrder, callback): super(SpacingMatrix, self).__init__(posSize) self.glyphNamesToDisplay = glyphNamesToDisplay self.fontsOrder = fontsOrder self.verticalMode = verticalMode self.callback = callback self.canvas = CanvasGroup((0, 0, 0, 0), delegate=self)
def __init__(self, posSize, displayedWord, canvasScalingFactor, fontObj, isKerningDisplayActive, areVerticalLettersDrawn, areGroupsShown, areCollisionsShown, isSidebearingsActive, isCorrectionActive, isMetricsActive, isColorsActive, isSymmetricalEditingOn, isSwappedEditingOn, indexPair): super(WordDisplay, self).__init__(posSize) self.fontObj = fontObj self.displayedWord = displayedWord self.displayedPairs = buildPairsFromString(self.displayedWord, self.fontObj) self.indexPair = indexPair if indexPair is not None: self.activePair = self.displayedPairs[self.indexPair] else: self.activePair = None self.canvasScalingFactor = canvasScalingFactor self.isKerningDisplayActive = isKerningDisplayActive self.areVerticalLettersDrawn = areVerticalLettersDrawn self.areGroupsShown = areGroupsShown self.areCollisionsShown = areCollisionsShown self.isSidebearingsActive = isSidebearingsActive self.isCorrectionActive = isCorrectionActive self.isMetricsActive = isMetricsActive self.isColorsActive = isColorsActive self.isSymmetricalEditingOn = isSymmetricalEditingOn self.isSwappedEditingOn = isSwappedEditingOn self.ctrlWidth, self.ctrlHeight = posSize[2], posSize[3] self.checkPairsQuality() self.wordCanvasGroup = CanvasGroup((0, 0, 0, 0), delegate=self)
def __init__(self): self.dotSize = 10 self.glyphs = None self.result = None self.pointer = None self.snap = 5 # snap distance self.snapped = None # index of which point we're snapping on self.orientation = 0.3 self.glyphScale = 0.18 self.glyphs = [None, None, None] self.mGlyphs = None self.startDrag = None self.p1 = self.p2 = self.p3 = None s = 400 self.w = vanilla.Window((s,s), "3nterpolation",minSize=(250,250)) self.w.c = CanvasGroup((0,0,0,0), delegate=self) self.w.bind('resize', self.resize) self.w.open() self.resize() self.w.c.update()
class SpacingMatrix(Group): lineViewSelectedGlyph = None activeGlyph = None activeSide = None activeElement = None def __init__(self, posSize, glyphNamesToDisplay, verticalMode, fontsOrder, callback): super(SpacingMatrix, self).__init__(posSize) self.glyphNamesToDisplay = glyphNamesToDisplay self.fontsOrder = fontsOrder self.verticalMode = verticalMode self.callback = callback self.canvas = CanvasGroup((0, 0, 0, 0), delegate=self) def setGlyphNamesToDisplay(self, glyphNamesToDisplay): self.glyphNamesToDisplay = glyphNamesToDisplay self.refreshActiveElements() if hasattr(self.canvas, 'activeEdit') is True: self.canvas.activeEdit.show(False) def setVerticalMode(self, verticalMode): self.verticalMode = verticalMode def setFontsOrder(self, fontsOrder): self.fontsOrder = fontsOrder def adjustSize(self, size): width, height = size x, y = self.getPosSize()[0:2] self.setPosSize((x, y, width, height)) self.canvas.resize(width, height) self.update() def refreshActiveElements(self): self.activeGlyph = None self.activeSide = None self.activeElement = None self.update() def _killActiveEdit(self): if hasattr(self.canvas, 'activeEdit') is True: delattr(self.canvas, 'activeEdit') def mouseDown(self, notification): self._killActiveEdit() # origin is bottom left of the window, here we adjust the coordinates to the canvas pointerX, pointerY = notification.locationInWindow( ).x - MARGIN_LFT, notification.locationInWindow().y - MARGIN_HALFROW # translate abs coordinates to element indexes xRatio = pointerX / SPACING_COL_WIDTH indexGlyphName = int(xRatio) if indexGlyphName >= len(self.glyphNamesToDisplay): indexGlyphName = None # more on the left or more on the right? if round(xRatio % 1, 0) == 0: self.activeSide = 'lft' else: self.activeSide = 'rgt' if pointerY < len(self.fontsOrder ) * vanillaControlsSize['EditTextSmallHeight'] * 2: yRatio = pointerY / (vanillaControlsSize['EditTextSmallHeight'] * 2) # it starts counting from the bottom, so I have to subtract the result from the length of the fonts order attribute indexFont = len(self.fontsOrder) - int(yRatio) # here I try to understand which ctrl has been clicked if round(yRatio % 1, 0) == 0: self.activeElement = 'margins' else: self.activeElement = 'width' else: indexFont = None # here I init a ctrl for changing metrics if indexGlyphName is None or indexFont is None: self.activeGlyph = None return None else: # we skip the fake .newLine glyphs if self.glyphNamesToDisplay[indexGlyphName] == '.newLine': return None # this is the glyph which should be addressed by the active ctrl self.activeGlyph = self.fontsOrder[indexFont - 1][ self.glyphNamesToDisplay[indexGlyphName]] # how wide the ctrls? it depends if self.activeElement == 'margins': activeEditWidth = SPACING_COL_WIDTH / 2. else: activeEditWidth = SPACING_COL_WIDTH # origin of vanilla ctrls is top left, but indexes are already ok for this, I guess if self.activeElement == 'margins' and self.activeSide == 'rgt': activeEditX = indexGlyphName * SPACING_COL_WIDTH + SPACING_COL_WIDTH / 2. else: activeEditX = indexGlyphName * SPACING_COL_WIDTH if self.activeElement == 'margins': activeEditY = indexFont * vanillaControlsSize[ 'EditTextSmallHeight'] * 2 else: activeEditY = indexFont * vanillaControlsSize[ 'EditTextSmallHeight'] * 2 - vanillaControlsSize[ 'EditTextSmallHeight'] # here I choose the value to display in the ctrl if self.activeElement == 'width': activeValue = self.activeGlyph.width else: if self.activeSide == 'lft': activeValue = self.activeGlyph.leftMargin else: activeValue = self.activeGlyph.rightMargin self.canvas.activeEdit = CustomEditText( (activeEditX, activeEditY, activeEditWidth, vanillaControlsSize['EditTextSmallHeight']), sizeStyle='small', continuous=False, text='{:d}'.format(int(round(activeValue, 0))), callback=self.activeEditCallback) self.canvas.activeEdit.centerAlignment() def activeEditCallback(self, sender): if self.activeGlyph and self.activeSide and self.activeElement: ctrlValue = sender.get() if self.verticalMode is False: glyphsToModify = [self.activeGlyph] else: glyphsToModify = [ ff[self.activeGlyph.name] for ff in self.fontsOrder if ff[self.activeGlyph.name].name == self.activeGlyph.name ] try: # using glyph reference if ctrlValue in self.activeGlyph.getParent().glyphOrder: for eachGlyph in glyphsToModify: sourceGlyph = eachGlyph.getParent()[ctrlValue] if self.activeElement == 'width': eachGlyph.width = sourceGlyph.width else: if self.activeSide == 'lft': eachGlyph.leftMargin = sourceGlyph.leftMargin else: eachGlyph.rightMargin = sourceGlyph.rightMargin # using a numerical value else: value = int(ctrlValue) for eachGlyph in glyphsToModify: if self.activeElement == 'width': eachGlyph.width = value else: if self.activeSide == 'lft': eachGlyph.leftMargin = value else: eachGlyph.rightMargin = value except ValueError: self.canvas.activeEdit.set('') # temp self._killActiveEdit() self.callback(self) self.update() def update(self): self.canvas.update() def draw(self): try: dt.save() dt.font(SYSTEM_FONT_NAME) dt.fontSize(CAPTION_BODY_SIZE) for indexGlyphName, eachGlyphName in enumerate( self.glyphNamesToDisplay): # in this way it does not draw what's outside the canvas frame! if SPACING_COL_WIDTH * indexGlyphName > self.getPosSize()[2]: continue self._drawMatrixColumn(eachGlyphName) dt.translate(SPACING_COL_WIDTH, 0) self._setBoxQualities() dt.line((0, 0), (0, self.getPosSize()[3])) dt.restore() except Exception, error: print traceback.format_exc()
def addInterface(self, notification): self.window = notification['window'] # self.cleanup(self.window) # CONTAINER xywh = (margin, -55, -margin, height) self.sbui = CanvasGroup(xywh, delegate=CanvasStuff(self.window)) # LEFT x, y, w, h = xywh = (0, -height, dfltLwidth, height) this = self.sbui.L = Group(xywh) # text input xywh = (x, y + 3, width * 1.5, height * .75) this.Ltext = EditText(xywh, placeholder='angledLeftMargin', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (x + width * 1.5 + (gap * 1), y, width, height) this.Lminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setLminus) this.Lminus.getNSButton().setToolTip_('Adjust LSB -' + str(unit)) xywh = (x + width * 2.5 + (gap * 2), y, width, height) this.Lplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setLplus) this.Lplus.getNSButton().setToolTip_('Adjust LSB +' + str(unit)) xywh = (x + width * 3.5 + (gap * 3), y, width, height) this.Lround = Button(xywh, iconround, sizeStyle='mini', callback=self.setLround) this.Lround.getNSButton().setToolTip_('Round LSB to ' + str(unit)) xywh = (x + width * 4.5 + (gap * 4), y, width, height) this.Lright = Button(xywh, iconcopyR, sizeStyle='mini', callback=self.setLright) this.Lright.getNSButton().setToolTip_('Copy Right Value') # stylize this.Ltext.getNSTextField().setBezeled_(False) this.Ltext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) self.flatButt(this.Lminus) self.flatButt(this.Lplus) self.flatButt(this.Lround) self.flatButt(this.Lright) # RIGHT x, y, w, h = xywh = (-dfltRwidth, y, dfltRwidth, h) this = self.sbui.R = Group(xywh) # text input xywh = (-x - width * 1.5, y + 3, width * 1.5, height * .75) this.Rtext = EditText(xywh, placeholder='angledRightMargin', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (-x - width * 5.5 - (gap * 4), y, width, height) this.Rleft = Button(xywh, iconcopyL, sizeStyle='mini', callback=self.setRleft) this.Rleft.getNSButton().setToolTip_('Copy Left Value') xywh = (-x - width * 4.5 - (gap * 3), y, width, height) this.Rround = Button(xywh, iconround, sizeStyle='mini', callback=self.setRround) this.Rround.getNSButton().setToolTip_('Round RSB to ' + str(unit)) xywh = (-x - width * 3.5 - (gap * 2), y, width, height) this.Rminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setRminus) this.Rminus.getNSButton().setToolTip_('Adjust RSB -' + str(unit)) xywh = (-x - width * 2.5 - (gap * 1), y, width, height) this.Rplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setRplus) this.Rplus.getNSButton().setToolTip_('Adjust RSB +' + str(unit)) # stylize this.Rtext.getNSTextField().setBezeled_(False) this.Rtext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) this.Rtext.getNSTextField().setAlignment_(NSTextAlignmentRight) self.flatButt(this.Rminus) self.flatButt(this.Rplus) self.flatButt(this.Rround) self.flatButt(this.Rleft) # CENTER winX, winY, winW, winH = self.window.getVisibleRect() winW = winW - margin * 5 x, y, w, h = xywh = ((winW / 2) - (dfltCwidth / 2), y, dfltCwidth, h) this = self.sbui.C = Group(xywh) x = 0 # text input c = (dfltCwidth / 2) xywh = (c - (width * .75), y + 3, width * 1.5, height * .75) this.Ctext = EditText(xywh, placeholder='width', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (c - (width * .75) - width * 2 - (gap * 2), y, width, height) this.Ccenter = Button(xywh, iconcenter, sizeStyle='mini', callback=self.setCcenter) this.Ccenter.getNSButton().setToolTip_('Center on Width') xywh = (c - (width * .75) - width - (gap * 1), y, width, height) this.Cround = Button(xywh, iconround, sizeStyle='mini', callback=self.setCround) this.Cround.getNSButton().setToolTip_('Round Width to ' + str(unit)) xywh = (c + (width * .75) + (gap * 1), y, width, height) this.Cminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setCminus) this.Cminus.getNSButton().setToolTip_('Adjust Width -' + str(2 * unit)) xywh = (c + (width * .75) + width + (gap * 2), y, width, height) this.Cplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setCplus) this.Cplus.getNSButton().setToolTip_('Adjust Width +' + str(2 * unit)) # stylize this.Ctext.getNSTextField().setBezeled_(False) this.Ctext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) this.Ctext.getNSTextField().setAlignment_(NSTextAlignmentCenter) self.flatButt(this.Cminus) self.flatButt(this.Cplus) self.flatButt(this.Cround) self.flatButt(this.Ccenter) # hide self.sbui.L.Lminus.show(False) self.sbui.L.Lround.show(False) self.sbui.L.Lplus.show(False) self.sbui.L.Lright.show(False) self.sbui.R.Rminus.show(False) self.sbui.R.Rround.show(False) self.sbui.R.Rplus.show(False) self.sbui.R.Rleft.show(False) self.sbui.C.Cminus.show(False) self.sbui.C.Cround.show(False) self.sbui.C.Ccenter.show(False) self.sbui.C.Cplus.show(False) # make it real self.sbWatcherInitialize() self.window.addGlyphEditorSubview(self.sbui) self.updateValues() self.buildMatchBase() windowViewManger[self.window] = self.sbui
class GlyphMetricsUI(object): def __init__(self): # debug windowname = 'Debug Glyph Metrics UI' windows = [w for w in NSApp().orderedWindows() if w.isVisible()] for window in windows: print(window.title()) if window.title() == windowname: window.close() if debug == True: self.debug = Window((333, 33), windowname) self.debug.bind('close', self.windowSideuiClose) self.debug.open() # setup self.showButtons = False self.sbui = None # add interface addObserver(self, 'addInterface', 'glyphWindowWillOpen') addObserver(self, 'updateSelfWindow', 'currentGlyphChanged') # toggle visibility of tool ui addObserver(self, 'showSideUIonDraw', 'draw') addObserver(self, 'hideSideUIonPreview', 'drawPreview') # remove UI and window manager when glyph window closes # addObserver(self, "observerGlyphWindowWillClose", "glyphWindowWillClose") # subscribe to glyph changes addObserver(self, "viewDidChangeGlyph", "viewDidChangeGlyph") # def observerGlyphWindowWillClose(self, notification): # self.window = notification['window'] # self.cleanup(self.window) # del windowViewManger[notification['window']] # del lll[notification['window']] # del ccc[notification['window']] # del rrr[notification['window']] def windowSideuiClose(self, sender): self.window.removeGlyphEditorSubview(self.sbui) removeObserver(self, 'glyphWindowWillOpen') removeObserver(self, 'glyphWindowWillClose') removeObserver(self, 'glyphWindowWillClose') removeObserver(self, 'currentGlyphChanged') removeObserver(self, 'draw') removeObserver(self, 'drawPreview') removeObserver(self, 'viewDidChangeGlyph') def cleanup(self, w): try: w.removeGlyphEditorSubview(self.sbui) except: return def addInterface(self, notification): self.window = notification['window'] # self.cleanup(self.window) # CONTAINER xywh = (margin, -55, -margin, height) self.sbui = CanvasGroup(xywh, delegate=CanvasStuff(self.window)) # LEFT x, y, w, h = xywh = (0, -height, dfltLwidth, height) this = self.sbui.L = Group(xywh) # text input xywh = (x, y + 3, width * 1.5, height * .75) this.Ltext = EditText(xywh, placeholder='angledLeftMargin', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (x + width * 1.5 + (gap * 1), y, width, height) this.Lminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setLminus) this.Lminus.getNSButton().setToolTip_('Adjust LSB -' + str(unit)) xywh = (x + width * 2.5 + (gap * 2), y, width, height) this.Lplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setLplus) this.Lplus.getNSButton().setToolTip_('Adjust LSB +' + str(unit)) xywh = (x + width * 3.5 + (gap * 3), y, width, height) this.Lround = Button(xywh, iconround, sizeStyle='mini', callback=self.setLround) this.Lround.getNSButton().setToolTip_('Round LSB to ' + str(unit)) xywh = (x + width * 4.5 + (gap * 4), y, width, height) this.Lright = Button(xywh, iconcopyR, sizeStyle='mini', callback=self.setLright) this.Lright.getNSButton().setToolTip_('Copy Right Value') # stylize this.Ltext.getNSTextField().setBezeled_(False) this.Ltext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) self.flatButt(this.Lminus) self.flatButt(this.Lplus) self.flatButt(this.Lround) self.flatButt(this.Lright) # RIGHT x, y, w, h = xywh = (-dfltRwidth, y, dfltRwidth, h) this = self.sbui.R = Group(xywh) # text input xywh = (-x - width * 1.5, y + 3, width * 1.5, height * .75) this.Rtext = EditText(xywh, placeholder='angledRightMargin', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (-x - width * 5.5 - (gap * 4), y, width, height) this.Rleft = Button(xywh, iconcopyL, sizeStyle='mini', callback=self.setRleft) this.Rleft.getNSButton().setToolTip_('Copy Left Value') xywh = (-x - width * 4.5 - (gap * 3), y, width, height) this.Rround = Button(xywh, iconround, sizeStyle='mini', callback=self.setRround) this.Rround.getNSButton().setToolTip_('Round RSB to ' + str(unit)) xywh = (-x - width * 3.5 - (gap * 2), y, width, height) this.Rminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setRminus) this.Rminus.getNSButton().setToolTip_('Adjust RSB -' + str(unit)) xywh = (-x - width * 2.5 - (gap * 1), y, width, height) this.Rplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setRplus) this.Rplus.getNSButton().setToolTip_('Adjust RSB +' + str(unit)) # stylize this.Rtext.getNSTextField().setBezeled_(False) this.Rtext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) this.Rtext.getNSTextField().setAlignment_(NSTextAlignmentRight) self.flatButt(this.Rminus) self.flatButt(this.Rplus) self.flatButt(this.Rround) self.flatButt(this.Rleft) # CENTER winX, winY, winW, winH = self.window.getVisibleRect() winW = winW - margin * 5 x, y, w, h = xywh = ((winW / 2) - (dfltCwidth / 2), y, dfltCwidth, h) this = self.sbui.C = Group(xywh) x = 0 # text input c = (dfltCwidth / 2) xywh = (c - (width * .75), y + 3, width * 1.5, height * .75) this.Ctext = EditText(xywh, placeholder='width', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (c - (width * .75) - width * 2 - (gap * 2), y, width, height) this.Ccenter = Button(xywh, iconcenter, sizeStyle='mini', callback=self.setCcenter) this.Ccenter.getNSButton().setToolTip_('Center on Width') xywh = (c - (width * .75) - width - (gap * 1), y, width, height) this.Cround = Button(xywh, iconround, sizeStyle='mini', callback=self.setCround) this.Cround.getNSButton().setToolTip_('Round Width to ' + str(unit)) xywh = (c + (width * .75) + (gap * 1), y, width, height) this.Cminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setCminus) this.Cminus.getNSButton().setToolTip_('Adjust Width -' + str(2 * unit)) xywh = (c + (width * .75) + width + (gap * 2), y, width, height) this.Cplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setCplus) this.Cplus.getNSButton().setToolTip_('Adjust Width +' + str(2 * unit)) # stylize this.Ctext.getNSTextField().setBezeled_(False) this.Ctext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) this.Ctext.getNSTextField().setAlignment_(NSTextAlignmentCenter) self.flatButt(this.Cminus) self.flatButt(this.Cplus) self.flatButt(this.Cround) self.flatButt(this.Ccenter) # hide self.sbui.L.Lminus.show(False) self.sbui.L.Lround.show(False) self.sbui.L.Lplus.show(False) self.sbui.L.Lright.show(False) self.sbui.R.Rminus.show(False) self.sbui.R.Rround.show(False) self.sbui.R.Rplus.show(False) self.sbui.R.Rleft.show(False) self.sbui.C.Cminus.show(False) self.sbui.C.Cround.show(False) self.sbui.C.Ccenter.show(False) self.sbui.C.Cplus.show(False) # make it real self.sbWatcherInitialize() self.window.addGlyphEditorSubview(self.sbui) self.updateValues() self.buildMatchBase() windowViewManger[self.window] = self.sbui def updateSelfWindow(self, notification): self.window = CurrentGlyphWindow() self.buildMatchBase() self.updateValues() def showSideUIonDraw(self, notification): self.sbWatcher() sbui = windowViewManger.get(self.window) if sbui is not None: sbui.show(True) def hideSideUIonPreview(self, notification): sbui = windowViewManger.get(self.window) if sbui is not None: sbui.show(False) def updateValues(self, notification=None): try: g = self.window.getGlyph() f = g.font sbui = windowViewManger.get(self.window) sbui.L.Ltext.set(str(g.angledLeftMargin)) sbui.R.Rtext.set(str(g.angledRightMargin)) sbui.C.Ctext.set(str(g.width)) except Exception as e: # if debug == True: # print('Exception updateValues', e) return # hack sidebearings changed observer # used when things redraw def sbWatcherInitialize(self): g = self.window.getGlyph() f = g.font if g is not None: lll[self.window] = g.angledLeftMargin ccc[self.window] = g.width rrr[self.window] = g.angledRightMargin def sbWatcher(self): g = CurrentGlyph() if g is not None: f = g.font if lll[self.window] != None and ccc[self.window] != None and rrr[ self.window] != None: if lll[self.window] != g.angledLeftMargin or ccc[ self.window] != g.width or rrr[ self.window] != g.angledRightMargin: lll[self.window] = g.angledLeftMargin ccc[self.window] = g.width rrr[self.window] = g.angledRightMargin self.updateValues() self.buildMatchBase() def setSB(self, sender): changeAttribute = sender.getPlaceholder() g = self.window.getGlyph() f = g.font v = sender.get() if is_number(v): if debug == True: print('value is a number') g.prepareUndo('Change ' + changeAttribute + ' SB') setattr(g, changeAttribute, float(v)) g.performUndo() self.updateValues() elif v in f: if debug == True: print('value is a glyph') g.prepareUndo('Change ' + changeAttribute + ' SB') sb = getattr(f[v], changeAttribute) setattr(g, changeAttribute, sb) g.performUndo() self.updateValues() else: if debug == True: print('value is not a number or a glyph') return def setLminus(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('➖ Left SB') g.angledLeftMargin += -1 * unit g.performUndo() self.updateValues() def setLround(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Round Left SB') g.angledLeftMargin = int(unit * round(float(g.angledLeftMargin) / unit)) g.performUndo() self.updateValues() def setLplus(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('➕ Left SB') g.angledLeftMargin += unit g.performUndo() self.updateValues() def setLright(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Copy Right SB') g.angledLeftMargin = g.angledRightMargin g.performUndo() self.updateValues() def setLmatch(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Match Left SB') f = g.font gmatch = sender.getTitle() if f[gmatch] is not None: g.angledLeftMargin = f[gmatch].angledLeftMargin g.performUndo() self.updateValues() def setRminus(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('➖ Right SB') g.angledRightMargin += -1 * unit g.performUndo() self.updateValues() def setRround(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Round Right SB') g.angledRightMargin = int(unit * round(float(g.angledRightMargin) / unit)) g.performUndo() self.updateValues() def setRplus(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('➕ Right SB') g.angledRightMargin += unit g.performUndo() self.updateValues() def setRmatch(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Match Right SB') gmatch = sender.getTitle() f = g.font if f[gmatch] is not None: g.angledRightMargin = f[gmatch].angledRightMargin g.performUndo() self.updateValues() def setRleft(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Copy Left SB') g.angledRightMargin = g.angledLeftMargin g.performUndo() self.updateValues() def setCminus(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('➖ Width') # use whole units, not floats oldwidth = g.width leftby = unit g.angledLeftMargin += -1 * leftby g.width = oldwidth - unit * 2 g.performUndo() self.updateValues() def setCround(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Round Width') g.width = int(unit * round(float(g.width) / unit)) g.performUndo() self.updateValues() def setCcenter(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Center on Width') # use whole units, not floats padding = g.angledLeftMargin + g.angledRightMargin gwidth = g.width g.angledLeftMargin = int(padding / 2) g.width = gwidth g.performUndo() self.updateValues() def setCplus(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('➕ Width') # use whole units, not floats oldwidth = g.width leftby = unit g.angledLeftMargin += leftby g.width = oldwidth + unit * 2 g.performUndo() self.updateValues() def setCmatch(self, sender): g = self.window.getGlyph() if g is None: return g.prepareUndo('Match Width') f = g.font gmatch = sender.getTitle() if f[gmatch] is not None: g.width = f[gmatch].width g.performUndo() self.updateValues() def flatButt(self, this, match=False): this = this.getNSButton() this.setBezelStyle_(buttstyle) this.setBordered_(False) this.setWantsLayer_(True) this.setBackgroundColor_(NSColor.whiteColor()) if match == True: this.setBackgroundColor_( NSColor.colorWithCalibratedRed_green_blue_alpha_( .9, 1, .85, 1)) def buildMatchBase(self, notification=None): self.newheight = height try: g = self.window.getGlyph() f = g.font # remove old buttons for i in range(10): if hasattr(self.sbui.L, 'buttobj_%s' % i): delattr(self.sbui.L, 'buttobj_%s' % i) delattr(self.sbui.R, 'buttobj_%s' % i) delattr(self.sbui.C, 'buttobj_%s' % i) # add button for each component self.uniquecomponents = [] for c in g.components: if c.baseGlyph not in self.uniquecomponents: self.uniquecomponents.append(c.baseGlyph) for i, c in enumerate(self.uniquecomponents): row = i + 1 yy = -height * (row + 1) - 3 xywh = (0, yy, width * 5.5 + (gap * 4), height) buttobj = Button(xywh, c, sizeStyle='mini', callback=self.setLmatch) setattr(self.sbui.L, 'buttobj_%s' % i, buttobj) this = getattr(self.sbui.L, 'buttobj_%s' % i) this.getNSButton().setAlignment_(NSTextAlignmentLeft) this.getNSButton().setToolTip_('Match LSB of ' + c) xywh = (-width * 5.5 - (gap * 4), yy, width * 5.5 + (gap * 4), height) buttobj = Button(xywh, c, sizeStyle='mini', callback=self.setRmatch) setattr(self.sbui.R, 'buttobj_%s' % i, buttobj) this = getattr(self.sbui.R, 'buttobj_%s' % i) this.getNSButton().setAlignment_(NSTextAlignmentRight) this.getNSButton().setToolTip_('Match RSB of ' + c) xywh = ((dfltLwidth / 2) - (width * 2.75 + (gap * 2)), yy, width * 5.5 + (gap * 4), height) buttobj = Button(xywh, c, sizeStyle='mini', callback=self.setCmatch) setattr(self.sbui.C, 'buttobj_%s' % i, buttobj) this = getattr(self.sbui.C, 'buttobj_%s' % i) this.getNSButton().setToolTip_('Match Width of ' + c) for i, c in enumerate(self.uniquecomponents): try: this = getattr(self.sbui.L, 'buttobj_%s' % i) # hide if hidden if self.showButtons == False: this.show(False) # check if metrics match base glyphs if int(f[c].angledLeftMargin) == int(g.angledLeftMargin): self.flatButt(this, True) else: self.flatButt(this) this = getattr(self.sbui.R, 'buttobj_%s' % i) if self.showButtons == False: this.show(False) if int(f[c].angledRightMargin) == int(g.angledRightMargin): self.flatButt(this, True) else: self.flatButt(this) this = getattr(self.sbui.C, 'buttobj_%s' % i) if self.showButtons == False: this.show(False) if f[c].width == g.width: self.flatButt(this, True) else: self.flatButt(this) except Exception as e: return # change height of canvas to fit buttons self.newheight = height * (len(self.uniquecomponents) + 2) newy = -55 - height * (len(self.uniquecomponents)) self.sbui.setPosSize((margin, newy, -margin, self.newheight)) self.sbui.L.setPosSize((0, 0, dfltLwidth, self.newheight)) self.sbui.R.setPosSize( (-dfltRwidth, 0, dfltRwidth, self.newheight)) winX, winY, winW, winH = self.window.getVisibleRect() winW = winW - margin * 5 offsetcenter = (winW / 2) - (width * 2.25) self.sbui.C.setPosSize( (offsetcenter, 0, width * 5 + 12, self.newheight)) except Exception as e: return ############################################# # watch for glyph changes ############################################# def viewDidChangeGlyph(self, notification): self.glyph = CurrentGlyph() self.unsubscribeGlyph() self.subscribeGlyph() self.glyphChanged() def subscribeGlyph(self): self.glyph.addObserver(self, 'glyphChanged', 'Glyph.Changed') def unsubscribeGlyph(self): if self.glyph is None: return self.glyph.removeObserver(self, 'Glyph.Changed') def glyphChanged(self, notification=None): self.updateValues()
class WordDisplay(Group): def __init__(self, posSize, displayedWord, canvasScalingFactor, fontObj, isKerningDisplayActive, areVerticalLettersDrawn, areGroupsShown, areCollisionsShown, isSidebearingsActive, isCorrectionActive, isMetricsActive, isColorsActive, isSymmetricalEditingOn, isSwappedEditingOn, indexPair): super(WordDisplay, self).__init__(posSize) self.fontObj = fontObj self.displayedWord = displayedWord self.displayedPairs = buildPairsFromString(self.displayedWord, self.fontObj) self.indexPair = indexPair if indexPair is not None: self.activePair = self.displayedPairs[self.indexPair] else: self.activePair = None self.canvasScalingFactor = canvasScalingFactor self.isKerningDisplayActive = isKerningDisplayActive self.areVerticalLettersDrawn = areVerticalLettersDrawn self.areGroupsShown = areGroupsShown self.areCollisionsShown = areCollisionsShown self.isSidebearingsActive = isSidebearingsActive self.isCorrectionActive = isCorrectionActive self.isMetricsActive = isMetricsActive self.isColorsActive = isColorsActive self.isSymmetricalEditingOn = isSymmetricalEditingOn self.isSwappedEditingOn = isSwappedEditingOn self.ctrlWidth, self.ctrlHeight = posSize[2], posSize[3] self.checkPairsQuality() self.wordCanvasGroup = CanvasGroup((0, 0, 0, 0), delegate=self) def checkPairsQuality(self): for eachPair in self.displayedPairs: status, pairsDB = checkPairConflicts(eachPair, self.fontObj) if status is False: print 'conflicting pairs' print 'please check the DB:', pairsDB def getActivePair(self): return self.activePair def switchGlyphFromGroup(self, location, indexPair): assert location in ['left', 'right'] if self.activePair is None: self.setActivePairIndex(indexPair) if location == 'left': theElem, otherElem = self.activePair else: otherElem, theElem = self.activePair groupReference = whichGroup(theElem, location, self.fontObj) if self.areGroupsShown is True and groupReference is not None: nextElemIndex = (self.fontObj.groups[groupReference].index(theElem) + 1) % len(self.fontObj.groups[groupReference]) if location == 'left': self.activePair = self.fontObj.groups[groupReference][ nextElemIndex], otherElem else: self.activePair = otherElem, self.fontObj.groups[ groupReference][nextElemIndex] self.wordCanvasGroup.update() def setSwappedEditingMode(self, value): self.isSwappedEditingOn = value def setSymmetricalEditingMode(self, value): self.isSymmetricalEditingOn = value def setGraphicsBooleans(self, isKerningDisplayActive, areVerticalLettersDrawn, areGroupsShown, areCollisionsShown, isSidebearingsActive, isCorrectionActive, isMetricsActive, isColorsActive): self.isKerningDisplayActive = isKerningDisplayActive self.areVerticalLettersDrawn = areVerticalLettersDrawn self.areGroupsShown = areGroupsShown self.areCollisionsShown = areCollisionsShown self.isSidebearingsActive = isSidebearingsActive self.isCorrectionActive = isCorrectionActive self.isMetricsActive = isMetricsActive self.isColorsActive = isColorsActive def adjustSize(self, posSize): x, y, width, height = posSize self.setPosSize((x, y, width, height)) self.wordCanvasGroup.setPosSize((0, 0, width, height)) self.wordCanvasGroup.resize(width, height) self.wordCanvasGroup.update() def setDisplayedWord(self, displayedWord): previousLength = len(self.displayedPairs) self.displayedWord = displayedWord self.displayedPairs = buildPairsFromString(self.displayedWord, self.fontObj) if self.indexPair is not None: self.setActivePairIndex(self.indexPair) self.checkPairsQuality() def setScalingFactor(self, scalingFactor): self.canvasScalingFactor = scalingFactor def setActivePairIndex(self, indexPair): self.indexPair = indexPair if self.indexPair is not None: try: self.activePair = self.displayedPairs[self.indexPair] except IndexError: self.activePair = self.displayedPairs[-1] self.indexPair = len(self.displayedPairs) - 1 else: self.activePair = None def setCtrlSize(self, ctrlWidth, ctrlHeight): self.ctrlWidth = ctrlWidth self.ctrlHeight = ctrlHeight def _drawColoredCorrection(self, correction): dt.save() if correction > 0: dt.fill(*LIGHT_GREEN) else: dt.fill(*LIGHT_RED) dt.rect(0, self.fontObj.info.descender, correction, self.fontObj.info.unitsPerEm) dt.restore() def _drawMetricsCorrection(self, correction): dt.save() dt.fill(*BLACK) dt.stroke(None) dt.translate( 0, self.fontObj.info.unitsPerEm + self.fontObj.info.descender + 100) dt.scale(1 / (self.ctrlHeight / (self.canvasScalingFactor * self.fontObj.info.unitsPerEm))) dt.font(SYSTEM_FONT_NAME) dt.fontSize(BODY_SIZE) textWidth, textHeight = dt.textSize('{:+d}'.format(correction)) dt.textBox('{:+d}'.format(correction), (-textWidth / 2., -textHeight / 2., textWidth, textHeight), align='center') dt.restore() def _drawGlyphOutlines(self, glyphName): dt.save() dt.fill(*BLACK) dt.stroke(None) glyphToDisplay = self.fontObj[glyphName] dt.drawGlyph(glyphToDisplay) dt.restore() def _drawMetricsData(self, glyphName, offset): dt.save() glyphToDisplay = self.fontObj[glyphName] dt.translate(0, self.fontObj.info.descender) reverseScalingFactor = 1 / ( self.ctrlHeight / (self.canvasScalingFactor * self.fontObj.info.unitsPerEm)) if self.isSidebearingsActive is True: dt.fill(None) dt.stroke(*BLACK) dt.strokeWidth(reverseScalingFactor) dt.line((0, 0), (0, -offset * reverseScalingFactor)) dt.line((glyphToDisplay.width, 0), (glyphToDisplay.width, -offset * reverseScalingFactor)) dt.restore() dt.save() dt.translate(0, self.fontObj.info.descender) dt.translate(0, -offset * reverseScalingFactor) dt.fill(*BLACK) dt.stroke(None) dt.font(SYSTEM_FONT_NAME) dt.fontSize(BODY_SIZE * reverseScalingFactor) textWidth, textHeight = dt.textSize(u'{}'.format(glyphToDisplay.width)) dt.textBox(u'{:d}'.format(int(glyphToDisplay.width)), (0, 0, glyphToDisplay.width, textHeight * 2), align='center') dt.textBox(u'\n{:d}'.format(int(glyphToDisplay.leftMargin)), (0, 0, glyphToDisplay.width / 2., textHeight * 2), align='center') dt.textBox(u'\n{:d}'.format(int(glyphToDisplay.rightMargin)), (glyphToDisplay.width / 2., 0, glyphToDisplay.width / 2., textHeight * 2), align='center') dt.restore() def _drawBaseline(self, glyphName): glyphToDisplay = self.fontObj[glyphName] dt.save() dt.stroke(*BLACK) dt.fill(None) # reversed scaling factor dt.strokeWidth( 1 / (self.ctrlHeight / (self.canvasScalingFactor * self.fontObj.info.unitsPerEm))) dt.line((0, 0), (glyphToDisplay.width, 0)) dt.restore() def _drawSidebearings(self, glyphName): glyphToDisplay = self.fontObj[glyphName] dt.save() dt.stroke(*BLACK) dt.fill(None) # reversed scaling factor dt.strokeWidth( 1 / (self.ctrlHeight / (self.canvasScalingFactor * self.fontObj.info.unitsPerEm))) dt.fill(*LIGHT_GRAY) dt.line( (0, self.fontObj.info.descender), (0, self.fontObj.info.descender + self.fontObj.info.unitsPerEm)) dt.line((glyphToDisplay.width, self.fontObj.info.descender), (glyphToDisplay.width, self.fontObj.info.descender + self.fontObj.info.unitsPerEm)) dt.restore() def _drawCursor(self, correction, pairKind): assert pairKind in ('gr2gr', 'gr2gl', 'gl2gr', 'gl2gl') or pairKind is None dt.save() if pairKind is None: lftColor = NON_KERNED_COLOR rgtColor = NON_KERNED_COLOR elif pairKind == 'gr2gr': lftColor = GROUP_COLOR rgtColor = GROUP_COLOR elif pairKind == 'gr2gl': lftColor = GROUP_COLOR rgtColor = GLYPH_COLOR elif pairKind == 'gl2gr': lftColor = GLYPH_COLOR rgtColor = GROUP_COLOR else: lftColor = GLYPH_COLOR rgtColor = GLYPH_COLOR lftGlyphName, rgtGlyphName = self.activePair lftGlyph = self.fontObj[lftGlyphName] rgtGlyph = self.fontObj[rgtGlyphName] lftCursorWidth = lftGlyph.width / 2. + correction / 2. rgtCursorWidth = rgtGlyph.width / 2. + correction / 2. cursorHeight = 50 # upm # lft dt.fill(*lftColor) dt.rect(-lftGlyph.width / 2. - correction, self.fontObj.info.descender - cursorHeight + cursorHeight / 2., lftCursorWidth, cursorHeight) # rgt dt.fill(*rgtColor) dt.rect(-correction / 2., self.fontObj.info.descender - cursorHeight + cursorHeight / 2., rgtCursorWidth, cursorHeight) dt.restore() def _drawGlyphOutlinesFromGroups(self, aPair, kerningReference, correction): prevGlyphName, eachGlyphName = aPair if kerningReference is not None: lftReference, rgtReference = kerningReference else: lftReference = whichGroup(prevGlyphName, 'left', self.fontObj) rgtReference = whichGroup(eachGlyphName, 'right', self.fontObj) prevGlyph, eachGlyph = self.fontObj[prevGlyphName], self.fontObj[ eachGlyphName] reverseScalingFactor = 1 / ( self.ctrlHeight / (self.canvasScalingFactor * self.fontObj.info.unitsPerEm)) # _L__ group if lftReference: if lftReference.startswith('@MMK_L_'): dt.save() dt.fill(*LAYERED_GLYPHS_COLOR) groupContent = self.fontObj.groups[lftReference] if len(groupContent) > 1: for eachGroupSibling in groupContent: if eachGroupSibling != prevGlyphName: glyphToDisplay = self.fontObj[eachGroupSibling] dt.save() dt.translate( -glyphToDisplay.width, 0 ) # back, according to his width, otherwise it does not coincide dt.drawGlyph(glyphToDisplay) dt.restore() dt.fill(*BLACK) # caption dt.translate(-prevGlyph.width, 0) # we need a caption in the right place dt.font(SYSTEM_FONT_NAME) dt.fontSize(GROUP_NAME_BODY_SIZE * reverseScalingFactor) textWidth, textHeight = dt.textSize(lftReference) dt.text(lftReference, (glyphToDisplay.width / 2. - textWidth / 2., -GROUP_NAME_BODY_SIZE * reverseScalingFactor * 2)) dt.restore() # _R__ group if rgtReference: if rgtReference.startswith('@MMK_R_'): dt.save() dt.translate(correction, 0) dt.fill(*LAYERED_GLYPHS_COLOR) groupContent = self.fontObj.groups[rgtReference] if len(groupContent) > 1: for eachGroupSibling in groupContent: if eachGroupSibling != eachGlyphName: glyphToDisplay = self.fontObj[eachGroupSibling] dt.drawGlyph(glyphToDisplay) dt.fill(*BLACK) dt.font(SYSTEM_FONT_NAME) dt.fontSize(GROUP_NAME_BODY_SIZE * reverseScalingFactor) textWidth, textHeight = dt.textSize(rgtReference) dt.text(rgtReference, (glyphToDisplay.width / 2. - textWidth / 2., -GROUP_NAME_BODY_SIZE * reverseScalingFactor * 2)) dt.restore() def _drawCollisions(self, aPair): dt.save() correction, kerningReference, pairKind = getCorrection( aPair, self.fontObj) if kerningReference is None: lftName, rgtName = aPair else: lftName, rgtName = kerningReference lftGlyphs = [] if lftName.startswith('@MMK') is True: lftGlyphs = self.fontObj.groups[lftName] else: lftGlyphs = [lftName] rgtGlyphs = [] if rgtName.startswith('@MMK') is True: rgtGlyphs = self.fontObj.groups[rgtName] else: rgtGlyphs = [rgtName] dt.fontSize(COLLISION_BODY_SIZE) breakCycle = False for eachLftName in lftGlyphs: for eachRgtName in rgtGlyphs: isTouching = checkIfPairOverlaps(self.fontObj[eachLftName], self.fontObj[eachRgtName]) if isTouching: dt.text(u'💥', (0, 0)) breakCycle = True break if breakCycle is True: break dt.restore() def _drawException(self, aPair, correction): lftGlyphName, rgtGlyphName = aPair lftGlyph, rgtGlyph = self.fontObj[lftGlyphName], self.fontObj[ rgtGlyphName] dt.save() dt.fill(None) dt.stroke(*LIGHT_GRAY) dt.strokeWidth(20) # calc wiggle line pt1 = Point(-lftGlyph.width, 0) pt2 = Point(rgtGlyph.width + correction, 0) wigglePoints = calcWiggle(pt1, pt2, 100, 100, .65) # draw wiggle line dt.newPath() dt.moveTo(wigglePoints[0]) for eachBcpOut, eachBcpIn, eachAnchor in wigglePoints[1:]: dt.curveTo(eachBcpOut, eachBcpIn, eachAnchor) dt.drawPath() dt.restore() def draw(self): try: glyphsToDisplay = splitText(self.displayedWord, self.fontObj.naked().unicodeData) # if the user switches the glyphs from the groups # here we have to arrange the list of glyphnames properly if self.activePair is not None: lftName, rgtName = self.activePair glyphsToDisplay[self.indexPair] = lftName glyphsToDisplay[self.indexPair + 1] = rgtName # here we draw dt.save() # this is for safety reason, user should be notified about possible unwanted kerning corrections if self.isSwappedEditingOn is True: dt.save() dt.fill(*FLIPPED_BACKGROUND_COLOR) dt.rect(0, 0, self.ctrlWidth, self.ctrlHeight) dt.restore() if self.isSymmetricalEditingOn is True: dt.save() dt.fill(*SYMMETRICAL_BACKGROUND_COLOR) dt.rect(0, 0, self.ctrlWidth, self.ctrlHeight) dt.restore() dt.scale( self.ctrlHeight / (self.canvasScalingFactor * self.fontObj.info.unitsPerEm) ) # the canvas is virtually scaled according to self.canvasScalingFactor value and canvasSize dt.translate(TEXT_MARGIN, 0) # group glyphs dt.translate(0, 600) if self.areGroupsShown is True: dt.save() prevGlyphName = None for indexChar, eachGlyphName in enumerate(glyphsToDisplay): eachGlyph = self.fontObj[eachGlyphName] # this is for kerning if indexChar > 0: correction, kerningReference, pairKind = getCorrection( (prevGlyphName, eachGlyphName), self.fontObj) if kerningReference: exceptionStatus, doesExists, exceptionParents = isPairException( kerningReference, self.fontObj) if exceptionStatus is True: self._drawException( (prevGlyphName, eachGlyphName), correction) if (indexChar - 1) == self.indexPair: if correction is None: offsetCorrection = 0 else: offsetCorrection = correction self._drawGlyphOutlinesFromGroups( (prevGlyphName, eachGlyphName), kerningReference, offsetCorrection) if correction and correction != 0 and self.isKerningDisplayActive: dt.translate(correction, 0) dt.translate(eachGlyph.width, 0) prevGlyphName = eachGlyphName dt.restore() # background loop dt.save() glyphsToDisplayTotalWidth = 0 prevGlyphName = None for indexChar, eachGlyphName in enumerate(glyphsToDisplay): eachGlyph = self.fontObj[eachGlyphName] # this is for kerning if indexChar > 0: correction, kerningReference, pairKind = getCorrection( (prevGlyphName, eachGlyphName), self.fontObj) if self.isKerningDisplayActive and correction is not None: if correction != 0 and self.isColorsActive is True: self._drawColoredCorrection(correction) if self.isCorrectionActive is True: self._drawMetricsCorrection(correction) dt.translate(correction, 0) glyphsToDisplayTotalWidth += correction if (indexChar - 1) == self.indexPair: if correction is None: offsetCorrection = 0 else: offsetCorrection = correction self._drawCursor(offsetCorrection, pairKind) # # draw metrics info if self.isMetricsActive is True: self._drawMetricsData(eachGlyphName, 52) if self.isSidebearingsActive is True: self._drawBaseline(eachGlyphName) self._drawSidebearings(eachGlyphName) dt.translate(eachGlyph.width, 0) glyphsToDisplayTotalWidth += eachGlyph.width prevGlyphName = eachGlyphName dt.restore() # foreground loop dt.save() prevGlyphName = None for indexChar, eachGlyphName in enumerate(glyphsToDisplay): eachGlyph = self.fontObj[eachGlyphName] # this is for kerning if indexChar > 0: correction, kerningReference, pairKind = getCorrection( (prevGlyphName, eachGlyphName), self.fontObj) if correction and correction != 0 and self.isKerningDisplayActive: dt.translate(correction, 0) self._drawGlyphOutlines(eachGlyphName) dt.translate(eachGlyph.width, 0) prevGlyphName = eachGlyphName dt.restore() # collisions loop if self.areCollisionsShown is True: dt.save() prevGlyphName = None for indexChar, eachGlyphName in enumerate(glyphsToDisplay): eachGlyph = self.fontObj[eachGlyphName] if indexChar > 0: correction, kerningReference, pairKind = getCorrection( (prevGlyphName, eachGlyphName), self.fontObj) if correction and correction != 0 and self.isKerningDisplayActive: dt.translate(correction, 0) if (indexChar - 1) == self.indexPair: self._drawCollisions( (prevGlyphName, eachGlyphName)) dt.translate(eachGlyph.width, 0) prevGlyphName = eachGlyphName dt.restore() # main restore, it wraps the three loops dt.restore() if self.areVerticalLettersDrawn is True: # separate from the rest, we put the vertical letters dt.save() # we push the matrix forward dt.translate(self.ctrlWidth, 0) # then we rotate dt.rotate(90) # then we scale, but how much? a quarter of the main lettering dt.scale( self.ctrlHeight / (self.canvasScalingFactor * self.fontObj.info.unitsPerEm) * .25) # the reference is the baseline, so we have to put some air below the letters dt.translate(0, 600) # upm value # let's define the graphics dt.fill(*BLACK) dt.stroke(None) # then we draw, we need a prevGlyphName in order to get kerning correction prevGlyphName = None # we iterate on the letters we need to draw + a space as a margin for indexChar, eachGlyphName in enumerate(['space'] + glyphsToDisplay): # accessing the glyph obj eachGlyph = self.fontObj[eachGlyphName] # if it isn't the first letter... if indexChar > 0: # ... we grab the kerning correction from the pair correction, kerningReference, pairKind = getCorrection( (prevGlyphName, eachGlyphName), self.fontObj) # if there is any correction... if correction and correction != 0 and self.isKerningDisplayActive: # ... we apply it to the transformation matrix dt.translate(correction, 0) # then we draw the outlines self._drawGlyphOutlines(eachGlyphName) # and we move the transformation matrix according to glyph width dt.translate(eachGlyph.width, 0) # then we load the glyph to the prevGlyphName prevGlyphName = eachGlyphName # restoring the vertical drawing dt.restore() except Exception: print traceback.format_exc()
def __init__(self, posSize, interface, sheet): super(DesignFrame, self).__init__(posSize) self.ui = interface self.s = sheet y = 10 self.EM_Dimension_title = TextBox((10,y,200,20), "EM Dimension (FU)", sizeStyle = "small") self.EM_DimensionX_title = TextBox((145,y,20,20), "X:", sizeStyle = "small") self.EM_DimensionX_editText = EditText((160,y-3,45,20), self.s.EM_Dimension_X, callback = self.EM_DimensionX_editText_callback, sizeStyle = "small") self.EM_DimensionY_title = TextBox((235,y,20,20), "Y:", sizeStyle = "small") self.EM_DimensionY_editText = EditText((250,y-3,45,20), self.s.EM_Dimension_Y, callback = self.EM_DimensionY_editText_callback, sizeStyle = "small") y += 30 self.characterFace_title = TextBox((10,y,200,20), "Character Face (EM%)", sizeStyle = "small") self.characterFacePercent_title = TextBox((208,y,30,20), "%", sizeStyle = "small") self.characterFace_editText = EditText((160,y-3,45,20), self.s.characterFace, callback = self.characterFace_editText_callback, sizeStyle = "small") y += 30 self.overshoot_title = TextBox((10,y,200,20), "Overshoot (FU)", sizeStyle = "small") self.overshootOutside_title = TextBox((110,y,70,20), "Outside:", sizeStyle = "small") self.overshootOutside_editText = EditText((160,y-3,45,20), self.s.overshootOutsideValue, callback = self.overshootOutside_editText_callback, sizeStyle = "small") self.overshootInside_title = TextBox((210,y,60,20), "Inside:", sizeStyle = "small") self.overshootInside_editText = EditText((250,y-3,45,20), self.s.overshootInsideValue, callback = self.overshootInside_editText_callback, sizeStyle = "small") y += 30 self.horizontalLine_title = TextBox((10,y,140,20), "Horizontal Line (EM%)", sizeStyle = "small") self.horizontalLine_slider = Slider((160,y-3 ,135,20), minValue = 0, maxValue = 50, value = 0, sizeStyle = "small", callback = self._horizontalLine_slider_callback) y += 30 self.verticalLine_title = TextBox((10,y,140,20), "Vertical Line (EM%)", sizeStyle = "small") self.verticalLine_slider = Slider((160,y-3 ,135,20), minValue = 0, maxValue = 50, value = 0, sizeStyle = "small", callback = self._verticalLine_slider_callback) y += 30 self.customsFrames_title = TextBox((10,y,200,20), "Customs Frames (EM%):", sizeStyle = "small") y += 20 slider = SliderListCell() self.customsFrames_list = List((10,y,285,-30), self.s.customsFrames, columnDescriptions = [{"title": "Name", "width" : 75}, {"title": "Values", "width" : 200, "cell": slider}], editCallback = self._customsFrames_list_editCallback, drawFocusRing = False) self.addCustomsFrames_button = Button((170,-28,62,-10), "+", callback = self._addCustomsFrames_button_callback, sizeStyle="small") self.removeCustomsFrames_button = Button((232,-28,62,-10), "-", callback = self._removeCustomsFrames_button_callback, sizeStyle="small") self.s.translateX,self.s.translateY = 0, 0 self.canvas = CanvasGroup((-295,10,-10,-10), delegate=ProjectCanvas(self.s, "DesignFrame", self)) self.s.w.bind('close', self.windowWillClose) self.observer()
class DesignFrame(Group): def __init__(self, posSize, interface, sheet): super(DesignFrame, self).__init__(posSize) self.ui = interface self.s = sheet y = 10 self.EM_Dimension_title = TextBox((10,y,200,20), "EM Dimension (FU)", sizeStyle = "small") self.EM_DimensionX_title = TextBox((145,y,20,20), "X:", sizeStyle = "small") self.EM_DimensionX_editText = EditText((160,y-3,45,20), self.s.EM_Dimension_X, callback = self.EM_DimensionX_editText_callback, sizeStyle = "small") self.EM_DimensionY_title = TextBox((235,y,20,20), "Y:", sizeStyle = "small") self.EM_DimensionY_editText = EditText((250,y-3,45,20), self.s.EM_Dimension_Y, callback = self.EM_DimensionY_editText_callback, sizeStyle = "small") y += 30 self.characterFace_title = TextBox((10,y,200,20), "Character Face (EM%)", sizeStyle = "small") self.characterFacePercent_title = TextBox((208,y,30,20), "%", sizeStyle = "small") self.characterFace_editText = EditText((160,y-3,45,20), self.s.characterFace, callback = self.characterFace_editText_callback, sizeStyle = "small") y += 30 self.overshoot_title = TextBox((10,y,200,20), "Overshoot (FU)", sizeStyle = "small") self.overshootOutside_title = TextBox((110,y,70,20), "Outside:", sizeStyle = "small") self.overshootOutside_editText = EditText((160,y-3,45,20), self.s.overshootOutsideValue, callback = self.overshootOutside_editText_callback, sizeStyle = "small") self.overshootInside_title = TextBox((210,y,60,20), "Inside:", sizeStyle = "small") self.overshootInside_editText = EditText((250,y-3,45,20), self.s.overshootInsideValue, callback = self.overshootInside_editText_callback, sizeStyle = "small") y += 30 self.horizontalLine_title = TextBox((10,y,140,20), "Horizontal Line (EM%)", sizeStyle = "small") self.horizontalLine_slider = Slider((160,y-3 ,135,20), minValue = 0, maxValue = 50, value = 0, sizeStyle = "small", callback = self._horizontalLine_slider_callback) y += 30 self.verticalLine_title = TextBox((10,y,140,20), "Vertical Line (EM%)", sizeStyle = "small") self.verticalLine_slider = Slider((160,y-3 ,135,20), minValue = 0, maxValue = 50, value = 0, sizeStyle = "small", callback = self._verticalLine_slider_callback) y += 30 self.customsFrames_title = TextBox((10,y,200,20), "Customs Frames (EM%):", sizeStyle = "small") y += 20 slider = SliderListCell() self.customsFrames_list = List((10,y,285,-30), self.s.customsFrames, columnDescriptions = [{"title": "Name", "width" : 75}, {"title": "Values", "width" : 200, "cell": slider}], editCallback = self._customsFrames_list_editCallback, drawFocusRing = False) self.addCustomsFrames_button = Button((170,-28,62,-10), "+", callback = self._addCustomsFrames_button_callback, sizeStyle="small") self.removeCustomsFrames_button = Button((232,-28,62,-10), "-", callback = self._removeCustomsFrames_button_callback, sizeStyle="small") self.s.translateX,self.s.translateY = 0, 0 self.canvas = CanvasGroup((-295,10,-10,-10), delegate=ProjectCanvas(self.s, "DesignFrame", self)) self.s.w.bind('close', self.windowWillClose) self.observer() def update(self): self.canvas.update() UpdateCurrentGlyphView() def EM_DimensionX_editText_callback(self, sender): try: self.s.EM_Dimension_X = int(sender.get()) except: sender.set(self.s.EM_Dimension_X) self.update() def EM_DimensionY_editText_callback(self, sender): try: self.s.EM_Dimension_Y = int(sender.get()) except: sender.set(self.s.EM_Dimension_Y) self.update() def characterFace_editText_callback(self, sender): try: value = int(sender.get()) if 0 <= value <= 100: self.s.characterFace = value else: sender.set(self.s.characterFace) except: sender.set(self.s.characterFace) self.update() def overshootOutside_editText_callback(self, sender): try: self.s.overshootOutsideValue = int(sender.get()) except: sender.set(self.s.overshootOutsideValue) self.update() def overshootInside_editText_callback(self, sender): try: self.s.overshootInsideValue = int(sender.get()) except: sender.set(self.s.overshootInsideValue) self.update() def _horizontalLine_slider_callback(self, sender): self.s.horizontalLine = int(sender.get()) self.update() def _verticalLine_slider_callback(self, sender): self.s.verticalLine = int(sender.get()) self.update() def _customsFrames_list_editCallback(self, sender): self.s.customsFrames = sender.get() self.update() def _addCustomsFrames_button_callback(self, sender): name = "Frame%i"%len(self.s.customsFrames) self.s.customsFrames.append({"Name":name}) self.customsFrames_list.set(self.s.customsFrames) self.update() def _removeCustomsFrames_button_callback(self, sender): # Get the customsFrames list selection sel = self.customsFrames_list.getSelection() if not sel: return # Delete the selection from the customsFrames self.s.customsFrames = [e for i, e in enumerate(self.s.customsFrames) if i not in sel] self.customsFrames_list.set(self.s.customsFrames) self.update() def draw(self, info): if self.s.glyph is None: return s = info['scale'] strokeWidth(.6*s) DesignFrameDrawer(self.s).draw() def windowWillClose(self, sender): self.observer(remove=True) def observer(self, remove = False): if not remove: addObserver(self, "draw", "draw") addObserver(self, "draw", "drawInactive") return removeObserver(self, "draw") removeObserver(self, "drawInactive")
def __init__(self, willOpen=True): super(SidebearingsLinker, self).__init__() # collecting fonts self.allFonts = AllFonts() if self.allFonts != []: self.selectedFont = self.allFonts[0] # interface self.w = FloatingWindow((PLUGIN_WIDTH, PLUGIN_HEIGHT), PLUGIN_TITLE) jumpingY = MARGIN_VER self.w.fontPopUp = PopUpButton( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['PopUpButtonRegularHeight']), getNamesFrom(self.allFonts), callback=self.fontPopUpCallback) jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_ROW self.w.canvas = CanvasGroup( (MARGIN_HOR, jumpingY, NET_WIDTH, CANVAS_HEIGHT), delegate=self) jumpingY += CANVAS_HEIGHT + MARGIN_ROW linksColumnDescriptions = [{ "title": "left", 'key': 'lft', 'width': LIST_WIDE_COL }, { "title": "active", "cell": CheckBoxListCell(), 'key': 'lftActive', 'width': LIST_NARROW_COL }, { "title": "glyph", 'key': 'servant', 'width': LIST_WIDE_COL, "editable": False }, { "title": "active", "cell": CheckBoxListCell(), 'key': 'rgtActive', 'width': LIST_NARROW_COL }, { "title": "right", 'key': 'rgt', 'width': LIST_WIDE_COL }] if self.selectedFont is not None: links = loadLinksFromFont(self.selectedFont) else: links = [] self.w.linksList = List( (MARGIN_HOR, jumpingY, NET_WIDTH, 200), links, showColumnTitles=False, allowsMultipleSelection=False, drawVerticalLines=True, columnDescriptions=linksColumnDescriptions, selectionCallback=self.selectionLinksListCallback, editCallback=self.editLinksListCallback) if self.selectedFont is not None: self.w.linksList.setSelection([0]) self.currentRow = self.w.linksList[0] self.matchDisplayedSubscriptions() jumpingY += self.w.linksList.getPosSize()[3] + MARGIN_ROW buttonWidth = (NET_WIDTH - MARGIN_HOR) / 2 self.w.linkAllButton = SquareButton( (MARGIN_HOR, jumpingY, buttonWidth, vanillaControlsSize['ButtonRegularHeight'] * 1.5), 'Link All', callback=self.linkAllButtonCallback) self.w.unlockAllButton = SquareButton( (MARGIN_HOR * 2 + buttonWidth, jumpingY, buttonWidth, vanillaControlsSize['ButtonRegularHeight'] * 1.5), 'Unlink All', callback=self.unlockAllButtonCallback) jumpingY += vanillaControlsSize[ 'ButtonRegularHeight'] * 1.5 + MARGIN_ROW self.w.separationLineOne = HorizontalLine( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['HorizontalLineThickness'])) jumpingY += MARGIN_ROW self.w.pushIntoFontButton = SquareButton( (MARGIN_HOR, jumpingY, buttonWidth, vanillaControlsSize['ButtonRegularHeight'] * 1.5), 'Push into font', callback=self.pushIntoFontButtonCallback) self.w.pushIntoFontButton.enable(False) self.w.clearLibsButton = SquareButton( (MARGIN_HOR * 2 + buttonWidth, jumpingY, buttonWidth, vanillaControlsSize['ButtonRegularHeight'] * 1.5), 'Clear Libs', callback=self.clearLibsButtonCallback) jumpingY += vanillaControlsSize[ 'ButtonRegularHeight'] * 1.5 + MARGIN_ROW self.w.loadFromTable = SquareButton( (MARGIN_HOR, jumpingY, buttonWidth, vanillaControlsSize['ButtonRegularHeight'] * 1.5), 'Load from table', callback=self.loadFromTableCallback) self.w.loadFromTable.enable(True) self.w.exportTable = SquareButton( (MARGIN_HOR * 2 + buttonWidth, jumpingY, buttonWidth, vanillaControlsSize['ButtonRegularHeight'] * 1.5), 'Export table', callback=self.exportTableCallback) self.w.exportTable.enable(True) jumpingY += vanillaControlsSize[ 'ButtonRegularHeight'] * 1.5 + MARGIN_VER * 2 self.w.resize(PLUGIN_WIDTH, jumpingY) self.setUpBaseWindowBehavior() if self.selectedFont is not None: self.matchSubscriptions() result = askYesNo('Warning', 'Do you want to align servants to masters?') if bool(result) is True: self._alignServantsToMasters() addObserver(self, "drawOnGlyphCanvas", "draw") addObserver(self, "drawOnGlyphCanvas", "drawInactive") addObserver(self, 'fontDidOpenCallback', 'fontDidOpen') addObserver(self, 'fontDidCloseCallback', 'fontDidClose') if willOpen is True: self.w.open()
def __init__(self): self.w = FloatingWindow((400, 450), "Tracer", minSize=(400, 400)) middle = 130 gap = 15 y = 10 self.w.thresholdText = TextBox((10, y + 1, middle, 22), "Threshold:", alignment="right") self.w.threshold = Slider((middle + gap, y, -10, 22), minValue=0, maxValue=1, value=.2, continuous=False, callback=self.makePreview) y += 30 self.w.blurText = TextBox((10, y + 1, middle, 22), "Blur:", alignment="right") self.w.blur = Slider((middle + gap, y, -10, 22), minValue=0, maxValue=30, value=0, continuous=False, callback=self.makePreview) y += 30 self.w.invert = CheckBox((middle + gap, y + 2, -10, 22), "Invert", callback=self.makePreview) y += 30 self.w.turdsizeText = TextBox((10, y + 1, middle, 22), "Suppress Speckles:", alignment="right") self.w.turdsize = Slider((middle + gap, y, -10, 22), minValue=0, maxValue=30, value=2, continuous=False, callback=self.makePreview) y += 30 self.w.opttoleranceText = TextBox((10, y + 1, middle, 22), "Tolerance:", alignment="right") self.w.opttolerance = Slider((middle + gap, y, -10, 22), minValue=0, maxValue=2, value=0.2, continuous=False, callback=self.makePreview) y += 25 _y = -40 self.w.preview = CanvasGroup((0, y, -0, _y), delegate=self) self._previewImage = None self._previewGlyph = None _y = -30 self.w.trace = Button((-100, _y, -10, 22), "Trace", callback=self.trace) self.w.traceFont = Button((-210, _y, -110, 22), "Trace Font", callback=self.traceFont) self.w.update = Button((-300, _y, -220, 22), "Update", callback=self.makePreview) self.w.showPreview = CheckBox((10, _y, 100, 22), "Preview", value=True, callback=self.makePreview) self.w.setDefaultButton(self.w.trace) self.makePreview() self.w.open()
def __init__(self, posSize, interface, sheet): super(ReferenceViewer, self).__init__(posSize) self.ui = interface self.s = sheet self.FontList_comboBox = ComboBox((10, 10, 130, 18), Global.fontsList.get(), sizeStyle='small') self.FontList_comboBox.set(Global.fontsList.get()[0]) self.addReferenceFont_button = Button( (150, 9, 70, 20), "Add", sizeStyle="small", callback=self._addReferenceFont_button_callback) self.removeReference_button = Button( (225, 9, 70, 20), "Remove", sizeStyle="small", callback=self._removeReference_button_callback) self.s.reference_list_selection = [] self.reference_list = List( (10, 35, 285, 125), self.s.referenceViewerList, columnDescriptions=[{ "title": "Font" }], selectionCallback=self._reference_list_selectionCallback, drawFocusRing=False) self.settings = Group((10, 170, 295, -0)) self.settings.show(0) y = 3 self.settings.size_title = TextBox((0, y, 100, 20), "Size (FU)", sizeStyle="small") self.settings.size_editText = EditText( (-60, y - 3, -10, 20), "", sizeStyle="small", callback=self._size_editText_callback) self.settings.size_slider = Slider((90, y - 3, -65, 20), minValue=0, maxValue=1000, value=250, sizeStyle="small", callback=self._size_slider_callback) y += 30 self.settings.color_title = TextBox((0, y, 100, 20), "Color (FU)", sizeStyle="small") self.settings.color_colorWell = ColorWell( (90, y - 3, -10, 20), callback=self._color_editText_callback, color=NSColor.grayColor()) self.canvas = CanvasGroup( (-295, 10, -10, -10), delegate=ProjectCanvas(self.s, "ReferenceViewer", self)) self.s.w.bind('close', self.windowWillClose) self.observer()
class ReferenceViewer(Group): def __init__(self, posSize, interface, sheet): super(ReferenceViewer, self).__init__(posSize) self.ui = interface self.s = sheet self.FontList_comboBox = ComboBox((10, 10, 130, 18), Global.fontsList.get(), sizeStyle='small') self.FontList_comboBox.set(Global.fontsList.get()[0]) self.addReferenceFont_button = Button( (150, 9, 70, 20), "Add", sizeStyle="small", callback=self._addReferenceFont_button_callback) self.removeReference_button = Button( (225, 9, 70, 20), "Remove", sizeStyle="small", callback=self._removeReference_button_callback) self.s.reference_list_selection = [] self.reference_list = List( (10, 35, 285, 125), self.s.referenceViewerList, columnDescriptions=[{ "title": "Font" }], selectionCallback=self._reference_list_selectionCallback, drawFocusRing=False) self.settings = Group((10, 170, 295, -0)) self.settings.show(0) y = 3 self.settings.size_title = TextBox((0, y, 100, 20), "Size (FU)", sizeStyle="small") self.settings.size_editText = EditText( (-60, y - 3, -10, 20), "", sizeStyle="small", callback=self._size_editText_callback) self.settings.size_slider = Slider((90, y - 3, -65, 20), minValue=0, maxValue=1000, value=250, sizeStyle="small", callback=self._size_slider_callback) y += 30 self.settings.color_title = TextBox((0, y, 100, 20), "Color (FU)", sizeStyle="small") self.settings.color_colorWell = ColorWell( (90, y - 3, -10, 20), callback=self._color_editText_callback, color=NSColor.grayColor()) self.canvas = CanvasGroup( (-295, 10, -10, -10), delegate=ProjectCanvas(self.s, "ReferenceViewer", self)) self.s.w.bind('close', self.windowWillClose) self.observer() def update(self): self.canvas.update() UpdateCurrentGlyphView() def _addReferenceFont_button_callback(self, sender): font = self.FontList_comboBox.get() if font is None or font == "": return # Default values new_elem = { "font": font, "size": 400, "x": -500, "y": 40, "color": (0, 0, 0, .56) } self.s.referenceViewerSettings.append(new_elem) self.s.referenceViewerList.append({"Font": font}) self.reference_list.set(self.s.referenceViewerList) self.reference_list.setSelection([len(self.s.referenceViewerList) - 1]) self.update() def _removeReference_button_callback(self, sender): sel = self.reference_list.getSelection() if sel is None: return def remove(l): return [e for i, e in enumerate(l) if i not in sel] self.s.referenceViewerSettings = remove(self.s.referenceViewerSettings) self.s.referenceViewerList = remove(self.s.referenceViewerList) self.reference_list.set(self.s.referenceViewerList) self.reference_list.setSelection([len(self.s.referenceViewerList) - 1]) self.update() def _reference_list_selectionCallback(self, sender): self.s.reference_list_selection = sender.getSelection() if not self.s.reference_list_selection: self.settings.show(0) return self.settings.show(1) settings = self.s.referenceViewerSettings[ self.s.reference_list_selection[0]] self.settings.size_editText.set(settings["size"]) self.settings.size_slider.set(settings["size"]) colors = settings["color"] color = NSColor.colorWithCalibratedRed_green_blue_alpha_( colors[0], colors[1], colors[2], colors[3]) self.settings.color_colorWell.set(color) def _size_editText_callback(self, sender): if not self.s.reference_list_selection: return size = self.s.referenceViewerSettings[ self.s.reference_list_selection[0]]["size"] try: size = int(sender.get()) except: sender.set(size) self.s.referenceViewerSettings[ self.s.reference_list_selection[0]]["size"] = size self.settings.size_slider.set(size) self.update() def _size_slider_callback(self, sender): if not self.s.reference_list_selection: return self.s.referenceViewerSettings[ self.s.reference_list_selection[0]]["size"] = int(sender.get()) self.settings.size_editText.set(self.s.referenceViewerSettings[ self.s.reference_list_selection[0]]["size"]) self.update() def _color_editText_callback(self, sender): if not self.s.reference_list_selection: return color = sender.get() self.s.referenceViewerSettings[ self.s.reference_list_selection[0]]["color"] = ( color.redComponent(), color.greenComponent(), color.blueComponent(), color.alphaComponent(), ) self.update() def draw(self, info): if self.s.glyph is None: return if self.s.glyph.name.startswith("uni"): txt = chr(int(self.s.glyph.name[3:7], 16)) elif self.s.glyph.unicode: txt = chr(self.s.glyph.unicode) else: txt = "" ReferenceViewerDraw(self.s, txt) def windowWillClose(self, sender): self.observer(remove=True) def observer(self, remove=False): if not remove: addObserver(self, "draw", "draw") addObserver(self, "draw", "drawInactive") return removeObserver(self, "draw") removeObserver(self, "drawInactive")