class JumpToLineWindow(BaseWindowController): lineNumber = None def __init__(self, callback): super(JumpToLineWindow, self).__init__() self.callback = callback # init the window self.w = FloatingWindow((WINDOW_WIDTH, 0), 'Jump to line') # edit text caption jumpingY = MARGIN_TOP self.w.caption = TextBox((MARGIN_LFT, jumpingY + 3, NET_WIDTH * .6, vanillaControlsSize['TextBoxRegularHeight']), 'Jump to line:') self.w.lineEdit = EditText( (MARGIN_LFT + NET_WIDTH * .6, jumpingY, -MARGIN_RGT, vanillaControlsSize['EditTextRegularHeight']), continuous=False) jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_INT self.w.cancelButton = Button( (-(BUTTON_WIDTH * 2 + MARGIN_INT + MARGIN_RGT), jumpingY, BUTTON_WIDTH, vanillaControlsSize['ButtonRegularHeight']), 'Cancel', callback=self.cancelButtonCallback) self.w.okButton = Button( (-(BUTTON_WIDTH + MARGIN_RGT), jumpingY, BUTTON_WIDTH, vanillaControlsSize['ButtonRegularHeight']), 'Ok', callback=self.okButtonCallback) jumpingY += vanillaControlsSize['ButtonRegularHeight'] + MARGIN_BTM self.setUpBaseWindowBehavior() self.w.resize(WINDOW_WIDTH, jumpingY) def get(self): try: self.lineNumber = int(self.w.lineEdit.get()) except ValueError: self.w.lineEdit.set('') self.lineNumber = None return self.lineNumber def enable(self, value): if value is True: self.w.center() self.w.show() else: self.w.hide() def cancelButtonCallback(self, sender): self.w.show(False) def okButtonCallback(self, sender): self.callback(self)
class AccentedMaker(BaseWindowController): fontOptions = [] whichFont = None actions = ['Place Anchors', 'Build Accents'] whichAction = actions[0] whichGlyphList = None markEditedGlyphs = False markColor = glyphCollectionColors[glyphCollectionColors.keys()[0]] uppercaseAccents = False def __init__(self): super(AccentedMaker, self).__init__() self.initLogger() self.fontOptions = ['All Fonts', 'Current Font'] + AllFonts() self.whichFont = self.fontOptions[0] self.pluginHeight = PLUGIN_HEIGHT self.loadAccentedData() self.parseGlyphListsFromAccentedData() firstKey = self.glyphLists[self.whichAction].keys()[0] self.whichGlyphList = self.glyphLists[self.whichAction][firstKey] self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, self.pluginHeight), PLUGIN_TITLE) self.w.sharedCtrls = SharedCtrls( (MARGIN_HOR, MARGIN_VER, NET_WIDTH, 104), fontOptions=self.fontOptions, whichFont=self.whichFont, actions=self.actions, whichAction=self.whichAction, glyphLists=self.glyphLists, whichGlyphList=self.whichGlyphList, markColor=self.markColor, markEditedGlyphs=self.markEditedGlyphs, callback=self.sharedCtrlsCallback) self.w.separationLine = HorizontalLine( (MARGIN_HOR, self.w.sharedCtrls.getPosSize()[3] + MARGIN_ROW, NET_WIDTH, vanillaControlsSize['HorizontalLineThickness'])) dependantCtrlsHgt = MARGIN_VER + self.w.sharedCtrls.getPosSize( )[3] + MARGIN_ROW self.w.anchorsCtrls = AnchorsCtrls( (MARGIN_HOR, dependantCtrlsHgt, NET_WIDTH, 76), callbackAttrs=self.anchorsVarsCallback, placeCallback=self.anchorsPlaceCallback, deleteCallback=self.anchorsDeleteCallback) self.w.buildingCtrls = BuildingCtrls( (MARGIN_HOR, dependantCtrlsHgt, NET_WIDTH, 50), self.uppercaseAccents, callbackAttrs=self.buildingVarsCallback, callbackCheck=self.checkAccentedCallback, callbackBuild=self.buildAccentedCallback) self.w.buildingCtrls.show(False) addObserver(self, 'updateFontOptions', "newFontDidOpen") addObserver(self, 'updateFontOptions', "fontDidOpen") addObserver(self, 'updateFontOptions', "fontWillClose") self.w.bind("close", self.windowCloseCallback) self.setUpBaseWindowBehavior() self.adjustPluginHeight() self.w.open() def initLogger(self): # create a logger self.accentedLogger = logging.getLogger('accentedLogger') # create file handler which logs info messages fileBasedHandler = logging.FileHandler('accentedLettersMaker.log') fileBasedHandler.setLevel(logging.INFO) # create console handler with a higher log level, only errors consoleHandler = logging.StreamHandler() consoleHandler.setLevel(logging.ERROR) # create formatter and add it to the handlers formatter = logging.Formatter( u'%(asctime)s | %(levelname)s | line: %(lineno)d | %(funcName)s | %(message)s' ) fileBasedHandler.setFormatter(formatter) consoleHandler.setFormatter(formatter) # add the handlers to the logger self.accentedLogger.addHandler(fileBasedHandler) self.accentedLogger.addHandler(consoleHandler) # deal with font data def prepareFontsToAction(self): if self.whichFont == 'All Fonts': fontsToProcess = AllFonts() elif self.whichFont == 'Current Font': fontsToProcess = [CurrentFont()] else: fontsToProcess = [self.whichFont] return fontsToProcess def deleteAnchors(self): self.accentedLogger.info( START_FUNC.format(funcName=self.deleteAnchors.__name__)) fontsToProcess = self.prepareFontsToAction() for eachFont in fontsToProcess: self.accentedLogger.info( START_FONT.format(familyName=eachFont.info.familyName, styleName=eachFont.info.styleName)) for eachGlyphName in self.whichGlyphList: eachGlyph = eachFont[eachGlyphName] if self.markEditedGlyphs is True: if version[0] == '2': eachGlyph.markColor = self.markColor else: eachGlyph.mark = self.markColor for eachAnchor in eachGlyph.anchors: eachGlyph.removeAnchor(eachAnchor) self.accentedLogger.info( REMOVE_ANCHOR.format(anchorName=self.anchorName, glyphName=eachGlyphName)) self.accentedLogger.info( END_FUNC.format(funcName=self.deleteAnchors.__name__)) def placeAnchors(self): assert self.anchorName is not None, '[WARNING] no anchor name provided' assert self.anchorHeight is not None, '[WARNING] no anchor height provided' self.accentedLogger.info( START_FUNC.format(funcName=self.placeAnchors.__name__)) fontsToProcess = self.prepareFontsToAction() for eachFont in fontsToProcess: self.accentedLogger.info( START_FONT.format(familyName=eachFont.info.familyName, styleName=eachFont.info.styleName)) for eachGlyphName in self.whichGlyphList: if eachGlyphName in eachFont: eachGlyph = eachFont[eachGlyphName] if self.markEditedGlyphs is True: if version[0] == '2': eachGlyph.markColor = self.markColor else: eachGlyph.mark = self.markColor if selectAnchorByName(eachGlyph, self.anchorName): anchorToDel = selectAnchorByName( eachGlyph, self.anchorName) eachGlyph.removeAnchor(anchorToDel) if version[0] == '2': xMin, yMin, xMax, yMax = eachGlyph.bounds else: xMin, yMin, xMax, yMax = eachGlyph.box if eachFont.info.italicAngle: anchorAngle = radians(-eachFont.info.italicAngle) else: anchorAngle = radians(0) tangentOffset = tan(anchorAngle) * self.anchorHeight anchorX = ( eachGlyph.width - eachGlyph.angledLeftMargin - eachGlyph.angledRightMargin ) / 2 + eachGlyph.angledLeftMargin + tangentOffset eachGlyph.appendAnchor(self.anchorName, (anchorX, self.anchorHeight)) self.accentedLogger.info( APPEND_ANCHOR.format(anchorName=self.anchorName, anchorX=anchorX, anchorHeight=self.anchorHeight, glyphName=eachGlyphName)) else: self.accentedLogger.error( GLYPH_NOT_IN_FONT.format( glyphName=eachGlyphName, familyName=eachFont.info.familyName, styleName=eachFont.info.styleName)) self.accentedLogger.info( END_FUNC.format(funcName=self.placeAnchors.__name__)) def checkAccented(self, isPrinting=True): report = [] notReady = OrderedDict() fontsToProcess = self.prepareFontsToAction() for eachFont in fontsToProcess: toSkip = [] report.append('Checking {} {}'.format(eachFont.info.familyName, eachFont.info.styleName)) for eachAccentedName, eachBaseName, eachAccentName, eachAnchorName in self.whichGlyphList: # base glyph if eachFont.has_key(eachBaseName) is False: report.append( BUILD_MISSING_GLYPH.format( glyphName=eachBaseName, accentedName=eachAccentedName)) if eachAccentedName not in toSkip: toSkip.append(eachAccentedName) else: eachBaseGlyph = eachFont[eachBaseName] if not eachBaseGlyph.anchors: report.append( NO_ANCHORS.format(glyphName=eachBaseName)) if eachAccentedName not in toSkip: toSkip.append(eachAccentedName) if version[0] == '2': eachBaseGlyph.markColor = ERROR_MARK_COLOR else: eachBaseGlyph.mark = ERROR_MARK_COLOR else: for eachAnchor in eachBaseGlyph.anchors: if eachAnchor.name == eachAnchorName: break else: report.append( BUILD_MISSING_ANCHOR.format( anchorName=eachAnchorName, glyphName=eachBaseName, accentedName=eachAccentedName)) if eachAccentedName not in toSkip: toSkip.append(eachAccentedName) if version[0] == '2': eachBaseGlyph.markColor = ERROR_MARK_COLOR else: eachBaseGlyph.mark = ERROR_MARK_COLOR # accent if eachFont.has_key(eachAccentName) is False: report.append( BUILD_MISSING_GLYPH.format( glyphName=eachAccentName, accentedName=eachAccentedName)) if eachAccentedName not in toSkip: toSkip.append(eachAccentedName) else: eachAccentGlyph = eachFont[eachAccentName] if not eachAccentGlyph.anchors: report.append( NO_ANCHORS.format(glyphName=eachAccentName)) if eachAccentedName not in toSkip: toSkip.append(eachAccentedName) if version[0] == '2': eachAccentGlyph.markColor = ERROR_MARK_COLOR else: eachAccentGlyph.mark = ERROR_MARK_COLOR else: for eachAnchor in eachAccentGlyph.anchors: if eachAnchor.name == '_{}'.format(eachAnchorName): break else: report.append( BUILD_MISSING_ANCHOR.format( anchorName=eachAnchorName, glyphName=eachAccentName, accentedName=eachAccentedName)) if eachAccentedName not in toSkip: toSkip.append(eachAccentedName) if version[0] == '2': eachAccentGlyph.markColor = ERROR_MARK_COLOR else: eachAccentGlyph.mark = ERROR_MARK_COLOR notReady['{} {}'.format(eachFont.info.familyName, eachFont.info.styleName)] = toSkip report.append('End checking {} {}'.format(eachFont.info.familyName, eachFont.info.styleName)) report.append('\n\n') if isPrinting is True: self.accentedLogger.error('\n'.join(report)) return notReady def buildAccented(self): notReady = self.checkAccented(isPrinting=False) self.accentedLogger.info( START_FUNC.format(funcName=self.buildAccented.__name__)) fontsToProcess = self.prepareFontsToAction() for eachFont in fontsToProcess: self.accentedLogger.info( START_FONT.format(familyName=eachFont.info.familyName, styleName=eachFont.info.styleName)) for eachAccentedName, eachBaseName, eachAccentName, eachAnchorName in self.whichGlyphList: if eachAccentedName in notReady['{} {}'.format( eachFont.info.familyName, eachFont.info.styleName)]: self.accentedLogger.error( NOT_READY.format(fontName='{} {}'.format( eachFont.info.familyName, eachFont.info.styleName), accentedName=eachAccentedName)) continue eachBaseGlyph = eachFont[eachBaseName] eachBaseAnchor = selectAnchorByName(eachBaseGlyph, eachAnchorName) eachAccentGlyph = eachFont[eachAccentName] eachAccentAnchor = selectAnchorByName( eachAccentGlyph, '_{}'.format(eachAnchorName)) if eachFont.has_key(eachAccentedName) is False: eachAccentedGlyph = eachFont.newGlyph(eachAccentedName) else: eachAccentedGlyph = eachFont[eachAccentedName] eachAccentedGlyph.clear() eachAccentedGlyph.width = eachBaseGlyph.width eachAccentedGlyph.appendComponent(eachBaseName, (0, 0), (1, 1)) accentOffsetX, accentOffsetY = eachBaseAnchor.x - eachAccentAnchor.x, eachBaseAnchor.y - eachAccentAnchor.y eachAccentedGlyph.appendComponent( eachAccentName, (accentOffsetX, accentOffsetY), (1, 1)) self.accentedLogger.info( BUILT_GLYPH.format(accentedName=eachAccentedName, baseName=eachBaseName, accentName=eachAccentName, anchorName=eachAnchorName)) if self.markEditedGlyphs is True: if version[0] == '2': eachAccentedGlyph.markColor = self.markColor else: eachAccentedGlyph.mark = self.markColor self.accentedLogger.info( END_FUNC.format(funcName=self.buildAccented.__name__)) # deal with table data def loadAccentedData(self): self.accentedData = [[cell.strip() for cell in row.split('\t')] for row in open(TABLE_PATH, 'r').readlines()] def parseGlyphListsFromAccentedData(self): assert self.accentedData is not None self.glyphLists = OrderedDict() # anchors self.glyphLists['Place Anchors'] = OrderedDict() accentsTop = [] _ = [ accentsTop.append(row[2]) for row in self.accentedData if row[3] == 'top' and row[2] not in accentsTop ] self.glyphLists['Place Anchors']['ACC TOP'] = accentsTop accentsBtm = [] _ = [ accentsBtm.append(row[2]) for row in self.accentedData if row[3] == 'bottom' and row[2] not in accentsBtm ] self.glyphLists['Place Anchors']['ACC BTM'] = accentsBtm accentsCaseTop = ['{}.case'.format(name) for name in accentsTop] self.glyphLists['Place Anchors']['ACC CASE TOP'] = accentsCaseTop accentsCaseBtm = ['{}.case'.format(name) for name in accentsBtm] self.glyphLists['Place Anchors']['ACC CASE BTM'] = accentsCaseBtm ucBaseTop = [] _ = [ ucBaseTop.append(row[1]) for row in self.accentedData if row[1][0].isupper() and row[3] == 'top' and row[1] not in ucBaseTop ] self.glyphLists['Place Anchors']['UC TOP'] = ucBaseTop ucBaseBtm = [] _ = [ ucBaseBtm.append(row[1]) for row in self.accentedData if row[1][0].isupper() and row[3] == 'bottom' and row[1] not in ucBaseBtm ] self.glyphLists['Place Anchors']['UC BTM'] = ucBaseBtm lcBaseTop = [] _ = [ lcBaseTop.append(row[1]) for row in self.accentedData if row[1][0].islower() and row[3] == 'top' and row[1] not in lcBaseTop ] self.glyphLists['Place Anchors']['LC TOP'] = lcBaseTop lcBaseBtm = [] _ = [ lcBaseBtm.append(row[1]) for row in self.accentedData if row[1][0].islower() and row[3] == 'bottom' and row[1] not in lcBaseBtm ] self.glyphLists['Place Anchors']['LC BTM'] = lcBaseBtm # build self.glyphLists['Build Accents'] = OrderedDict() self.glyphLists['Build Accents']['ALL'] = self.accentedData buildUC = [ row for row in self.accentedData if row[1][0].isupper() is True ] self.glyphLists['Build Accents']['UC'] = buildUC buildLC = [ row for row in self.accentedData if row[1][0].islower() is True ] self.glyphLists['Build Accents']['LC'] = buildLC # ui def adjustPluginHeight(self): if self.whichAction == 'Place Anchors': self.pluginHeight = MARGIN_VER + self.w.sharedCtrls.getPosSize( )[3] + MARGIN_ROW + self.w.anchorsCtrls.getPosSize( )[3] + MARGIN_VER else: self.pluginHeight = MARGIN_VER + self.w.sharedCtrls.getPosSize( )[3] + MARGIN_ROW + self.w.buildingCtrls.getPosSize( )[3] + MARGIN_VER lft, top, wdt, hgt = self.w.getPosSize() self.w.resize(wdt, self.pluginHeight) def switchDependantCtrl(self): if self.whichAction == 'Place Anchors': self.w.anchorsCtrls.show(True) self.w.buildingCtrls.show(False) else: self.w.anchorsCtrls.show(False) self.w.buildingCtrls.show(True) # observers def updateFontOptions(self, sender): self.fontOptions = ['All Fonts', 'Current Font'] + AllFonts() self.w.sharedCtrls.setFontOptions(self.fontOptions) # callbacks def sharedCtrlsCallback(self, sender): self.whichFont = sender.getWhichFont() self.whichAction = sender.getWhichAction() self.switchDependantCtrl() self.adjustPluginHeight() self.whichGlyphList = sender.getWhichGlyphList() self.markEditedGlyphs, self.markColor = sender.getMarkEditedGlyphs() def anchorsVarsCallback(self, sender): self.anchorHeight = sender.getHeight() self.anchorName = sender.getName() def anchorsPlaceCallback(self, sender): self.placeAnchors() def anchorsDeleteCallback(self, sender): self.deleteAnchors() def buildingVarsCallback(self, sender): self.uppercaseAccents = sender.getUppercaseAccents() def checkAccentedCallback(self, sender): self.checkAccented() def buildAccentedCallback(self, sender): self.buildAccented() def windowCloseCallback(self, sender): removeObserver(self, "newFontDidOpen") removeObserver(self, "fontDidOpen") removeObserver(self, "fontWillClose") super(AccentedMaker, self).windowCloseCallback(sender)
class SpeedPunkPrefWindow(object): def __init__(self, parent): self.parent = parent self.w = FloatingWindow((150, 130), "Speed Punk %s" % VERSION, closable = False, autosaveName = 'de_yanone_speedPunk_%s.prefWindow' % (environment), ) self.w.illustrationPositionRadioGroup = RadioGroup((10, 10, -10, 40), ["Outside of glyph", "Outer side of curve"], callback=self.radioGroupCallback, sizeStyle = "small") self.w.curveGainTextBox = TextBox((10, 60, -10, 17), "Gain", sizeStyle = "mini") self.w.curveGainSlider = Slider((10, 70, -10, 25), tickMarkCount=5, callback=self.curveGainSliderCallback, sizeStyle = "small", minValue = curveGain[0], maxValue = curveGain[1], value = self.parent.getPreference('curveGain')) self.w.illustrationPositionRadioGroup.set(self.parent.getPreference('illustrationPositionIndex')) self.w.faderCheckBox = CheckBox((10, 100, -10, 17), "Fader", sizeStyle = "small", callback = self.faderCheckBoxCallback) self.w.faderSlider = Slider((10, 125, -10, 25), sizeStyle = "small", minValue = 0, maxValue = 1.0, value = 1.0, callback = self.faderSliderCallback) self.w.gradientImage = ImageView((10, 150, -10, 15)) self.w.histogramImage = ImageView((10, 150, -10, 15)) def radioGroupCallback(self, sender): self.parent.setPreference('illustrationPositionIndex', sender.get()) self.parent.RefreshView() def curveGainSliderCallback(self, sender): self.parent.setPreference('curveGain', sender.get()) self.parent.RefreshView() def faderSliderCallback(self, sender): self.parent.setPreference('fader', sender.get()) self.parent.RefreshView() def faderCheckBoxCallback(self, sender): self.parent.setPreference('useFader', sender.get()) self.parent.RefreshView() if sender.get(): self.w.faderCheckBox.setPosSize(((10, 105, -10, 17))) self.w.resize(150, 175, animate=True) else: self.w.faderCheckBox.setPosSize(((10, 100, -10, 17))) self.w.resize(150, 130, animate=True)
class SpeedPunkPrefWindow(object): def __init__(self, parent): self.parent = parent self.w = FloatingWindow((150, 130), "Speed Punk %s" % VERSION, closable = False, autosaveName = 'de_yanone_speedPunk_%s.prefWindow' % (environment), ) self.w.illustrationPositionRadioGroup = RadioGroup((10, 10, -10, 40), ( Glyphs.localize({ 'en': 'Outside of glyph', 'de': 'Außen an Form', 'fr': 'Éxterieur de la forme', 'es': 'Exterior del glifo', 'pt': 'Fora do glifo', }), Glyphs.localize({ 'en': 'Outer side of curve', 'de': 'Außen am Pfad', 'fr': 'Éxterieur de la courbe', 'es': 'Exterior del trazo', 'pt': 'Fora da curva', }), ), callback=self.radioGroupCallback, sizeStyle = "small") self.w.curveGainTextBox = TextBox((10, 60, -10, 17), Glyphs.localize({ 'en': 'Gain', 'de': 'Stärke', 'fr': 'Volume', 'es': 'Volumen', 'pt': 'Volume', }), sizeStyle = "mini") self.w.curveGainSlider = Slider((10, 70, -10, 25), tickMarkCount=5, callback=self.curveGainSliderCallback, sizeStyle = "small", minValue = curveGain[0], maxValue = curveGain[1], value = self.parent.getPreference('curveGain')) self.w.illustrationPositionRadioGroup.set(self.parent.getPreference('illustrationPositionIndex')) self.w.faderCheckBox = CheckBox((10, 100, -10, 17), Glyphs.localize({ 'en': 'Fade', 'de': 'Ausblenden', 'fr': 'Opacité', 'es': 'Opacidad', 'pt': 'Opacidade', }), sizeStyle = "small", callback = self.faderCheckBoxCallback) self.w.faderSlider = Slider((10, 125, -10, 25), sizeStyle = "small", minValue = 0, maxValue = 1.0, value = 1.0, callback = self.faderSliderCallback) self.w.gradientImage = ImageView((10, 150, -10, 15)) self.w.histogramImage = ImageView((10, 150, -10, 15)) def radioGroupCallback(self, sender): self.parent.setPreference('illustrationPositionIndex', sender.get()) self.parent.RefreshView() def curveGainSliderCallback(self, sender): self.parent.setPreference('curveGain', sender.get()) self.parent.RefreshView() def faderSliderCallback(self, sender): self.parent.setPreference('fader', sender.get()) self.parent.RefreshView() def faderCheckBoxCallback(self, sender): self.parent.setPreference('useFader', sender.get()) self.parent.RefreshView() if sender.get(): self.w.faderCheckBox.setPosSize(((10, 105, -10, 17))) self.w.resize(150, 175, animate=True) else: self.w.faderCheckBox.setPosSize(((10, 100, -10, 17))) self.w.resize(150, 130, animate=True)
class Adhesiontext(BaseWindowController): def __init__(self): flushAlign = 76 firstRowY = 12 rowOffsetY = 30 firstCheckY = 135 checkOffsetY = 27 rightMarginX = -12 self.windowWidth = 410 self.windowHeightWithoutOptions = 45 self.windowHeightWithOptions = 280 self.scriptIsRTL = False windowPos = getExtensionDefault("%s.%s" % (extensionKey, "windowPos")) if not windowPos: windowPos = (100, 100) self.optionsVisible = getExtensionDefault("%s.%s" % (extensionKey, "optionsVisible")) if self.optionsVisible: optionsButtonSign = '-' windowHeight = self.windowHeightWithOptions else: self.optionsVisible = False # needs to be set because the first time the extension runs self.optionsVisible will be None optionsButtonSign = '+' windowHeight = self.windowHeightWithoutOptions self.chars = getExtensionDefault("%s.%s" % (extensionKey, "chars")) if not self.chars: self.chars = '' self.sliderValue = getExtensionDefault("%s.%s" % (extensionKey, "sliderValue")) if not self.sliderValue: self.sliderValue = 25 self.scriptsIndex = getExtensionDefault("%s.%s" % (extensionKey, "scriptsIndex")) if not self.scriptsIndex: self.scriptsIndex = 0 self.langsIndex = getExtensionDefault("%s.%s" % (extensionKey, "langsIndex")) if not self.langsIndex: self.langsIndex = 0 self.w = FloatingWindow((windowPos[0], windowPos[1], self.windowWidth, windowHeight), "adhesiontext") # 1st row self.w.labelChars = TextBox((10, firstRowY, flushAlign, 20), "Characters:", alignment="right") self.w.chars = EditText((flushAlign +15, firstRowY -1, 199, 22), self.chars, callback=self.charsCallback) self.w.button = Button((300, firstRowY, 68, 20), "Get text", callback=self.buttonCallback) self.w.spinner = FixedSpinner((325, firstRowY, 20, 20), displayWhenStopped=False) self.w.optionsButton = SquareButton((378, firstRowY +1, 18, 18), optionsButtonSign, sizeStyle="small", callback=self.optionsCallback) # set the initial state of the button according to the content of the chars EditText if len(self.w.chars.get()): self.w.button.enable(True) else: self.w.button.enable(False) # keep track of the content of chars EditText self.previousChars = self.w.chars.get() # 2nd row self.w.labelWords = TextBox((10, firstRowY + rowOffsetY, flushAlign, 20), "Words:", alignment="right") self.w.wordCount = TextBox((flushAlign +12, firstRowY + rowOffsetY, 40, 20), alignment="left") self.w.slider = Slider((flushAlign +47, firstRowY + rowOffsetY +1, 165, 20), value=self.sliderValue, minValue=5, maxValue=200, callback=self.sliderCallback) # set the initial wordCount value according to the position of the slider self.w.wordCount.set(int(self.w.slider.get())) # 3rd row self.w.labelScripts = TextBox((10, firstRowY + rowOffsetY *2, flushAlign, 20), "Script:", alignment="right") self.w.scriptsPopup = PopUpButton((flushAlign +15, firstRowY + rowOffsetY *2, 150, 20), scriptsNameList, callback=self.scriptsCallback) self.w.scriptsPopup.set(self.scriptsIndex) # 4th row self.w.labelLangs = TextBox((10, firstRowY + rowOffsetY *3, flushAlign, 20), "Language:", alignment="right") self.w.langsPopup = PopUpButton((flushAlign +15, firstRowY + rowOffsetY *3, 150, 20), []) # set the initial list of languages according to the script value self.w.langsPopup.setItems(langsNameDict[scriptsNameList[self.w.scriptsPopup.get()]]) self.w.langsPopup.set(self.langsIndex) self.punctCheck = getExtensionDefault("%s.%s" % (extensionKey, "punctCheck")) if not self.punctCheck: self.punctCheck = 0 self.figsCheck = getExtensionDefault("%s.%s" % (extensionKey, "figsCheck")) if not self.figsCheck: self.figsCheck = 0 self.figsPopup = getExtensionDefault("%s.%s" % (extensionKey, "figsPopup")) if not self.figsPopup: self.figsPopup = 0 self.trimCheck = getExtensionDefault("%s.%s" % (extensionKey, "trimCheck")) if not self.trimCheck: self.trimCheck = 0 self.caseCheck = getExtensionDefault("%s.%s" % (extensionKey, "caseCheck")) if not self.caseCheck: self.caseCheck = 0 self.casingCheck = getExtensionDefault("%s.%s" % (extensionKey, "casingCheck")) if not self.casingCheck: self.casingCheck = 0 self.casingPopup = getExtensionDefault("%s.%s" % (extensionKey, "casingPopup")) if not self.casingPopup: self.casingPopup = 0 # 1st checkbox self.w.punctCheck = CheckBox((flushAlign +15, firstCheckY, 130, 20), "Add punctuation") self.w.punctCheck.set(self.punctCheck) # 2nd checkbox self.w.figsCheck = CheckBox((flushAlign +15, firstCheckY + checkOffsetY, 120, 20), "Insert numbers", callback=self.figsCallback) self.w.figsCheck.set(self.figsCheck) self.w.figsPopup = PopUpButton((210, firstCheckY + checkOffsetY, 90, 20), figOptionsList) self.w.figsPopup.set(self.figsPopup) # enable or disable the figure options PopUp depending on the figures CheckBox if scriptsNameList[self.w.scriptsPopup.get()] in enableFigOptionList: self.w.figsPopup.show(True) if self.w.figsCheck.get(): self.w.figsPopup.enable(True) else: self.w.figsPopup.enable(False) else: self.w.figsPopup.show(False) # 3rd checkbox self.w.trimCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *2, 120, 20), "Trim accents") self.w.trimCheck.set(self.trimCheck) if scriptsNameList[self.w.scriptsPopup.get()] in enableTrimCheckList: self.w.trimCheck.enable(True) else: self.w.trimCheck.enable(False) # 4th checkbox self.w.caseCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *3, 120, 20), "Ignore casing") self.w.caseCheck.set(self.caseCheck) if scriptsNameList[self.w.scriptsPopup.get()] in enableCaseCheckList: self.w.caseCheck.enable(True) else: self.w.caseCheck.enable(False) # 5th checkbox self.w.casingCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *4, 115, 20), "Change casing", callback=self.casingCallback) self.w.casingCheck.set(self.casingCheck) if scriptsNameList[self.w.scriptsPopup.get()] in enableCaseCheckList: self.w.casingCheck.enable(True) else: self.w.casingCheck.enable(False) self.w.casingPopup = PopUpButton((210, firstCheckY + checkOffsetY *4, 90, 20), casingNameList) self.w.casingPopup.set(self.casingPopup) # enable or disable the casing PopUp depending on the casing CheckBox if self.w.casingCheck.get() and self.w.casingCheck.isEnable(): self.w.casingPopup.enable(True) else: self.w.casingPopup.enable(False) self.nsTextField = self.w.chars.getNSTextField() self.w.setDefaultButton(self.w.button) self.w.bind("close", self.windowClose) self.w.open() self.w.makeKey() def windowClose(self, sender): self.saveExtensionDefaults() def saveExtensionDefaults(self): setExtensionDefault("%s.%s" % (extensionKey, "windowPos"), self.w.getPosSize()[0:2]) setExtensionDefault("%s.%s" % (extensionKey, "optionsVisible"), self.optionsVisible) setExtensionDefault("%s.%s" % (extensionKey, "chars"), self.w.chars.get()) setExtensionDefault("%s.%s" % (extensionKey, "sliderValue"), int(self.w.slider.get())) setExtensionDefault("%s.%s" % (extensionKey, "scriptsIndex"), int(self.w.scriptsPopup.get())) setExtensionDefault("%s.%s" % (extensionKey, "langsIndex"), int(self.w.langsPopup.get())) setExtensionDefault("%s.%s" % (extensionKey, "punctCheck"), self.w.punctCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "figsCheck"), self.w.figsCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "figsPopup"), self.w.figsPopup.get()) setExtensionDefault("%s.%s" % (extensionKey, "trimCheck"), self.w.trimCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "caseCheck"), self.w.caseCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "casingCheck"), self.w.casingCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "casingPopup"), self.w.casingPopup.get()) def buttonCallback(self, sender): sender.enable(False) self.w.spinner.start() self.getText() self.w.spinner.stop() sender.enable(True) def optionsCallback(self, sender): sign = sender.getTitle() if sign == "+": sender.setTitle("-") self.w.resize(self.windowWidth, self.windowHeightWithOptions, animate=True) self.optionsVisible = True else: sender.setTitle("+") self.w.resize(self.windowWidth, self.windowHeightWithoutOptions, animate=True) self.optionsVisible = False def charsCallback(self, sender): charsContent = sender.get() if len(charsContent): self.w.button.enable(True) nsTextView = self.nsTextField.currentEditor() # NOTE: the field editor is only available when NSTextField is in editing mode. # when only one glyph is selected and copied, the contents of the clipboard are the glyph's XML # instead of its unicode character or its name; therefore, post-process the pasted content. if xmlHeader in charsContent: caretIndex = charsContent.index(xmlHeader) codepointString = re_glyphUnicode.search(charsContent) glyphName = re_glyphName.search(charsContent) if codepointString: replacement = unichr(eval('0x' + codepointString.group(1))) elif glyphName: replacement = '/' + glyphName.group(1) else: replacement = '' # replace the glyph's XML by its unicode character or its name self.w.chars.set(re_glyph.sub(replacement, charsContent)) # restore the location of the caret location = caretIndex + len(replacement) nsTextView.setSelectedRange_((location, 0)) # update the variable charsContent = sender.get() caretIndex = nsTextView.selectedRanges()[0].rangeValue().location # Limit the number of characters numeralWasFound = self.stringHasNumeral(charsContent) if len(charsContent) > maxChars or numeralWasFound: NSBeep() if numeralWasFound: self.showMessage("Sorry, numerals are not allowed.", "") else: self.showMessage("You've reached the maximum \rnumber of characters.", "The limit is %d." % maxChars) # restore the content of chars EditText to the previous string sender.set(self.previousChars) # restore the focus on the chars EditText and restore the location of the caret caretIndexAdjust = len(self.previousChars) - len(charsContent) self.w.getNSWindow().makeFirstResponder_(self.nsTextField) nsTextView.setSelectedRange_((caretIndex + caretIndexAdjust, 0)) # update the stored string self.previousChars = sender.get() else: self.w.button.enable(False) def sliderCallback(self, sender): self.w.wordCount.set(int(sender.get())) def scriptsCallback(self, sender): self.w.langsPopup.setItems(langsNameDict[scriptsNameList[sender.get()]]) # toggle RTL/LTR if scriptsNameList[sender.get()] in rightToLeftList: self.scriptIsRTL = True self.nsTextField.setBaseWritingDirection_(NSWritingDirectionRightToLeft) self.nsTextField.setAlignment_(NSRightTextAlignment) else: self.scriptIsRTL = False self.nsTextField.setBaseWritingDirection_(NSWritingDirectionLeftToRight) self.nsTextField.setAlignment_(NSLeftTextAlignment) # restore the focus on the chars EditText self.w.getNSWindow().makeFirstResponder_(self.nsTextField) # toggle figsPopup if scriptsNameList[sender.get()] in enableFigOptionList: self.w.figsPopup.show(True) if self.w.figsCheck.get(): self.w.figsPopup.enable(True) else: self.w.figsPopup.enable(False) else: self.w.figsPopup.show(False) # toggle trimCheck if scriptsNameList[sender.get()] in enableTrimCheckList: self.w.trimCheck.enable(True) else: self.w.trimCheck.enable(False) # toggle caseCheck and casingCheck if scriptsNameList[sender.get()] in enableCaseCheckList: self.w.caseCheck.enable(True) self.w.casingCheck.enable(True) if self.w.casingCheck.get(): self.w.casingPopup.enable(True) else: self.w.caseCheck.enable(False) self.w.casingCheck.enable(False) self.w.casingPopup.enable(False) def figsCallback(self, sender): if sender.get(): self.w.figsPopup.enable(True) else: self.w.figsPopup.enable(False) def casingCallback(self, sender): if sender.get(): self.w.casingPopup.enable(True) else: self.w.casingPopup.enable(False) def stringHasNumeral(self, string): if re_numeral.search(string): return True return False def isConnected(self): try: urlopen(url, timeout=3) return True except URLError: pass return False def getText(self): if CurrentFont() is None: NSBeep() self.showMessage("Open a font first.", "") return if not self.isConnected(): NSBeep() self.showMessage("Required internet connection not found.", "") return values = {'chars' : self.w.chars.get().encode('utf-8'), 'script' : scriptsTagDict[scriptsNameList[self.w.scriptsPopup.get()]], 'tb' : langsTagDict[langsNameDict[scriptsNameList[self.w.scriptsPopup.get()]][self.w.langsPopup.get()]] } if self.w.punctCheck.get(): values['punct'] = True if self.w.figsCheck.get(): values['figs'] = True if self.w.figsPopup.isVisible(): figsOptTagsList = ["dflt", "locl"] values['figsOpt'] = figsOptTagsList[self.w.figsPopup.get()] if self.w.trimCheck.get() and self.w.trimCheck.isEnable(): values['trim'] = True if self.w.caseCheck.get() and self.w.caseCheck.isEnable(): values['case'] = True if self.w.casingCheck.get() and self.w.casingCheck.isEnable(): values['casing'] = casingNameList[self.w.casingPopup.get()].lower() data = urlencode(values) data = data.encode('utf-8') print(data) request = Request(url, data) response = urlopen(request) text = response.read() textU = unicode(text, 'utf-8') if (msgStr in textU): textU = textU.replace(msgStr, "") NSBeep() self.showMessage(textU, "") return elif (wrnStr in textU): resultIndex = textU.find(rsltStr) secmsgIndex = textU.find(sndStr) frstmsgU = textU[:secmsgIndex].replace(wrnStr, "") scndmsgU = textU[secmsgIndex:resultIndex].replace(sndStr, "") textU = textU[resultIndex:].replace(rsltStr, "") NSBeep() self.showMessage(frstmsgU, scndmsgU) textList = textU.split() trimmedText = ' '.join(textList[:int(self.w.slider.get())]) if CurrentSpaceCenter() is None: OpenSpaceCenter(CurrentFont(), newWindow=False) sp = CurrentSpaceCenter() print(trimmedText) sp.setRaw(trimmedText) # Toggle RTL-LTR try: sp.setLeftToRight(not self.scriptIsRTL) sp.setInputWritingDirection('Right to Left' if self.scriptIsRTL else 'Left to Right') except AttributeError: pass return
class VariableController(object): def __init__(self, attributes, callback, document=None): self._callback = callback self._attributes = None self.w = FloatingWindow((250, 50)) self.buildUI(attributes) self.w.open() if document: self.w.assignToDocument(document) self.w.setTitle("Variables") def buildUI(self, attributes): if self._attributes == attributes: return self._attributes = attributes if hasattr(self.w, "ui"): del self.w.ui self.w.ui = ui = vanilla.Group((0, 0, -0, -0)) y = 10 labelSize = 100 gutter = 5 for attribute in self._attributes: uiElement = attribute["ui"] name = attribute["name"] args = dict(attribute.get("args", {})) height = 19 # adjust the height if a radioGroup is vertical if uiElement == "RadioGroup": if args.get("isVertical", True): height = height * len(args.get("titles", [""])) # create a label for every ui element except a checkbox if uiElement not in ("CheckBox", "Button"): # create the label view label = vanilla.TextBox((0, y + 2, labelSize - gutter, height), "%s:" % name, alignment="right", sizeStyle="small") # set the label view setattr(ui, "%sLabel" % name, label) else: args["title"] = name # check the provided args and add required keys if uiElement == "ColorWell": # a color well needs a color to be set # no size style if "color" not in args: args["color"] = AppKit.NSColor.blackColor() elif uiElement == "TextEditor": # different control height # no size style height = attribute.get("height", 75) else: # all other get a size style args["sizeStyle"] = "small" # create the control view attr = getattr(vanilla, uiElement)((labelSize, y, -10, height), callback=self.changed, **args) # set the control view setattr(ui, name, attr) y += height + 6 # resize the window according the provided ui elements self.w.resize(250, y) def changed(self, sender): self.documentWindowToFront() if self._callback: self._callback() def get(self): data = {} for attribute in self._attributes: if attribute["ui"] in ("Button", ): continue name = attribute["name"] data[name] = getattr(self.w.ui, name).get() return data def show(self): self.w.show() def documentWindowToFront(self, sender=None): self.w.makeKey()
class VFB2UFO(BaseWindowController): inputOptions = ['Single File', 'Multiple files from a Folder'] chosenMode = inputOptions[0] conversionOptions = ["From VFB to UFO", "From UFO to VFB"] suffix2conversionOption = { "From VFB to UFO": '.vfb', "From UFO to VFB": '.ufo' } chosenSuffix = suffix2conversionOption[conversionOptions[0]] def __init__(self): super(VFB2UFO, self).__init__() self.w = FloatingWindow((PLUGIN_WIDTH, 2), PLUGIN_TITLE) self.jumpingY = MARGIN_VER # options button self.w.optionsPopUp = PopUpButton( (MARGIN_HOR, self.jumpingY, NET_WIDTH, vanillaControlsSize['PopUpButtonRegularHeight']), self.inputOptions, callback=self.optionsPopUpCallback) self.jumpingY += vanillaControlsSize[ 'PopUpButtonRegularHeight'] + MARGIN_HOR # suffix option self.w.suffixRadio = RadioGroup( (MARGIN_HOR, self.jumpingY, NET_WIDTH, vanillaControlsSize['ButtonRegularHeight'] * 2), ["From VFB to UFO", "From UFO to VFB"], callback=self.suffixRadioCallback) self.w.suffixRadio.set(0) self.w.suffixRadio.enable(False) self.jumpingY += vanillaControlsSize[ 'ButtonRegularHeight'] * 2 + MARGIN_HOR # convert button self.w.convertButton = Button( (MARGIN_HOR, self.jumpingY, NET_WIDTH, vanillaControlsSize['ButtonRegularHeight']), 'Choose file and convert', callback=self.convertButtonCallback) self.jumpingY += vanillaControlsSize['ButtonRegularHeight'] + MARGIN_HOR self.w.resize(PLUGIN_WIDTH, self.jumpingY) self.setUpBaseWindowBehavior() self.w.open() def optionsPopUpCallback(self, sender): self.chosenMode = self.inputOptions[sender.get()] if self.chosenMode == 'Single File': self.w.suffixRadio.enable(False) self.w.convertButton.setTitle('Choose file and convert') else: self.w.suffixRadio.enable(True) self.w.convertButton.setTitle('Choose folder and convert') def suffixRadioCallback(self, sender): self.chosenSuffix = self.suffix2conversionOption[ self.conversionOptions[sender.get()]] def convertButtonCallback(self, sender): if self.chosenMode == 'Single File': inputPath = getFile('Choose the file to convert')[0] if inputPath.endswith('.vfb') or inputPath.endswith('.ufo'): executeCommand(['vfb2ufo', '-fo', inputPath], shell=True) else: message('input file path is not correct') else: inputFolder = getFolder('Choose a folder with files to convert')[0] if inputFolder: for eachPath in catchFilesAndFolders(inputFolder, self.chosenSuffix): executeCommand(['vfb2ufo', '-fo', eachPath], shell=True) else: message('input folder path is not correct')
class Labeler(object): labelCltrIndex = 0 def __init__(self): # init window self.w = FloatingWindow((PLUGIN_WIDTH, 300), 'labeler.py') self.jumpingY = MARGIN_VER self.w.labelCtrl_0 = LabelCtrl((MARGIN_HOR, self.jumpingY, NET_WIDTH, vanillaControlsSize['EditTextRegularHeight']), index=self.labelCltrIndex, callback=self.labelCtrlsCallback) self.jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER self.w.separation = HorizontalLine((MARGIN_HOR, self.jumpingY, NET_WIDTH, vanillaControlsSize['HorizontalLineThickness'])) self.w.clearButton = SquareButton((MARGIN_HOR, self.jumpingY+vanillaControlsSize['HorizontalLineThickness'] + MARGIN_VER, NET_WIDTH, vanillaControlsSize['ButtonRegularHeight']), 'Clear Glyph Labels', sizeStyle='small', callback=self.clearButtonCallback) # resize window self._computeWindowHeight() self.w.resize(PLUGIN_WIDTH, self.windowHeight) # open window self.w.open() def _computeWindowHeight(self): self.windowHeight = self.jumpingY + vanillaControlsSize['ButtonRegularHeight'] + vanillaControlsSize['HorizontalLineThickness'] + MARGIN_VER*2 def _updateCtrlsPos(self): self.w.separation.setPosSize((MARGIN_HOR, self.jumpingY, NET_WIDTH, vanillaControlsSize['HorizontalLineThickness'])) self.w.clearButton.setPosSize((MARGIN_HOR, self.jumpingY+vanillaControlsSize['HorizontalLineThickness'] + MARGIN_VER, NET_WIDTH, vanillaControlsSize['ButtonRegularHeight'])) def labelCtrlsCallback(self, sender): lastAction, labelName = sender.get() if lastAction == 'attach': attachLabelToSelectedPoints(labelName) elif lastAction == 'add': self.labelCltrIndex += 1 labelCtrl = LabelCtrl((MARGIN_HOR, self.jumpingY, NET_WIDTH, vanillaControlsSize['EditTextRegularHeight']), index=self.labelCltrIndex, callback=self.labelCtrlsCallback) setattr(self.w, 'labelCtrl_{:d}'.format(labelCtrl.index), labelCtrl) self.jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER self._computeWindowHeight() self._updateCtrlsPos() self.w.resize(PLUGIN_WIDTH, self.windowHeight) elif lastAction == 'subtract': delattr(self.w, 'labelCtrl_{:d}'.format(labelCtrl.index)) self.jumpingY -= vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER self.w.resize(PLUGIN_WIDTH, self.windowHeight) # else: # None def clearButtonCallback(self, sender): myGlyph = CurrentGlyph() for eachContour in myGlyph: for eachPt in eachContour.points: if eachPt.name is not None: eachPt.name = None myGlyph.update()
class SidebearingsLinker(BaseWindowController): allFonts = [] servantSubscriptions = [] masterSubscriptions = [] displayedSubscriptions = [] currentRow = None selectedFont = None 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() # drawing callbacks def drawOnGlyphCanvas(self, infoDict): glyphOnCanvas = infoDict['glyph'] scalingFactor = infoDict['scale'] bodySize = .25 horizontalOffset = 80 if PLUGIN_LIB_NAME in glyphOnCanvas.lib: thisLib = glyphOnCanvas.lib[PLUGIN_LIB_NAME] else: return None lftGlyph = None if thisLib['lft'] != '': lftGlyph = self.selectedFont[thisLib['lft']] rgtGlyph = None if thisLib['rgt'] != '': rgtGlyph = self.selectedFont[thisLib['rgt']] try: dt.fill(*GRAY) if lftGlyph is not None: dt.save() dt.translate(-lftGlyph.width * bodySize - horizontalOffset, -self.selectedFont.info.unitsPerEm * bodySize) # glyph dt.scale(bodySize) dt.drawGlyph(lftGlyph) # lock if thisLib['lftActive'] is True: txt = u'🔒' else: txt = u'🔓' dt.fontSize(300) txtWdt, txtHgt = dt.textSize(txt) dt.text(txt, (-txtWdt, 0)) dt.restore() if rgtGlyph is not None: dt.save() dt.translate(glyphOnCanvas.width + horizontalOffset, -self.selectedFont.info.unitsPerEm * bodySize) dt.scale(bodySize) dt.drawGlyph(rgtGlyph) # lock if thisLib['rgtActive'] is True: txt = u'🔒' else: txt = u'🔓' dt.fontSize(300) dt.text(txt, (rgtGlyph.width, 0)) dt.restore() except Exception as error: print(error) def draw(self): try: if self.selectedFont is not None and self.currentRow is not None: scalingFactor = CANVAS_HEIGHT / ( self.selectedFont.info.unitsPerEm + UPM_MARGIN) if self.currentRow['lft'] in self.selectedFont: lftGlyph = self.selectedFont[self.currentRow['lft']] if lftGlyph is not None: drawReferenceGlyph(aGlyph=lftGlyph, scalingFactor=scalingFactor, startingX=NET_WIDTH * (1 / 6), left=True, right=False) drawLock(closed=self.currentRow['lftActive'], startingX=NET_WIDTH * (2 / 6), glyphQuota=self.selectedFont.info.xHeight, scalingFactor=scalingFactor) if self.currentRow['servant'] in self.selectedFont: servantGlyph = self.selectedFont[ self.currentRow['servant']] if servantGlyph is not None: drawReferenceGlyph(aGlyph=servantGlyph, scalingFactor=scalingFactor, startingX=NET_WIDTH * (3 / 6), left=True, right=True) if self.currentRow['rgt'] in self.selectedFont: rgtGlyph = self.selectedFont[self.currentRow['rgt']] if rgtGlyph is not None: drawReferenceGlyph(aGlyph=rgtGlyph, scalingFactor=scalingFactor, startingX=NET_WIDTH * (5 / 6), right=True) drawLock(closed=self.currentRow['rgtActive'], startingX=NET_WIDTH * (4 / 6), glyphQuota=self.selectedFont.info.xHeight, scalingFactor=scalingFactor) except Exception as error: print(error) # observers def unsubscribeGlyphs(self): for eachGlyph in self.servantSubscriptions: eachGlyph.removeObserver(self, "Glyph.WidthChanged") self.servantSubscriptions = list() for eachGlyph in self.masterSubscriptions: eachGlyph.removeObserver(self, "Glyph.WidthChanged") self.masterSubscriptions = list() def unsubscribeDisplayedGlyphs(self): for eachGlyph in self.displayedSubscriptions: eachGlyph.removeObserver(self, "Glyph.Changed") self.displayedSubscriptions = list() def matchDisplayedSubscriptions(self): self.unsubscribeDisplayedGlyphs() if self.currentRow['lft'] != '': lftGlyph = self.selectedFont[self.currentRow['lft']] if lftGlyph not in self.displayedSubscriptions: lftGlyph.addObserver(self, 'displayedGlyphChanged', 'Glyph.Changed') self.displayedSubscriptions.append(lftGlyph) if self.currentRow['rgt'] != '': rgtGlyph = self.selectedFont[self.currentRow['rgt']] if rgtGlyph not in self.displayedSubscriptions: rgtGlyph.addObserver(self, 'displayedGlyphChanged', 'Glyph.Changed') self.displayedSubscriptions.append(rgtGlyph) if self.currentRow['servant'] != '': servantGlyph = self.selectedFont[self.currentRow['servant']] if servantGlyph not in self.displayedSubscriptions: servantGlyph.addObserver(self, 'displayedGlyphChanged', 'Glyph.Changed') self.displayedSubscriptions.append(servantGlyph) def matchSubscriptions(self): self.unsubscribeGlyphs() for servantGlyph in self.selectedFont: if PLUGIN_LIB_NAME in servantGlyph.lib: thisLib = servantGlyph.lib[PLUGIN_LIB_NAME] if (thisLib['lft'] != '' and thisLib['lftActive'] is True) or ( thisLib['rgt'] != '' and thisLib['rgtActive'] is True): if servantGlyph not in self.servantSubscriptions: servantGlyph.addObserver(self, "servantGlyphChanged", "Glyph.WidthChanged") self.servantSubscriptions.append(servantGlyph) # servants if thisLib['lftActive'] is True and thisLib['lft'] != '': lftMaster = self.selectedFont[thisLib['lft']] if lftMaster not in self.masterSubscriptions: lftMaster.addObserver(self, "masterGlyphChanged", "Glyph.WidthChanged") self.masterSubscriptions.append(lftMaster) if thisLib['rgtActive'] is True and thisLib['rgt'] != '': rgtMaster = self.selectedFont[thisLib['rgt']] if rgtMaster not in self.masterSubscriptions: rgtMaster.addObserver(self, "masterGlyphChanged", "Glyph.WidthChanged") self.masterSubscriptions.append(rgtMaster) def servantGlyphChanged(self, notification): glyph = notification.object warningMessage = 'The glyph <{servantName}> is linked to <{masterName}>, do you want to broke the link?' if PLUGIN_LIB_NAME in glyph.lib: thisLib = glyph.lib[PLUGIN_LIB_NAME] if thisLib['lftActive'] is True: lftMaster = self.selectedFont[thisLib['lft']] if glyph.leftMargin != lftMaster.leftMargin: result = askYesNo( 'Warning', warningMessage.format(servantName=glyph.name, masterName=lftMaster.name)) if bool(result) is False: glyph.leftMargin = lftMaster.leftMargin thisLib['lftActive'] = True else: thisLib['lftActive'] = False if thisLib['rgtActive'] is True: rgtMaster = self.selectedFont[thisLib['rgt']] if glyph.rightMargin != rgtMaster.rightMargin: result = askYesNo( 'Warning', warningMessage.format(servantName=glyph.name, masterName=rgtMaster.name)) if bool(result) is False: glyph.rightMargin = rgtMaster.rightMargin thisLib['rgtActive'] = True else: thisLib['rgtActive'] = False links = loadLinksFromFont(self.selectedFont) self.w.linksList.set(links) self.w.canvas.update() def masterGlyphChanged(self, notification): masterGlyph = notification.object for eachGlyph in self.selectedFont: if PLUGIN_LIB_NAME in eachGlyph.lib: thisLib = eachGlyph.lib[PLUGIN_LIB_NAME] if thisLib['lft'] == masterGlyph.name and thisLib[ 'lftActive'] is True: eachGlyph.leftMargin = masterGlyph.leftMargin if thisLib['rgt'] == masterGlyph.name and thisLib[ 'rgtActive'] is True: eachGlyph.rightMargin = masterGlyph.rightMargin self.w.canvas.update() def displayedGlyphChanged(self, notification): self.w.canvas.update() # callbacks def fontDidOpenCallback(self, notification): self.allFonts = AllFonts() if self.selectedFont is not None: previousFontName = self.w.fontPopUp.getItems()[ self.w.fontPopUp.get()] else: self.selectedFont = self.allFonts[0] previousFontName = None newNames = getNamesFrom(self.allFonts) self.w.fontPopUp.setItems(newNames) if previousFontName is not None: self.w.fontPopUp.set(newNames.index(previousFontName)) links = loadLinksFromFont(self.selectedFont) self.w.linksList.set(links) self.w.linksList.setSelection([0]) self.currentRow = self.w.linksList[self.w.linksList.getSelection()[0]] self.matchSubscriptions() self.matchDisplayedSubscriptions() def fontDidCloseCallback(self, notification): self.allFonts = AllFonts() if self.selectedFont is None and self.allFonts != []: self.selectedFont = self.allFonts[0] links = loadLinksFromFont(self.selectedFont) self.w.linksList.set(links) currentFontName = self.w.fontPopUp.getItems()[self.w.fontPopUp.get()] newNames = getNamesFrom(self.allFonts) self.w.fontPopUp.setItems(newNames) if self.allFonts != []: if currentName in newNames: self.w.fontPopUp.set(newNames.index(currentName)) else: self.w.fontPopUp.set( newNames.index(os.path.basename(self.selectedFont))) def fontPopUpCallback(self, sender): if self._compareLibsToList() is False: result = askYesNo( 'Some changes were not pushed into font, would you like to do it now? Otherwise the changes will be lost' ) if bool(result) is True: self.pushIntoFontButtonCallback(sender=None) self.selectedFont = self.allFonts[sender.get()] links = loadLinksFromFont(self.selectedFont) self.w.linksList.set(links) def selectionLinksListCallback(self, sender): if sender.getSelection() == []: sender.setSelection([0]) self.currentRow = sender[sender.getSelection()[0]] self.matchDisplayedSubscriptions() self.w.canvas.update() def editLinksListCallback(self, sender): self.w.canvas.update() self.w.pushIntoFontButton.enable(not self._compareLibsToList()) def linkAllButtonCallback(self, sender): for eachRow in self.w.linksList: if eachRow['lft'] != '': eachRow['lftActive'] = True if eachRow['rgt'] != '': eachRow['rgtActive'] = True def unlockAllButtonCallback(self, sender): for eachRow in self.w.linksList: if eachRow['lft'] is not None: eachRow['lftActive'] = False if eachRow['rgt'] is not None: eachRow['rgtActive'] = False def pushIntoFontButtonCallback(self, sender): for eachRow in self.w.linksList: eachGlyph = self.selectedFont[eachRow['servant']] newLib = { 'lft': eachRow['lft'], 'lftActive': bool(eachRow['lftActive']), 'rgt': eachRow['rgt'], 'rgtActive': bool(eachRow['rgtActive']) } if newLib['lft'] == '' and newLib['rgt'] == '': if PLUGIN_LIB_NAME in eachGlyph.lib: del eachGlyph.lib[PLUGIN_LIB_NAME] else: eachGlyph.lib[PLUGIN_LIB_NAME] = newLib self.matchSubscriptions() self._alignServantsToMasters() self.w.pushIntoFontButton.enable(False) def clearLibsButtonCallback(self, sender): for eachGlyph in self.selectedFont: if PLUGIN_LIB_NAME in eachGlyph.lib: del eachGlyph.lib[PLUGIN_LIB_NAME] selectionIndex = self.w.linksList.getSelection() links = loadLinksFromFont(self.selectedFont) self.w.linksList.set(links) self.w.linksList.setSelection(selectionIndex) def loadFromTableCallback(self, sender): loadingPath = getFile("Select table with linked sidebearings") if loadingPath is None: return None with open(loadingPath[0], 'r') as linksTable: rawTable = [item for item in linksTable.readlines()] changedItems = [] toBeLinksList = list(self.selectedFont.glyphOrder) for indexRow, eachRow in enumerate(rawTable): lft, lftActive, servant, rgtActive, rgt = [ item.strip() for item in eachRow.split('\t') ] servantResult = self._isGlyphNameAllowed(servant) lftResult = self._isGlyphNameAllowed(lft) rgtResult = self._isGlyphNameAllowed(rgt) if all([servantResult, lftResult, rgtResult]) is False: message( 'Line {} contains a mistake'.format(indexRow + 1), 'One or more glyphs [lft:<{}> servant:<{}> rgt:<{}>] are not allowed in this font' .format(lft, servant, rgt)) return None if servant in toBeLinksList: servantIndex = toBeLinksList.index(servant) toBeLinksList[servantIndex] = { 'lft': lft, 'lftActive': True if lftActive == 'True' else False, 'servant': servant, 'rgt': rgt, 'rgtActive': True if rgtActive == 'True' else False } changedItems.append(servantIndex) for eachUnchangedIndex in [ ii for ii in range(len(toBeLinksList)) if ii not in changedItems ]: toBeLinksList[eachUnchangedIndex] = { 'lft': '', 'lftActive': False, 'servant': toBeLinksList[eachUnchangedIndex], 'rgt': '', 'rgtActive': False } self.w.linksList.set(toBeLinksList) self._compareLibsToList() def exportTableCallback(self, sender): savingPath = putFile("") if savingPath is None: return None with open(savingPath, 'w') as linksTable: for eachRow in self.w.linksList: if eachRow['lft'] != '' or eachRow['rgt'] != '': linksTable.write( '{lft}\t{lftActive}\t{servant}\t{rgtActive}\t{rgt}\n'. format(**eachRow)) def windowCloseCallback(self, sender): self.unsubscribeGlyphs() self.unsubscribeDisplayedGlyphs() removeObserver(self, 'fontDidOpen') removeObserver(self, 'fontDidClose') removeObserver(self, "draw") removeObserver(self, "drawInactive") super(SidebearingsLinker, self).windowCloseCallback(sender) # private methods def _isGlyphNameAllowed(self, glyphName): if glyphName == '': return True elif glyphName not in self.selectedFont: return False else: return True def _compareLibsToList(self): inFont = loadLinksFromFont(self.selectedFont) return inFont == [item for item in self.w.linksList] def _alignServantsToMasters(self): for eachGlyph in self.selectedFont: if PLUGIN_LIB_NAME in eachGlyph.lib: thisLib = eachGlyph.lib[PLUGIN_LIB_NAME] if thisLib['lftActive'] is True and thisLib['lft'] != '': lftMaster = self.selectedFont[thisLib['lft']] eachGlyph.leftMargin = lftMaster.leftMargin if thisLib['rgtActive'] is True and thisLib['rgt'] != '': rgtMaster = self.selectedFont[thisLib['rgt']] eachGlyph.rightMargin = rgtMaster.rightMargin
class AscenderDescenderCalculator(BaseWindowController): lowerExtreme = None higherExtreme = None is_hhea = False is_vhea = False is_osTwo = False is_usWin = False def __init__(self): super(AscenderDescenderCalculator, self).__init__() self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, PLUGIN_HEIGHT), PLUGIN_TITLE) jumpingY = MARGIN_VER self.w.calcButton = SquareButton( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['ButtonRegularHeight'] * 1.5), 'Measure Extremes', callback=self.calcButtonCallback) jumpingY += vanillaControlsSize[ 'ButtonRegularHeight'] * 1.5 + MARGIN_ROW self.w.topCaption = TextBox( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['TextBoxRegularHeight']), 'Top: None') jumpingY += vanillaControlsSize['TextBoxRegularHeight'] + MARGIN_ROW self.w.btmCaption = TextBox( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['TextBoxRegularHeight']), 'Bottom: None') jumpingY += vanillaControlsSize['TextBoxRegularHeight'] self.w.separationLine = HorizontalLine( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['TextBoxRegularHeight'])) jumpingY += vanillaControlsSize['TextBoxRegularHeight'] + MARGIN_ROW self.w.check_hhea = CheckBox( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['CheckBoxRegularHeight']), 'hhea table', value=self.is_hhea, callback=self.check_hheaCallback) jumpingY += vanillaControlsSize['CheckBoxRegularHeight'] + MARGIN_ROW self.w.check_vhea = CheckBox( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['CheckBoxRegularHeight']), 'vhea table', value=self.is_vhea, callback=self.check_vheaCallback) jumpingY += vanillaControlsSize['CheckBoxRegularHeight'] + MARGIN_ROW self.w.check_osTwo = CheckBox( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['CheckBoxRegularHeight']), 'OS/2 table', value=self.is_osTwo, callback=self.check_osTwoCallback) jumpingY += vanillaControlsSize['CheckBoxRegularHeight'] + MARGIN_ROW self.w.check_usWin = CheckBox( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['CheckBoxRegularHeight']), 'usWin table', value=self.is_usWin, callback=self.check_usWinCallback) jumpingY += vanillaControlsSize['CheckBoxRegularHeight'] + MARGIN_ROW self.w.writeButton = SquareButton( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['ButtonRegularHeight'] * 1.5), 'Write values into fonts', callback=self.writeButtonCallback) jumpingY += vanillaControlsSize[ 'ButtonRegularHeight'] * 1.5 + MARGIN_VER * 1.5 self.w.resize(PLUGIN_WIDTH, jumpingY) self.setUpBaseWindowBehavior() self.w.open() def calcButtonCallback(self, sender): self.lowerExtreme, self.higherExtreme = findFamilyExtremes(AllFonts()) self.updateCaptions() def updateCaptions(self): self.w.topCaption.set( 'Highest: {ex.y} ({ex.glyphName}, {ex.styleName})'.format( ex=self.higherExtreme)) self.w.btmCaption.set( 'Lowest: {ex.y} ({ex.glyphName}, {ex.styleName})'.format( ex=self.lowerExtreme)) def check_hheaCallback(self, sender): self.is_hhea = bool(sender.get()) def check_vheaCallback(self, sender): self.is_vhea = bool(sender.get()) def check_osTwoCallback(self, sender): self.is_osTwo = bool(sender.get()) def check_usWinCallback(self, sender): self.is_usWin = bool(sender.get()) def writeButtonCallback(self, sender): if self.lowerExtreme is not None and self.higherExtreme is not None: for eachFont in AllFonts(): if self.is_hhea is True: eachFont.info.openTypeHheaAscender = self.higherExtreme.y eachFont.info.openTypeHheaDescender = self.lowerExtreme.y if self.is_vhea is True: eachFont.info.openTypeVheaVertTypoAscender = self.higherExtreme.y eachFont.info.openTypeVheaVertTypoDescender = self.lowerExtreme.y if self.is_osTwo is True: eachFont.info.openTypeOS2TypoAscender = self.higherExtreme.y eachFont.info.openTypeOS2TypoDescender = self.lowerExtreme.y if self.is_usWin is True: eachFont.info.openTypeOS2WinAscent = self.higherExtreme.y eachFont.info.openTypeOS2WinDescent = self.lowerExtreme.y else: message('Calc Extremes first!')
class Adhesiontext(BaseWindowController): def __init__(self): flushAlign = 76 firstRowY = 12 rowOffsetY = 30 firstCheckY = 135 checkOffsetY = 27 rightMarginX = -12 self.windowWidth = 410 self.windowHeightWithoutOptions = 45 self.windowHeightWithOptions = 280 self.scriptIsRTL = False windowPos = getExtensionDefault("%s.%s" % (extensionKey, "windowPos")) if not windowPos: windowPos = (100, 100) self.optionsVisible = getExtensionDefault( "%s.%s" % (extensionKey, "optionsVisible")) if self.optionsVisible: optionsButtonSign = '-' windowHeight = self.windowHeightWithOptions else: self.optionsVisible = False # needs to be set because the first time the extension runs self.optionsVisible will be None optionsButtonSign = '+' windowHeight = self.windowHeightWithoutOptions self.chars = getExtensionDefault("%s.%s" % (extensionKey, "chars")) if not self.chars: self.chars = '' self.sliderValue = getExtensionDefault("%s.%s" % (extensionKey, "sliderValue")) if not self.sliderValue: self.sliderValue = 25 self.scriptsIndex = getExtensionDefault("%s.%s" % (extensionKey, "scriptsIndex")) if not self.scriptsIndex: self.scriptsIndex = 0 self.langsIndex = getExtensionDefault("%s.%s" % (extensionKey, "langsIndex")) if not self.langsIndex: self.langsIndex = 0 self.w = FloatingWindow( (windowPos[0], windowPos[1], self.windowWidth, windowHeight), "adhesiontext") # 1st row self.w.labelChars = TextBox((10, firstRowY, flushAlign, 20), "Characters:", alignment="right") self.w.chars = EditText((flushAlign + 15, firstRowY - 1, 199, 22), self.chars, callback=self.charsCallback) self.w.button = Button((300, firstRowY, 68, 20), "Get text", callback=self.buttonCallback) self.w.spinner = FixedSpinner((325, firstRowY, 20, 20), displayWhenStopped=False) self.w.optionsButton = SquareButton((378, firstRowY + 1, 18, 18), optionsButtonSign, sizeStyle="small", callback=self.optionsCallback) # set the initial state of the button according to the content of the chars EditText if len(self.w.chars.get()): self.w.button.enable(True) else: self.w.button.enable(False) # keep track of the content of chars EditText self.previousChars = self.w.chars.get() # 2nd row self.w.labelWords = TextBox( (10, firstRowY + rowOffsetY, flushAlign, 20), "Words:", alignment="right") self.w.wordCount = TextBox( (flushAlign + 12, firstRowY + rowOffsetY, 40, 20), alignment="left") self.w.slider = Slider( (flushAlign + 47, firstRowY + rowOffsetY + 1, 165, 20), value=self.sliderValue, minValue=5, maxValue=200, callback=self.sliderCallback) # set the initial wordCount value according to the position of the slider self.w.wordCount.set(int(self.w.slider.get())) # 3rd row self.w.labelScripts = TextBox( (10, firstRowY + rowOffsetY * 2, flushAlign, 20), "Script:", alignment="right") self.w.scriptsPopup = PopUpButton( (flushAlign + 15, firstRowY + rowOffsetY * 2, 150, 20), scriptsNameList, callback=self.scriptsCallback) self.w.scriptsPopup.set(self.scriptsIndex) # 4th row self.w.labelLangs = TextBox( (10, firstRowY + rowOffsetY * 3, flushAlign, 20), "Language:", alignment="right") self.w.langsPopup = PopUpButton( (flushAlign + 15, firstRowY + rowOffsetY * 3, 150, 20), []) # set the initial list of languages according to the script value self.w.langsPopup.setItems( langsNameDict[scriptsNameList[self.w.scriptsPopup.get()]]) self.w.langsPopup.set(self.langsIndex) self.punctCheck = getExtensionDefault("%s.%s" % (extensionKey, "punctCheck")) if not self.punctCheck: self.punctCheck = 0 self.figsCheck = getExtensionDefault("%s.%s" % (extensionKey, "figsCheck")) if not self.figsCheck: self.figsCheck = 0 self.figsPopup = getExtensionDefault("%s.%s" % (extensionKey, "figsPopup")) if not self.figsPopup: self.figsPopup = 0 self.trimCheck = getExtensionDefault("%s.%s" % (extensionKey, "trimCheck")) if not self.trimCheck: self.trimCheck = 0 self.caseCheck = getExtensionDefault("%s.%s" % (extensionKey, "caseCheck")) if not self.caseCheck: self.caseCheck = 0 self.casingCheck = getExtensionDefault("%s.%s" % (extensionKey, "casingCheck")) if not self.casingCheck: self.casingCheck = 0 self.casingPopup = getExtensionDefault("%s.%s" % (extensionKey, "casingPopup")) if not self.casingPopup: self.casingPopup = 0 # 1st checkbox self.w.punctCheck = CheckBox((flushAlign + 15, firstCheckY, 130, 20), "Add punctuation") self.w.punctCheck.set(self.punctCheck) # 2nd checkbox self.w.figsCheck = CheckBox( (flushAlign + 15, firstCheckY + checkOffsetY, 120, 20), "Insert numbers", callback=self.figsCallback) self.w.figsCheck.set(self.figsCheck) self.w.figsPopup = PopUpButton( (210, firstCheckY + checkOffsetY, 90, 20), figOptionsList) self.w.figsPopup.set(self.figsPopup) # enable or disable the figure options PopUp depending on the figures CheckBox if scriptsNameList[self.w.scriptsPopup.get()] in enableFigOptionList: self.w.figsPopup.show(True) if self.w.figsCheck.get(): self.w.figsPopup.enable(True) else: self.w.figsPopup.enable(False) else: self.w.figsPopup.show(False) # 3rd checkbox self.w.trimCheck = CheckBoxPlus( (flushAlign + 15, firstCheckY + checkOffsetY * 2, 120, 20), "Trim accents") self.w.trimCheck.set(self.trimCheck) if scriptsNameList[self.w.scriptsPopup.get()] in enableTrimCheckList: self.w.trimCheck.enable(True) else: self.w.trimCheck.enable(False) # 4th checkbox self.w.caseCheck = CheckBoxPlus( (flushAlign + 15, firstCheckY + checkOffsetY * 3, 120, 20), "Ignore casing") self.w.caseCheck.set(self.caseCheck) if scriptsNameList[self.w.scriptsPopup.get()] in enableCaseCheckList: self.w.caseCheck.enable(True) else: self.w.caseCheck.enable(False) # 5th checkbox self.w.casingCheck = CheckBoxPlus( (flushAlign + 15, firstCheckY + checkOffsetY * 4, 115, 20), "Change casing", callback=self.casingCallback) self.w.casingCheck.set(self.casingCheck) if scriptsNameList[self.w.scriptsPopup.get()] in enableCaseCheckList: self.w.casingCheck.enable(True) else: self.w.casingCheck.enable(False) self.w.casingPopup = PopUpButton( (210, firstCheckY + checkOffsetY * 4, 90, 20), casingNameList) self.w.casingPopup.set(self.casingPopup) # enable or disable the casing PopUp depending on the casing CheckBox if self.w.casingCheck.get() and self.w.casingCheck.isEnable(): self.w.casingPopup.enable(True) else: self.w.casingPopup.enable(False) self.nsTextField = self.w.chars.getNSTextField() self.w.setDefaultButton(self.w.button) self.w.bind("close", self.windowClose) self.w.open() self.w.makeKey() def windowClose(self, sender): self.saveExtensionDefaults() def saveExtensionDefaults(self): setExtensionDefault("%s.%s" % (extensionKey, "windowPos"), self.w.getPosSize()[0:2]) setExtensionDefault("%s.%s" % (extensionKey, "optionsVisible"), self.optionsVisible) setExtensionDefault("%s.%s" % (extensionKey, "chars"), self.w.chars.get()) setExtensionDefault("%s.%s" % (extensionKey, "sliderValue"), int(self.w.slider.get())) setExtensionDefault("%s.%s" % (extensionKey, "scriptsIndex"), int(self.w.scriptsPopup.get())) setExtensionDefault("%s.%s" % (extensionKey, "langsIndex"), int(self.w.langsPopup.get())) setExtensionDefault("%s.%s" % (extensionKey, "punctCheck"), self.w.punctCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "figsCheck"), self.w.figsCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "figsPopup"), self.w.figsPopup.get()) setExtensionDefault("%s.%s" % (extensionKey, "trimCheck"), self.w.trimCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "caseCheck"), self.w.caseCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "casingCheck"), self.w.casingCheck.get()) setExtensionDefault("%s.%s" % (extensionKey, "casingPopup"), self.w.casingPopup.get()) def buttonCallback(self, sender): sender.enable(False) self.w.spinner.start() self.getText() self.w.spinner.stop() sender.enable(True) def optionsCallback(self, sender): sign = sender.getTitle() if sign == "+": sender.setTitle("-") self.w.resize(self.windowWidth, self.windowHeightWithOptions, animate=True) self.optionsVisible = True else: sender.setTitle("+") self.w.resize(self.windowWidth, self.windowHeightWithoutOptions, animate=True) self.optionsVisible = False def charsCallback(self, sender): charsContent = sender.get() if len(charsContent): self.w.button.enable(True) nsTextView = self.nsTextField.currentEditor( ) # NOTE: the field editor is only available when NSTextField is in editing mode. # when only one glyph is selected and copied, the contents of the clipboard are the glyph's XML # instead of its unicode character or its name; therefore, post-process the pasted content. if xmlHeader in charsContent: caretIndex = charsContent.index(xmlHeader) codepointString = re_glyphUnicode.search(charsContent) glyphName = re_glyphName.search(charsContent) if codepointString: replacement = unichr(eval('0x' + codepointString.group(1))) elif glyphName: replacement = '/' + glyphName.group(1) else: replacement = '' # replace the glyph's XML by its unicode character or its name self.w.chars.set(re_glyph.sub(replacement, charsContent)) # restore the location of the caret location = caretIndex + len(replacement) nsTextView.setSelectedRange_((location, 0)) # update the variable charsContent = sender.get() caretIndex = nsTextView.selectedRanges()[0].rangeValue().location # Limit the number of characters numeralWasFound = self.stringHasNumeral(charsContent) if len(charsContent) > maxChars or numeralWasFound: NSBeep() if numeralWasFound: self.showMessage("Sorry, numerals are not allowed.", "") else: self.showMessage( "You've reached the maximum \rnumber of characters.", "The limit is %d." % maxChars) # restore the content of chars EditText to the previous string sender.set(self.previousChars) # restore the focus on the chars EditText and restore the location of the caret caretIndexAdjust = len(self.previousChars) - len(charsContent) self.w.getNSWindow().makeFirstResponder_(self.nsTextField) nsTextView.setSelectedRange_( (caretIndex + caretIndexAdjust, 0)) # update the stored string self.previousChars = sender.get() else: self.w.button.enable(False) def sliderCallback(self, sender): self.w.wordCount.set(int(sender.get())) def scriptsCallback(self, sender): self.w.langsPopup.setItems( langsNameDict[scriptsNameList[sender.get()]]) # toggle RTL/LTR if scriptsNameList[sender.get()] in rightToLeftList: self.scriptIsRTL = True self.nsTextField.setBaseWritingDirection_( NSWritingDirectionRightToLeft) self.nsTextField.setAlignment_(NSRightTextAlignment) else: self.scriptIsRTL = False self.nsTextField.setBaseWritingDirection_( NSWritingDirectionLeftToRight) self.nsTextField.setAlignment_(NSLeftTextAlignment) # restore the focus on the chars EditText self.w.getNSWindow().makeFirstResponder_(self.nsTextField) # toggle figsPopup if scriptsNameList[sender.get()] in enableFigOptionList: self.w.figsPopup.show(True) if self.w.figsCheck.get(): self.w.figsPopup.enable(True) else: self.w.figsPopup.enable(False) else: self.w.figsPopup.show(False) # toggle trimCheck if scriptsNameList[sender.get()] in enableTrimCheckList: self.w.trimCheck.enable(True) else: self.w.trimCheck.enable(False) # toggle caseCheck and casingCheck if scriptsNameList[sender.get()] in enableCaseCheckList: self.w.caseCheck.enable(True) self.w.casingCheck.enable(True) if self.w.casingCheck.get(): self.w.casingPopup.enable(True) else: self.w.caseCheck.enable(False) self.w.casingCheck.enable(False) self.w.casingPopup.enable(False) def figsCallback(self, sender): if sender.get(): self.w.figsPopup.enable(True) else: self.w.figsPopup.enable(False) def casingCallback(self, sender): if sender.get(): self.w.casingPopup.enable(True) else: self.w.casingPopup.enable(False) def stringHasNumeral(self, string): if re_numeral.search(string): return True return False def isConnected(self): try: urlopen(url, timeout=3) return True except URLError: pass return False def getText(self): if CurrentFont() is None: NSBeep() self.showMessage("Open a font first.", "") return if not self.isConnected(): NSBeep() self.showMessage("Required internet connection not found.", "") return values = { 'chars': self.w.chars.get().encode('utf-8'), 'script': scriptsTagDict[scriptsNameList[self.w.scriptsPopup.get()]], 'tb': langsTagDict[langsNameDict[scriptsNameList[ self.w.scriptsPopup.get()]][self.w.langsPopup.get()]] } if self.w.punctCheck.get(): values['punct'] = True if self.w.figsCheck.get(): values['figs'] = True if self.w.figsPopup.isVisible(): figsOptTagsList = ["dflt", "locl"] values['figsOpt'] = figsOptTagsList[self.w.figsPopup.get()] if self.w.trimCheck.get() and self.w.trimCheck.isEnable(): values['trim'] = True if self.w.caseCheck.get() and self.w.caseCheck.isEnable(): values['case'] = True if self.w.casingCheck.get() and self.w.casingCheck.isEnable(): values['casing'] = casingNameList[self.w.casingPopup.get()].lower() data = urlencode(values) data = data.encode('utf-8') print(data) request = Request(url, data) response = urlopen(request) text = response.read() textU = unicode(text, 'utf-8') if (msgStr in textU): textU = textU.replace(msgStr, "") NSBeep() self.showMessage(textU, "") return elif (wrnStr in textU): resultIndex = textU.find(rsltStr) secmsgIndex = textU.find(sndStr) frstmsgU = textU[:secmsgIndex].replace(wrnStr, "") scndmsgU = textU[secmsgIndex:resultIndex].replace(sndStr, "") textU = textU[resultIndex:].replace(rsltStr, "") NSBeep() self.showMessage(frstmsgU, scndmsgU) textList = textU.split() trimmedText = ' '.join(textList[:int(self.w.slider.get())]) if CurrentSpaceCenter() is None: OpenSpaceCenter(CurrentFont(), newWindow=False) sp = CurrentSpaceCenter() print(trimmedText) sp.setRaw(trimmedText) # Toggle RTL-LTR try: sp.setLeftToRight(not self.scriptIsRTL) sp.setInputWritingDirection( 'Right to Left' if self.scriptIsRTL else 'Left to Right') except AttributeError: pass return