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 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 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 GroupSpacingWindow(BaseWindowController): ''' A tool to enable group spacing in the Space Center. - works with the selected glyph in the Space Center - shows a preview of all other glyphs in the same spacing group - transfer margins from current glyph to all glyphs in the same spacing group - supports measurements using the current beam ''' def __init__(self): padding = 10 lineHeight = 20 buttonHeight = 20 width = 123 height = lineHeight * 6 + buttonHeight * 4 + padding * 9 self.w = FloatingWindow((width, height), title='spacing') x = y = padding self.w.makeGroupButton = Button((x, y, -padding, buttonHeight), 'make group', callback=self.makeGroupCallback, sizeStyle='small') y += buttonHeight + padding self.w.side = RadioGroup((x, y, -padding, lineHeight), ['left', 'right'], isVertical=False, callback=self.updateViewsCallback, sizeStyle='small') self.w.side.set(0) y += lineHeight + padding self.w.copySpacingButton = Button((x, y, -padding, buttonHeight), 'copy margin', callback=self.copySpacingCallback, sizeStyle='small') y += buttonHeight + padding self.w.useBeam = CheckBox((x, y, -padding, lineHeight), 'use beam', callback=self.useBeamCallback, sizeStyle='small') y += lineHeight self.w.allLayers = CheckBox((x, y, -padding, lineHeight), 'all layers', callback=self.updateViewsCallback, sizeStyle='small') y += lineHeight + padding self.w.opacityLabel = TextBox((x, y, -padding, lineHeight), 'opacity:', sizeStyle='small') y += lineHeight self.w.opacity = Slider((x, y, -padding, lineHeight), value=0.4, minValue=0.0, maxValue=0.9, callback=self.updateViewsCallback, sizeStyle='small') y += lineHeight + padding self.w.exportButton = Button((x, y, -padding, buttonHeight), 'export…', callback=self.exportCallback, sizeStyle='small') y += buttonHeight + padding self.w.importButton = Button((x, y, -padding, buttonHeight), 'import…', callback=self.importCallback, sizeStyle='small') y += buttonHeight + padding self.w.verbose = CheckBox((x, y, -padding, lineHeight), 'verbose', value=True, sizeStyle='small') self.setUpBaseWindowBehavior() addObserver(self, "drawGlyphsInGroup", "spaceCenterDraw") self.w.getNSWindow().setTitlebarAppearsTransparent_(True) self.w.open() # dynamic attrs. @property def side(self): '''The selected spacing group side.''' return ['left', 'right'][int(self.w.side.get())] @property def useBeam(self): '''Use or not the beam to measure margins. Value taken from the checkbox.''' return self.w.useBeam.get() @property def allLayers(self): '''Set margins in all layers. Value taken from the checkbox.''' return self.w.allLayers.get() @property def beam(self): '''The beam’s y position in the Space Center.''' sp = CurrentSpaceCenter() if not sp: return return sp.beam() @property def opacity(self): '''The opacity of the fill color of glyphs in group.''' return self.w.opacity.get() @property def verbose(self): '''Output action info to the console.''' return self.w.verbose.get() # --------- # callbacks # --------- def makeGroupCallback(self, sender): '''Make a new spacing group with the selected glyph.''' glyph = CurrentGlyph() if not glyph: return if glyph.font is None: return prefix = PREFIX_LEFTSIDE if self.side == 'left' else PREFIX_RIGHTSIDE groupName = prefix + glyph.name if not groupName in glyph.font.groups: glyph.font.groups[groupName] = [glyph.name] def copySpacingCallback(self, sender): '''Copy margin from current glyph to other glyphs in left/right spacing class.''' glyph = CurrentGlyph() if not glyph: return if glyph.bounds is None: return if glyph.font is None: return siblings = getSiblings(glyph, self.side) if not siblings: return beam = self.beam if self.useBeam else None copyMargins(glyph, siblings, self.side, beam=beam, allLayers=self.allLayers, verbose=self.verbose) def useBeamCallback(self, sender): '''Show/hide the beam according to checkbox selection.''' S = CurrentSpaceCenter() if not S: return value = sender.get() options = S.glyphLineView.getDisplayStates() options['Beam'] = value S.glyphLineView.setDisplayStates(options) def exportCallback(self, sender): '''Export spacing groups to .json file.''' font = CurrentFont() filePath = PutFile(message='export spacing groups', fileName='spacingGroups.json') exportSpacingGroups(font, filePath) def importCallback(self, sender): '''Import spacing groups from .json file.''' font = CurrentFont() filePath = GetFile(message='import spacing groups', fileTypes=['json']) importSpacingGroups(font, filePath) def windowCloseCallback(self, sender): '''Remove observers when closing window.''' super().windowCloseCallback(sender) removeObserver(self, "spaceCenterDraw") def updateViewsCallback(self, sender): '''Update the Space Center.''' S = CurrentSpaceCenter() if not S: return S.glyphLineView.refresh() # --------- # observers # --------- def drawGlyphsInGroup(self, notification): '''Display all glyphs belonging to the same spacing group in the background.''' glyph = notification['glyph'] font = glyph.font if font is None: return siblings = getSiblings(glyph, self.side) if not siblings: return if not notification['selected']: return S = CurrentSpaceCenter() if not S: return inverse = S.glyphLineView.getDisplayStates()['Inverse'] # hide solid color glyph R, G, B, A = getDefault( "spaceCenterBackgroundColor") if not inverse else getDefault( "spaceCenterGlyphColor") bounds = glyph.bounds if bounds: save() fill(R, G, B, A) stroke(R, G, B, A) drawGlyph(glyph) restore() # draw side indicator save() stroke(1, 0, 0) strokeWidth(10) xPos = 0 if self.side == 'left' else glyph.width yMin = font.info.descender yMax = yMin + font.info.unitsPerEm line((xPos, yMin), (xPos, yMax)) restore() # draw glyph and siblings R, G, B, A = getDefault( "spaceCenterGlyphColor") if not inverse else getDefault( "spaceCenterBackgroundColor") alpha = (1.0 / len(siblings) + self.opacity) / 2 stroke(None) for glyphName in siblings: if glyphName not in glyph.layer: continue g = font[glyphName].getLayer(glyph.layer.name) save() if self.side == 'right': dx = glyph.width - g.width translate(dx, 0) color = (R, G, B, 0.4) if glyphName == glyph.name else (R, G, B, alpha) fill(*color) drawGlyph(g) restore()
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 TempEditGlyphs: key = 'com.hipertipo.tempEdit' width = 123*3 height = 640 padding = 10 lineHeight = 22 verbose = True _designspaces = {} _sources = {} def __init__(self): self.w = FloatingWindow( (self.width, self.height), title='tempEdit', minSize=(self.width*0.9, self.width*0.5)) self.designspaces = Group((0, 0, -0, -0)) x = y = p = self.padding self.designspaces.list = List( (x, y, -p, -p), [], allowsMultipleSelection=False, allowsEmptySelection=False, # editCallback=self.selectDesignspaceCallback, selectionCallback=self.selectDesignspaceCallback, enableDelete=True, otherApplicationDropSettings=dict( type=NSFilenamesPboardType, operation=NSDragOperationCopy, callback=self.dropCallback)) self.sources = Group((0, 0, -0, -0)) x = y = p = self.padding self.sources.list = List((x, y, -p, -p), []) self.glyphs = Group((0, 0, -0, -0)) x = y = p = self.padding textBoxHeight = -(self.lineHeight * 5) - (p * 3) self.glyphs.names = EditText( (x, y, -p, textBoxHeight), 'a b c A B C one two three') y = -(p + self.lineHeight) * 4 self.glyphs.importButton = Button( (x, y, -p, self.lineHeight), 'import glyphs', callback=self.importButtonCallback) y = -(p + self.lineHeight) * 3 self.glyphs.importMode = RadioGroup( (x, y, -p, self.lineHeight), ['fonts → fonts', 'fonts → glyphs', 'fonts → layers'], sizeStyle='small', isVertical=False) self.glyphs.importMode.set(2) y = -(p + self.lineHeight) * 2 self.glyphs.exportButton = Button( (x, y, -p, self.lineHeight), 'export selected glyphs', callback=self.exportButtonCallback) y = -(p + self.lineHeight) self.glyphs.progress = ProgressBar((x, y, -p, self.lineHeight)) descriptions = [ dict(label="designspaces", view=self.designspaces, size=self.lineHeight*5, minSize=self.lineHeight*3, collapsed=False, canResize=True), dict(label="sources", view=self.sources, size=self.lineHeight*8, minSize=self.lineHeight*6, collapsed=False, canResize=True), dict(label="glyphs", view=self.glyphs, size=self.lineHeight*10, minSize=self.lineHeight*8, collapsed=False, canResize=True), ] self.w.accordionView = AccordionView((0, 0, -0, -0), descriptions) self.w.getNSWindow().setTitlebarAppearsTransparent_(True) self.w.open() # ------------- # dynamic attrs # ------------- @property def glyphNames(self): return self.glyphs.names.get().split() @property def selectedDesignspace(self): selection = self.designspaces.list.getSelection() designspaces = self.designspaces.list.get() return [designspace for i, designspace in enumerate(designspaces)] \ if len(designspaces) else None @property def selectedMasters(self): selection = self.sources.list.getSelection() masters = self.sources.list.get() return [master for i, master in enumerate(masters) if i in selection] @property def glyphSetPathKey(self): return f'{self.key}.glyphSetPath' @property def importMode(self): return self.glyphs.importMode.get() # --------- # callbacks # --------- def selectDesignspaceCallback(self, sender): selection = sender.getSelection() designSpaces = self.designspaces.list.get() # delete current list posSize = self.sources.list.getPosSize() del self.sources.list # list of sources is empty if not selection or not len(designSpaces): items = [] self.sources.list = List(posSize, []) return # get sources from selected designspace designSpaceLabel = [D for i, D in enumerate(designSpaces) if i in selection][0] designSpacePath = self._designspaces[designSpaceLabel] designSpace = DesignSpaceDocument() designSpace.read(designSpacePath) # get column descriptions titles = ['name'] titles += [axis.name for axis in designSpace.axes] descriptions = [{"title": D} for D in titles] # make list items self._sources = {} items = [] for source in designSpace.sources: sourceName = os.path.splitext(os.path.split(source.path)[-1])[0] self._sources[sourceName] = source.path item = { 'name' : sourceName } for axis in designSpace.axes: item[axis.name] = source.location[axis.name] items.append(item) # create list UI with items self.sources.list = List( posSize, items, columnDescriptions=descriptions, allowsMultipleSelection=True, enableDelete=False) def dropCallback(self, sender, dropInfo): isProposal = dropInfo["isProposal"] existingPaths = sender.get() paths = dropInfo["data"] paths = [path for path in paths if path not in existingPaths] paths = [path for path in paths if os.path.splitext(path)[-1].lower() == '.designspace'] if not paths: return False if not isProposal: for path in paths: label = os.path.splitext(os.path.split(path)[-1])[0] self._designspaces[label] = path self.designspaces.list.append(label) self.designspaces.list.setSelection([0]) return True def importButtonCallback(self, sender): if not len(self.selectedMasters): return if self.verbose: print('importing glyphs from selected sources...\n') # mode 0 : fonts → fonts if self.importMode == 0: for master in self.selectedMasters: ufoPath = self._sources[master['name']] srcFont = OpenFont(ufoPath, showInterface=False) tmpFont = NewFont(familyName=srcFont.info.familyName, styleName=srcFont.info.styleName, showInterface=False) glyphsFolder = os.path.join(ufoPath, 'glyphs') ufoName = splitall(glyphsFolder)[-2] if self.verbose: print(f'\t{ufoName}:') for glyphName in self.glyphNames: if glyphName not in srcFont: if self.verbose: print(f'\t\t{glyphName} not in font.') continue srcGlyph = srcFont[glyphName] if srcGlyph.components: for component in srcGlyph.components: if not component.baseGlyph in tmpFont: if self.verbose: print(f'\t\timporting {component.baseGlyph} ({glyphName})...') tmpFont[component.baseGlyph] = srcFont[component.baseGlyph] tmpFont[component.baseGlyph].lib[self.glyphSetPathKey] = glyphsFolder if self.verbose: print(f'\t\timporting {glyphName}...') tmpFont[glyphName] = srcGlyph tmpFont[glyphName].lib[self.glyphSetPathKey] = glyphsFolder tmpFont.openInterface() if self.verbose: print() # mode 1 : fonts → glyphs if self.importMode == 1: tmpFont = CurrentFont() if tmpFont is None: tmpFont = NewFont(familyName='tempEdit') for i, master in enumerate(self.selectedMasters): ufoPath = self._sources[master['name']] if not os.path.exists(ufoPath): if self.verbose: print(f'source file does not exist: {ufoPath}') continue srcFont = OpenFont(ufoPath, showInterface=False) glyphsFolder = os.path.join(ufoPath, 'glyphs') ufoName = splitall(glyphsFolder)[-2] glyphNameExtension = os.path.splitext(ufoName)[0] for glyphName in self.glyphNames: tmpGlyphName = f'{glyphName}.{glyphNameExtension}' if glyphName not in srcFont: if self.verbose: print(f'\t\tcreating {glyphName}...') tmpFont.newGlyph(tmpGlyphName) else: srcGlyph = srcFont[glyphName] for component in srcGlyph.components: if component.baseGlyph not in tmpFont: if component.baseGlyph not in srcFont: continue if self.verbose: print(f'\t\timporting {component.baseGlyph} ({glyphName})...') tmpBaseGlyph = f'{component.baseGlyph}.{glyphNameExtension}' tmpFont[tmpBaseGlyph] = srcFont[component.baseGlyph] tmpFont[tmpBaseGlyph].lib[self.glyphSetPathKey] = glyphsFolder if self.verbose: print(f'\t\timporting {glyphName}...') tmpFont.newGlyph(tmpGlyphName) tmpFont[tmpGlyphName].appendGlyph(srcGlyph) tmpFont[tmpGlyphName].width = srcGlyph.width tmpFont[tmpGlyphName].lib[self.glyphSetPathKey] = glyphsFolder if 'background' not in tmpFont.layerOrder: tmpFont.newLayer('background') if self.verbose: print() # mode 2 : fonts → layers else: tmpFont = CurrentFont() if tmpFont is None: tmpFont = NewFont(familyName='tempEdit') for i, master in enumerate(self.selectedMasters): ufoPath = self._sources[master['name']] if not os.path.exists(ufoPath): if self.verbose: print(f'source file does not exist: {ufoPath}') continue srcFont = OpenFont(ufoPath, showInterface=False) glyphsFolder = os.path.join(ufoPath, 'glyphs') ufoName = splitall(glyphsFolder)[-2] layerName = os.path.splitext(ufoName)[0] tmpLayer = tmpFont.newLayer(layerName) if self.verbose: print(f'\t{ufoName}:') if i == 0: tmpFont.defaultLayer = tmpLayer if 'foreground' in tmpFont.layerOrder: tmpFont.removeLayer('foreground') for glyphName in self.glyphNames: if glyphName not in srcFont: if self.verbose: print(f'\t\tcreating {glyphName}...') tmpLayer.newGlyph(glyphName) else: srcGlyph = srcFont[glyphName] for component in srcGlyph.components: if component.baseGlyph not in tmpLayer: if component.baseGlyph not in srcFont: continue if self.verbose: print(f'\t\timporting {component.baseGlyph} ({glyphName})...') tmpLayer[component.baseGlyph] = srcFont[component.baseGlyph] tmpLayer[component.baseGlyph].lib[self.glyphSetPathKey] = glyphsFolder if self.verbose: print(f'\t\timporting {glyphName}...') tmpLayer[glyphName] = srcGlyph tmpLayer[glyphName].width = srcGlyph.width tmpLayer[glyphName].lib[self.glyphSetPathKey] = glyphsFolder if self.verbose: print() if self.verbose: print('...done.\n') def exportButtonCallback(self, sender): f = CurrentFont() if f is None: return if self.verbose: print('exporting selected glyphs back to their sources...\n') for glyphName in f.selectedGlyphNames: if self.importMode == 1: glyph = f[glyphName].getLayer('foreground') if self.glyphSetPathKey not in glyph.lib: continue glyphsFolder = glyph.lib[self.glyphSetPathKey] ufoName = splitall(glyphsFolder)[-2] glyphNameExtension = os.path.splitext(ufoName)[0] glyphNameParts = glyphName.split('.') if not (len(glyphNameParts) > 1 and glyphNameParts[-1] == os.path.splitext(ufoName)[0]): print(f'{glyphName} does not have the expected glyph name extension, skipping...') continue if self.verbose: print(f'\twriting {glyphName} to {ufoName}...') outputGlyphName = '.'.join(glyphNameParts[:-1]) glyphSet = GlyphSet(glyphsFolder, validateWrite=True) glyphSet.writeGlyph(outputGlyphName, glyph.naked(), glyph.drawPoints) glyphSet.writeContents() else: for layerName in f.layerOrder: glyph = f[glyphName].getLayer(layerName) if self.glyphSetPathKey not in glyph.lib: continue glyphsFolder = glyph.lib[self.glyphSetPathKey] # mode 0 if not '.ufoz' in glyphsFolder: glyphSet = GlyphSet(glyphsFolder, validateWrite=True) ufoName = splitall(glyphsFolder)[-2] if self.verbose: print(f'\twriting {glyphName} to {ufoName}...') glyphSet.writeGlyph(glyphName, glyph.naked(), glyph.drawPoints) glyphSet.writeContents() # mode 2 else: ufoPath = os.path.dirname(glyphsFolder) ufoName = splitall(ufoPath)[-1] dstFont = OpenFont(ufoPath, showInterface=False) if self.verbose: print(f'\twriting {glyphName} to {ufoName}...') dstFont.insertGlyph(glyph, name=glyph.name) dstFont.save() dstFont.close() if self.verbose: print() print('...done.\n')