class ColdtypeSerializer(BaseWindowController): def __init__(self): self.w = FloatingWindow((300, 40), "Coldtype Serializer", minSize=(123, 200)) self.w.globalToggle = CheckBox((10, 10, -10, 20), 'serialize?', value=True) self.output = Path("~/robofont-coldtype.json").expanduser().absolute() addObserver(self, "shouldDraw", "draw") self.setUpBaseWindowBehavior() self.w.open() def windowCloseCallback(self, sender): removeObserver(self, 'draw') super(ColdtypeSerializer, self).windowCloseCallback(sender) def shouldDraw(self, notification): if not self.w.globalToggle.get(): return glyph = notification['glyph'] data_out = {"name": glyph.name, "layers": {}} for g in glyph.layers: rp = RecordingPen() g.draw(rp) data_out["layers"][g.layer.name] = dict(value=rp.value, width=g.width) self.output.write_text(json.dumps(data_out)) print("> wrote glyph data", glyph.name)
class highlightPointsOnMetrics(BaseWindowController): def __init__(self): self.w = FloatingWindow((135, 40), "", minSize=(123, 200)) # a checkbox to turn the tool on/off self.w.showPoints = CheckBox((10, 10, -10, 20), 'highlight points', value=True) # add an observer to the drawPreview event addObserver(self, "highlightPoints", "draw") # open window self.setUpBaseWindowBehavior() self.w.open() def windowCloseCallback(self, sender): # remove observer when window is closed removeObserver(self, 'draw') super(highlightPointsOnMetrics, self).windowCloseCallback(sender) def highlightPoints(self, info): # check if checkbox is selected if not self.w.showPoints.get(): return # get the current glyph glyph = info["glyph"] sc = info['scale'] # Anything more than 3 could be considered an intentional overshoot? rang = 3 asc = f.info.ascender xhe = f.info.xHeight cap = f.info.capHeight dsc = f.info.descender size = 8 * sc # draw highlight stroke(None) if glyph is not None: for c in glyph: for s in c: for p in s: if p.y == asc or p.y == xhe or p.y == cap or p.y == dsc or p.y == 0: pass else: if (asc + -rang <= p.y <= asc + rang) or ( xhe + -rang <= p.y <= xhe + rang) or ( cap + -rang <= p.y <= cap + rang) or ( dsc + -rang <= p.y <= dsc + rang) or (-rang <= p.y <= rang): # fill(1, 0, 0, .6) fill(None) stroke(1.0, 0.0, 0.0, .5) strokeWidth(7 * sc) oval(p.x - size / 2, p.y - size / 2, size, size)
def __init__(self): # base window self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, PLUGIN_HEIGHT)) jumpingY = MARGIN_VER self.w.libChoice = PopUpButton( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['PopUpButtonRegularHeight']), ['A', 'B', 'C'], callback=self.libChoiceCallback) jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER self.w.addButton = SquareButton( (MARGIN_HOR, jumpingY, NET_WIDTH * .6, SQUARE_BUTTON_HEIGHT), 'add stem', callback=self.addButtonCallback) self.w.checkBoxStar = CheckBoxStar( (MARGIN_HOR + MARGIN_VER + NET_WIDTH * .6, jumpingY, NET_WIDTH * .35, NET_WIDTH * .35), callback=self.checkBoxStarCallback) jumpingY += SQUARE_BUTTON_HEIGHT + MARGIN_VER self.w.removeButton = SquareButton( (MARGIN_HOR, jumpingY, NET_WIDTH * .6, SQUARE_BUTTON_HEIGHT), 'remove stem', callback=self.removeButtonCallback) # lit up! self.w.open()
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 __init__(self, options, callback): super(ChooseExceptionWindow, self).__init__() self.options = options self.callback = callback self.whichException = options[0] self.w = FloatingWindow((300, 120), 'Choose exception') self.w.optionsRadio = RadioGroup( (MARGIN, MARGIN, -MARGIN, len(options) * 20), options, callback=self.optionsCallback) self.w.optionsRadio.set(0) self.w.cancel = Button( (-(90 * 2 + MARGIN * 2), -(vanillaControlsSize['ButtonRegularHeight'] + MARGIN), 90, vanillaControlsSize['ButtonRegularHeight']), 'Cancel', callback=self.cancelCallback) self.w.submit = Button( (-(90 + MARGIN), -(vanillaControlsSize['ButtonRegularHeight'] + MARGIN), 90, vanillaControlsSize['ButtonRegularHeight']), 'Submit', callback=self.submitCallback) self.setUpBaseWindowBehavior()
class ColorThemesDialog: colorThemesFolder = os.path.join(os.getcwd(), 'themes') def __init__(self): self.w = FloatingWindow((246, 300), "CodeColors") x = y = p = 10 self.w.colorThemesList = List((x, y, -p, -p), sorted(self.colorThemes.keys()), selectionCallback=self.selectionCallback, allowsMultipleSelection=False, allowsEmptySelection=False) self.w.open() @property def colorThemes(self): return getColorThemes(self.colorThemesFolder) @property def colorTheme(self): i = self.w.colorThemesList.getSelection()[0] colorThemeName = sorted(self.colorThemes.keys())[i] return self.colorThemes[colorThemeName] def selectionCallback(self, sender): setColorTheme(self.colorTheme)
def __init__(self): self.glyph = None # Typical RoboFont function self.updating = False pad = 10 leading = 32 y = pad w = 300 h = 400 buttonWidth = 100 buttonHeight = 48 self.w = FloatingWindow((100, 100, w, h), 'DemoWindowTool') self.w.doDraw = CheckBox((pad, y, 100, 24), 'Draw', callback=self.doDrawCallback) y += leading self.w.mySlider = Slider((pad, y, -pad, 24), minValue=0, maxValue=2000, value=0, tickMarkCount=10, callback=self.mySliderCallback) y = self.w.saveFont = Button((-buttonWidth - pad, -buttonHeight - pad, buttonWidth, buttonHeight), 'Save', callback=self.saveFontCallback) addObserver(self, "currentGlyphChanged", "currentGlyphChanged") # Subscribe to application event addObserver(self, 'draw', 'draw') addObserver(self, 'drawBackground', 'drawBackground') self.w.bind('close', self.windowCloseCallback) self.w.open()
def __init__(self): self.w = FloatingWindow((100, 100), "Tester") self.w.bind("close", self.closeCB) self.guideView = None addObserver(self, "glyphWindowOpenCB", "glyphWindowDidOpen")
def showWindow_(self, sender): if Glyphs.font is None: self.helperWindow(self.warningNoFontOpen) elif len(Glyphs.font.masters) < 2: self.helperWindow(self.warningOnlyOneMaster) else: mastersList = [] for m in Glyphs.font.masters: mastersList.append(m.name) currentMasterIndex = Glyphs.font.masterIndex self.windowWidth = 250 self.windowHeight = 25 * len(mastersList) + 23 + 30 self.w = FloatingWindow((self.windowWidth, self.windowHeight), self.name) self.w.radiomasters = RadioGroup( (10, 10, -10, 25 * len(mastersList)), mastersList, callback=self.changeMaster) self.w.slider = Slider((10, -35, -10, 23), tickMarkCount=len(mastersList), stopOnTickMarks=True, value=currentMasterIndex, minValue=0, maxValue=len(mastersList) - 1, sizeStyle="small", continuous=False, callback=self.changeMasterSlider) self.w.open()
def __init__(self, glyph): # if glyph is None, show a message if glyph is None: Message('no glyph selected', title='moveTool', informativeText='Please select one glyph first!') return # store the glyph and initial move values as object attributes self.glyph = glyph self.moveXTRA = 0 # create a floating window self.w = FloatingWindow((200, 74), "move %s" % self.glyph.name) # add a slider for moving in the x axis self.w.sliderXTRA = Slider((10, 10, -10, 22), value=0, maxValue=200, minValue=0, callback=self.adjustXTRA) # self.w.sliderXOPQ = Slider( # (10, 10, -10, 22), # value=0, maxValue=200, minValue=-200, # callback=self.adjust) # open the window self.w.open()
def __init__(self): self.searchResults = [] self.selectedChars = "" self.w = FloatingWindow((300, 400), "Unicode Picker", minSize=(250, 300), autosaveName="UnicodePicker") y = 15 self.w.searchField = EditText((20, y, -20, 25), placeholder="Search Unicode name or value", callback=self.searchTextChanged_) y += 40 columnDescriptions = [ dict(title="char", width=40, cell=makeTextCell(align="center", font=AppKit.NSFont.systemFontOfSize_(14))), dict(title="unicode", width=60, cell=makeTextCell(align="right")), dict(title="name"), ] self.w.unicodeList = List((0, y, 0, -100), [], columnDescriptions=columnDescriptions, rowHeight=18, selectionCallback=self.listSelectionChanged_, doubleClickCallback=self.listDoubleClickCallback_) y = -95 self.w.unicodeText = TextBox((20, y, -10, 55), "") self.w.unicodeText._nsObject.cell().setFont_(AppKit.NSFont.systemFontOfSize_(36)) self.w.unicodeText._nsObject.cell().setLineBreakMode_(AppKit.NSLineBreakByTruncatingMiddle) y += 55 self.w.copyButton = Button((20, y, 120, 25), "Copy", callback=self.copy_) self.w.copyButton.enable(False) self.w.open() self.w._window.setWindowController_(self) self.w._window.setBecomesKeyOnlyIfNeeded_(False) self.w._window.makeKeyWindow()
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)
def __init__(self): '''Initialize the dialog.''' x = y = padding = 10 buttonHeight = 20 windowWidth = 400 rows = 4.5 self.w = FloatingWindow( (windowWidth, buttonHeight * rows + padding * (rows)), "Glyph Fax Machine") self.fonts = {} # self.w.textBox = TextBox((x, y, -padding, buttonHeight), "Glyphs to Copy") # y += buttonHeight self.w.editText = EditText( (x, y, -padding, buttonHeight * 2 + padding), placeholder="Space-separated list of glyphs to copy") y += buttonHeight * 2 + padding * 2 # self.w.overwriteGlyphsCheckBox = CheckBox((x, y, -padding, buttonHeight), "Overwrite Glyphs", value=False, callback=self.overwriteGlyphsOptions) # y += buttonHeight + padding self.w.overwriteNormalWidthGlyphsCheckBox = CheckBox( (x, y, -padding, buttonHeight), "Overwrite 600w Glyphs", value=False, sizeStyle="small") # self.w.overwriteNormalWidthGlyphsCheckBox.show(False) self.w.overwriteAdjustedWidthGlyphsCheckBox = CheckBox( (windowWidth * 0.4, y, -padding, buttonHeight), "Overwrite non-600w Glyphs", value=False, sizeStyle="small") # self.w.overwriteAdjustedWidthGlyphsCheckBox.show(False) self.w.colorWell = ColorWell( (windowWidth * 0.85, y, -padding, buttonHeight), color=NSColor.orangeColor()) y += buttonHeight + padding self.w.sans2mono = Button( (x, y, windowWidth / 3 - padding / 2, buttonHeight), "Sans → Mono", callback=self.sans2monoCallback) self.w.mono2sans = Button( (windowWidth / 3 + padding, y, -padding, buttonHeight), "Mono → Sans", callback=self.mono2SansCallback) self.w.open()
def __init__(self): self.w = FloatingWindow((246, 300), "CodeColors") x = y = p = 10 self.w.colorThemesList = List((x, y, -p, -p), sorted(self.colorThemes.keys()), selectionCallback=self.selectionCallback, allowsMultipleSelection=False, allowsEmptySelection=False) self.w.open()
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 __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 __init__(self): self.fontTarget = FONT_TARGET_OPTIONS[0] self.glyphTarget = GLYPH_TARGET_OPTIONS[0] self.gridSize = 4 self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, 400), PLUGIN_TITLE) jumpingY = MARGIN_VER # font target self.w.fontTargetPopUp = PopUpButton( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['PopUpButtonRegularHeight']), FONT_TARGET_OPTIONS, callback=self.fontTargetPopUpCallback) jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER # glyph target self.w.glyphTargetPopUp = PopUpButton( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['PopUpButtonRegularHeight']), GLYPH_TARGET_OPTIONS, callback=self.glyphTargetPopUpCallback) jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER # grid size captions self.w.gridSizeCaption = TextBox( (MARGIN_HOR, jumpingY + 2, NET_WIDTH * .32, vanillaControlsSize['TextBoxRegularHeight']), 'Grid Size:') # grid size edit self.w.gridSizeEdit = EditText( (MARGIN_HOR + NET_WIDTH * .32, jumpingY, NET_WIDTH * .3, vanillaControlsSize['EditTextRegularHeight']), text='{:d}'.format(self.gridSize), callback=self.gridSizeEditCallback) jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER self.w.moveBcpHandlesCheck = CheckBox( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['CheckBoxRegularHeight']), 'move bcp handles', value=self.bcpHandlesFit, callback=self.moveBcpHandlesCheckCallback) jumpingY += vanillaControlsSize['CheckBoxRegularHeight'] + MARGIN_VER # fit button self.w.fitButton = Button((MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['ButtonRegularHeight']), 'Fit!', callback=self.fitButtonCallback) jumpingY += vanillaControlsSize['ButtonRegularHeight'] + MARGIN_VER self.w.setPosSize((0, 0, PLUGIN_WIDTH, jumpingY)) self.w.open()
def __init__(self): self.transferList = NAME_2_GLYPHLIST[GLYPHLISTS_OPTIONS[0]] self.target = TARGET_OPTIONS[0] self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, 400), PLUGIN_TITLE) jumpingY = MARGIN_VER # target fonts self.w.targetFontsPopUp = PopUpButton( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['PopUpButtonRegularHeight']), TARGET_OPTIONS, callback=self.targetFontsPopUpCallback) jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER # transfer lists pop up self.w.glyphListPopUp = PopUpButton( (MARGIN_HOR, jumpingY, NET_WIDTH, vanillaControlsSize['PopUpButtonRegularHeight']), GLYPHLISTS_OPTIONS, callback=self.glyphListPopUpCallback) jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER # offset caption self.w.offsetCaption = TextBox( (MARGIN_HOR, jumpingY + 2, NET_WIDTH * .22, vanillaControlsSize['TextBoxRegularHeight']), 'Offset:') # offset edit text self.w.offsetEdit = EditText( (MARGIN_HOR + NET_WIDTH * .25, jumpingY, NET_WIDTH * .35, vanillaControlsSize['EditTextRegularHeight']), continuous=False, callback=self.offsetEditCallback) self.w.offsetEdit.set('%d' % self.verticalOffset) jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER # clean button self.w.cleanButton = Button( (MARGIN_HOR, jumpingY, NET_WIDTH * .45, vanillaControlsSize['ButtonRegularHeight']), 'Clean', callback=self.cleanButtonCallback) # run button self.w.runButton = Button( (MARGIN_HOR + NET_WIDTH * .55, jumpingY, NET_WIDTH * .45, vanillaControlsSize['ButtonRegularHeight']), 'Run!', callback=self.runButtonCallback) jumpingY += vanillaControlsSize['ButtonRegularHeight'] + MARGIN_VER self.w.setPosSize((0, 0, PLUGIN_WIDTH, jumpingY)) self.w.open()
def __init__(self): self.w = FloatingWindow((300, 40), "Coldtype Serializer", minSize=(123, 200)) self.w.globalToggle = CheckBox((10, 10, -10, 20), 'serialize?', value=True) self.output = Path("~/robofont-coldtype.json").expanduser().absolute() addObserver(self, "shouldDraw", "draw") self.setUpBaseWindowBehavior() self.w.open()
def spaceCenterOpenCallback(self, notification): if (not self.popupOpen) and (len(self.metricsGroups) > 0): self.w = FloatingWindow((160, 36), 'Group Spacing') self.w.activateGroups = CheckBox( (9, -27, 151, 18), "Activate Group spacing", value=self.enableGroupSpacing, callback=self.enableGroupSpacingCallback, sizeStyle="small") self.w.bind('close', self.windowCloseCallback) self.w.open() self.popupOpen = True
def __init__(self): self.w = FloatingWindow((135, 40), "", minSize=(123, 200)) # a checkbox to turn the tool on/off self.w.showPoints = CheckBox((10, 10, -10, 20), 'highlight points', value=True) # add an observer to the drawPreview event addObserver(self, "highlightPoints", "draw") # open window self.setUpBaseWindowBehavior() self.w.open()
def __init__(self): self.valuesPrefsKey = prefsKey + ".delta." + basename( Glyphs.font.filepath) # UI metrics spacing = 8 height = 22 # calculate window height minWinSize = (220, 120 + (len(Glyphs.font.masters) * (height + spacing))) # create UI window self.w = FloatingWindow(minWinSize, "Adjust sidebearings", minSize=minWinSize, maxSize=(500, 500), autosaveName=prefsKey + ".win") # layout UI controls y = 16 self.w.label = TextBox((16, y, -16, height), "Sidebearing delta adjustment:") y += height + spacing inputWidth = 64 for master in Glyphs.font.masters: setattr(self.w, "deltaLabel%s" % master.id, TextBox((16, y, -16 - inputWidth, height), master.name)) setattr(self.w, "deltaInput%s" % master.id, EditText((-16 - inputWidth, y, -16, height), "16")) # print("self.w.deltaInputs[master.id]", getattr(self.w, "deltaInput%s" % master.id)) y += height + spacing self.w.submitButton = Button((16, -16 - height, -16, height), "Adjust all sidebearings", callback=self.onSubmit) # finalize UI self.w.setDefaultButton(self.w.submitButton) self.loadPreferences() self.w.bind("close", self.savePreferences) # make sure window is large enough to show all masters x, y, w, h = self.w.getPosSize() if w < minWinSize[0] and h < minWinSize[1]: self.w.setPosSize((x, y, minWinSize[0], minWinSize[1]), animate=False) elif w < minWinSize[0]: self.w.setPosSize((x, y, minWinSize[0], h), animate=False) elif h < minWinSize[1]: self.w.setPosSize((x, y, w, minWinSize[1]), animate=False) self.w.open() self.w.makeKey()
def _buildUI(self): w = FloatingWindow((300, 340), "Rotated Glyph Preview", (300, 340), (2560, 1440)) w.preview = GlyphPreview((2, 2, -2, -40)) w.rotationSlider = Slider((10, -30, -10, 20), minValue=-180, maxValue=180, value=self.settings["rotation"], tickMarkCount=5, stopOnTickMarks=False, continuous=True, callback=self._setRotation, sizeStyle="small", ) return w
def __init__(self): self.draw = False self.swap = True self.radius = getExtensionDefault( "%s.%s" % (WurstSchreiberDefaultKey, "radius"), 60) color = NSColor.colorWithCalibratedRed_green_blue_alpha_(1, 0, 0, .5) colorValue = getExtensionDefaultColor( "%s.%s" % (WurstSchreiberDefaultKey, "color"), color) self.w = FloatingWindow((150, 170), "WurstSchreiber") x = 15 y = 15 self.w.preview = CheckBox( (x, y, -x, 20), "Preview", callback=self.previewChanged, value=True) y+=30 self.w.slider = SliderGroup( (x, y, -x, 22), 0, 100, self.radius, callback=self.sliderChanged) y+=35 self.w.color = ColorWell( (x, y, -x, 40), callback=self.colorChanged, color=colorValue) y+=55 self.w.button = Button( (x, y, -x, 20), "Trace!", callback=self.traceButton) addObserver(self, "drawWurst", "drawBackground") self.w.bind("close", self.closing) self.w.open()
def spaceCenterOpenCallback(self, notification): if (not self.popupOpen) and (len(self.metricsGroups) > 0): self.w = FloatingWindow((160, 36), 'Group Spacing') self.w.activateGroups = CheckBox((9, -27, 151, 18), "Activate Group spacing", value=self.enableGroupSpacing, callback=self.enableGroupSpacingCallback, sizeStyle="small") self.w.bind('close', self.windowCloseCallback) self.w.open() self.popupOpen = True
def __init__(self): self.errorList = [ 'Extremum', 'Mixed cubic and quadratic segments', 'Fractional Coordinates', 'Fractional transformation', 'Incorrect smooth connection', 'Empty segment', 'Vector on closepath', 'Collinear vectors', 'Semi-horizontal vector', 'Semi-vertical vector', 'Zero handle', ] self.errorList.insert(0, "select Red Arrow Error") self.heightOfTool = 360 self.widthOfTool = 200 self.w = FloatingWindow((self.widthOfTool, self.heightOfTool), "Red Arrow Error Filter") ### FloatingWindow #self.w.text = TextBox((10, 5, -10, 16), "...", sizeStyle='regular') self.w.select_test = PopUpButton((10, 10, -10, 16), self.errorList, sizeStyle='regular', callback=self.select_test) self.w.extremumToleranceText = TextBox((10, 35, -25, 18), "Extremum Tolerance", sizeStyle='small') self.w.extremumToleranceInput = EditText((160, 35, -10, 18), "2", sizeStyle='small') self.w.smooth_connection_max_distance_Text = TextBox((10, 57, -25, 18), "Smooth Connect max_dist", sizeStyle='small') self.w.smooth_connection_max_distance_Input = EditText((160, 55, -10, 18), "4", sizeStyle='small') self.w.collinear_vectors_max_distance_Text = TextBox((10, 77, -25, 18), "Collinear Vectors max_dist", sizeStyle='small') self.w.collinear_vectors_max_distance_Input = EditText((160, 75, -10, 18), "2", sizeStyle='small') self.w.report = EditText((10, 100, -10, -10), "...", sizeStyle='regular') self.w.report.enable(False) self.count = [] self.report = [] self.w.open()
def __init__(self): self.modifiedGlyph = None self.w = FloatingWindow((400, 170), 'Corner Tool') self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor()) self.modes = ['Break', 'Build','Pit'] self.objectTypes = {'Build':'Segment', 'Break':'Corner point', 'Pit':'Corner point'} self.parameters = { 'radius': VanillaSingleValueParameter('radius', 20, (-200, 200), numType='int'), 'roundness': VanillaSingleValueParameter('roundness', 1.25, (0, 4), numType='float'), 'depth': VanillaSingleValueParameter('depth', 30, (-100, 100), numType='int'), 'breadth': VanillaSingleValueParameter('breadth', 30, (0, 150), numType='int'), 'bottom': VanillaSingleValueParameter('bottom', 5, (0, 40), numType='int') } self.currentMode = 'Break' self.previewGlyph = None self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode) for i, mode in enumerate(self.modes): setattr(self.w, mode, Group((120, 15, -15, -15))) modeGroup = getattr(self.w, mode) modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u'>', callback=self.apply) modeGroup.infoBox = Box((0, 0, -50, 35)) modeGroup.info = TextBox((10, 8, -50, 20), 'No selection') if i > 0: modeGroup.show(False) self.w.Break.radius = ParameterSliderTextInput(self.parameters['radius'], (0, 60, -25, 25), title='Radius', callback=self.makePreviewGlyph) self.w.Break.roundness = ParameterSliderTextInput(self.parameters['roundness'], (0, 95, -25, 25), title='Roundness', callback=self.makePreviewGlyph) self.w.Pit.depth = ParameterSliderTextInput(self.parameters['depth'], (0, 50, -25, 25), title='Depth', callback=self.makePreviewGlyph) self.w.Pit.breadth = ParameterSliderTextInput(self.parameters['breadth'], (0, 80, -25, 25), title='Breadth', callback=self.makePreviewGlyph) self.w.Pit.bottom = ParameterSliderTextInput(self.parameters['bottom'], (0, 110, -25, 25), title='bottom', callback=self.makePreviewGlyph) addObserver(self, 'preview', 'draw') addObserver(self, 'preview', 'drawInactive') addObserver(self, 'previewSolid', 'drawPreview') addObserver(self, 'makePreviewGlyph', 'mouseDown') addObserver(self, 'makePreviewGlyph', 'mouseDragged') addObserver(self, 'makePreviewGlyph', 'keyDown') addObserver(self, 'makePreviewGlyph', 'keyUp') addObserver(self, 'setControls', 'mouseUp') addObserver(self, 'setControls', 'selectAll') addObserver(self, 'setControls', 'deselectAll') addObserver(self, 'setControls', 'currentGlyphChanged') self.w.bind('close', self.windowClose) self.setControls() self.w.open()
def __init__(self): self.w = FloatingWindow( (120, 140), minSize=(100, 40), textured=True, ) self.w.ti_checkbox = CheckBox((10, 10, -10, 20), 'Test Install', value=True) self.w.otf_checkbox = CheckBox((10, 30, -10, 20), 'OTF Backup', value=True) self.w.button = SquareButton((10, 60, -10, -10), 'GO', callback=self.button_callback) self.w.open()
def _buildUI(self): w = FloatingWindow((300, 340), "Rotated Glyph Preview", (300, 340), (2560, 1440)) w.preview = GlyphPreview((2, 2, -2, -40)) w.rotationSlider = Slider( (10, -30, -10, 20), minValue=-180, maxValue=180, value=self.settings["rotation"], tickMarkCount=5, stopOnTickMarks=False, continuous=True, callback=self._setRotation, sizeStyle="small", ) return w
class TesterWindow: def __init__(self): self.w = FloatingWindow((100, 100), "Tester") self.w.bind("close", self.closeCB) self.guideView = None addObserver(self, "glyphWindowOpenCB", "glyphWindowDidOpen") def glyphWindowOpenCB(self, info): glyphWindow = info["window"] self.guideView = GuideStatusView() self.guideView.view.statusText.set("TEST") self.guideView.addViewToWindow(glyphWindow) self.guideView.turnStatusTextOn() def closeCB(self, sender): removeObserver(self, "glyphWindowDidOpen")
def __init__(self): self.modifiedGlyph = None self.w = FloatingWindow((400, 170), "Corner Tool") self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor()) self.modes = ["Break", "Build", "Pit"] self.objectTypes = {"Build": "Segment", "Break": "Corner point", "Pit": "Corner point"} self.parameters = { "radius": VanillaSingleValueParameter("radius", 20, (-200, 200), numType="int"), "roundness": VanillaSingleValueParameter("roundness", 1.25, (0, 4), numType="float"), "depth": VanillaSingleValueParameter("depth", 30, (-100, 100), numType="int"), "breadth": VanillaSingleValueParameter("breadth", 30, (0, 150), numType="int"), "bottom": VanillaSingleValueParameter("bottom", 5, (0, 40), numType="int"), } self.currentMode = "Break" self.previewGlyph = None self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode) for i, mode in enumerate(self.modes): setattr(self.w, mode, Group((120, 15, -15, -15))) modeGroup = getattr(self.w, mode) modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u">", callback=self.apply) modeGroup.infoBox = Box((0, 0, -50, 35)) modeGroup.info = TextBox((10, 8, -50, 20), "No selection") if i > 0: modeGroup.show(False) self.w.Break.radius = ParameterSliderTextInput( self.parameters["radius"], (0, 60, -25, 25), title="Radius", callback=self.makePreviewGlyph ) self.w.Break.roundness = ParameterSliderTextInput( self.parameters["roundness"], (0, 95, -25, 25), title="Roundness", callback=self.makePreviewGlyph ) self.w.Pit.depth = ParameterSliderTextInput( self.parameters["depth"], (0, 50, -25, 25), title="Depth", callback=self.makePreviewGlyph ) self.w.Pit.breadth = ParameterSliderTextInput( self.parameters["breadth"], (0, 80, -25, 25), title="Breadth", callback=self.makePreviewGlyph ) self.w.Pit.bottom = ParameterSliderTextInput( self.parameters["bottom"], (0, 110, -25, 25), title="bottom", callback=self.makePreviewGlyph ) addObserver(self, "preview", "draw") addObserver(self, "preview", "drawInactive") addObserver(self, "previewSolid", "drawPreview") addObserver(self, "makePreviewGlyph", "mouseDown") addObserver(self, "makePreviewGlyph", "mouseDragged") addObserver(self, "makePreviewGlyph", "keyDown") addObserver(self, "makePreviewGlyph", "keyUp") addObserver(self, "setControls", "mouseUp") addObserver(self, "setControls", "selectAll") addObserver(self, "setControls", "deselectAll") addObserver(self, "setControls", "currentGlyphChanged") self.w.bind("close", self.windowClose) self.setControls() self.w.open()
class MoveGlyphWindow: '''Move the current glyph using sliders.''' def __init__(self, glyph): # if glyph is None, show a message if glyph is None: Message('no glyph selected', title='moveTool', informativeText='Please select one glyph first!') return # store the glyph and initial move values as object attributes self.glyph = glyph self.moveX = 0 # create a floating window self.w = FloatingWindow((200, 74), "move %s" % self.glyph.name) # add a slider for moving in the x axis self.w.sliderX = Slider((10, 10, -10, 22), value=0, maxValue=200, minValue=-200, callback=self.adjust) # open the window self.w.open() def adjust(self, sender): # get the current x and y values from the sliders valueX = self.w.sliderX.get() # calculate actual move distance x = self.moveX - valueX # move the glyph self.glyph.moveBy((x, y)) # update saved values self.moveX = valueX # print the current move distance print(self.moveX)
def __init__(self, glyph): # if glyph is None, show a message # store the glyph and initial move values as object attributes self.w = FloatingWindow((200, 64), "move "+str(labelslider)) for labelslider in BuildLabelsList(f): # create a floating window # add a slider for moving in the x axis self.g = glyph self.moveX = 0 self.label= labelslider self.w.labelslider = Slider( (10, 10, -10, 22), value=0, maxValue=100, minValue=-100, callback=self.adjust) # open the window self.w.button = Button((15, -35, -15, 20), "Done") self.w.open()
class MoveGlyphWindow: '''Move the current glyph using sliders.''' def __init__(self, glyph): # if glyph is None, show a message # store the glyph and initial move values as object attributes self.w = FloatingWindow((200, 64), "move "+str(labelslider)) for labelslider in BuildLabelsList(f): # create a floating window # add a slider for moving in the x axis self.g = glyph self.moveX = 0 self.label= labelslider self.w.labelslider = Slider( (10, 10, -10, 22), value=0, maxValue=100, minValue=-100, callback=self.adjust) # open the window self.w.button = Button((15, -35, -15, 20), "Done") self.w.open() def adjust(self, sender): # get the current x and y values from the sliders valueX = self.w.labelslider.get() # calculate actual move distance x = self.moveX - valueX # move the glyph for contour in self.g: for point in counter.points: if point.labels is 'CROSSBAR': point.moveBy((x, 0)) # update saved values self.moveX = valueX # print the current move distance print(self.moveX)
def __init__(self): NSUserDefaults.standardUserDefaults().registerDefaults_({"ToucheWindowHeight":340}) self.windowHeight = NSUserDefaults.standardUserDefaults().integerForKey_("ToucheWindowHeight") self.minWindowHeight = 340 if self.windowHeight < self.minWindowHeight: self.windowHeight = self.minWindowHeight self.closedWindowHeight = 100 self.w = FloatingWindow((180, self.windowHeight), u'Touché!', minSize=(180,340), maxSize=(250,898)) self.w.bind("resize", self.windowResized) self.isResizing = False p = 10 w = 160 # options self.w.options = Group((0, 0, 180, 220)) buttons = { "checkSelBtn": {"text": "Check selected glyphs", "callback": self.checkSel, "y": p}, } for button, data in buttons.iteritems(): setattr(self.w.options, button, Button((p, data["y"], w - 22, 22), data["text"], callback=data["callback"], sizeStyle="small")) self.w.options.zeroCheck = CheckBox((p, 35, w, 20), "Ignore zero-width glyphs", value=True, sizeStyle="small") self.w.options.progress = ProgressSpinner((w - 8, 13, 16, 16), sizeStyle="small") # results self.w.results = Group((0, 220, 180, -0)) self.w.results.show(False) textBoxes = {"stats": -34, "result": -18} for box, y in textBoxes.iteritems(): setattr(self.w.results, box, TextBox((p, y, w, 14), "", sizeStyle="small")) # list and preview self.w.outputList = List((0,58,-0,-40), [{"left glyph": "", "right glyph": ""}], columnDescriptions=[{"title": "left glyph", "width": 90}, {"title": "right glyph"}], showColumnTitles=False, allowsMultipleSelection=False, enableDelete=False, selectionCallback=self.showPair) self.w.outputList._setColumnAutoresizing() self._resizeWindow(False) self.w.open()
def __init__(self): self.modifiedGlyph = None self.w = FloatingWindow((400, 170), 'Corner Tool') self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor()) self.modes = ['Break', 'Build','Pit'] self.objectTypes = {'Build':'Segment', 'Break':'Corner point', 'Pit':'Corner point'} self.parameters = { 'radius': VanillaSingleValueParameter('radius', 20, (-200, 200), numType='int'), 'roundness': VanillaSingleValueParameter('roundness', 1.25, (0, 4), numType='float'), 'depth': VanillaSingleValueParameter('depth', 30, (-100, 100), numType='int'), 'breadth': VanillaSingleValueParameter('breadth', 30, (0, 150), numType='int'), 'bottom': VanillaSingleValueParameter('bottom', 5, (0, 40), numType='int') } self.currentMode = 'Break' self.previewGlyph = None self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode) for i, mode in enumerate(self.modes): setattr(self.w, mode, Group((120, 15, -15, -15))) modeGroup = getattr(self.w, mode) modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u'>', callback=self.apply) modeGroup.infoBox = Box((0, 0, -50, 35)) modeGroup.info = TextBox((10, 8, -50, 20), 'No selection') if i > 0: modeGroup.show(False) self.w.Break.radius = ParameterSliderTextInput(self.parameters['radius'], (0, 60, -25, 25), title='Radius', callback=self.makePreviewGlyph) self.w.Break.roundness = ParameterSliderTextInput(self.parameters['roundness'], (0, 95, -25, 25), title='Roundness', callback=self.makePreviewGlyph) self.w.Pit.depth = ParameterSliderTextInput(self.parameters['depth'], (0, 50, -25, 25), title='Depth', callback=self.makePreviewGlyph) self.w.Pit.breadth = ParameterSliderTextInput(self.parameters['breadth'], (0, 80, -25, 25), title='Breadth', callback=self.makePreviewGlyph) self.w.Pit.bottom = ParameterSliderTextInput(self.parameters['bottom'], (0, 110, -25, 25), title='bottom', callback=self.makePreviewGlyph) addObserver(self, 'preview', 'draw') addObserver(self, 'preview', 'drawInactive') addObserver(self, 'makePreviewGlyph', 'mouseDown') addObserver(self, 'makePreviewGlyph', 'mouseDragged') addObserver(self, 'makePreviewGlyph', 'keyDown') addObserver(self, 'makePreviewGlyph', 'keyUp') addObserver(self, 'setControls', 'mouseUp') addObserver(self, 'setControls', 'selectAll') addObserver(self, 'setControls', 'deselectAll') addObserver(self, 'setControls', 'currentGlyphChanged') self.w.bind('close', self.windowClose) self.setControls() self.w.open()
def __init__(self): self.glyphOrder = [] self.orderFileName = '' self.formats = ['otf', 'ttf', 'pfa'] self.format = 'otf' self.decompose = True self.overlap = True self.autohint = True self.release = True self.w = FloatingWindow((200,270), "Generate", minSize=(200,270),) self.w.getEncoding = Button((10, 10, 180, 20), 'Get .enc file', callback=self.getEncodingCallback) self.w.viewEncoding = Button((10, 75, 180, 20), 'View encoding', callback=self.viewEncodingCallback) self.w.line = HorizontalLine((12, 103, -12, 1)) self.w.formatLabel = TextBox((15, 117, 60, 20), "Format") self.w.formatChoice = PopUpButton((70, 115, 80, 20), self.formats, callback=self.formatCallback) self.w.decomposeCheck = CheckBox((20, 141, -10, 20), "Decompose", callback=self.decomposeCallback, value=self.decompose) self.w.overlapCheck = CheckBox((20, 161, -10, 20), "Remove Overlap", callback=self.overlapCallback, value=self.overlap) self.w.autohintCheck = CheckBox((20, 181, -10, 20), "Autohint", callback=self.autohintCallback, value=self.autohint) self.w.releaseCheck = CheckBox((20, 201, -10, 20), "Release Mode", callback=self.releaseCallback, value=self.release) self.w.generate = Button((10, 232, 180, 20), 'Generate Font', callback=self.generateCallback) self.w.decomposeCheck.enable(False) self.w.viewEncoding.enable(False) self.w.formatChoice.enable(False) self.w.overlapCheck.enable(False) self.w.autohintCheck.enable(False) self.w.releaseCheck.enable(False) self.w.generate.enable(False) self.d = Drawer((170, 400), self.w, preferredEdge="right") self.d.text = TextEditor((10, 10, -10, -10), readOnly=True) self.d.open() self.d.toggle() self.w.open()
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()
class WurstSchreiber(object): def __init__(self): self.draw = False self.swap = True self.radius = getExtensionDefault( "%s.%s" % (WurstSchreiberDefaultKey, "radius"), 60) color = NSColor.colorWithCalibratedRed_green_blue_alpha_(1, 0, 0, .5) colorValue = getExtensionDefaultColor( "%s.%s" % (WurstSchreiberDefaultKey, "color"), color) self.w = FloatingWindow((150, 170), "WurstSchreiber") x = 15 y = 15 self.w.preview = CheckBox( (x, y, -x, 20), "Preview", callback=self.previewChanged, value=True) y+=30 self.w.slider = SliderGroup( (x, y, -x, 22), 0, 100, self.radius, callback=self.sliderChanged) y+=35 self.w.color = ColorWell( (x, y, -x, 40), callback=self.colorChanged, color=colorValue) y+=55 self.w.button = Button( (x, y, -x, 20), "Trace!", callback=self.traceButton) addObserver(self, "drawWurst", "drawBackground") self.w.bind("close", self.closing) self.w.open() def closing(self, sender): removeObserver(self, "drawBackground") def previewChanged(self, sender): UpdateCurrentGlyphView() def sliderChanged(self, sender): self.radius = int(sender.get()) setExtensionDefault( "%s.%s" % (WurstSchreiberDefaultKey, "radius"), self.radius) UpdateCurrentGlyphView() def colorChanged(self, sender): setExtensionDefaultColor( "%s.%s" % (WurstSchreiberDefaultKey, "color"), sender.get()) UpdateCurrentGlyphView() def getColor(self): color = self.w.color.get() return color.getRed_green_blue_alpha_(None, None, None, None) def traceButton(self, sender): if self.w.preview.get(): self.draw = True UpdateCurrentGlyphView() def drawWurst(self, sender): if self.w.preview.get(): radius = self.radius draw = self.draw r,g,b,a = self.getColor() fill(r,g,b,a) glyph = CurrentGlyph() pen = WurstPen(None, radius, draw) glyph.draw(pen) if self.draw: glyph.prepareUndo("WurstTrace") if self.swap: glyph.getLayer("background").clear() glyph.swapToLayer("background") glyph.appendGlyph(pen.glyphcopy) self.draw = False self.w.preview.set(False) glyph.performUndo() glyph.update()
class CornerController: def __init__(self): self.modifiedGlyph = None self.w = FloatingWindow((400, 170), 'Corner Tool') self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor()) self.modes = ['Break', 'Build','Pit'] self.objectTypes = {'Build':'Segment', 'Break':'Corner point', 'Pit':'Corner point'} self.parameters = { 'radius': VanillaSingleValueParameter('radius', 20, (-200, 200), numType='int'), 'roundness': VanillaSingleValueParameter('roundness', 1.25, (0, 4), numType='float'), 'depth': VanillaSingleValueParameter('depth', 30, (-100, 100), numType='int'), 'breadth': VanillaSingleValueParameter('breadth', 30, (0, 150), numType='int'), 'bottom': VanillaSingleValueParameter('bottom', 5, (0, 40), numType='int') } self.currentMode = 'Break' self.previewGlyph = None self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode) for i, mode in enumerate(self.modes): setattr(self.w, mode, Group((120, 15, -15, -15))) modeGroup = getattr(self.w, mode) modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u'>', callback=self.apply) modeGroup.infoBox = Box((0, 0, -50, 35)) modeGroup.info = TextBox((10, 8, -50, 20), 'No selection') if i > 0: modeGroup.show(False) self.w.Break.radius = ParameterSliderTextInput(self.parameters['radius'], (0, 60, -25, 25), title='Radius', callback=self.makePreviewGlyph) self.w.Break.roundness = ParameterSliderTextInput(self.parameters['roundness'], (0, 95, -25, 25), title='Roundness', callback=self.makePreviewGlyph) self.w.Pit.depth = ParameterSliderTextInput(self.parameters['depth'], (0, 50, -25, 25), title='Depth', callback=self.makePreviewGlyph) self.w.Pit.breadth = ParameterSliderTextInput(self.parameters['breadth'], (0, 80, -25, 25), title='Breadth', callback=self.makePreviewGlyph) self.w.Pit.bottom = ParameterSliderTextInput(self.parameters['bottom'], (0, 110, -25, 25), title='bottom', callback=self.makePreviewGlyph) addObserver(self, 'preview', 'draw') addObserver(self, 'preview', 'drawInactive') addObserver(self, 'makePreviewGlyph', 'mouseDown') addObserver(self, 'makePreviewGlyph', 'mouseDragged') addObserver(self, 'makePreviewGlyph', 'keyDown') addObserver(self, 'makePreviewGlyph', 'keyUp') addObserver(self, 'setControls', 'mouseUp') addObserver(self, 'setControls', 'selectAll') addObserver(self, 'setControls', 'deselectAll') addObserver(self, 'setControls', 'currentGlyphChanged') self.w.bind('close', self.windowClose) self.setControls() self.w.open() def changeMode(self, sender): index = sender.get() previousModeGroup = getattr(self.w, self.currentMode) previousModeGroup.show(False) self.currentMode = self.modes[index] modeGroup = getattr(self.w, self.currentMode) modeGroup.show(True) self.setControls() def setControls(self, notification=None): mode = self.currentMode selection = self.getSelection() modeGroup = getattr(self.w, mode) if not len(selection): modeGroup.apply.enable(False) modeGroup.info.set('No selection (%ss)'%(self.objectTypes[mode].lower())) elif len(selection): modeGroup.apply.enable(True) info = '%s valid %s'%(len(selection), self.objectTypes[mode].lower()) if len(selection) > 1: info += 's' modeGroup.info.set(info) self.makePreviewGlyph() def getSelection(self, notification=None): glyph = CurrentGlyph() if len(glyph.selection) == 0: return [] elif len(glyph.selection) > 0: iG = IntelGlyph(glyph) if self.currentMode == 'Build': selection = iG.getSelection(True) elif self.currentMode in ['Break', 'Pit']: selection = [point for point in iG.getSelection() if (point.segmentType is not None) and (abs(point.turn()) > pi/18)] return selection def preview(self, notification): sc = notification['scale'] if self.previewGlyph is not None: self.previewGlyph.drawPreview(sc, styleFill=True, showNodes=False, strokeWidth=2, fillColor=cornerOutlineSoftColor, strokeColor=cornerOutlineStrongColor) def makePreviewGlyph(self, sender=None): if (sender is not None) and isinstance(sender, dict): if sender.has_key('notificationName') and sender['notificationName'] == 'mouseDragged': g = sender['glyph'] if not len(g.selection): return self.previewGlyph = self.makeCornerGlyph() UpdateCurrentGlyphView() def makeCornerGlyph(self, sender=None): mode = self.currentMode if mode == 'Build': cornerGlyph = self.buildCorners() elif mode == 'Break': cornerGlyph = self.breakCorners() elif mode == 'Pit': cornerGlyph = self.pitCorners() return cornerGlyph def buildCorners(self): g = CurrentGlyph() iG = IntelGlyph(g) for contour in iG: segments = contour.collectSegments()['selection'] l = len(segments) lines, curves = self.checkComposition(segments) if l > 1 and lines and curves: segments = [segment for segment in segments if len(segment) == 4] elif l > 1 and lines and not curves: segments = segments[:1] + segments[-1:] for segment in reversed(segments): contour.buildCorner(segment) return iG def breakCorners(self): g = CurrentGlyph() iG = IntelGlyph(g) radius = self.parameters['radius'].get() roundness = self.parameters['roundness'].get() for contour in iG: selection = contour.getSelection() for point in selection: contour.breakCorner(point, radius, velocity=roundness) contour.correctSmoothness() return iG def pitCorners(self): g = CurrentGlyph() iG = IntelGlyph(g) depth = self.parameters['depth'].get() breadth = self.parameters['breadth'].get() bottom = self.parameters['bottom'].get() for contour in iG: selection = contour.getSelection() for point in selection: contour.pitCorner(point, depth, breadth, bottom) contour.removeOverlappingPoints() contour.correctSmoothness() return iG def apply(self, sender): targetGlyph = CurrentGlyph() modifiedGlyph = self.makeCornerGlyph() targetGlyph.prepareUndo('un.round') targetGlyph.clearContours() for p in targetGlyph.selection: p.selected = False pen = targetGlyph.getPointPen() modifiedGlyph.drawPoints(pen) targetGlyph.performUndo() targetGlyph.update() def checkComposition(self, segmentsList): lines = 0 curves = 0 for segment in segmentsList: if len(segment) == 2: lines += 1 elif len(segment) == 4: curves += 1 return lines, curves def windowClose(self, notification): removeObserver(self, 'draw') removeObserver(self, 'drawInactive') removeObserver(self, 'mouseUp') removeObserver(self, 'mouseDown') removeObserver(self, 'mouseDragged') removeObserver(self, 'keyDown') removeObserver(self, 'keyUp') removeObserver(self, 'selectAll') removeObserver(self, 'deselectAll') removeObserver(self, 'currentGlyphChanged')
class GenerateWithOrder(object): """A simple extension to generate font with order from a FL Encoding file """ def __init__(self): self.glyphOrder = [] self.orderFileName = '' self.formats = ['otf', 'ttf', 'pfa'] self.format = 'otf' self.decompose = True self.overlap = True self.autohint = True self.release = True self.w = FloatingWindow((200,270), "Generate", minSize=(200,270),) self.w.getEncoding = Button((10, 10, 180, 20), 'Get .enc file', callback=self.getEncodingCallback) self.w.viewEncoding = Button((10, 75, 180, 20), 'View encoding', callback=self.viewEncodingCallback) self.w.line = HorizontalLine((12, 103, -12, 1)) self.w.formatLabel = TextBox((15, 117, 60, 20), "Format") self.w.formatChoice = PopUpButton((70, 115, 80, 20), self.formats, callback=self.formatCallback) self.w.decomposeCheck = CheckBox((20, 141, -10, 20), "Decompose", callback=self.decomposeCallback, value=self.decompose) self.w.overlapCheck = CheckBox((20, 161, -10, 20), "Remove Overlap", callback=self.overlapCallback, value=self.overlap) self.w.autohintCheck = CheckBox((20, 181, -10, 20), "Autohint", callback=self.autohintCallback, value=self.autohint) self.w.releaseCheck = CheckBox((20, 201, -10, 20), "Release Mode", callback=self.releaseCallback, value=self.release) self.w.generate = Button((10, 232, 180, 20), 'Generate Font', callback=self.generateCallback) self.w.decomposeCheck.enable(False) self.w.viewEncoding.enable(False) self.w.formatChoice.enable(False) self.w.overlapCheck.enable(False) self.w.autohintCheck.enable(False) self.w.releaseCheck.enable(False) self.w.generate.enable(False) self.d = Drawer((170, 400), self.w, preferredEdge="right") self.d.text = TextEditor((10, 10, -10, -10), readOnly=True) self.d.open() self.d.toggle() self.w.open() def process_enc(self, p): order = [] f = open(p) for line in f: if line.startswith(('#', '%')): pass else: l = line.split() if len(l[0]) != 0: for i in l: if not i.startswith(('#', '%', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) and len(i) != 0: order.append(i) f.close() self.glyphOrder = order def getEncodingCallback(self, sender): getFile(parentWindow=self.w, fileTypes=['enc', 'Enc'], resultCallback=self.processEncodingCallback) def viewEncodingCallback(self, sender): if not self.d.isOpen(): t = "\n".join(self.glyphOrder) self.d.text.set(t) self.d.toggle() def processEncodingCallback(self, sender): if sender[0] is not None: fn = os.path.split(sender[0])[1] self.process_enc(sender[0]) self.w.encodingTitle = TextBox((15, 34, 180, 17), "Encoding File:", alignment="left") self.w.encodingFileTitle = TextBox((15, 52, 180, 17), fn, alignment="left") self.w.viewEncoding.enable(True) self.w.formatChoice.enable(True) self.w.overlapCheck.enable(True) self.w.autohintCheck.enable(True) self.w.releaseCheck.enable(True) self.w.generate.enable(True) def formatCallback(self, sender): self.format = self.formats[sender.get()] if self.format == 'otf' or self.format == 'pfa': self.decompose = True self.w.decomposeCheck.enable(False) self.w.decomposeCheck.set(True) else: self.w.decomposeCheck.enable(True) def decomposeCallback(self, sender): if sender.get() == 0: self.decompose = False else: self.decompose = True def overlapCallback(self, sender): if sender.get() == 0: self.overlap = False else: self.overlap = True def autohintCallback(self, sender): if sender.get() == 0: self.autohint = False else: self.autohint = True def releaseCallback(self, sender): if sender.get() == 0: self.release = False else: self.release = True def generateCallback(self, sender): font = CurrentFont() d,f = os.path.split(font.path) f = f[:-3] + self.format putFile(messageText="Save Font", directory=d, fileName=f, parentWindow=self.w, resultCallback=self.processGenerateCallback) def processGenerateCallback(self, sender): path = sender font = CurrentFont() font.generate(path, self.format, decompose=self.decompose, autohint=self.autohint, releaseMode=self.release, glyphOrder=self.glyphOrder)
class ToucheTool(): def __init__(self): NSUserDefaults.standardUserDefaults().registerDefaults_({"ToucheWindowHeight":340}) self.windowHeight = NSUserDefaults.standardUserDefaults().integerForKey_("ToucheWindowHeight") self.minWindowHeight = 340 if self.windowHeight < self.minWindowHeight: self.windowHeight = self.minWindowHeight self.closedWindowHeight = 100 self.w = FloatingWindow((180, self.windowHeight), u'Touché!', minSize=(180,340), maxSize=(250,898)) self.w.bind("resize", self.windowResized) self.isResizing = False p = 10 w = 160 # options self.w.options = Group((0, 0, 180, 220)) buttons = { "checkSelBtn": {"text": "Check selected glyphs", "callback": self.checkSel, "y": p}, } for button, data in buttons.iteritems(): setattr(self.w.options, button, Button((p, data["y"], w - 22, 22), data["text"], callback=data["callback"], sizeStyle="small")) self.w.options.zeroCheck = CheckBox((p, 35, w, 20), "Ignore zero-width glyphs", value=True, sizeStyle="small") self.w.options.progress = ProgressSpinner((w - 8, 13, 16, 16), sizeStyle="small") # results self.w.results = Group((0, 220, 180, -0)) self.w.results.show(False) textBoxes = {"stats": -34, "result": -18} for box, y in textBoxes.iteritems(): setattr(self.w.results, box, TextBox((p, y, w, 14), "", sizeStyle="small")) # list and preview self.w.outputList = List((0,58,-0,-40), [{"left glyph": "", "right glyph": ""}], columnDescriptions=[{"title": "left glyph", "width": 90}, {"title": "right glyph"}], showColumnTitles=False, allowsMultipleSelection=False, enableDelete=False, selectionCallback=self.showPair) self.w.outputList._setColumnAutoresizing() self._resizeWindow(False) self.w.open() # callbacks def checkAll(self, sender=None): self.check(useSelection=False) def checkSel(self, sender=None): self.check(useSelection=True) def check(self, useSelection): self._resizeWindow(enlarge=False) self.checkFont(useSelection=useSelection, excludeZeroWidth=self.w.options.zeroCheck.get()) def showPair(self, sender=None): try: index = sender.getSelection()[0] glyphs = [self.f[gName] for gName in self.touchingPairs[index]] ActiveFont = self.f._font EditViewController = ActiveFont.currentTab if EditViewController is None: tabText = "/%s/%s" %(glyphs[0].name, glyphs[1].name) ActiveFont.newTab(tabText) else: textStorage = EditViewController.graphicView() if not hasattr(textStorage, "replaceCharactersInRange_withString_"): # compatibility with API change in 2.5 textStorage = EditViewController.graphicView().textStorage() LeftChar = ActiveFont.characterForGlyph_(glyphs[0]._object) RightChar = ActiveFont.characterForGlyph_(glyphs[1]._object) if LeftChar != 0 and RightChar != 0: selection = textStorage.selectedRange() if selection.length < 2: selection.length = 2 if selection.location > 0: selection.location -= 1 NewString = "" if LeftChar < 0xffff and RightChar < 0xffff: NewString = u"%s%s" % (unichr(LeftChar), unichr(RightChar)) else: print "Upper plane codes are not supported yet" textStorage.replaceCharactersInRange_withString_(selection, NewString) selection.length = 0 selection.location += 1 textStorage.setSelectedRange_(selection) #self.w.preview.set(glyphs) except IndexError: pass # checking def _hasSufficientWidth(self, g): # to ignore combining accents and the like if self.excludeZeroWidth: # also skips 1-unit wide glyphs which many use instead of 0 if g.width < 2 or g._object.subCategory == "Nonspacing": return False return True def _trimGlyphList(self, glyphList): newGlyphList = [] for g in glyphList: if g.box is not None and self._hasSufficientWidth(g): newGlyphList.append(g) return newGlyphList def windowResized(self, window): posSize = self.w.getPosSize() Height = posSize[3] if Height > self.closedWindowHeight and self.isResizing is False: print "set new Height", Height NSUserDefaults.standardUserDefaults().setInteger_forKey_(Height, "ToucheWindowHeight") self.windowHeight = Height def _resizeWindow(self, enlarge=True): posSize = self.w.getPosSize() if enlarge: self.w.results.show(True) self.w.outputList.show(True) targetHeight = self.windowHeight if targetHeight < 340: targetHeight = 340 else: self.w.results.show(False) self.w.outputList.show(False) targetHeight = self.closedWindowHeight self.isResizing = True self.w.setPosSize((posSize[0], posSize[1], posSize[2], targetHeight)) self.isResizing = False # ok let's do this def checkFont(self, useSelection=False, excludeZeroWidth=True): f = CurrentFont() if f is not None: # initialize things self.w.options.progress.start() time0 = time.time() self.excludeZeroWidth = excludeZeroWidth self.f = f glyphNames = f.selection if useSelection else f.keys() glyphList = [f[x] for x in glyphNames] glyphList = self._trimGlyphList(glyphList) self.touchingPairs = Touche(f).findTouchingPairs(glyphList) # display output self.w.results.stats.set("%d glyphs checked" % len(glyphList)) self.w.results.result.set("%d touching pairs found" % len(self.touchingPairs)) self.w.results.show(True) outputList = [{"left glyph": g1, "right glyph": g2} for (g1, g2) in self.touchingPairs] self.w.outputList.set(outputList) if len(self.touchingPairs) > 0: self.w.outputList.setSelection([0]) #self.w.preview.setFont(f) self.w.options.progress.stop() self._resizeWindow(enlarge=True) time1 = time.time() print u'Touché: finished checking %d glyphs in %.2f seconds' % (len(glyphList), time1-time0) else: Message(u'Touché: Can’t find a font to check')
class spacingObserver(object): def __init__(self): self.enableGroupSpacing = False self.popupOpen = False addObserver(self, 'glyphEditCallback', 'spaceCenterKeyDown') addObserver(self, 'glyphEditedCallback', 'spaceCenterKeyUp') addObserver(self, 'spaceCenterOpenCallback', 'spaceCenterDidOpen') addObserver(self, 'fontOpenCallback', 'fontDidOpen') self.previousMargins = {'left': 0, 'right': 0} def processMetricsGroups(self, baseGlyph=None): for groupName in self.metricsGroups: if (baseGlyph is None) and len(self.font.groups[groupName]) > 0: baseGlyph = self.font.groups[groupName][0] self.previousMargins['left'] = self.font[baseGlyph].angledLeftMargin self.previousMargins['right'] = self.font[baseGlyph].angledRightMargin if (metricsPrefix in groupName) and (baseGlyph in self.font.groups[groupName]): if (leftIndicator in groupName) and (self.previousMargins['left'] != self.font[baseGlyph].angledLeftMargin): self.setGroupSpacing(baseGlyph, self.font.groups[groupName], 'Left') elif (rightIndicator in groupName) and (self.previousMargins['right'] != self.font[baseGlyph].angledRightMargin): self.setGroupSpacing(baseGlyph, self.font.groups[groupName], 'Right') def setGroupSpacing(self, baseGlyphName, group, side): for glyphName in group: baseGlyph = self.font[baseGlyphName] targetGlyph = self.font[glyphName] if glyphName is not baseGlyphName: if (len(targetGlyph.components) > 0) and (side == 'Left'): for component in targetGlyph.components: if component.baseGlyph in group: component.move((self.previousMargins['left']-baseGlyph.angledLeftMargin, 0)) self.setSidebearing(baseGlyph, targetGlyph, side) elif glyphName is baseGlyphName: if (len(baseGlyph.components) > 0) and (side == 'Left'): for component in baseGlyph.components: if component.baseGlyph in group: component.move((self.previousMargins['left']-baseGlyph.angledLeftMargin, 0)) targetGlyph.update() def setSidebearing(self, baseGlyph, targetGlyph, side): baseMargin = getattr(baseGlyph, 'angled' + side + 'Margin') targetMargin = getattr(targetGlyph, 'angled' + side + 'Margin') if targetMargin != baseMargin: setattr(targetGlyph, 'angled' + side + 'Margin', baseMargin) def getMetricsGroups(self, notification=None): self.font = CurrentFont() if self.font is not None: self.metricsGroups = [group for group in self.font.groups.keys() if metricsPrefix in group and leftIndicator in group or rightIndicator in group] if (notification is not None) and (self.enableGroupSpacing == True): self.processMetricsGroups() def enableGroupSpacingCallback(self, sender): self.enableGroupSpacing = sender.get() def glyphEditCallback(self, notification): edGlyph = notification['glyph'] self.previousMargins = {'width': edGlyph.width, 'left': edGlyph.angledLeftMargin, 'right': edGlyph.angledRightMargin} def glyphEditedCallback(self, notification): if self.enableGroupSpacing == True: edGlyph = notification['glyph'] if self.font != CurrentFont(): self.getMetricsGroups() self.processMetricsGroups(edGlyph.name) def spaceCenterOpenCallback(self, notification): if (not self.popupOpen) and (len(self.metricsGroups) > 0): self.w = FloatingWindow((160, 36), 'Group Spacing') self.w.activateGroups = CheckBox((9, -27, 151, 18), "Activate Group spacing", value=self.enableGroupSpacing, callback=self.enableGroupSpacingCallback, sizeStyle="small") self.w.bind('close', self.windowCloseCallback) self.w.open() self.popupOpen = True def windowCloseCallback(self, notification): self.popupOpen = False def fontOpenCallback(self, notification): font = notification['font'] font.groups.addObserver(self, 'getMetricsGroups', 'Groups.Changed') self.getMetricsGroups(notification)
def __init__(self): # Preferences self._drawing = getExtensionDefault(self.DEFAULTKEY_DRAW, True) self._fill = getExtensionDefault(self.DEFAULTKEY_FILL, True) self._stroke = getExtensionDefault(self.DEFAULTKEY_STROKE, True) self._points = getExtensionDefault(self.DEFAULTKEY_POINTS, True) self._fillColor = getExtensionDefaultColor(self.DEFAULTKEY_FILLCOLOR, self.FALLBACK_FILLCOLOR) self._strokeColor = getExtensionDefaultColor(self.DEFAULTKEY_STROKECOLOR, self.FALLBACK_STROKECOLOR) self._pointsColor = getExtensionDefaultColor(self.DEFAULTKEY_POINTSCOLOR, self.FALLBACK_POINTSCOLOR) self._alignment = getExtensionDefault(self.DEFAULTKEY_ALIGNMENT, 0) self._kerning = getExtensionDefault(self.DEFAULTKEY_KERNING, 1) self._floating = getExtensionDefault(self.DEFAULTKEY_FLOATING, 1) # User preferences self._onCurvePointsSize = getDefault("glyphViewOncurvePointsSize") # typo, should be: OnCurve self._offCurvePointsSize = getDefault("glyphViewOffCurvePointsSize") self._strokeWidth = getDefault("glyphViewStrokeWidth") w, h = 400, 195 x = y = 10 self.initAllFonts() self.w = FloatingWindow((w, h), "Overlay UFOs") self.w.draw = CheckBox((x, y, 95, 18), "Draw", callback=self.drawCallback, value=self._drawing, sizeStyle="small") x += 60 self.w.fill = CheckBox((x, y, 95, 18), "Fill", callback=self.fillCallback, value=self._fill, sizeStyle="small") x += 40 self.w.fillColor = ColorWell((x, y, 45, 20), callback=self.fillColorCallback, color=self._fillColor) x += 60 self.w.stroke = CheckBox((x, y, 95, 18), "Stroke", callback=self.strokeCallback, value=self._stroke, sizeStyle="small") x += 60 self.w.strokeColor = ColorWell((x, y, 45, 20), callback=self.strokeColorCallback, color=self._strokeColor) x += 60 self.w.points = CheckBox((x, y, 95, 18), "Points", callback=self.pointsCallback, value=self._points, sizeStyle="small") x += 60 self.w.pointsColor = ColorWell((x, y, 45, 20), callback=self.pointsColorCallback, color=self._pointsColor) x, y = 10, 40 self.w.alignText = TextBox((x, y, 250, 15), "Alignment:", sizeStyle="small") y += 18 self.w.alignment = RadioGroup((x, y, 80, 55), ['Left', 'Center', 'Right'], isVertical=True, callback=self.alignmentCallback, sizeStyle="small") self.w.alignment.set(self._alignment) y += 62 self.w.kerning = CheckBox((x, y, 100, 10), "Show kerning", callback=self.kerningCallback, value=self._kerning, sizeStyle="mini") y += 18 self.w.floating = CheckBox((x, y, 100, 10), "Floating Window", callback=self.floatingCallback, value=self._floating, sizeStyle="mini") y += 25 self.w.resetDefaults = Button((x, y, 85, 14), "Reset settings", callback=self.resetSettingsCallback, sizeStyle="mini") x, y = 110, 40 self.w.fontList = List((x, y, 240, 55), self.getFontItems(), columnDescriptions=self.getListDescriptor(), showColumnTitles=False, selectionCallback=None, doubleClickCallback=self.fontListCallback, allowsMultipleSelection=True, allowsEmptySelection=True, drawVerticalLines=False, drawHorizontalLines=True, drawFocusRing=False, rowHeight=16 ) y += 55 self.w.hiddenFontList = List((x, y, 240, 55), self.getHiddenFontItems(), columnDescriptions=self.getListDescriptor(), showColumnTitles=False, selectionCallback=None, doubleClickCallback=self.hiddenFontListCallback, allowsMultipleSelection=True, allowsEmptySelection=True, drawVerticalLines=False, drawHorizontalLines=True, drawFocusRing=False, rowHeight=16 ) self._selectionChanging = False self.w.fontList.setSelection([]) # unselect y += 65 self.w.contextLeft = EditText((x, y, 90, 20), callback=self.contextCallback, continuous=True, placeholder="Left", sizeStyle="small") self.w.contextCurrent = EditText((x+95, y, 50, 20), callback=self.contextCallback, continuous=True, placeholder="?", sizeStyle="small") self.w.contextRight = EditText((x+150, y, 90, 20), callback=self.contextCallback, continuous=True, placeholder="Right", sizeStyle="small") x, y = 360, 100 self.w.addFonts = Button((x, y, 30, 20), "+", callback=self.addHiddenFontsCallback, sizeStyle="regular") y += 25 self.w.removeFonts = Button((x, y, 30, 20), unichr(8722), callback=self.removeHiddenFontsCallback, sizeStyle="regular") # Observers addObserver(self, "fontDidOpen", "fontDidOpen") addObserver(self, "fontWillClose", "fontWillClose") # fontDidClose? addObserver(self, "draw", "drawInactive") addObserver(self, "draw", "draw") # Prepare and open window self.setWindowLevel() self.setUpBaseWindowBehavior() self.w.open()
def __init__(self): self.font = CurrentFont() self.glyph = CurrentGlyph() self.upm = self.font.info.unitsPerEm self.glyphPreviewCacheDict = {} # key: glyph name -- value: list containing assembled glyphs self.anchorsOnMarksDict = {} # key: anchor name -- value: list of mark glyph names self.anchorsOnBasesDict = {} # key: anchor name -- value: list of base glyph names self.marksDict = {} # key: mark glyph name -- value: anchor name (NOTE: It's expected that each mark glyph only has one type of anchor) self.fillAnchorsAndMarksDicts() self.glyphNamesList = [] # list of glyph names that will be displayed in the UI list self.selectedGlyphNamesList = [] # list of glyph names selected in the UI list self.extraGlyphsList = [] # list of the glyph objects that should be inserted before and after the accented glyphs self.Blue, self.Alpha = 1, 0.6 self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") addObserver(self, "_fontWillClose", "fontWillClose") addObserver(self, "_currentFontChanged", "fontResignCurrent") addObserver(self, "_currentGlyphChanged", "currentGlyphChanged") addObserver(self, "_drawFill", "draw") addObserver(self, "_drawFill", "drawInactive") addObserver(self, "_previewFill", "drawPreview") addObserver(self, "_drawGlyphs", "draw") # observer for the draw event addObserver(self, "_drawGlyphs", "drawInactive") # draw the glyphs when the glyph window is not in focus addObserver(self, "_drawGlyphs", "drawPreview") integerNumFormatter = NSNumberFormatter.alloc().init() integerNumFormatter.setAllowsFloats_(False) integerNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter = NSNumberFormatter.alloc().init() intPosMinZeroNumFormatter.setAllowsFloats_(False) intPosMinZeroNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter.setMinimum_(NSNumber.numberWithInt_(0)) intPosMinOneNumFormatter = NSNumberFormatter.alloc().init() intPosMinOneNumFormatter.setAllowsFloats_(False) intPosMinOneNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinOneNumFormatter.setMinimum_(NSNumber.numberWithInt_(1)) self.textSize = getExtensionDefault("%s.%s" % (extensionKey, "textSize")) if not self.textSize: self.textSize = 150 self.lineHeight = getExtensionDefault("%s.%s" % (extensionKey, "lineHeight")) if not self.lineHeight: self.lineHeight = 200 self.extraSidebearings = getExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings")) if not self.extraSidebearings: self.extraSidebearings = [0, 0] self.extraGlyphs = getExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs")) if not self.extraGlyphs: self.extraGlyphs = '' posSize = getExtensionDefault("%s.%s" % (extensionKey, "posSize")) if not posSize: posSize = (100, 100, 1200, 400) self.calibrateMode = getExtensionDefault("%s.%s" % (extensionKey, "calibrateMode")) if not self.calibrateMode: self.calibrateMode = False calibrateModeStrings = getExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings")) if not calibrateModeStrings: calibrateModeStrings = { 'group1.baseInput': 'dotlessi o s', 'group1.markInput': 'dieresis circumflex macron breve caron', 'group2.baseInput': 'I O S', 'group2.markInput': 'dieresis.cap circumflex.cap macron.cap breve.cap caron.cap', 'group3.baseInput': 'I.sc O.sc S.sc', 'group3.markInput': 'dieresis circumflex macron breve caron', 'group4.baseInput': '', 'group4.markInput': '', } # -- Window -- self.w = FloatingWindow(posSize, extensionName, minSize=(500, 400)) self.w.fontList = List((10, 10, 190, -41), self.glyphNamesList, selectionCallback=self.listSelectionCallback) if roboFontVersion < '1.7': self.w.fontList.getNSTableView().sizeToFit() # use the full width of the column self.w.fontList.show(not self.calibrateMode) self.w.lineView = MultiLineView((210, 10, -10, -41), pointSize = self.textSize, lineHeight = self.lineHeight, displayOptions={"Beam" : False, "displayMode" : "Multi Line"} ) # -- Calibration Mode -- baseLabel = "Bases" markLabel = "Marks" width, height = 190, 140 self.cm = Group((0, 0, 0, 0)) # --- self.cm.group1 = Group((5, height*0, width, height-10)) self.cm.group1.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group1.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group1.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group1.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group1.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group2 = Group((5, height*1, width, height-10)) self.cm.group2.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group2.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group2.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group2.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group2.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group3 = Group((5, height*2, width, height-10)) self.cm.group3.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group3.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group3.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group3.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group3.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group4 = Group((5, height*3, width, height-10)) self.cm.group4.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group4.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group4.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group4.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group4.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group4.markInput'], callback=self.updateCalibrateMode, continuous=False) # --- view = DefconAppKitTopAnchoredNSView.alloc().init() view.addSubview_(self.cm.getNSView()) view.setFrame_(((0, 0), (width+10, height*4-23))) self.cm.setPosSize((0, 0, width+10, height*4-22)) self.w.scrollView = ScrollView((5, 10, width+10, -41), view, drawsBackground=False, hasHorizontalScroller=False) self.w.scrollView.getNSScrollView().setBorderType_(NSNoBorder) self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1) # NSScrollElasticityNone self.w.scrollView.show(self.calibrateMode) # -- Footer -- self.w.calibrateModeCheck = CheckBox((10, -32, 200, -10), "Calibration Mode", callback=self.calibrateModeCallback, value=self.calibrateMode) self.w.textSizeLabel = TextBox((210, -30, 100, -10), "Text Size") self.w.textSize = EditText((270, -32, 35, -10), self.textSize, callback=self.textSizeCallback, continuous=False, formatter=intPosMinOneNumFormatter) self.w.lineHeightLabel = TextBox((320, -30, 100, -10), "Line Height") self.w.lineHeight = EditText((395, -32, 35, -10), self.lineHeight, callback=self.lineHeightCallback, continuous=False, formatter=integerNumFormatter) self.w.extraSidebearingsLabel = TextBox((446, -30, 180, -10), "Extra Sidebearings") self.w.extraSidebearingsChar = TextBox((602, -30, 20, -10), "&") self.w.extraSidebearingLeft = EditText((567, -32, 35, -10), self.extraSidebearings[0], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.extraSidebearingRight = EditText((614, -32, 35, -10), self.extraSidebearings[1], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.extraGlyphsLabel = TextBox((665, -30, 180, -10), "Extra Glyphs") self.w.extraGlyphs = EditText((749, -32, -10, -10), self.extraGlyphs, callback=self.extraGlyphsCallback, continuous=False) # trigger the initial state and contents of the window self.extraGlyphsCallback() # this will call self.updateExtensionWindow() self.w.bind("close", self.windowClose) self.w.open() self.w.makeKey()
class OverlayUFOs(BaseWindowController): DEFAULTKEY = "com.fontbureau.overlayUFO" DEFAULTKEY_DRAW = "%s.draw" % DEFAULTKEY DEFAULTKEY_FILL = "%s.fill" % DEFAULTKEY DEFAULTKEY_FILLCOLOR = "%s.fillColor" % DEFAULTKEY DEFAULTKEY_STROKE = "%s.stroke" % DEFAULTKEY DEFAULTKEY_STROKECOLOR = "%s.strokeColor" % DEFAULTKEY DEFAULTKEY_POINTS = "%s.points" % DEFAULTKEY DEFAULTKEY_POINTSCOLOR = "%s.pointsColor" % DEFAULTKEY DEFAULTKEY_ALIGNMENT = "%s.alignment" % DEFAULTKEY DEFAULTKEY_KERNING = "%s.kerning" % DEFAULTKEY DEFAULTKEY_FLOATING = "%s.floating" % DEFAULTKEY FALLBACK_FILLCOLOR = NSColor.colorWithCalibratedRed_green_blue_alpha_(0, 0.3, 1, .1) FALLBACK_STROKECOLOR = NSColor.colorWithCalibratedRed_green_blue_alpha_(0, 0.3, 1, .5) FALLBACK_POINTSCOLOR = NSColor.colorWithCalibratedRed_green_blue_alpha_(0, 0.3, 1, .5) def getListDescriptor(self): return [ dict(title="Status", key="status", width=10, cell=SmallTextListCell(), editable=False), dict(title="Name", key="name", width=230, cell=SmallTextListCell(), editable=False), ] def __init__(self): # Preferences self._drawing = getExtensionDefault(self.DEFAULTKEY_DRAW, True) self._fill = getExtensionDefault(self.DEFAULTKEY_FILL, True) self._stroke = getExtensionDefault(self.DEFAULTKEY_STROKE, True) self._points = getExtensionDefault(self.DEFAULTKEY_POINTS, True) self._fillColor = getExtensionDefaultColor(self.DEFAULTKEY_FILLCOLOR, self.FALLBACK_FILLCOLOR) self._strokeColor = getExtensionDefaultColor(self.DEFAULTKEY_STROKECOLOR, self.FALLBACK_STROKECOLOR) self._pointsColor = getExtensionDefaultColor(self.DEFAULTKEY_POINTSCOLOR, self.FALLBACK_POINTSCOLOR) self._alignment = getExtensionDefault(self.DEFAULTKEY_ALIGNMENT, 0) self._kerning = getExtensionDefault(self.DEFAULTKEY_KERNING, 1) self._floating = getExtensionDefault(self.DEFAULTKEY_FLOATING, 1) # User preferences self._onCurvePointsSize = getDefault("glyphViewOncurvePointsSize") # typo, should be: OnCurve self._offCurvePointsSize = getDefault("glyphViewOffCurvePointsSize") self._strokeWidth = getDefault("glyphViewStrokeWidth") w, h = 400, 195 x = y = 10 self.initAllFonts() self.w = FloatingWindow((w, h), "Overlay UFOs") self.w.draw = CheckBox((x, y, 95, 18), "Draw", callback=self.drawCallback, value=self._drawing, sizeStyle="small") x += 60 self.w.fill = CheckBox((x, y, 95, 18), "Fill", callback=self.fillCallback, value=self._fill, sizeStyle="small") x += 40 self.w.fillColor = ColorWell((x, y, 45, 20), callback=self.fillColorCallback, color=self._fillColor) x += 60 self.w.stroke = CheckBox((x, y, 95, 18), "Stroke", callback=self.strokeCallback, value=self._stroke, sizeStyle="small") x += 60 self.w.strokeColor = ColorWell((x, y, 45, 20), callback=self.strokeColorCallback, color=self._strokeColor) x += 60 self.w.points = CheckBox((x, y, 95, 18), "Points", callback=self.pointsCallback, value=self._points, sizeStyle="small") x += 60 self.w.pointsColor = ColorWell((x, y, 45, 20), callback=self.pointsColorCallback, color=self._pointsColor) x, y = 10, 40 self.w.alignText = TextBox((x, y, 250, 15), "Alignment:", sizeStyle="small") y += 18 self.w.alignment = RadioGroup((x, y, 80, 55), ['Left', 'Center', 'Right'], isVertical=True, callback=self.alignmentCallback, sizeStyle="small") self.w.alignment.set(self._alignment) y += 62 self.w.kerning = CheckBox((x, y, 100, 10), "Show kerning", callback=self.kerningCallback, value=self._kerning, sizeStyle="mini") y += 18 self.w.floating = CheckBox((x, y, 100, 10), "Floating Window", callback=self.floatingCallback, value=self._floating, sizeStyle="mini") y += 25 self.w.resetDefaults = Button((x, y, 85, 14), "Reset settings", callback=self.resetSettingsCallback, sizeStyle="mini") x, y = 110, 40 self.w.fontList = List((x, y, 240, 55), self.getFontItems(), columnDescriptions=self.getListDescriptor(), showColumnTitles=False, selectionCallback=None, doubleClickCallback=self.fontListCallback, allowsMultipleSelection=True, allowsEmptySelection=True, drawVerticalLines=False, drawHorizontalLines=True, drawFocusRing=False, rowHeight=16 ) y += 55 self.w.hiddenFontList = List((x, y, 240, 55), self.getHiddenFontItems(), columnDescriptions=self.getListDescriptor(), showColumnTitles=False, selectionCallback=None, doubleClickCallback=self.hiddenFontListCallback, allowsMultipleSelection=True, allowsEmptySelection=True, drawVerticalLines=False, drawHorizontalLines=True, drawFocusRing=False, rowHeight=16 ) self._selectionChanging = False self.w.fontList.setSelection([]) # unselect y += 65 self.w.contextLeft = EditText((x, y, 90, 20), callback=self.contextCallback, continuous=True, placeholder="Left", sizeStyle="small") self.w.contextCurrent = EditText((x+95, y, 50, 20), callback=self.contextCallback, continuous=True, placeholder="?", sizeStyle="small") self.w.contextRight = EditText((x+150, y, 90, 20), callback=self.contextCallback, continuous=True, placeholder="Right", sizeStyle="small") x, y = 360, 100 self.w.addFonts = Button((x, y, 30, 20), "+", callback=self.addHiddenFontsCallback, sizeStyle="regular") y += 25 self.w.removeFonts = Button((x, y, 30, 20), unichr(8722), callback=self.removeHiddenFontsCallback, sizeStyle="regular") # Observers addObserver(self, "fontDidOpen", "fontDidOpen") addObserver(self, "fontWillClose", "fontWillClose") # fontDidClose? addObserver(self, "draw", "drawInactive") addObserver(self, "draw", "draw") # Prepare and open window self.setWindowLevel() self.setUpBaseWindowBehavior() self.w.open() def setWindowLevel(self): if self._floating: self.w._window.setLevel_(NSFloatingWindowLevel) else: self.w._window.setLevel_(NSNormalWindowLevel) def windowCloseCallback(self, sender): removeObserver(self, "fontDidOpen") removeObserver(self, "fontWillClose") removeObserver(self, "drawInactive") removeObserver(self, "draw") self.updateView() super(OverlayUFOs, self).windowCloseCallback(sender) def updateView(self): UpdateCurrentGlyphView() def initAllFonts(self): fonts = [] for font in AllFonts(): fonts.append({"font": font, "status": u"•"}) self.fonts = fonts self.hiddenFonts = [] def getFontName(self, font): if font.document(): name = font.document().displayName() else: name = font.fileName.split("/")[-1] return name def getHiddenFontItems(self): hiddenFonts = self.hiddenFonts hiddenFontItems = self.getItems(hiddenFonts) return hiddenFontItems def getFontItems(self): fonts = self.fonts fontItems = self.getItems(fonts) return fontItems def getItems(self, fonts): items = [] uniqueNames = {} for f in fonts: font = f["font"] status = f["status"] path = font.path name = self.getFontName(font) if not uniqueNames.has_key(name): uniqueNames[name] = [] uniqueNames[name].append(path) paths = uniqueNames[name] if len(paths) > 1: prefix = commonprefix(paths) if prefix: suffix = " ...%s" % path[len(prefix):] else: suffix = " %s" % path name += suffix items.append({"status": status, "name": name}) return items def getActiveFonts(self): fonts = self.fonts + self.hiddenFonts activeFonts = [] for font in fonts: if font["status"]: activeFonts.append(font["font"]) return activeFonts def getContexts(self): return self.w.contextLeft.get(), self.w.contextCurrent.get(), self.w.contextRight.get() def getAlignment(self): index = self._alignment if index == 0: return 'left' elif index == 1: return 'center' elif index == 2: return 'right' def getKernValue(self, nakedFont, leftGlyph, rightGlyph): if not leftGlyph or not rightGlyph: return 0 if not self._kerning: return 0 return nakedFont.flatKerning.get((leftGlyph.name, rightGlyph.name)) or 0 def draw(self, info): if not self._drawing: return glyph = info.get("glyph") drawingScale = info.get('scale') if glyph is None: return current = glyph.getParent() fonts = self.getActiveFonts() for font in fonts: nakedFont = font.naked() contextLeft, contextCurrent, contextRight = self.getContexts() contextLeft = splitText(contextLeft or '', nakedFont.unicodeData or '') contextLeft = [font[gname] for gname in contextLeft if gname in font.keys()] contextRight = splitText(contextRight or '', nakedFont.unicodeData or '') contextRight = [font[gname] for gname in contextRight if gname in font.keys()] contextCurrent = splitText(contextCurrent or '', nakedFont.unicodeData or '') if len(contextCurrent) > 0: contextCurrent = [font[gname] for gname in [contextCurrent[0]] if gname in font.keys()] if len(contextCurrent) > 0: sourceGlyph = contextCurrent[0] else: sourceGlyph = None elif glyph.name in font.keys(): sourceGlyph = font[glyph.name] contextCurrent = [sourceGlyph] else: sourceGlyph = None contextCurrent = [] save() self._fillColor.setFill() self._strokeColor.setStroke() scale(current.info.unitsPerEm/float(font.info.unitsPerEm)) # Draw left context previousGlyph = sourceGlyph contextLeft.reverse() totalWidth = 0 for i, cbGlyph in enumerate(contextLeft): kernValue = self.getKernValue(nakedFont, cbGlyph, previousGlyph) # right to left translate(-cbGlyph.width-kernValue, 0) totalWidth += cbGlyph.width + kernValue glyphBezierPath = cbGlyph.naked().getRepresentation("defconAppKit.NSBezierPath") if self._fill: glyphBezierPath.fill() if self._stroke: glyphBezierPath.setLineWidth_(self._strokeWidth*drawingScale) strokePixelPath(glyphBezierPath) previousGlyph = cbGlyph translate(totalWidth, 0) # Draw current context or current glyph if contextCurrent: previousGlyph = None alignment = self.getAlignment() if alignment == 'left': offset = 0 elif alignment == 'center': offset = (glyph.width - contextCurrent[0].width)/2 elif alignment == 'right': offset = glyph.width - contextCurrent[0].width totalWidth = offset translate(totalWidth, 0) for i, cbGlyph in enumerate(contextCurrent): #if cbGlyph == glyph: # continue # Don't show if is current glyph kernValue = self.getKernValue(nakedFont, previousGlyph, cbGlyph) translate(kernValue, 0) glyphBezierPath = cbGlyph.naked().getRepresentation("defconAppKit.NSBezierPath") if self._fill: glyphBezierPath.fill() if self._stroke: glyphBezierPath.setLineWidth_(self._strokeWidth*drawingScale) strokePixelPath(glyphBezierPath) if self._points: self.drawPoints(cbGlyph, info['scale']) translate(cbGlyph.width, 0) totalWidth += cbGlyph.width + kernValue previousGlyph = cbGlyph translate(-totalWidth, 0) # Draw right context translate(glyph.width) totalWidth = glyph.width for i, cbGlyph in enumerate(contextRight): kernValue = self.getKernValue(nakedFont, previousGlyph, cbGlyph) translate(kernValue, 0) glyphBezierPath = cbGlyph.naked().getRepresentation("defconAppKit.NSBezierPath") if self._fill: glyphBezierPath.fill() if self._stroke: glyphBezierPath.setLineWidth_(self._strokeWidth*drawingScale) strokePixelPath(glyphBezierPath) translate(cbGlyph.width, 0) totalWidth += cbGlyph.width + kernValue previousGlyph = cbGlyph restore() def drawPoints(self, glyph, scale): save() _onCurveSize = self._onCurvePointsSize * scale _offCurveSize = self._offCurvePointsSize * scale _strokeWidth = self._strokeWidth * scale self._pointsColor.set() path = NSBezierPath.bezierPath() offCurveHandlesPath = NSBezierPath.bezierPath() pointsData = glyph.getRepresentation("doodle.OutlineInformation") for point1, point2 in pointsData["bezierHandles"]: offCurveHandlesPath.moveToPoint_(point1) offCurveHandlesPath.lineToPoint_(point2) for point in pointsData.get("offCurvePoints"): (x, y) = point["point"] path.appendBezierPathWithOvalInRect_(NSMakeRect(x - _offCurveSize, y - _offCurveSize, _offCurveSize * 2, _offCurveSize * 2)) for point in pointsData.get("onCurvePoints"): (x, y) = point["point"] path.appendBezierPathWithRect_(NSMakeRect(x - _onCurveSize, y - _onCurveSize, _onCurveSize * 2, _onCurveSize * 2)) path.fill() offCurveHandlesPath.setLineWidth_(_strokeWidth) strokePixelPath(offCurveHandlesPath) restore() def fontDidOpen(self, event): font = event["font"] self.fonts.append({"font": font, "status": u"•"}) self.w.fontList.set(self.getFontItems()) self.updateView() def fontWillClose(self, event): # not always working... try from path or name? closingFont = event["font"] for i, font in enumerate(self.fonts): if font["font"] == closingFont: del self.fonts[i] item = self.w.fontList.get()[i] self.w.fontList.remove(item) break self.updateView() def fontListCallback(self, sender): fonts = self.fonts self.listCallback(sender, fonts) def hiddenFontListCallback(self, sender): fonts = self.hiddenFonts self.listCallback(sender, fonts) def listCallback(self, sender, fonts): for index in sender.getSelection(): item = sender.get()[index] font = fonts[index] if item["status"]: item["status"] = font["status"] = "" else: item["status"] = font["status"] = u"•" self.updateView() def contextCallback(self, sender): self.updateView() def drawCallback(self, sender): drawing = sender.get() setExtensionDefault(self.DEFAULTKEY_DRAW, drawing) self._drawing = drawing self.updateView() def fillCallback(self, sender): fill = sender.get() setExtensionDefault(self.DEFAULTKEY_FILL, fill) self._fill = fill self.updateView() def fillColorCallback(self, sender): fillColor = sender.get() setExtensionDefaultColor(self.DEFAULTKEY_FILLCOLOR, fillColor) self._fillColor = fillColor self.updateView() def strokeCallback(self, sender): stroke = sender.get() setExtensionDefault(self.DEFAULTKEY_STROKE, stroke) self._stroke = stroke self.updateView() def strokeColorCallback(self, sender): strokeColor = sender.get() setExtensionDefaultColor(self.DEFAULTKEY_STROKECOLOR, strokeColor) self._strokeColor = strokeColor self.updateView() def pointsCallback(self, sender): points = sender.get() setExtensionDefault(self.DEFAULTKEY_POINTS, points) self._points = points self.updateView() def pointsColorCallback(self, sender): pointsColor = sender.get() setExtensionDefaultColor(self.DEFAULTKEY_POINTSCOLOR, pointsColor) self._pointsColor = pointsColor self.updateView() def alignmentCallback(self, sender): alignment = sender.get() setExtensionDefault(self.DEFAULTKEY_ALIGNMENT, alignment) self._alignment = alignment self.updateView() def kerningCallback(self, sender): kerning = sender.get() setExtensionDefault(self.DEFAULTKEY_KERNING, kerning) self._kerning = kerning self.updateView() def floatingCallback(self, sender): floating = sender.get() setExtensionDefault(self.DEFAULTKEY_FLOATING, floating) self._floating = floating self.setWindowLevel() def resetSettingsCallback(self, sender): drawing = True fill = True fillColor = self.FALLBACK_FILLCOLOR stroke = True strokeColor = self.FALLBACK_STROKECOLOR points = True pointsColor = self.FALLBACK_POINTSCOLOR alignment = 0 kerning = True floating = True setExtensionDefault(self.DEFAULTKEY_DRAW, drawing) setExtensionDefault(self.DEFAULTKEY_FILL, fill) setExtensionDefaultColor(self.DEFAULTKEY_FILLCOLOR, fillColor) setExtensionDefault(self.DEFAULTKEY_STROKE, stroke) setExtensionDefaultColor(self.DEFAULTKEY_STROKECOLOR, strokeColor) setExtensionDefault(self.DEFAULTKEY_POINTS, points) setExtensionDefaultColor(self.DEFAULTKEY_POINTSCOLOR, pointsColor) setExtensionDefault(self.DEFAULTKEY_ALIGNMENT, alignment) setExtensionDefault(self.DEFAULTKEY_KERNING, kerning) setExtensionDefault(self.DEFAULTKEY_FLOATING, floating) self.w.draw.set(drawing) self.w.fill.set(fill) self.w.fillColor.set(fillColor) self.w.stroke.set(stroke) self.w.strokeColor.set(strokeColor) self.w.points.set(points) self.w.pointsColor.set(strokeColor) self.w.alignment.set(alignment) self.w.kerning.set(kerning) self.w.floating.set(floating) self._drawing = drawing self._fill = fill self._fillColor = fillColor self._stroke = stroke self._strokeColor = strokeColor self._points = points self._pointsColor = strokeColor self._alignment = alignment self._kerning = kerning self._floating = floating self.updateView() def addHiddenFontsCallback(self, sender): fonts = OpenFont(None, False) if fonts is None: return if not isinstance(fonts, list): # make sure it's a list fonts = [fonts] paths = [font["font"].path for font in self.hiddenFonts] for font in fonts: if font.path in paths: continue # already open self.hiddenFonts.append({"font": font, "status": u"•"}) self.w.hiddenFontList.set(self.getHiddenFontItems()) self.updateView() def removeHiddenFontsCallback(self, sender): hiddenFontList = self.w.hiddenFontList.get() selection = self.w.hiddenFontList.getSelection() for i in reversed(selection): del self.hiddenFonts[i] item = hiddenFontList[i] self.w.hiddenFontList.remove(item) self.updateView()
class AdjustAnchors(BaseWindowController): def __init__(self): self.font = CurrentFont() self.glyph = CurrentGlyph() self.upm = self.font.info.unitsPerEm self.glyphPreviewCacheDict = {} # key: glyph name -- value: list containing assembled glyphs self.anchorsOnMarksDict = {} # key: anchor name -- value: list of mark glyph names self.anchorsOnBasesDict = {} # key: anchor name -- value: list of base glyph names self.marksDict = {} # key: mark glyph name -- value: anchor name (NOTE: It's expected that each mark glyph only has one type of anchor) self.fillAnchorsAndMarksDicts() self.glyphNamesList = [] # list of glyph names that will be displayed in the UI list self.selectedGlyphNamesList = [] # list of glyph names selected in the UI list self.extraGlyphsList = [] # list of the glyph objects that should be inserted before and after the accented glyphs self.Blue, self.Alpha = 1, 0.6 self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") addObserver(self, "_fontWillClose", "fontWillClose") addObserver(self, "_currentFontChanged", "fontResignCurrent") addObserver(self, "_currentGlyphChanged", "currentGlyphChanged") addObserver(self, "_drawFill", "draw") addObserver(self, "_drawFill", "drawInactive") addObserver(self, "_previewFill", "drawPreview") addObserver(self, "_drawGlyphs", "draw") # observer for the draw event addObserver(self, "_drawGlyphs", "drawInactive") # draw the glyphs when the glyph window is not in focus addObserver(self, "_drawGlyphs", "drawPreview") integerNumFormatter = NSNumberFormatter.alloc().init() integerNumFormatter.setAllowsFloats_(False) integerNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter = NSNumberFormatter.alloc().init() intPosMinZeroNumFormatter.setAllowsFloats_(False) intPosMinZeroNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter.setMinimum_(NSNumber.numberWithInt_(0)) intPosMinOneNumFormatter = NSNumberFormatter.alloc().init() intPosMinOneNumFormatter.setAllowsFloats_(False) intPosMinOneNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinOneNumFormatter.setMinimum_(NSNumber.numberWithInt_(1)) self.textSize = getExtensionDefault("%s.%s" % (extensionKey, "textSize")) if not self.textSize: self.textSize = 150 self.lineHeight = getExtensionDefault("%s.%s" % (extensionKey, "lineHeight")) if not self.lineHeight: self.lineHeight = 200 self.extraSidebearings = getExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings")) if not self.extraSidebearings: self.extraSidebearings = [0, 0] self.extraGlyphs = getExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs")) if not self.extraGlyphs: self.extraGlyphs = '' posSize = getExtensionDefault("%s.%s" % (extensionKey, "posSize")) if not posSize: posSize = (100, 100, 1200, 400) self.calibrateMode = getExtensionDefault("%s.%s" % (extensionKey, "calibrateMode")) if not self.calibrateMode: self.calibrateMode = False calibrateModeStrings = getExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings")) if not calibrateModeStrings: calibrateModeStrings = { 'group1.baseInput': 'dotlessi o s', 'group1.markInput': 'dieresis circumflex macron breve caron', 'group2.baseInput': 'I O S', 'group2.markInput': 'dieresis.cap circumflex.cap macron.cap breve.cap caron.cap', 'group3.baseInput': 'I.sc O.sc S.sc', 'group3.markInput': 'dieresis circumflex macron breve caron', 'group4.baseInput': '', 'group4.markInput': '', } # -- Window -- self.w = FloatingWindow(posSize, extensionName, minSize=(500, 400)) self.w.fontList = List((10, 10, 190, -41), self.glyphNamesList, selectionCallback=self.listSelectionCallback) if roboFontVersion < '1.7': self.w.fontList.getNSTableView().sizeToFit() # use the full width of the column self.w.fontList.show(not self.calibrateMode) self.w.lineView = MultiLineView((210, 10, -10, -41), pointSize = self.textSize, lineHeight = self.lineHeight, displayOptions={"Beam" : False, "displayMode" : "Multi Line"} ) # -- Calibration Mode -- baseLabel = "Bases" markLabel = "Marks" width, height = 190, 140 self.cm = Group((0, 0, 0, 0)) # --- self.cm.group1 = Group((5, height*0, width, height-10)) self.cm.group1.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group1.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group1.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group1.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group1.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group2 = Group((5, height*1, width, height-10)) self.cm.group2.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group2.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group2.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group2.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group2.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group3 = Group((5, height*2, width, height-10)) self.cm.group3.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group3.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group3.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group3.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group3.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group4 = Group((5, height*3, width, height-10)) self.cm.group4.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group4.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group4.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group4.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group4.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group4.markInput'], callback=self.updateCalibrateMode, continuous=False) # --- view = DefconAppKitTopAnchoredNSView.alloc().init() view.addSubview_(self.cm.getNSView()) view.setFrame_(((0, 0), (width+10, height*4-23))) self.cm.setPosSize((0, 0, width+10, height*4-22)) self.w.scrollView = ScrollView((5, 10, width+10, -41), view, drawsBackground=False, hasHorizontalScroller=False) self.w.scrollView.getNSScrollView().setBorderType_(NSNoBorder) self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1) # NSScrollElasticityNone self.w.scrollView.show(self.calibrateMode) # -- Footer -- self.w.calibrateModeCheck = CheckBox((10, -32, 200, -10), "Calibration Mode", callback=self.calibrateModeCallback, value=self.calibrateMode) self.w.textSizeLabel = TextBox((210, -30, 100, -10), "Text Size") self.w.textSize = EditText((270, -32, 35, -10), self.textSize, callback=self.textSizeCallback, continuous=False, formatter=intPosMinOneNumFormatter) self.w.lineHeightLabel = TextBox((320, -30, 100, -10), "Line Height") self.w.lineHeight = EditText((395, -32, 35, -10), self.lineHeight, callback=self.lineHeightCallback, continuous=False, formatter=integerNumFormatter) self.w.extraSidebearingsLabel = TextBox((446, -30, 180, -10), "Extra Sidebearings") self.w.extraSidebearingsChar = TextBox((602, -30, 20, -10), "&") self.w.extraSidebearingLeft = EditText((567, -32, 35, -10), self.extraSidebearings[0], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.extraSidebearingRight = EditText((614, -32, 35, -10), self.extraSidebearings[1], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.extraGlyphsLabel = TextBox((665, -30, 180, -10), "Extra Glyphs") self.w.extraGlyphs = EditText((749, -32, -10, -10), self.extraGlyphs, callback=self.extraGlyphsCallback, continuous=False) # trigger the initial state and contents of the window self.extraGlyphsCallback() # this will call self.updateExtensionWindow() self.w.bind("close", self.windowClose) self.w.open() self.w.makeKey() def calibrateModeCallback(self, sender): self.calibrateMode = not self.calibrateMode self.w.fontList.show(not sender.get()) self.w.scrollView.show(self.calibrateMode) self.updateExtensionWindow() def textSizeCallback(self, sender): try: # in case the user submits an empty field self.textSize = int(sender.get()) except: # reset to the previous value NSBeep() self.sender.set(self.textSize) self.w.lineView.setPointSize(self.textSize) def lineHeightCallback(self, sender): try: self.lineHeight = int(sender.get()) except: NSBeep() self.sender.set(self.lineHeight) self.w.lineView.setLineHeight(self.lineHeight) def extraSidebearingsCallback(self, sender): left = self.w.extraSidebearingLeft right = self.w.extraSidebearingRight try: self.extraSidebearings = [int(left.get()), int(right.get())] except: NSBeep() left.set(self.extraSidebearings[0]) right.set(self.extraSidebearings[1]) self.extraGlyphsCallback() # this will call self.updateExtensionWindow() def extraGlyphsCallback(self, *sender): del self.extraGlyphsList[:] # empty the list self.extraGlyphs = self.w.extraGlyphs.get() glyphNamesList = self.extraGlyphs.split() for gName in glyphNamesList: try: extraGlyph = self.font[gName] # must create a new glyph in order to be able to increase the sidebearings without modifying the font newGlyph = RGlyph() newGlyph.setParent(self.font) # must use deepAppend because the extra glyph may have components (which will cause problems to the MultiLineView) newGlyph = self.deepAppendGlyph(newGlyph, extraGlyph) newGlyph.width = extraGlyph.width except RoboFontError: continue newGlyph.leftMargin += self.extraSidebearings[0] newGlyph.rightMargin += self.extraSidebearings[1] self.extraGlyphsList.append(newGlyph) self.glyphPreviewCacheDict.clear() self.updateExtensionWindow() def windowClose(self, sender): self.font.naked().removeObserver(self, "Font.Changed") removeObserver(self, "fontWillClose") removeObserver(self, "fontResignCurrent") removeObserver(self, "currentGlyphChanged") removeObserver(self, "draw") removeObserver(self, "drawInactive") removeObserver(self, "drawPreview") self.saveExtensionDefaults() def getCalibrateModeStrings(self): calibrateModeStringsDict = {} for i in range(1,5): group = getattr(self.cm, "group%d" % i) calibrateModeStringsDict["group%d.baseInput" % i] = group.baseInput.get() calibrateModeStringsDict["group%d.markInput" % i] = group.markInput.get() return calibrateModeStringsDict def saveExtensionDefaults(self): setExtensionDefault("%s.%s" % (extensionKey, "posSize"), self.w.getPosSize()) setExtensionDefault("%s.%s" % (extensionKey, "textSize"), self.textSize) setExtensionDefault("%s.%s" % (extensionKey, "lineHeight"), self.lineHeight) setExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings"), self.extraSidebearings) setExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs"), self.extraGlyphs) setExtensionDefault("%s.%s" % (extensionKey, "calibrateMode"), self.calibrateMode) setExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings"), self.getCalibrateModeStrings()) def _previewFill(self, info): self.Blue, self.Alpha = 0, 1 def _drawFill(self, info): self.Blue, self.Alpha = 1, 0.6 def _fontWillClose(self, info): """ Close the window when the last font is closed """ if len(AllFonts()) < 2: self.windowClose(self) self.w.close() def _currentFontChanged(self, info): self.font.naked().removeObserver(self, "Font.Changed") self.font = CurrentFont() self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") self.fillAnchorsAndMarksDicts() del self.glyphNamesList[:] del self.selectedGlyphNamesList[:] self.updateExtensionWindow() def _currentGlyphChanged(self, info): self.updateExtensionWindow() def fontWasModified(self, info): OutputWindow().clear() self.fillAnchorsAndMarksDicts() del self.glyphNamesList[:] del self.selectedGlyphNamesList[:] self.updateExtensionWindow() def deepAppendGlyph(self, glyph, gToAppend, offset=(0,0)): if not gToAppend.components: glyph.appendGlyph(gToAppend, offset) else: for component in gToAppend.components: compGlyph = self.font[component.baseGlyph].copy() # handle component transformations componentTransformation = component.transformation # when undoing a paste anchor or a delete anchor action, RoboFont returns component.transformation as a list instead of a tuple if type(componentTransformation) is list: componentTransformation = tuple(componentTransformation) if componentTransformation != (1, 0, 0, 1, 0, 0): # if component is skewed and/or is shifted matrix = componentTransformation[0:4] if matrix != (1, 0, 0, 1): # if component is skewed transformObj = Identity.transform(matrix + (0, 0)) # ignore the original component's shifting values compGlyph.transform(transformObj) glyph.appendGlyph(compGlyph, map(sum, zip(component.offset, offset))) # add the two tuples of offset for contour in gToAppend: glyph.appendContour(contour, offset) # if the assembled glyph still has components, recursively remove and replace them 1-by-1 by the glyphs they reference if glyph.components: nestedComponent = glyph.components[-1] # start from the end glyph.removeComponent(nestedComponent) glyph = self.deepAppendGlyph(glyph, self.font[nestedComponent.baseGlyph], nestedComponent.offset) return glyph def updateCalibrateMode(self, *sender): glyphsList = [] newLine = self.w.lineView.createNewLineGlyph() # cycle thru the UI Groups and collect the strings for i in range(1,5): group = getattr(self.cm, "group%d" % i) baseGlyphsNamesList = group.baseInput.get().split() markGlyphsNamesList = group.markInput.get().split() # iterate thru the base+mark combinations for gBaseName, gMarkName in product(baseGlyphsNamesList, markGlyphsNamesList): newGlyph = RGlyph() newGlyph.setParent(self.font) # skip invalid glyph names try: baseGlyph = self.font[gBaseName] markGlyph = self.font[gMarkName] except RoboFontError: continue # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, baseGlyph) # append mark glyph newGlyph = self.deepAppendGlyph(newGlyph, markGlyph, self.getAnchorOffsets(baseGlyph, markGlyph)) # set the advanced width dfltSidebearings = self.upm * .05 # 5% of the UPM newGlyph.leftMargin = dfltSidebearings + self.extraSidebearings[0] newGlyph.rightMargin = dfltSidebearings + self.extraSidebearings[1] # append the assembled glyph to the list glyphsList.extend(self.extraGlyphsList) glyphsList.append(newGlyph) # add line break, if both input fields have content if baseGlyphsNamesList and markGlyphsNamesList: glyphsList.extend(self.extraGlyphsList) glyphsList.append(newLine) # update the contents of the MultiLineView self.w.lineView.set(glyphsList) def updateExtensionWindow(self): if self.calibrateMode: self.updateCalibrateMode() return if CurrentGlyph() is not None: # NOTE: CurrentGlyph() will return zero (its length), so "is not None" is necessary self.glyph = CurrentGlyph() self.glyphNamesList = self.makeGlyphNamesList(self.glyph) self.updateListView() currentGlyphName = self.glyph.name # base glyph + accent combinations preview # first check if there's a cached glyph if currentGlyphName in self.glyphPreviewCacheDict: self.w.lineView.set(self.glyphPreviewCacheDict[currentGlyphName]) # assemble the glyphs else: glyphsList = [] for glyphNameInUIList in self.glyphNamesList: newGlyph = RGlyph() newGlyph.setParent(self.font) # the glyph in the UI list is a mark if glyphNameInUIList in self.marksDict: markGlyph = self.font[glyphNameInUIList] # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, self.glyph) # append mark glyph newGlyph = self.deepAppendGlyph(newGlyph, markGlyph, self.getAnchorOffsets(self.glyph, markGlyph)) # set the advanced width if self.glyph.width < 10: # combining marks or other glyphs with a small advanced width newGlyph.leftMargin = self.upm * .05 # 5% of the UPM newGlyph.rightMargin = newGlyph.leftMargin else: newGlyph.width = self.glyph.width # the glyph in the UI list is a base else: baseGlyph = self.font[glyphNameInUIList] # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, baseGlyph) # append mark glyph newGlyph = self.deepAppendGlyph(newGlyph, self.glyph, self.getAnchorOffsets(baseGlyph, self.glyph)) # set the advanced width if self.glyph.width < 10: # combining marks or other glyphs with a small advanced width newGlyph.leftMargin = self.upm * .05 newGlyph.rightMargin = newGlyph.leftMargin else: newGlyph.width = baseGlyph.width # pad the new glyph if it has too much overhang if newGlyph.leftMargin < self.upm * .15: newGlyph.leftMargin = self.upm * .05 if newGlyph.rightMargin < self.upm * .15: newGlyph.rightMargin = self.upm * .05 # add extra sidebearings newGlyph.leftMargin += self.extraSidebearings[0] newGlyph.rightMargin += self.extraSidebearings[1] # one last check for making sure the new glyph can be displayed if not newGlyph.components: glyphsList.extend(self.extraGlyphsList) glyphsList.append(newGlyph) else: print "Combination with mark glyph %s can't be previewed because it contains component %s." % (glyphNameInUIList, newGlyph.components[0].baseGlyph) glyphsList.extend(self.extraGlyphsList) self.w.lineView.set(glyphsList) # add to the cache self.glyphPreviewCacheDict[currentGlyphName] = glyphsList else: self.w.lineView.set([]) def listSelectionCallback(self, sender): selectedGlyphNamesList = [] for index in sender.getSelection(): selectedGlyphNamesList.append(self.glyphNamesList[index]) self.selectedGlyphNamesList = selectedGlyphNamesList self.updateGlyphView() def updateGlyphView(self): # update the current glyph view UpdateCurrentGlyphView() def fillAnchorsAndMarksDicts(self): # reset all the dicts self.glyphPreviewCacheDict.clear() self.anchorsOnMarksDict.clear() self.anchorsOnBasesDict.clear() self.marksDict.clear() markGlyphsWithMoreThanOneAnchorTypeList = [] for glyphName in self.font.glyphOrder: glyphAnchorsList = self.font[glyphName].anchors for anchor in glyphAnchorsList: if anchor.name[0] == '_': anchorName = anchor.name[1:] # add to AnchorsOnMarks dictionary if anchorName not in self.anchorsOnMarksDict: self.anchorsOnMarksDict[anchorName] = [glyphName] else: tempList = self.anchorsOnMarksDict[anchorName] tempList.append(glyphName) self.anchorsOnMarksDict[anchorName] = tempList # add to Marks dictionary if glyphName not in self.marksDict: self.marksDict[glyphName] = anchorName else: if glyphName not in markGlyphsWithMoreThanOneAnchorTypeList: markGlyphsWithMoreThanOneAnchorTypeList.append(glyphName) else: anchorName = anchor.name # add to AnchorsOnBases dictionary if anchorName not in self.anchorsOnBasesDict: self.anchorsOnBasesDict[anchorName] = [glyphName] else: tempList = self.anchorsOnBasesDict[anchorName] tempList.append(glyphName) self.anchorsOnBasesDict[anchorName] = tempList if markGlyphsWithMoreThanOneAnchorTypeList: for glyphName in markGlyphsWithMoreThanOneAnchorTypeList: print "ERROR: Glyph %s has more than one type of anchor." % glyphName def makeGlyphNamesList(self, glyph): glyphNamesList = [] markGlyphIsAbleToBeBase = False if glyph is not None: # NOTE: "if glyph" will return zero (its length), so "is not None" is necessary # assemble the list for the UI list for anchor in glyph.anchors: anchorName = anchor.name if anchorName in self.anchorsOnMarksDict: glyphNamesList.extend(self.anchorsOnMarksDict[anchorName]) elif anchorName[1:] in self.anchorsOnBasesDict: # skips the leading underscore glyphNamesList.extend(self.anchorsOnBasesDict[anchorName[1:]]) # for mark glyphs, test if they're able to get other mark glyphs attached to them # this will (correctly) prevent the UI list from including glyph names that cannot be displayed with the current glyph if glyph.name in self.marksDict: for anchor in glyph.anchors: if anchor.name[0] != '_': # the current mark glyph has anchors that allow it to be a base for other marks markGlyphIsAbleToBeBase = True break # remove marks from the glyph list if the current mark glyph can't work as a base if not markGlyphIsAbleToBeBase: for glyphName in glyphNamesList[::-1]: # iterate from the end of the list if glyphName in self.marksDict: glyphNamesList.remove(glyphName) return glyphNamesList def updateListView(self): self.w.fontList.set(self.glyphNamesList) def getAnchorOffsets(self, canvasGlyph, glyphToDraw): # the current glyph is a mark if canvasGlyph.name in self.marksDict: # glyphToDraw is also a mark (mark-to-mark case) if glyphToDraw.name in self.marksDict: # pick the (mark glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name[0] != '_': anchorName = anchor.name markAnchor = anchor break # pick the (base glyph) anchor to draw on for anchor in glyphToDraw.anchors: try: if anchor.name == '_'+ anchorName: baseAnchor = anchor break except UnboundLocalError: continue # glyphToDraw is not a mark else: # pick the (mark glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name[0] == '_': anchorName = anchor.name[1:] markAnchor = anchor break # pick the (base glyph) anchor to draw on for anchor in glyphToDraw.anchors: try: if anchor.name == anchorName: baseAnchor = anchor break except UnboundLocalError: continue try: offsetX = markAnchor.x - baseAnchor.x offsetY = markAnchor.y - baseAnchor.y except UnboundLocalError: offsetX = 0 offsetY = 0 # the current glyph is a base else: try: anchorName = self.marksDict[glyphToDraw.name] except KeyError: anchorName = None if anchorName: # pick the (base glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name == anchorName: baseAnchor = anchor break # pick the (mark glyph) anchor to draw on for anchor in glyphToDraw.anchors: if anchor.name == '_'+ anchorName: markAnchor = anchor break try: offsetX = baseAnchor.x - markAnchor.x offsetY = baseAnchor.y - markAnchor.y except UnboundLocalError: offsetX = 0 offsetY = 0 return (offsetX, offsetY) def _drawGlyphs(self, info): """ draw stuff in the glyph window view """ translateBefore = (0, 0) for glyphName in self.selectedGlyphNamesList: glyphToDraw = self.font[glyphName] # determine the offset of the anchors offset = self.getAnchorOffsets(self.glyph, glyphToDraw) # set the offset of the drawing translate(offset[0] - translateBefore[0], offset[1] - translateBefore[1]) # record the shift amounts (these are needed for resetting the drawing position when more than one mark is selected on the list) translateBefore = offset # set the fill & stroke fill(0, 0, self.Blue, self.Alpha) strokeWidth(None) # draw it mojoPen = MojoDrawingToolsPen(glyphToDraw, self.font) glyphToDraw.draw(mojoPen) mojoPen.draw()
class CornerController: def __init__(self): self.modifiedGlyph = None self.w = FloatingWindow((400, 170), "Corner Tool") self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor()) self.modes = ["Break", "Build", "Pit"] self.objectTypes = {"Build": "Segment", "Break": "Corner point", "Pit": "Corner point"} self.parameters = { "radius": VanillaSingleValueParameter("radius", 20, (-200, 200), numType="int"), "roundness": VanillaSingleValueParameter("roundness", 1.25, (0, 4), numType="float"), "depth": VanillaSingleValueParameter("depth", 30, (-100, 100), numType="int"), "breadth": VanillaSingleValueParameter("breadth", 30, (0, 150), numType="int"), "bottom": VanillaSingleValueParameter("bottom", 5, (0, 40), numType="int"), } self.currentMode = "Break" self.previewGlyph = None self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode) for i, mode in enumerate(self.modes): setattr(self.w, mode, Group((120, 15, -15, -15))) modeGroup = getattr(self.w, mode) modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u">", callback=self.apply) modeGroup.infoBox = Box((0, 0, -50, 35)) modeGroup.info = TextBox((10, 8, -50, 20), "No selection") if i > 0: modeGroup.show(False) self.w.Break.radius = ParameterSliderTextInput( self.parameters["radius"], (0, 60, -25, 25), title="Radius", callback=self.makePreviewGlyph ) self.w.Break.roundness = ParameterSliderTextInput( self.parameters["roundness"], (0, 95, -25, 25), title="Roundness", callback=self.makePreviewGlyph ) self.w.Pit.depth = ParameterSliderTextInput( self.parameters["depth"], (0, 50, -25, 25), title="Depth", callback=self.makePreviewGlyph ) self.w.Pit.breadth = ParameterSliderTextInput( self.parameters["breadth"], (0, 80, -25, 25), title="Breadth", callback=self.makePreviewGlyph ) self.w.Pit.bottom = ParameterSliderTextInput( self.parameters["bottom"], (0, 110, -25, 25), title="bottom", callback=self.makePreviewGlyph ) addObserver(self, "preview", "draw") addObserver(self, "preview", "drawInactive") addObserver(self, "previewSolid", "drawPreview") addObserver(self, "makePreviewGlyph", "mouseDown") addObserver(self, "makePreviewGlyph", "mouseDragged") addObserver(self, "makePreviewGlyph", "keyDown") addObserver(self, "makePreviewGlyph", "keyUp") addObserver(self, "setControls", "mouseUp") addObserver(self, "setControls", "selectAll") addObserver(self, "setControls", "deselectAll") addObserver(self, "setControls", "currentGlyphChanged") self.w.bind("close", self.windowClose) self.setControls() self.w.open() def changeMode(self, sender): index = sender.get() previousModeGroup = getattr(self.w, self.currentMode) previousModeGroup.show(False) self.currentMode = self.modes[index] modeGroup = getattr(self.w, self.currentMode) modeGroup.show(True) self.setControls() def setControls(self, notification=None): mode = self.currentMode selection = self.getSelection() modeGroup = getattr(self.w, mode) if not len(selection): modeGroup.apply.enable(False) modeGroup.info.set("No selection (%ss)" % (self.objectTypes[mode].lower())) elif len(selection): modeGroup.apply.enable(True) info = "%s valid %s" % (len(selection), self.objectTypes[mode].lower()) if len(selection) > 1: info += "s" modeGroup.info.set(info) self.makePreviewGlyph() def getSelection(self, notification=None): glyph = CurrentGlyph() if len(glyph.selection) == 0: return [] elif len(glyph.selection) > 0: iG = IntelGlyph(glyph) if self.currentMode == "Build": selection = iG.getSelection(True) elif self.currentMode in ["Break", "Pit"]: selection = [ point for point in iG.getSelection() if (point.segmentType is not None) and (abs(point.turn()) > pi / 18) ] return selection def preview(self, notification): sc = notification["scale"] if self.previewGlyph is not None: self.previewGlyph.drawPreview( sc, styleFill=True, showNodes=False, strokeWidth=2, fillColor=cornerOutlineSoftColor, strokeColor=cornerOutlineStrongColor, ) def previewSolid(self, notification): sc = notification["scale"] if self.previewGlyph is not None: self.previewGlyph.drawPreview(sc, plain=True) def makePreviewGlyph(self, sender=None): if (sender is not None) and isinstance(sender, dict): if sender.has_key("notificationName") and sender["notificationName"] == "mouseDragged": g = sender["glyph"] if not len(g.selection): return self.previewGlyph = self.makeCornerGlyph() UpdateCurrentGlyphView() def makeCornerGlyph(self, sender=None): mode = self.currentMode if mode == "Build": cornerGlyph = self.buildCorners() elif mode == "Break": cornerGlyph = self.breakCorners() elif mode == "Pit": cornerGlyph = self.pitCorners() return cornerGlyph def buildCorners(self): g = CurrentGlyph() iG = IntelGlyph(g) for contour in iG: segments = contour.collectSegments()["selection"] l = len(segments) lines, curves = self.checkComposition(segments) if l > 1 and lines and curves: segments = [segment for segment in segments if len(segment) == 4] elif l > 1 and lines and not curves: segments = segments[:1] + segments[-1:] for segment in reversed(segments): contour.buildCorner(segment) return iG def breakCorners(self): g = CurrentGlyph() iG = IntelGlyph(g) radius = self.parameters["radius"].get() roundness = self.parameters["roundness"].get() for contour in iG: selection = contour.getSelection() for point in selection: contour.breakCorner(point, radius, velocity=roundness) contour.correctSmoothness() return iG def pitCorners(self): g = CurrentGlyph() iG = IntelGlyph(g) depth = self.parameters["depth"].get() breadth = self.parameters["breadth"].get() bottom = self.parameters["bottom"].get() for contour in iG: selection = contour.getSelection() for point in selection: contour.pitCorner(point, depth, breadth, bottom) contour.removeOverlappingPoints() contour.correctSmoothness() return iG def apply(self, sender): targetGlyph = CurrentGlyph() modifiedGlyph = self.makeCornerGlyph() targetGlyph.prepareUndo("un.round") targetGlyph.clearContours() for p in targetGlyph.selection: p.selected = False pen = targetGlyph.getPointPen() modifiedGlyph.drawPoints(pen) targetGlyph.performUndo() targetGlyph.update() def checkComposition(self, segmentsList): lines = 0 curves = 0 for segment in segmentsList: if len(segment) == 2: lines += 1 elif len(segment) == 4: curves += 1 return lines, curves def windowClose(self, notification): removeObserver(self, "draw") removeObserver(self, "drawInactive") removeObserver(self, "drawPreview") removeObserver(self, "mouseUp") removeObserver(self, "mouseDown") removeObserver(self, "mouseDragged") removeObserver(self, "keyDown") removeObserver(self, "keyUp") removeObserver(self, "selectAll") removeObserver(self, "deselectAll") removeObserver(self, "currentGlyphChanged")
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 RedArrowErrorFilter(): def __init__(self): self.errorList = [ 'Extremum', 'Mixed cubic and quadratic segments', 'Fractional Coordinates', 'Fractional transformation', 'Incorrect smooth connection', 'Empty segment', 'Vector on closepath', 'Collinear vectors', 'Semi-horizontal vector', 'Semi-vertical vector', 'Zero handle', ] self.errorList.insert(0, "select Red Arrow Error") self.heightOfTool = 360 self.widthOfTool = 200 self.w = FloatingWindow((self.widthOfTool, self.heightOfTool), "Red Arrow Error Filter") ### FloatingWindow #self.w.text = TextBox((10, 5, -10, 16), "...", sizeStyle='regular') self.w.select_test = PopUpButton((10, 10, -10, 16), self.errorList, sizeStyle='regular', callback=self.select_test) self.w.extremumToleranceText = TextBox((10, 35, -25, 18), "Extremum Tolerance", sizeStyle='small') self.w.extremumToleranceInput = EditText((160, 35, -10, 18), "2", sizeStyle='small') self.w.smooth_connection_max_distance_Text = TextBox((10, 57, -25, 18), "Smooth Connect max_dist", sizeStyle='small') self.w.smooth_connection_max_distance_Input = EditText((160, 55, -10, 18), "4", sizeStyle='small') self.w.collinear_vectors_max_distance_Text = TextBox((10, 77, -25, 18), "Collinear Vectors max_dist", sizeStyle='small') self.w.collinear_vectors_max_distance_Input = EditText((160, 75, -10, 18), "2", sizeStyle='small') self.w.report = EditText((10, 100, -10, -10), "...", sizeStyle='regular') self.w.report.enable(False) self.count = [] self.report = [] self.w.open() def select_test(self, sender): # options try: extremumTolerance = int(self.w.extremumToleranceInput.get()) except ValueError: self.w.extremumToleranceInput.set(2) extremumTolerance = 2 try: smooth_connection_max_distance_Input = int(self.w.smooth_connection_max_distance_Input.get()) except ValueError: self.w.smooth_connection_max_distance_Input.set(4) smooth_connection_max_distance_Input = 4 try: collinear_vectors_max_distance_Input = int(self.w.collinear_vectors_max_distance_Input.get()) except ValueError: self.w.collinear_vectors_max_distance_Input.set(2) collinear_vectors_max_distance_Input = 2 options = { "extremum_calculate_badness": True, "extremum_ignore_badness_below": extremumTolerance, "smooth_connection_max_distance": smooth_connection_max_distance_Input, "fractional_ignore_point_zero": True, "collinear_vectors_max_distance": collinear_vectors_max_distance_Input, } # a random number to change the mark color #randomNumber = random.random() # check if a font is open or not if CurrentFont(): font = CurrentFont() glyphnames = CurrentFont().keys() else: self.w.report.set("Open a Font") return # start the outline test selection = [] otp = OutlineTestPen(CurrentFont(), options) for n in glyphnames: otp.errors = [] g = font[n] g.drawPoints(otp) if otp.errors: for e in otp.errors: # convert error object to string errorString = str(e).split(" ")[0] # if the first part of error string = the first part of selection from PopUp if errorString == str(sender.getItems()[sender.get()]).split(" ")[0]: #g.mark = (1, randomNumber, 0.6, 1) selection.append(g.name) #print(e) font.selection = selection # output of glyphs with errors in UI result = dict((x,selection.count(x)) for x in set(selection)) formattedResult = ' '.join("%s=%r" % (key,val) for (key,val) in sorted(result.items())) self.w.report.set(formattedResult)