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()
Example #6
0
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
Example #7
0
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')