def downloadCurrentVersion(): """ Download the current version (dmg) and mount it """ path = "https://github.com/typemytype/drawbot/releases/latest/download/DrawBot.dmg" try: context = ssl._create_unverified_context() request = Request(path, headers={'User-Agent': 'Drawbot'}) # download and mount with tempfile.NamedTemporaryFile(mode='w+b') as dmgFile: response = urlopen(request, timeout=5, context=context) dmgFile.write(response.read()) response.close() cmds = ["hdiutil", "attach", "-plist", dmgFile.name] popen = subprocess.Popen(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = popen.communicate() if popen.returncode != 0: raise DrawBotError("Mounting failed") output = plistlib.loads(out) dmgPath = None for item in output["system-entities"]: if "mount-point" in item: dmgPath = item["mount-point"] break AppKit.NSWorkspace.sharedWorkspace().openFile_(dmgPath) except Exception: exc = traceback.format_exc() message("Something went wrong while downloading %s" % path, exc)
def __init__(self): self.font = CurrentFont() self.spaceCenter = None if self.font: addObserver(self, 'SpaceCenterObserver', 'spaceCenterDidOpen') self.spaceCenter = OpenSpaceCenter(self.font, newWindow=True) addObserver(self, 'pressedKey', 'spaceCenterKeyDown') addObserver(self, 'closeSpaceCenter', 'spaceCenterWillClose') # get kerning from CurrentFont and build text list self.pairsTextCheck = [] self.kKeys = self.getKerningPairsRef(self.font) for key, gkey in self.kKeys: self.pairsTextCheck.append(self.returnPattern(key)) # index of text self.i = 0 self.maxi = len(self.kKeys) if self.pairsTextCheck: self.hasKerning = True self.spaceCenter.set(self.pairsTextCheck[self.i]) else: self.hasKerning = False self.spaceCenter.setRaw('YOUR FONT HAS NO KERNING PAIRS -- your font has no kerning pairs') else: message('You need to open a font first!')
def __init__(self): self.font = CurrentFont() if self.font is None: from vanilla.dialogs import message message("No Font is open.", "Open or create a font to convert groups to feature syntax groups.") return groupsNames = self.font.groups.keys() groupsNames.sort() self.w = Window((400, 400), "Feature Group Converter", minSize=(300, 300)) toolbarItems = [ dict(itemIdentifier="insert", label="Insert In Font", imageObject=insertFeatureToolbarImage(), callback=self.toolbarInsert, ), ] toolbar = self.w.addToolbar(toolbarIdentifier="GroupsToFeatureTextToolbar", toolbarItems=toolbarItems, addStandardItems=False) self.w.groupList = List((0, 0, 150, -0), groupsNames, selectionCallback=self.groupListSelectionCallback) self.w.feaText = DoodleFeatureTextEditor((150, 0, -0, -0), "") self.w.groupList.setSelection([]) self.w.assignToDocument(self.font.document()) self.w.open()
def _assignLayerToGlyph_Button_callback(self, sender): storageGlyphName = self.ui.w.deepComponentsEditorGroup.GlyphLayers.storageGlyphName StorageGlyphCurrentLayer = self.ui.w.deepComponentsEditorGroup.GlyphLayers.StorageGlyphCurrentLayer if storageGlyphName is None: message("Warning there is no selected glyph") return if not self.selectedLayerName: message("Warning there is no selected layer") return storageFont = self.ui.font2Storage[self.ui.font] layer = StorageGlyphCurrentLayer if not layer: layer = storageFont[storageGlyphName] layer.round() if self.selectedLayerName not in storageFont[storageGlyphName].lib[ "deepComponentsLayer"]: storageFont.getLayer(self.selectedLayerName).insertGlyph(layer) storageFont[storageGlyphName].lib["deepComponentsLayer"].append( self.selectedLayerName) storageFont[storageGlyphName].update() self.ui.w.deepComponentsEditorGroup.GlyphLayers.layersCanvas.update() self.ui.w.deepComponentsEditorGroup.GlyphLayers.setSliderList()
def windowShouldClose(self, window): if self.isRunning: message("Window can’t be closed", "The ‘pip’ process is still running.", parentWindow=self.w) return False return True
def applicationOpenFile(self, notification): path = notification["path"] ext = notification["ext"] fileHandler = notification["fileHandler"] if ext == ".%s" % fileExtension: singleItems = list(getExtensionDefault("com.mechanic.singleExtensionItems")) try: with open(path, "rb") as f: item = yaml.load(f.read()) except Exception as e: logger.error("Cannot read '%s' file" % path) logger.error(e) try: ExtensionYamlItem(item) if item not in singleItems: singleItems.append(item) setExtensionDefault("com.mechanic.singleExtensionItems", singleItems) title = "Opening Mechanic file." text = "Added '%s' to Mechanic" % path else: title = "Duplicate Mechanic file." text = "The extension '%s' was not added to Mechanic" % path except Exception as e: logger.error("Cannot parse the file '%s'" % path) logger.error(e) title = "Failed to read the file '%s'." % path text = "See the output window for a detailed traceback." message(title, text) fileHandler["opened"] = True
def generateGlyphsToFont(self, exportFont=None, layerName=None): font = RFont(showInterface=False) if exportFont is None else exportFont currentFont = self.currentFont filterName = self.currentFilterName currentFilter = self.filters[filterName] if currentFont is not None and len(currentFont.selectedGlyphs): glyphs = [ currentFont[glyphName] for glyphName in currentFont.selectedGlyphNames if glyphName in currentFont ] for glyph in glyphs: if len(glyph.components) > 0: for comp in glyph.components: baseGlyphName = comp.baseGlyph baseGlyph = currentFont[baseGlyphName] baseFilteredGlyph = currentFilter(baseGlyph) newFont.insertGlyph(baseFilteredGlyph, baseGlyphName) newFont[ baseGlyphName].unicode = baseFilteredGlyph.unicode filteredGlyph = currentFilter(glyph) if filteredGlyph is not None: if exportFont is None: font.insertGlyph(filteredGlyph, glyph.name) else: glyph = font[ glyph.name] if layerName is None else font[ glyph.name].getLayer(layerName) glyph.clearContours() glyph.clearComponents() glyph.appendGlyph(filteredGlyph) font.openInterface() else: message('PenBallWizard', 'No selected glyphs to generate')
def averageWidth(): Glyphs.clearLog() try: averageWidth = 0 count = 0 alreadyCheckedGlyphs = [] msg_txt = "" for layer in Glyphs.font.selectedLayers: thisGlyph = layer.parent if thisGlyph.name is None: continue if thisGlyph.name == "None": continue if thisGlyph.name in alreadyCheckedGlyphs: continue # this will omitt glyphs.width that was already checked averageWidth += layer.width count += 1 print("\t", thisGlyph.name) msg_txt += "'" + str(thisGlyph.name) + "' " + "width: " + str( layer.width) + "\n" print("\t" "Width =>", layer.width) alreadyCheckedGlyphs.append(thisGlyph.name) averageWidth = averageWidth / count print("Average Width =>", averageWidth) msg_txt += "\n\nAverage Width: %s" % averageWidth vd.message(msg_txt) except Exception as e: # print error Glyphs.showMacroWindow() print("Change Width Centered Error: %s" % e)
def checkReqVsCase(self, required, case): """Check that required letters do not contradict case selection. This seems to be a frequent source of user error. Only implemented for text mode (character list), not grep. """ errNotLower = "word-o-mat: Conflict: You have specified all-lowercase words, but required uppercase characters. Please revise." errNotUpper = "word-o-mat: Conflict: You have specified words in ALL CAPS, but required lowercase characters. Please revise." if self.matchMode != "grep": # all lowercase words -- catch caps if case == 1: for c in required: if not c.islower(): message(errNotLower) return False return True # all caps -- catch lowercase letters elif case == 3: for c in required: if not c.isupper(): message(errNotUpper) return False return True return True
def checkReqVsCase(self, required, case): """Check that required letters do not contradict case selection. This seems to be a frequent source of user error. Only implemented for text mode (character list), not grep. """ errNotLower = "word-o-mat: Conflict: You have specified all-lowercase words, but required uppercase characters. Please revise." errNotUpper = "word-o-mat: Conflict: You have specified words in ALL CAPS, but required lowercase characters. Please revise." if self.matchMode != "grep": # all lowercase words -- catch caps if case == 1: for c in required: if not c.islower(): message (errNotLower) return False return True # all caps -- catch lowercase letters elif case == 3: for c in required: if not c.isupper(): message (errNotUpper) return False return True return True
def generateGlyphsToFont(self, exportFont=None, layerName=None): font = RFont(showUI=False) if exportFont is None else exportFont currentFont = self.currentFont filterName = self.currentFilterName currentFilter = self.filters[filterName] if currentFont is not None and len(currentFont.selection): glyphs = [currentFont[glyphName] for glyphName in currentFont.selection if glyphName in currentFont] for glyph in glyphs: if len(glyph.components) > 0: for comp in glyph.components: baseGlyphName = comp.baseGlyph baseGlyph = currentFont[baseGlyphName] baseFilteredGlyph = currentFilter(baseGlyph) newFont.insertGlyph(baseFilteredGlyph, baseGlyphName) newFont[baseGlyphName].unicode = baseFilteredGlyph.unicode filteredGlyph = currentFilter(glyph) if filteredGlyph is not None: if exportFont is None: font.insertGlyph(filteredGlyph, glyph.name) else: glyph = font[glyph.name] if layerName is None else font[glyph.name].getLayer(layerName) glyph.clearContours() glyph.clearComponents() glyph.appendGlyph(filteredGlyph) font.showUI() else: message(u'PenBallWizard', 'No selected glyphs to generate')
def __init__(self): self.font = CurrentFont() self.spaceCenter = None if self.font: addObserver(self, 'SpaceCenterObserver', 'spaceCenterDidOpen') self.spaceCenter = OpenSpaceCenter(self.font, newWindow=True) # addObserver(self, None, 'spaceCenterDraw') addObserver(self, 'pressedKey', 'spaceCenterKeyDown') addObserver(self, 'closeSpaceCenter', 'spaceCenterWillClose') # get kerning from CurrentFont and build text list self.pairsTextCheck = [] self.kKeys = self.getKerningPairsRef(self.font) # get reference pairs for flipping self.refPairs = [pair[0] for pair in self.kKeys] for key, gkey in self.kKeys: self.pairsTextCheck.append(self.returnPattern(key)) # index of text self.i = 0 self.maxi = len(self.kKeys) self.spaceCenter.set(self.pairsTextCheck[self.i]) else: message('You need to open a font first!')
def send(self, sender): recipients = self.window.recipients.get() selection = [ recipients[i] for i in self.window.recipients.getSelection() ] if selection == []: selection = self.window.recipients.get() recipients = ', '.join(selection) progress = ProgressWindow('', tickCount=3, parentWindow=self.window) try: tmpdir = tempfile.mkdtemp(prefix="ghostlines") progress.update('Generating OTF') # Should be controlled which options are used somewhere filename = os.path.join(tmpdir, self.font.info.familyName + '.otf') self.font.generate(format="otf", path=filename, decompose=True, checkOutlines=True, autohint=True) progress.update('Sending via Ghostlines') with open(filename, 'rb') as otf: params = dict(otf=otf, recipients=recipients, notes=self.window.notes_field.get(), designer_email_address=self.window. email_address_field.get()) license_path = self.license_storage.retrieve() if license_path is not '' and os.path.exists(license_path): with open(license_path, 'rb') as license: filename = os.path.basename(license_path) _, extension = os.path.splitext(license_path) content_type = filetypes[extension] params['license'] = (filename, license, content_type) response = Ghostlines('v0.1').send(**params) else: response = Ghostlines('v0.1').send(**params) if response.status_code == requests.codes.created: message("{} was delivered".format(self.font.info.familyName)) else: print repr(response) message( "{} could not be delivered".format( self.font.info.familyName), "Error code: {}\n{}".format(response.status_code, response.json())) finally: progress.close()
def send(self, *_): subscribers = self.window.subscriber_info.subscribers.get() subscriber_ids = [ subscribers[i]["id"] for i in self.window.subscriber_info.subscribers.getSelection() ] notes = self.note_draft_storage.retrieve() font_family_id = self.family_id_storage.retrieve() license_path = self.license_storage.retrieve() progress = ProgressWindow('', tickCount=3, parentWindow=self.window) try: tmpdir = tempfile.mkdtemp(prefix="ghostlines") progress.update('Generating OTF') # Should be controlled which options are used somewhere otf_path = os.path.join(tmpdir, '{}.otf'.format(self.font.info.familyName)) self.font.generate(format="otf", path=otf_path, decompose=True, checkOutlines=True, autohint=True) progress.update('Sending via Ghostlines') params = dict(notes=notes, font_family_id=font_family_id) with open(otf_path, 'rb') as otf: params['otfs'] = [(os.path.basename(otf_path), otf.read(), "application/octet-stream")] if subscriber_ids: params['subscriber_ids[]'] = subscriber_ids if self.license_exists: with open(license_path, 'rb') as license: filename = os.path.basename(license_path) _, extension = os.path.splitext(license_path) content_type = filetypes[extension] params['license'] = (filename, license.read(), content_type) token = AppStorage("accessToken").retrieve() response = Ghostlines('v1', token=token).create_release(**params) if response.status_code == requests.codes.created: message("{} was delivered".format(self.font.info.familyName)) self.refresh_releases() else: ErrorMessage( "{} could not be delivered".format( self.font.info.familyName), response.json()["errors"]) finally: progress.close()
def testFontButtonCallback(self, sender): font = CurrentFont() if font is None: dialogs.message("There is no font to test.", "Open a font and try again.") return testStates = self._getSettings() results = getFontReport(font, testStates, format=True) print results
def checkMinVsMax(self, minLength, maxLength): """Check user input for minimal/maximal word length and see if it makes sense.""" if not minLength <= maxLength: message( "word-o-mat: Confusing input for minimal/maximal word length. Please fix." ) return False return True
def commitInfoNote(infoNoteContent, font, fontState): if infoNoteContent == "": message("info note is blank, operation aborted") else: font.info.note = infoNoteContent print "saving changes on font: %s" % font.path font.copy().save(font.path) commitVersion(font, fontState)
def main(): font = CurrentFont() success, maybeFontState = getFontState(font) if not success: message("script validation failed(fix and try again):\n" + maybeFontState) else: userChecksInfoNote(font, maybeFontState)
def revealInstallFolderCallback(self, sender): if not os.path.exists(self.targetPath): message("The install folder does not yet exists.", "Try again after installing a package.", parentWindow=self.w) else: AppKit.NSWorkspace.sharedWorkspace( ).selectFile_inFileViewerRootedAtPath_(None, self.targetPath)
def checkReqVsLen(self, required, maxLength): """Check for conflicts between number of required characters and specified word length. Only implemented for text input for now. """ if self.matchMode != "grep": if len(required) > maxLength: message ("word-o-mat: Conflict: Required characters exceed maximum word length. Please revise.") return False return True
def application_openFile_(self, app, path): ext = os.path.splitext(path)[-1] if ext.lower() == ".drawbot": succes, report = DrawBotPackage(path).run() if not succes: fileName = os.path.basename(path) message("The DrawBot package '%s' failed." % fileName, report) return True return False
def open(self): if not self.font.info.familyName: message("Family Name must be set", full_requirements_message) return if not self.font.info.openTypeNameDesigner: message("Designer must be set", full_requirements_message) return self.window.open()
def open(self): if not self.font.info.familyName: message("Family Name must be set", full_requirements_message) return if not self.font.info.designer: message("Designer must be set", full_requirements_message) return self.window.open()
def getExampleRootPath(self, site): view = self.getView() root = os.path.expanduser(view.exampleRoot.get()) # File root of server. if not root.endswith('/'): root += '/' if not os.path.exists(root): message(messageText='Error in Examples path.', informativeText='The Examples folder "%s" does not exist.' % root, alertStyle=NSInformationalAlertStyle, parentWindow=view) return None return root + site.getPythonClassName().lower() + '/'
def checkReqVsLen(self, required, maxLength): """Check for conflicts between number of required characters and specified word length. Only implemented for text input for now. """ if self.matchMode != "grep": if len(required) > maxLength: message( "word-o-mat: Conflict: Required characters exceed maximum word length. Please revise." ) return False return True
def getMampRootPath(self, site): view = self.getView() root = os.path.expanduser(view.mampRoot.get()) # File root of server. if not root.endswith('/'): root += '/' if not os.path.exists(root): message(messageText='Error in MAMP path.', informativeText='The MAMP folder "%s" does not exist.' % root, alertStyle=NSInformationalAlertStyle, parentWindow=view) return None return root + site.getPythonClassName().lower() + '/'
def checkRE(self): """Check if the regular expression entered by the user compiles.""" if self.matchMode == "grep": try: self.matchPatternRE = re.compile(self.matchPattern) return True except re.error: self.matchPatternRE = None message ("word-o-mat: Could not compile regular expression.") return False else: self.matchPatternRE = None return True
def checkRE(self): """Check if the regular expression entered by the user compiles.""" if self.matchMode == "grep": try: self.matchPatternRE = re.compile(self.matchPattern) return True except re.error: self.matchPatternRE = None message("word-o-mat: Could not compile regular expression.") return False else: self.matchPatternRE = None return True
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 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')
def _segmentedButton_callback(self, sender): sel = sender.get() if not sel: self.w.df.show(1) self.w.rv.show(0) self.w.c.show(0) elif sel == 1: self.w.df.show(0) self.w.rv.show(1) self.w.c.show(0) else: self.w.df.show(0) self.w.rv.show(0) self.w.c.show(1) message("Work in Progress...")
def checkReqVsFont(self, required, limitTo, fontChars, customCharset): """Check if a char is required from a font/selection/mark color that doesn't have it.""" if limitTo == False: return True else: if len(customCharset) > 0: useCharset = customCharset messageCharset = "selection of glyphs you would like me to use" else: useCharset = fontChars messageCharset = "font" for c in required: if not c in useCharset: message ("word-o-mat: Conflict: Character \"%s\" was specified as required, but not found in the %s." % (c, messageCharset)) return False return True
def __init__(self): self.font = CurrentFont() self.mark = 0 if not self.font: message('Open a font first!') return # window and UI self.w = Window((250, 500), "Groups To Selection", minSize=(250, 200), maxSize=(250, 1000)) # font groups self.w.groupsList = List((10, 10, -10, -70), [], columnDescriptions=[ {'title': 'sel', 'editable': True, 'cell': CheckBoxListCell(), 'width': 20}, {'title': 'Group Name'}], doubleClickCallback=self.doubleClickCallback ) self.buildGroupsList(self.font) # select/unselect all glyphs in font self.w.resetButton = Button((10, -60, -120, 20), '(un)Select All', sizeStyle='mini', callback=self.selectAllCallback) # mark and color selection self.w.markCheckbox = CheckBox((160, -60, -10, 20), 'mark', value=self.mark, sizeStyle='small', callback=self.markCallback) self.w.markColor = ColorWell((210, -60, -10, 20)) self.w.markColor.enable(False) self.w.markColor.set(NSColor.redColor()) # select self.w.makeSelection = Button((10, -30, -10, 20), "Make Selection", # minSize=(150, 150), callback=self.makeSelectionCallback) # removeObserver if the window closes self.w.bind("close", self.windowCloseCallback) self.w.open() addObserver(self, "updateCurrentFontCallback", "fontBecameCurrent")
def send(self, sender): recipients = ', '.join(self.window.recipients.get()) progress = ProgressWindow('', tickCount=3, parentWindow=self.window) try: tmpdir = tempfile.mkdtemp(prefix="ghostlines") progress.update('Generating OTF') # Should be controlled which options are used somewhere filename = os.path.join(tmpdir, self.font.info.familyName + '.otf') self.font.generate(filename, "otf", decompose=True, checkOutlines=True, autohint=True) progress.update('Sending via Ghostlines') with open(filename, 'rb') as otf: params = dict( otf=otf, recipients=recipients, notes=self.window.notes_field.get(), designer_email_address=self.window.email_address_field.get() ) license_path = self.license_storage.retrieve() if license_path is not '' and os.path.exists(license_path): with open(license_path, 'rb') as license: filename = os.path.basename(license_path) _, extension = os.path.splitext(license_path) content_type = filetypes[extension] params['license'] = (filename, license, content_type) response = Ghostlines('v0.1').send(**params) else: response = Ghostlines('v0.1').send(**params) if response.status_code == requests.codes.created: message("{} was delivered".format(self.font.info.familyName)) else: print repr(response) message("{} could not be delivered".format(self.font.info.familyName), "Error code: {}\n{}".format(response.status_code, response.json())) finally: progress.close()
def checkReqVsFont(self, required, limitTo, fontChars, customCharset): """Check if a char is required from a font/selection/mark color that doesn't have it.""" if limitTo == False: return True else: if len(customCharset) > 0: useCharset = customCharset messageCharset = "selection of glyphs you would like me to use" else: useCharset = fontChars messageCharset = "font" for c in required: if not c in useCharset: message( "word-o-mat: Conflict: Character \"%s\" was specified as required, but not found in the %s." % (c, messageCharset)) return False return True
def dispatch(self, sender): token = AppStorage("accessToken").retrieve() font_family_id = self.font_family_id_storage.retrieve(default=None) if font_family_id is not None and token is not None and token is not '': window = self.window.window().getNSWindow() mouseDown = window.mouseLocationOutsideOfEventStream() height = self.content_view.frame().size.height rect = (mouseDown.x, height - 1, 1, 1) headers = {'Authorization': 'Bearer {}'.format(token)} self.popover.open(preferredEdge="top", relativeRect=rect) if not self.popover.web.url: comment_ui_url ="{}/ui/font_families/{}/comments".format(env.api_url, font_family_id) self.popover.web.load(comment_ui_url, headers) else: message("You must register a font first", "Click on the Ghostlines menu item to create a record for this font on Ghostlines. You will then be able to view the comments from all of your releases by clicking this icon.")
def getInputString(self, field, stripColon): """Read an input string from a field, and convert it to a list of glyphnames.""" inputString = field.get() pattern = re.compile(" *, *| +") if stripColon: i = inputString.find(":") if i != -1: inputString = inputString[i+1:] result1 = pattern.split(inputString) result2 = [] for c in result1: if len(c)>1: # glyph names if self.f is not None: if self.f.has_key(c): g = self.f[c] try: value = unicode(unichr(int(g.unicode))) result2.append(value) except TypeError: # unicode not set message ("word-o-mat: Glyph \"%s\" was found, but does not appear to have a Unicode value set. It can therefore not be processed, and will be skipped." % c) else: message ("word-o-mat: Conflict: Character \"%s\" was specified as required, but not found. It will be skipped." % c) else: message ("word-o-mat: Sorry, matching by glyph name is only supported when a font is open. Character \"%s\" will be skipped." % c) else: # character values result2.append(c) result = [unicode(s) for s in result2 if s] return result
def getInputString(self, field, stripColon): """Read an input string from a field, and convert it to a list of glyphnames.""" inputString = field.get() pattern = re.compile(" *, *| +") if stripColon: i = inputString.find(":") if i != -1: inputString = inputString[i + 1:] result1 = pattern.split(inputString) result2 = [] for c in result1: if len(c) > 1: # glyph names if self.f is not None: if self.f.has_key(c): g = self.f[c] try: value = str(chr(int(g.unicode))) result2.append(value) except TypeError: # unicode not set message( "word-o-mat: Glyph \"%s\" was found, but does not appear to have a Unicode value set. It can therefore not be processed, and will be skipped." % c) else: message( "word-o-mat: Conflict: Character \"%s\" was specified as required, but not found. It will be skipped." % c) else: message( "word-o-mat: Sorry, matching by glyph name is only supported when a font is open. Character \"%s\" will be skipped." % c) else: # character values result2.append(c) result = [str(s) for s in result2 if s] return result
def __init__(self): self.font = CurrentFont() if self.font is None: from vanilla.dialogs import message message( "No Font is open.", "Open or create a font to convert groups to feature syntax groups." ) return groupsNames = self.font.groups.keys() groupsNames.sort() self.w = Window((400, 400), "Feature Group Converter", minSize=(300, 300)) toolbarItems = [ dict( itemIdentifier="insert", label="Insert In Font", imageObject=insertFeatureToolbarImage(), callback=self.toolbarInsert, ), ] toolbar = self.w.addToolbar( toolbarIdentifier="GroupsToFeatureTextToolbar", toolbarItems=toolbarItems, addStandardItems=False) self.w.groupList = List( (0, 0, 150, -0), groupsNames, selectionCallback=self.groupListSelectionCallback) self.w.feaText = DoodleFeatureTextEditor((150, 0, -0, -0), "") self.w.groupList.setSelection([]) self.w.assignToDocument(self.font.document()) self.w.open()
def logToFile(fontState, infoNoteContent): directory, filename, extension = explodePath(fontState.fullPath) logFileName = "%schangelog.md" % fontState.basename[:-1] logPath = os.path.join(directory,logFileName) if (os.path.exists(logPath)): with codecs.open(logPath, 'r', 'utf-8') as f: logContent = f.read() else: logContent = u"" newLogContent = time.strftime("### %d.%m.%Y (%H:%M) \n") newLogContent += "**%s%s** \n" % (filename, extension) newLogContent += "version: 0.%03d \n" % fontState.versionMinor newLogContent += " \n" newLogContent += infoNoteContent + " \n" newLogContent += u"\n---------------------------\n" logContent = newLogContent + logContent with codecs.open(logPath, 'w', 'utf-8') as f: f.write(logContent) message("operation completed\n" + newLogContent)
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!')
def downloadCurrentVersion(): """ Download the current version (dmg) and mount it """ path = "https://static.typemytype.com/drawBot/DrawBot.dmg" try: # download and mount cmds = ["hdiutil", "attach", "-plist", path] popen = subprocess.Popen(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = popen.communicate() if popen.returncode != 0: raise DrawBotError("Mounting failed") output = plistlib.loads(out) dmgPath = None for item in output["system-entities"]: if "mount-point" in item: dmgPath = item["mount-point"] break AppKit.NSWorkspace.sharedWorkspace().openFile_(dmgPath) except Exception: exc = traceback.format_exc() message("Something went wrong while downloading %s" % path, exc)
def openSelectedComponent(self, f, g): selectedComponents = [c for c in g.components if c.selected] if not len(selectedComponents): message("There is no selected components") return selectedComponent = selectedComponents[0] self.selectedComponentName = selectedComponent.baseGlyph self.selectedComponentOffset = selectedComponent.transformation[-2:] self.oldGlyph = g OpenGlyphWindow(f[self.selectedComponentName]) self.currentGlyph = CurrentGlyph() addObserver(self, "currentGlyphChanged", "currentGlyphChanged") addObserver(self, "draw", "draw") addObserver(self, "draw", "drawPreview") addObserver(self, "draw", "drawInactive") addObserver(self, "mouseDown", "mouseDown") UpdateCurrentGlyphView()
def __init__(self): if AllFonts() is None: from vanilla.dialogs import message message("No fonts open.", "Open or create a font to copy data to and fro.") return self.sourceFontList = AllFonts() self.destinationFontList = AllFonts() self.source_font = self.sourceFontList[0] self.destination_fonts = None self.groups = None self.kerning = None ## create a window self.w = Window((400, 500), "Copy Groups and Kerning", minSize=(500, 600)) self.w.sourceTitle = TextBox((15, 20, 200, 20), "Source Font:") self.w.sourceFont = PopUpButton((15, 42, 340, 20), [f.info.familyName + ' ' + f.info.styleName for f in self.sourceFontList], callback=self.sourceCallback) self.w.desTitle = TextBox((15, 76, 200, 20), "Destination Fonts:") self.w.destinationFonts = FontList((15, 96, -15, -115), self.destinationFontList, selectionCallback=self.desCallback) self.w.copyButton = Button((-215, -40, 200, 20), 'Copy Groups & Kerning', callback=self.copyCallback) self.w.line = HorizontalLine((10, -60, -10, 1)) self._updateDest() ## open the window self.w.open()
def _selection2DeepCompo_Button_Callback(self, sender): if not self.ui.selectedCompositionGlyphName: message("Warning, there is no selected composition glyph name") return if self.ui.glyph is None: message("Warning, there is no glyph") return selectedContours = [ c for c in self.ui.glyph if c.selected or [p for p in c.points if p.selected] ] if not selectedContours: message("Warning, there is no selectedContours") return Select2DeepCompoSheet(self.ui, self, self.ui.selectedCompositionGlyphName["Name"], selectedContours)
def isInGitRepository(self): # Check if the folder is a git repository if not os.path.exists(os.path.join(self._path, ".git")): message('Warning: this is not a GIT repository') return False return True
def _textCenter_callback(self, sender): if not self.font: message("Warning there is no current font") return from interface.TextCenter import TextCenter TextCenter(self)
def makeWords(self, sender=None): """Parse user input, save new values to prefs, compile and display the resulting words. I think this function is too long and bloated, it should be taken apart. ######## """ global warned self.f = CurrentFont() if self.f is not None: self.fontChars, self.glyphNames = self.fontCharacters(self.f) self.glyphNamesForValues = {self.fontChars[i]: self.glyphNames[i] for i in range(len(self.fontChars))} else: self.fontChars = [] self.glyphNames = [] self.wordCount = self.getIntegerValue(self.g1.wordCount) self.minLength = self.getIntegerValue(self.g1.minLength) self.maxLength = self.getIntegerValue(self.g1.maxLength) self.case = self.g1.case.get() self.customCharset = [] charset = self.g1.base.get() self.limitToCharset = True if charset == 0: self.limitToCharset = False elif charset == 2: # use selection if len(self.f.selection) == 0: # nothing selected message("word-o-mat: No glyphs were selected in the font window. Will use any characters available in the current font.") self.g1.base.set(1) # use font chars else: try: self.customCharset = [] for gname in self.f.selection: if self.f[gname].unicode is not None: try: self.customCharset.append(unichr(int(self.f[gname].unicode))) except ValueError: pass except AttributeError: pass elif charset == 3: # use mark color c = self.g1.colorWell.get() if c is None: pass elif c.className() == "NSCachedWhiteColor": # not set, corresponds to mark color set to None c = None self.customCharset = [] self.reqMarkColor = (c.redComponent(), c.greenComponent(), c.blueComponent(), c.alphaComponent()) if c is not None else None for g in self.f: if g.mark == self.reqMarkColor: try: self.customCharset.append(unichr(int(g.unicode))) except: pass if len(self.customCharset) == 0: message("word-o-mat: Found no glyphs that match the specified mark color. Will use any characters available in the current font.") self.g1.base.set(1) # use font chars self.toggleColorSwatch(0) self.matchMode = "text" if self.g2.matchMode.get() == 0 else "grep" # braucht es diese zeile noch? self.requiredLetters = self.getInputString(self.g2.textMode.mustLettersBox, False) self.requiredGroups[0] = self.getInputString(self.g2.textMode.group1box, True) self.requiredGroups[1] = self.getInputString(self.g2.textMode.group2box, True) self.requiredGroups[2] = self.getInputString(self.g2.textMode.group3box, True) self.matchPattern = self.g2.grepMode.grepBox.get() self.banRepetitions = self.g3.checkbox0.get() self.outputWords = [] # initialize/empty self.source = self.g1.source.get() languageCount = len(self.textfiles) if self.source == languageCount: # User Dictionary self.allWords = self.dictWords["user"] elif self.source == languageCount+1: # Use all languages for i in range(languageCount): # if any language: concatenate all the wordlists self.allWords.extend(self.dictWords[self.textfiles[i]]) elif self.source == languageCount+2: # Custom word list try: if self.customWords != []: self.allWords = self.customWords else: self.allWords = self.dictWords["ukacd"] self.g1.source.set(0) except AttributeError: self.allWords = self.dictWords["ukacd"] self.g1.source.set(0) else: # language lists for i in range(languageCount): if self.source == i: self.allWords = self.dictWords[self.textfiles[i]] # store new values as defaults markColorPref = self.reqMarkColor if self.reqMarkColor is not None else "None" extDefaults = { "wordCount": self.wordCount, "minLength": self.minLength, "maxLength": self.maxLength, "case": self.case, "limitToCharset": self.writeExtDefaultBoolean(self.limitToCharset), "source": self.source, "matchMode": self.matchMode, "matchPattern": self.matchPattern, # non compiled string "markColor": markColorPref, } for key, value in extDefaults.items(): setExtensionDefault("com.ninastoessinger.word-o-mat."+key, value) # go make words if self.checkInput(self.limitToCharset, self.fontChars, self.customCharset, self.requiredLetters, self.minLength, self.maxLength, self.case) == True: checker = wordcheck.wordChecker(self.limitToCharset, self.fontChars, self.customCharset, self.requiredLetters, self.requiredGroups, self.matchPatternRE, self.banRepetitions, self.minLength, self.maxLength, matchMode=self.matchMode) for i in self.allWords: if len(self.outputWords) >= self.wordCount: break else: w = choice(self.allWords) if self.case == 1: w = w.lower() elif self.case == 2: # special capitalization rules for Dutch IJ # this only works when Dutch is selected as language, not "any". try: ijs = ["ij", "IJ", "Ij"] if self.languageNames[self.source] == "Dutch" and w[:2] in ijs: wNew = "IJ" + w[2:] w = wNew else: w = w.title() except IndexError: w = w.title() elif self.case == 3: # special capitalization rules for German double s if u"ß" in w: w2 = w.replace(u"ß", "ss") w = w2 w = w.upper() if checker.checkWord(w, self.outputWords): self.outputWords.append(w) # output if len(self.outputWords) < 1: message("word-o-mat: no matching words found <sad trombone>") else: joinString = " " if self.g3.listOutput.get() == True: joinString = "\\n" self.outputWords = self.sortWordsByWidth(self.outputWords) outputString = joinString.join(self.outputWords) try: sp = OpenSpaceCenter(CurrentFont()) sp.setRaw(outputString) except: if warned == False: message("word-o-mat: No open fonts found; words will be displayed in the Output Window.") warned = True print("word-o-mat: %s" % outputString) else: print("word-o-mat: Aborted because of errors")
def checkMinVsMax(self, minLength, maxLength): """Check user input for minimal/maximal word length and see if it makes sense.""" if not minLength <= maxLength: message ("word-o-mat: Confusing input for minimal/maximal word length. Please fix.") return False return True
import os from vanilla.dialogs import message from replicant.helpers import createArchiveYesNo from replicant.models import Replicant replicant = Replicant(CurrentFont()) if not replicant.font: message("No open font", "You must have an open, saved font to replicate.") elif os.path.exists(replicant.path) or createArchiveYesNo(): replicant.replicate()
def __init__(self): self.font = CurrentFont() if self.font is None: from vanilla.dialogs import message message("Oops!", "You need a font to use this tool.") return x = 10 y = 10 h = 40 w = -10 layers = self.font.layerOrder if len(layers) < 1: from vanilla.dialogs import message message("Oops!", "You need two layers to use this tool.") return lh = len(layers)*20+20 self.layerName = layers[0] self.currentPen = None self.w = FloatingWindow((200, 330), "Broad Nib Background") stepValue = getExtensionDefault("%s.%s" %(BroadNibBackgroundDefaultKey, "step"), 20) self.w.step = SliderGroup((x, y, w, h), "Steps:", 0, 60, stepValue, callback=self.stepChanged) y+=h widthValue = getExtensionDefault("%s.%s" %(BroadNibBackgroundDefaultKey, "width"), 50) self.w.width = SliderGroup((x, y, w, h), "Width:", 0, 300, widthValue, callback=self.widthChanged) y+=h heightValue = getExtensionDefault("%s.%s" %(BroadNibBackgroundDefaultKey, "height"), 10) self.w.height = SliderGroup((x, y, w, h), "Height:", 0, 300, heightValue, callback=self.heightChanged) y+=h angleValue = getExtensionDefault("%s.%s" %(BroadNibBackgroundDefaultKey, "angle"), 30) self.w.angle = SliderGroup((x, y, w, h), "Angle:", 0, 360, angleValue, callback=self.angleChanged) self.w.angle.slider.getNSSlider().cell().setSliderType_(NSCircularSlider) self.w.angle.text.setPosSize((0, 15, -0, 20)) self.w.angle.slider.setPosSize((60, 10, 30, 30)) self.w.angle.slider._nsObject.cell().setControlSize_(NSRegularControlSize) y+=h + 20 shapeValue = getExtensionDefault("%s.%s" %(BroadNibBackgroundDefaultKey, "shape"), 0) self.w.shapetext = TextBox((x, y, -0, 20), "Shape:") self.w.shape = RadioGroup((74, y, -0, 20), ["oval", "rect"], isVertical=False, callback=self.shapeChanged) self.w.shape.set(shapeValue) y+=h + 5 color = NSColor.colorWithCalibratedRed_green_blue_alpha_(1, 0, 0, .5) colorValue = getExtensionDefaultColor("%s.%s" %(BroadNibBackgroundDefaultKey, "color"), color) self.w.colortext = TextBox((x, y, -0, 20), "Color:") self.w.color = ColorWell((70, y-5, w, 30), callback=self.colorChanged, color=colorValue) y+=h + 20 self.w.layertext = TextBox((x, y-20, -0, 20), "Layer:") self.w.layer = List((x, y, w, lh), layers, allowsMultipleSelection=False, selectionCallback=self.layerChanged) y+=lh+15 self.w.setPosSize((100, 100, 200, y)) addObserver(self, "drawBroadNibBackground", "drawBackground") # needed for windowCloseCallback self.setUpBaseWindowBehavior() self.w.open()