Пример #1
0
class ColdtypeSerializer(BaseWindowController):
    def __init__(self):
        self.w = FloatingWindow((300, 40),
                                "Coldtype Serializer",
                                minSize=(123, 200))
        self.w.globalToggle = CheckBox((10, 10, -10, 20),
                                       'serialize?',
                                       value=True)
        self.output = Path("~/robofont-coldtype.json").expanduser().absolute()
        addObserver(self, "shouldDraw", "draw")

        self.setUpBaseWindowBehavior()
        self.w.open()

    def windowCloseCallback(self, sender):
        removeObserver(self, 'draw')
        super(ColdtypeSerializer, self).windowCloseCallback(sender)

    def shouldDraw(self, notification):
        if not self.w.globalToggle.get():
            return
        glyph = notification['glyph']
        data_out = {"name": glyph.name, "layers": {}}
        for g in glyph.layers:
            rp = RecordingPen()
            g.draw(rp)
            data_out["layers"][g.layer.name] = dict(value=rp.value,
                                                    width=g.width)
        self.output.write_text(json.dumps(data_out))
        print("> wrote glyph data", glyph.name)
Пример #2
0
class highlightPointsOnMetrics(BaseWindowController):
    def __init__(self):
        self.w = FloatingWindow((135, 40), "", minSize=(123, 200))

        # a checkbox to turn the tool on/off
        self.w.showPoints = CheckBox((10, 10, -10, 20),
                                     'highlight points',
                                     value=True)

        # add an observer to the drawPreview event
        addObserver(self, "highlightPoints", "draw")

        # open window
        self.setUpBaseWindowBehavior()
        self.w.open()

    def windowCloseCallback(self, sender):
        # remove observer when window is closed
        removeObserver(self, 'draw')
        super(highlightPointsOnMetrics, self).windowCloseCallback(sender)

    def highlightPoints(self, info):
        # check if checkbox is selected
        if not self.w.showPoints.get():
            return

        # get the current glyph
        glyph = info["glyph"]
        sc = info['scale']

        # Anything more than 3 could be considered an intentional overshoot?
        rang = 3

        asc = f.info.ascender
        xhe = f.info.xHeight
        cap = f.info.capHeight
        dsc = f.info.descender
        size = 8 * sc
        # draw highlight
        stroke(None)
        if glyph is not None:
            for c in glyph:
                for s in c:
                    for p in s:
                        if p.y == asc or p.y == xhe or p.y == cap or p.y == dsc or p.y == 0:
                            pass
                        else:
                            if (asc + -rang <= p.y <= asc + rang) or (
                                    xhe + -rang <= p.y <= xhe + rang) or (
                                        cap + -rang <= p.y <= cap + rang) or (
                                            dsc + -rang <= p.y <= dsc +
                                            rang) or (-rang <= p.y <= rang):

                                # fill(1, 0, 0, .6)

                                fill(None)
                                stroke(1.0, 0.0, 0.0, .5)
                                strokeWidth(7 * sc)
                                oval(p.x - size / 2, p.y - size / 2, size,
                                     size)
Пример #3
0
    def __init__(self):

        # base window
        self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, PLUGIN_HEIGHT))

        jumpingY = MARGIN_VER
        self.w.libChoice = PopUpButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['PopUpButtonRegularHeight']), ['A', 'B', 'C'],
            callback=self.libChoiceCallback)

        jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER
        self.w.addButton = SquareButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH * .6, SQUARE_BUTTON_HEIGHT),
            'add stem',
            callback=self.addButtonCallback)

        self.w.checkBoxStar = CheckBoxStar(
            (MARGIN_HOR + MARGIN_VER + NET_WIDTH * .6, jumpingY,
             NET_WIDTH * .35, NET_WIDTH * .35),
            callback=self.checkBoxStarCallback)

        jumpingY += SQUARE_BUTTON_HEIGHT + MARGIN_VER
        self.w.removeButton = SquareButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH * .6, SQUARE_BUTTON_HEIGHT),
            'remove stem',
            callback=self.removeButtonCallback)

        # lit up!
        self.w.open()
Пример #4
0
    def __init__(self, callback):
        super(JumpToLineWindow, self).__init__()
        self.callback = callback

        # init the window
        self.w = FloatingWindow((WINDOW_WIDTH, 0), 'Jump to line')

        # edit text caption
        jumpingY = MARGIN_TOP
        self.w.caption = TextBox((MARGIN_LFT, jumpingY + 3, NET_WIDTH * .6,
                                  vanillaControlsSize['TextBoxRegularHeight']),
                                 'Jump to line:')

        self.w.lineEdit = EditText(
            (MARGIN_LFT + NET_WIDTH * .6, jumpingY, -MARGIN_RGT,
             vanillaControlsSize['EditTextRegularHeight']),
            continuous=False)

        jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_INT
        self.w.cancelButton = Button(
            (-(BUTTON_WIDTH * 2 + MARGIN_INT + MARGIN_RGT), jumpingY,
             BUTTON_WIDTH, vanillaControlsSize['ButtonRegularHeight']),
            'Cancel',
            callback=self.cancelButtonCallback)

        self.w.okButton = Button(
            (-(BUTTON_WIDTH + MARGIN_RGT), jumpingY, BUTTON_WIDTH,
             vanillaControlsSize['ButtonRegularHeight']),
            'Ok',
            callback=self.okButtonCallback)

        jumpingY += vanillaControlsSize['ButtonRegularHeight'] + MARGIN_BTM
        self.setUpBaseWindowBehavior()
        self.w.resize(WINDOW_WIDTH, jumpingY)
Пример #5
0
    def __init__(self, options, callback):
        super(ChooseExceptionWindow, self).__init__()
        self.options = options
        self.callback = callback
        self.whichException = options[0]

        self.w = FloatingWindow((300, 120), 'Choose exception')

        self.w.optionsRadio = RadioGroup(
            (MARGIN, MARGIN, -MARGIN, len(options) * 20),
            options,
            callback=self.optionsCallback)
        self.w.optionsRadio.set(0)

        self.w.cancel = Button(
            (-(90 * 2 + MARGIN * 2),
             -(vanillaControlsSize['ButtonRegularHeight'] + MARGIN), 90,
             vanillaControlsSize['ButtonRegularHeight']),
            'Cancel',
            callback=self.cancelCallback)

        self.w.submit = Button(
            (-(90 + MARGIN),
             -(vanillaControlsSize['ButtonRegularHeight'] + MARGIN), 90,
             vanillaControlsSize['ButtonRegularHeight']),
            'Submit',
            callback=self.submitCallback)
        self.setUpBaseWindowBehavior()
Пример #6
0
class ColorThemesDialog:

    colorThemesFolder = os.path.join(os.getcwd(), 'themes')

    def __init__(self):
        self.w = FloatingWindow((246, 300), "CodeColors")
        x = y = p = 10
        self.w.colorThemesList = List((x, y, -p, -p),
                                      sorted(self.colorThemes.keys()),
                                      selectionCallback=self.selectionCallback,
                                      allowsMultipleSelection=False,
                                      allowsEmptySelection=False)
        self.w.open()

    @property
    def colorThemes(self):
        return getColorThemes(self.colorThemesFolder)

    @property
    def colorTheme(self):
        i = self.w.colorThemesList.getSelection()[0]
        colorThemeName = sorted(self.colorThemes.keys())[i]
        return self.colorThemes[colorThemeName]

    def selectionCallback(self, sender):
        setColorTheme(self.colorTheme)
Пример #7
0
    def __init__(self):
        self.glyph = None  # Typical RoboFont function
        self.updating = False

        pad = 10
        leading = 32
        y = pad
        w = 300
        h = 400
        buttonWidth = 100
        buttonHeight = 48

        self.w = FloatingWindow((100, 100, w, h), 'DemoWindowTool')
        self.w.doDraw = CheckBox((pad, y, 100, 24),
                                 'Draw',
                                 callback=self.doDrawCallback)
        y += leading
        self.w.mySlider = Slider((pad, y, -pad, 24),
                                 minValue=0,
                                 maxValue=2000,
                                 value=0,
                                 tickMarkCount=10,
                                 callback=self.mySliderCallback)
        y = self.w.saveFont = Button((-buttonWidth - pad, -buttonHeight - pad,
                                      buttonWidth, buttonHeight),
                                     'Save',
                                     callback=self.saveFontCallback)

        addObserver(self, "currentGlyphChanged",
                    "currentGlyphChanged")  # Subscribe to application event
        addObserver(self, 'draw', 'draw')
        addObserver(self, 'drawBackground', 'drawBackground')

        self.w.bind('close', self.windowCloseCallback)
        self.w.open()
Пример #8
0
        def __init__(self):
            self.w = FloatingWindow((100, 100), "Tester")
            self.w.bind("close", self.closeCB)

            self.guideView = None

            addObserver(self, "glyphWindowOpenCB", "glyphWindowDidOpen")
Пример #9
0
    def showWindow_(self, sender):
        if Glyphs.font is None:
            self.helperWindow(self.warningNoFontOpen)
        elif len(Glyphs.font.masters) < 2:
            self.helperWindow(self.warningOnlyOneMaster)
        else:
            mastersList = []
            for m in Glyphs.font.masters:
                mastersList.append(m.name)
            currentMasterIndex = Glyphs.font.masterIndex

            self.windowWidth = 250
            self.windowHeight = 25 * len(mastersList) + 23 + 30
            self.w = FloatingWindow((self.windowWidth, self.windowHeight),
                                    self.name)
            self.w.radiomasters = RadioGroup(
                (10, 10, -10, 25 * len(mastersList)),
                mastersList,
                callback=self.changeMaster)
            self.w.slider = Slider((10, -35, -10, 23),
                                   tickMarkCount=len(mastersList),
                                   stopOnTickMarks=True,
                                   value=currentMasterIndex,
                                   minValue=0,
                                   maxValue=len(mastersList) - 1,
                                   sizeStyle="small",
                                   continuous=False,
                                   callback=self.changeMasterSlider)

            self.w.open()
Пример #10
0
    def __init__(self, glyph):

        # if glyph is None, show a message
        if glyph is None:
            Message('no glyph selected',
                    title='moveTool',
                    informativeText='Please select one glyph first!')
            return

        # store the glyph and initial move values as object attributes
        self.glyph = glyph
        self.moveXTRA = 0

        # create a floating window
        self.w = FloatingWindow((200, 74), "move %s" % self.glyph.name)

        # add a slider for moving in the x axis
        self.w.sliderXTRA = Slider((10, 10, -10, 22),
                                   value=0,
                                   maxValue=200,
                                   minValue=0,
                                   callback=self.adjustXTRA)

        # self.w.sliderXOPQ = Slider(
        #         (10, 10, -10, 22),
        #         value=0, maxValue=200, minValue=-200,
        #         callback=self.adjust)

        # open the window

        self.w.open()
Пример #11
0
    def __init__(self):
        self.searchResults = []
        self.selectedChars = ""

        self.w = FloatingWindow((300, 400), "Unicode Picker", minSize=(250, 300),
                                autosaveName="UnicodePicker")
        y = 15
        self.w.searchField = EditText((20, y, -20, 25),
                                      placeholder="Search Unicode name or value",
                                      callback=self.searchTextChanged_)

        y += 40
        columnDescriptions = [
            dict(title="char", width=40,
                 cell=makeTextCell(align="center", font=AppKit.NSFont.systemFontOfSize_(14))),
            dict(title="unicode", width=60, cell=makeTextCell(align="right")),
            dict(title="name"),
        ]
        self.w.unicodeList = List((0, y, 0, -100), [], columnDescriptions=columnDescriptions,
                                  rowHeight=18,
                                  selectionCallback=self.listSelectionChanged_,
                                  doubleClickCallback=self.listDoubleClickCallback_)

        y = -95
        self.w.unicodeText = TextBox((20, y, -10, 55), "")
        self.w.unicodeText._nsObject.cell().setFont_(AppKit.NSFont.systemFontOfSize_(36))
        self.w.unicodeText._nsObject.cell().setLineBreakMode_(AppKit.NSLineBreakByTruncatingMiddle)
        y += 55
        self.w.copyButton = Button((20, y, 120, 25), "Copy", callback=self.copy_)
        self.w.copyButton.enable(False)

        self.w.open()
        self.w._window.setWindowController_(self)
        self.w._window.setBecomesKeyOnlyIfNeeded_(False)
        self.w._window.makeKeyWindow()
Пример #12
0
class JumpToLineWindow(BaseWindowController):

    lineNumber = None

    def __init__(self, callback):
        super(JumpToLineWindow, self).__init__()
        self.callback = callback

        # init the window
        self.w = FloatingWindow((WINDOW_WIDTH, 0), 'Jump to line')

        # edit text caption
        jumpingY = MARGIN_TOP
        self.w.caption = TextBox((MARGIN_LFT, jumpingY + 3, NET_WIDTH * .6,
                                  vanillaControlsSize['TextBoxRegularHeight']),
                                 'Jump to line:')

        self.w.lineEdit = EditText(
            (MARGIN_LFT + NET_WIDTH * .6, jumpingY, -MARGIN_RGT,
             vanillaControlsSize['EditTextRegularHeight']),
            continuous=False)

        jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_INT
        self.w.cancelButton = Button(
            (-(BUTTON_WIDTH * 2 + MARGIN_INT + MARGIN_RGT), jumpingY,
             BUTTON_WIDTH, vanillaControlsSize['ButtonRegularHeight']),
            'Cancel',
            callback=self.cancelButtonCallback)

        self.w.okButton = Button(
            (-(BUTTON_WIDTH + MARGIN_RGT), jumpingY, BUTTON_WIDTH,
             vanillaControlsSize['ButtonRegularHeight']),
            'Ok',
            callback=self.okButtonCallback)

        jumpingY += vanillaControlsSize['ButtonRegularHeight'] + MARGIN_BTM
        self.setUpBaseWindowBehavior()
        self.w.resize(WINDOW_WIDTH, jumpingY)

    def get(self):
        try:
            self.lineNumber = int(self.w.lineEdit.get())
        except ValueError:
            self.w.lineEdit.set('')
            self.lineNumber = None
        return self.lineNumber

    def enable(self, value):
        if value is True:
            self.w.center()
            self.w.show()
        else:
            self.w.hide()

    def cancelButtonCallback(self, sender):
        self.w.show(False)

    def okButtonCallback(self, sender):
        self.callback(self)
Пример #13
0
    def __init__(self):
        '''Initialize the dialog.'''
        x = y = padding = 10
        buttonHeight = 20
        windowWidth = 400

        rows = 4.5

        self.w = FloatingWindow(
            (windowWidth, buttonHeight * rows + padding * (rows)),
            "Glyph Fax Machine")

        self.fonts = {}

        # self.w.textBox = TextBox((x, y, -padding, buttonHeight), "Glyphs to Copy")

        # y += buttonHeight

        self.w.editText = EditText(
            (x, y, -padding, buttonHeight * 2 + padding),
            placeholder="Space-separated list of glyphs to copy")

        y += buttonHeight * 2 + padding * 2

        # self.w.overwriteGlyphsCheckBox = CheckBox((x, y, -padding, buttonHeight), "Overwrite Glyphs", value=False, callback=self.overwriteGlyphsOptions)

        # y += buttonHeight + padding

        self.w.overwriteNormalWidthGlyphsCheckBox = CheckBox(
            (x, y, -padding, buttonHeight),
            "Overwrite 600w Glyphs",
            value=False,
            sizeStyle="small")
        # self.w.overwriteNormalWidthGlyphsCheckBox.show(False)

        self.w.overwriteAdjustedWidthGlyphsCheckBox = CheckBox(
            (windowWidth * 0.4, y, -padding, buttonHeight),
            "Overwrite non-600w Glyphs",
            value=False,
            sizeStyle="small")
        # self.w.overwriteAdjustedWidthGlyphsCheckBox.show(False)
        self.w.colorWell = ColorWell(
            (windowWidth * 0.85, y, -padding, buttonHeight),
            color=NSColor.orangeColor())

        y += buttonHeight + padding

        self.w.sans2mono = Button(
            (x, y, windowWidth / 3 - padding / 2, buttonHeight),
            "Sans → Mono",
            callback=self.sans2monoCallback)

        self.w.mono2sans = Button(
            (windowWidth / 3 + padding, y, -padding, buttonHeight),
            "Mono → Sans",
            callback=self.mono2SansCallback)

        self.w.open()
Пример #14
0
 def __init__(self):
     self.w = FloatingWindow((246, 300), "CodeColors")
     x = y = p = 10
     self.w.colorThemesList = List((x, y, -p, -p),
                                   sorted(self.colorThemes.keys()),
                                   selectionCallback=self.selectionCallback,
                                   allowsMultipleSelection=False,
                                   allowsEmptySelection=False)
     self.w.open()
Пример #15
0
 def __init__(self, attributes, callback, document=None):
     self._callback = callback
     self._attributes = None
     self.w = FloatingWindow((250, 50))
     self.buildUI(attributes)
     self.w.open()
     if document:
         self.w.assignToDocument(document)
     self.w.setTitle("Variables")
Пример #16
0
    def __init__(self):
        super(AccentedMaker, self).__init__()
        self.initLogger()

        self.fontOptions = ['All Fonts', 'Current Font'] + AllFonts()
        self.whichFont = self.fontOptions[0]
        self.pluginHeight = PLUGIN_HEIGHT

        self.loadAccentedData()
        self.parseGlyphListsFromAccentedData()

        firstKey = self.glyphLists[self.whichAction].keys()[0]
        self.whichGlyphList = self.glyphLists[self.whichAction][firstKey]

        self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, self.pluginHeight),
                                PLUGIN_TITLE)

        self.w.sharedCtrls = SharedCtrls(
            (MARGIN_HOR, MARGIN_VER, NET_WIDTH, 104),
            fontOptions=self.fontOptions,
            whichFont=self.whichFont,
            actions=self.actions,
            whichAction=self.whichAction,
            glyphLists=self.glyphLists,
            whichGlyphList=self.whichGlyphList,
            markColor=self.markColor,
            markEditedGlyphs=self.markEditedGlyphs,
            callback=self.sharedCtrlsCallback)
        self.w.separationLine = HorizontalLine(
            (MARGIN_HOR, self.w.sharedCtrls.getPosSize()[3] + MARGIN_ROW,
             NET_WIDTH, vanillaControlsSize['HorizontalLineThickness']))

        dependantCtrlsHgt = MARGIN_VER + self.w.sharedCtrls.getPosSize(
        )[3] + MARGIN_ROW
        self.w.anchorsCtrls = AnchorsCtrls(
            (MARGIN_HOR, dependantCtrlsHgt, NET_WIDTH, 76),
            callbackAttrs=self.anchorsVarsCallback,
            placeCallback=self.anchorsPlaceCallback,
            deleteCallback=self.anchorsDeleteCallback)

        self.w.buildingCtrls = BuildingCtrls(
            (MARGIN_HOR, dependantCtrlsHgt, NET_WIDTH, 50),
            self.uppercaseAccents,
            callbackAttrs=self.buildingVarsCallback,
            callbackCheck=self.checkAccentedCallback,
            callbackBuild=self.buildAccentedCallback)
        self.w.buildingCtrls.show(False)

        addObserver(self, 'updateFontOptions', "newFontDidOpen")
        addObserver(self, 'updateFontOptions', "fontDidOpen")
        addObserver(self, 'updateFontOptions', "fontWillClose")
        self.w.bind("close", self.windowCloseCallback)
        self.setUpBaseWindowBehavior()
        self.adjustPluginHeight()
        self.w.open()
Пример #17
0
    def __init__(self):
        self.fontTarget = FONT_TARGET_OPTIONS[0]
        self.glyphTarget = GLYPH_TARGET_OPTIONS[0]
        self.gridSize = 4

        self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, 400), PLUGIN_TITLE)
        jumpingY = MARGIN_VER

        # font target
        self.w.fontTargetPopUp = PopUpButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            FONT_TARGET_OPTIONS,
            callback=self.fontTargetPopUpCallback)
        jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER

        # glyph target
        self.w.glyphTargetPopUp = PopUpButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            GLYPH_TARGET_OPTIONS,
            callback=self.glyphTargetPopUpCallback)
        jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER

        # grid size captions
        self.w.gridSizeCaption = TextBox(
            (MARGIN_HOR, jumpingY + 2, NET_WIDTH * .32,
             vanillaControlsSize['TextBoxRegularHeight']), 'Grid Size:')

        # grid size edit
        self.w.gridSizeEdit = EditText(
            (MARGIN_HOR + NET_WIDTH * .32, jumpingY, NET_WIDTH * .3,
             vanillaControlsSize['EditTextRegularHeight']),
            text='{:d}'.format(self.gridSize),
            callback=self.gridSizeEditCallback)
        jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER

        self.w.moveBcpHandlesCheck = CheckBox(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['CheckBoxRegularHeight']),
            'move bcp handles',
            value=self.bcpHandlesFit,
            callback=self.moveBcpHandlesCheckCallback)
        jumpingY += vanillaControlsSize['CheckBoxRegularHeight'] + MARGIN_VER

        # fit button
        self.w.fitButton = Button((MARGIN_HOR, jumpingY, NET_WIDTH,
                                   vanillaControlsSize['ButtonRegularHeight']),
                                  'Fit!',
                                  callback=self.fitButtonCallback)
        jumpingY += vanillaControlsSize['ButtonRegularHeight'] + MARGIN_VER

        self.w.setPosSize((0, 0, PLUGIN_WIDTH, jumpingY))
        self.w.open()
Пример #18
0
    def __init__(self):
        self.transferList = NAME_2_GLYPHLIST[GLYPHLISTS_OPTIONS[0]]
        self.target = TARGET_OPTIONS[0]

        self.w = FloatingWindow((0, 0, PLUGIN_WIDTH, 400), PLUGIN_TITLE)
        jumpingY = MARGIN_VER

        # target fonts
        self.w.targetFontsPopUp = PopUpButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            TARGET_OPTIONS,
            callback=self.targetFontsPopUpCallback)
        jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER

        # transfer lists pop up
        self.w.glyphListPopUp = PopUpButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            GLYPHLISTS_OPTIONS,
            callback=self.glyphListPopUpCallback)
        jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER

        # offset caption
        self.w.offsetCaption = TextBox(
            (MARGIN_HOR, jumpingY + 2, NET_WIDTH * .22,
             vanillaControlsSize['TextBoxRegularHeight']), 'Offset:')

        # offset edit text
        self.w.offsetEdit = EditText(
            (MARGIN_HOR + NET_WIDTH * .25, jumpingY, NET_WIDTH * .35,
             vanillaControlsSize['EditTextRegularHeight']),
            continuous=False,
            callback=self.offsetEditCallback)
        self.w.offsetEdit.set('%d' % self.verticalOffset)
        jumpingY += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER

        # clean button
        self.w.cleanButton = Button(
            (MARGIN_HOR, jumpingY, NET_WIDTH * .45,
             vanillaControlsSize['ButtonRegularHeight']),
            'Clean',
            callback=self.cleanButtonCallback)

        # run button
        self.w.runButton = Button(
            (MARGIN_HOR + NET_WIDTH * .55, jumpingY, NET_WIDTH * .45,
             vanillaControlsSize['ButtonRegularHeight']),
            'Run!',
            callback=self.runButtonCallback)
        jumpingY += vanillaControlsSize['ButtonRegularHeight'] + MARGIN_VER

        self.w.setPosSize((0, 0, PLUGIN_WIDTH, jumpingY))
        self.w.open()
Пример #19
0
    def __init__(self):
        self.w = FloatingWindow((300, 40),
                                "Coldtype Serializer",
                                minSize=(123, 200))
        self.w.globalToggle = CheckBox((10, 10, -10, 20),
                                       'serialize?',
                                       value=True)
        self.output = Path("~/robofont-coldtype.json").expanduser().absolute()
        addObserver(self, "shouldDraw", "draw")

        self.setUpBaseWindowBehavior()
        self.w.open()
Пример #20
0
 def spaceCenterOpenCallback(self, notification):
     if (not self.popupOpen) and (len(self.metricsGroups) > 0):
         self.w = FloatingWindow((160, 36), 'Group Spacing')
         self.w.activateGroups = CheckBox(
             (9, -27, 151, 18),
             "Activate Group spacing",
             value=self.enableGroupSpacing,
             callback=self.enableGroupSpacingCallback,
             sizeStyle="small")
         self.w.bind('close', self.windowCloseCallback)
         self.w.open()
         self.popupOpen = True
Пример #21
0
    def __init__(self):
        self.w = FloatingWindow((135, 40), "", minSize=(123, 200))

        # a checkbox to turn the tool on/off
        self.w.showPoints = CheckBox((10, 10, -10, 20),
                                     'highlight points',
                                     value=True)

        # add an observer to the drawPreview event
        addObserver(self, "highlightPoints", "draw")

        # open window
        self.setUpBaseWindowBehavior()
        self.w.open()
Пример #22
0
    def __init__(self):
        self.valuesPrefsKey = prefsKey + ".delta." + basename(
            Glyphs.font.filepath)
        # UI metrics
        spacing = 8
        height = 22
        # calculate window height
        minWinSize = (220,
                      120 + (len(Glyphs.font.masters) * (height + spacing)))
        # create UI window
        self.w = FloatingWindow(minWinSize,
                                "Adjust sidebearings",
                                minSize=minWinSize,
                                maxSize=(500, 500),
                                autosaveName=prefsKey + ".win")
        # layout UI controls
        y = 16
        self.w.label = TextBox((16, y, -16, height),
                               "Sidebearing delta adjustment:")
        y += height + spacing

        inputWidth = 64
        for master in Glyphs.font.masters:
            setattr(self.w, "deltaLabel%s" % master.id,
                    TextBox((16, y, -16 - inputWidth, height), master.name))
            setattr(self.w, "deltaInput%s" % master.id,
                    EditText((-16 - inputWidth, y, -16, height), "16"))
            # print("self.w.deltaInputs[master.id]", getattr(self.w, "deltaInput%s" % master.id))
            y += height + spacing

        self.w.submitButton = Button((16, -16 - height, -16, height),
                                     "Adjust all sidebearings",
                                     callback=self.onSubmit)
        # finalize UI
        self.w.setDefaultButton(self.w.submitButton)
        self.loadPreferences()
        self.w.bind("close", self.savePreferences)

        # make sure window is large enough to show all masters
        x, y, w, h = self.w.getPosSize()
        if w < minWinSize[0] and h < minWinSize[1]:
            self.w.setPosSize((x, y, minWinSize[0], minWinSize[1]),
                              animate=False)
        elif w < minWinSize[0]:
            self.w.setPosSize((x, y, minWinSize[0], h), animate=False)
        elif h < minWinSize[1]:
            self.w.setPosSize((x, y, w, minWinSize[1]), animate=False)

        self.w.open()
        self.w.makeKey()
Пример #23
0
 def _buildUI(self):
     w = FloatingWindow((300, 340), "Rotated Glyph Preview", (300, 340), (2560, 1440))
     w.preview = GlyphPreview((2, 2, -2, -40))
     w.rotationSlider = Slider((10, -30, -10, 20),
         minValue=-180,
         maxValue=180,
         value=self.settings["rotation"],
         tickMarkCount=5,
         stopOnTickMarks=False,
         continuous=True,
         callback=self._setRotation,
         sizeStyle="small",
     )
     
     return w
    def __init__(self):

        self.draw = False
        self.swap = True

        self.radius = getExtensionDefault(
            "%s.%s" % (WurstSchreiberDefaultKey, "radius"), 60)

        color = NSColor.colorWithCalibratedRed_green_blue_alpha_(1, 0, 0, .5)
        colorValue = getExtensionDefaultColor(
            "%s.%s" % (WurstSchreiberDefaultKey, "color"), color)

        self.w = FloatingWindow((150, 170), "WurstSchreiber")
        x = 15
        y = 15
        self.w.preview = CheckBox(
            (x, y, -x, 20),
            "Preview",
            callback=self.previewChanged,
            value=True)
        y+=30
        self.w.slider = SliderGroup(
            (x, y, -x, 22), 0, 100, self.radius, callback=self.sliderChanged)
        y+=35
        self.w.color = ColorWell(
            (x, y, -x, 40), callback=self.colorChanged, color=colorValue)
        y+=55
        self.w.button = Button(
            (x, y, -x, 20), "Trace!", callback=self.traceButton)
        addObserver(self, "drawWurst", "drawBackground")
        self.w.bind("close", self.closing)
        self.w.open()
Пример #25
0
 def spaceCenterOpenCallback(self, notification):
     if (not self.popupOpen) and (len(self.metricsGroups) > 0):
         self.w = FloatingWindow((160, 36), 'Group Spacing')
         self.w.activateGroups = CheckBox((9, -27, 151, 18), "Activate Group spacing", value=self.enableGroupSpacing, callback=self.enableGroupSpacingCallback, sizeStyle="small")
         self.w.bind('close', self.windowCloseCallback)
         self.w.open()
         self.popupOpen = True
Пример #26
0
    def __init__(self):
        self.errorList = [
            'Extremum',
            'Mixed cubic and quadratic segments',
            'Fractional Coordinates',
            'Fractional transformation',
            'Incorrect smooth connection',
            'Empty segment',
            'Vector on closepath',
            'Collinear vectors',
            'Semi-horizontal vector',
            'Semi-vertical vector',
            'Zero handle',
        ]
        self.errorList.insert(0, "select Red Arrow Error")
        self.heightOfTool = 360
        self.widthOfTool = 200 
        self.w = FloatingWindow((self.widthOfTool, self.heightOfTool), "Red Arrow Error Filter") ### FloatingWindow
        #self.w.text = TextBox((10, 5, -10, 16), "...", sizeStyle='regular')       
        self.w.select_test = PopUpButton((10, 10, -10, 16), self.errorList, sizeStyle='regular', callback=self.select_test)
        self.w.extremumToleranceText = TextBox((10, 35, -25, 18), "Extremum Tolerance", sizeStyle='small')       
        self.w.extremumToleranceInput = EditText((160, 35, -10, 18), "2", sizeStyle='small')       

        self.w.smooth_connection_max_distance_Text = TextBox((10, 57, -25, 18), "Smooth Connect max_dist", sizeStyle='small')       
        self.w.smooth_connection_max_distance_Input = EditText((160, 55, -10, 18), "4", sizeStyle='small')

        self.w.collinear_vectors_max_distance_Text = TextBox((10, 77, -25, 18), "Collinear Vectors max_dist", sizeStyle='small')       
        self.w.collinear_vectors_max_distance_Input = EditText((160, 75, -10, 18), "2", sizeStyle='small')        
        
        self.w.report = EditText((10, 100, -10, -10), "...", sizeStyle='regular')       
        self.w.report.enable(False)

        self.count = []
        self.report = []
        self.w.open()
    def __init__(self):
        self.modifiedGlyph = None
        self.w = FloatingWindow((400, 170), 'Corner Tool')
        self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor())
        self.modes = ['Break', 'Build','Pit']
        self.objectTypes = {'Build':'Segment', 'Break':'Corner point', 'Pit':'Corner point'}
        self.parameters = {
            'radius': VanillaSingleValueParameter('radius', 20, (-200, 200), numType='int'),
            'roundness': VanillaSingleValueParameter('roundness', 1.25, (0, 4), numType='float'),
            'depth': VanillaSingleValueParameter('depth', 30, (-100, 100), numType='int'),
            'breadth': VanillaSingleValueParameter('breadth', 30, (0, 150), numType='int'),
            'bottom': VanillaSingleValueParameter('bottom', 5, (0, 40), numType='int')
        }
        self.currentMode = 'Break'
        self.previewGlyph = None

        self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode)
        for i, mode in enumerate(self.modes):
            setattr(self.w, mode, Group((120, 15, -15, -15)))
            modeGroup = getattr(self.w, mode)
            modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u'>', callback=self.apply)
            modeGroup.infoBox = Box((0, 0, -50, 35))
            modeGroup.info = TextBox((10, 8, -50, 20), 'No selection')
            if i > 0: modeGroup.show(False)

        self.w.Break.radius = ParameterSliderTextInput(self.parameters['radius'], (0, 60, -25, 25), title='Radius', callback=self.makePreviewGlyph)
        self.w.Break.roundness = ParameterSliderTextInput(self.parameters['roundness'], (0, 95, -25, 25), title='Roundness', callback=self.makePreviewGlyph)

        self.w.Pit.depth = ParameterSliderTextInput(self.parameters['depth'], (0, 50, -25, 25), title='Depth', callback=self.makePreviewGlyph)
        self.w.Pit.breadth = ParameterSliderTextInput(self.parameters['breadth'], (0, 80, -25, 25), title='Breadth', callback=self.makePreviewGlyph)
        self.w.Pit.bottom = ParameterSliderTextInput(self.parameters['bottom'], (0, 110, -25, 25), title='bottom', callback=self.makePreviewGlyph)

        addObserver(self, 'preview', 'draw')
        addObserver(self, 'preview', 'drawInactive')
        addObserver(self, 'previewSolid', 'drawPreview')
        addObserver(self, 'makePreviewGlyph', 'mouseDown')
        addObserver(self, 'makePreviewGlyph', 'mouseDragged')
        addObserver(self, 'makePreviewGlyph', 'keyDown')
        addObserver(self, 'makePreviewGlyph', 'keyUp')
        addObserver(self, 'setControls', 'mouseUp')
        addObserver(self, 'setControls', 'selectAll')
        addObserver(self, 'setControls', 'deselectAll')
        addObserver(self, 'setControls', 'currentGlyphChanged')
        self.w.bind('close', self.windowClose)
        self.setControls()
        self.w.open()
    def __init__(self):
        self.w = FloatingWindow(
            (120, 140),
            minSize=(100, 40),
            textured=True,
        )
        self.w.ti_checkbox = CheckBox((10, 10, -10, 20),
                                      'Test Install',
                                      value=True)
        self.w.otf_checkbox = CheckBox((10, 30, -10, 20),
                                       'OTF Backup',
                                       value=True)
        self.w.button = SquareButton((10, 60, -10, -10),
                                     'GO',
                                     callback=self.button_callback)

        self.w.open()
Пример #29
0
    def _buildUI(self):
        w = FloatingWindow((300, 340), "Rotated Glyph Preview", (300, 340),
                           (2560, 1440))
        w.preview = GlyphPreview((2, 2, -2, -40))
        w.rotationSlider = Slider(
            (10, -30, -10, 20),
            minValue=-180,
            maxValue=180,
            value=self.settings["rotation"],
            tickMarkCount=5,
            stopOnTickMarks=False,
            continuous=True,
            callback=self._setRotation,
            sizeStyle="small",
        )

        return w
Пример #30
0
    class TesterWindow:
        def __init__(self):
            self.w = FloatingWindow((100, 100), "Tester")
            self.w.bind("close", self.closeCB)

            self.guideView = None

            addObserver(self, "glyphWindowOpenCB", "glyphWindowDidOpen")

        def glyphWindowOpenCB(self, info):
            glyphWindow = info["window"]
            self.guideView = GuideStatusView()
            self.guideView.view.statusText.set("TEST")
            self.guideView.addViewToWindow(glyphWindow)
            self.guideView.turnStatusTextOn()

        def closeCB(self, sender):
            removeObserver(self, "glyphWindowDidOpen")
    def __init__(self):
        self.modifiedGlyph = None
        self.w = FloatingWindow((400, 170), "Corner Tool")
        self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor())
        self.modes = ["Break", "Build", "Pit"]
        self.objectTypes = {"Build": "Segment", "Break": "Corner point", "Pit": "Corner point"}
        self.parameters = {
            "radius": VanillaSingleValueParameter("radius", 20, (-200, 200), numType="int"),
            "roundness": VanillaSingleValueParameter("roundness", 1.25, (0, 4), numType="float"),
            "depth": VanillaSingleValueParameter("depth", 30, (-100, 100), numType="int"),
            "breadth": VanillaSingleValueParameter("breadth", 30, (0, 150), numType="int"),
            "bottom": VanillaSingleValueParameter("bottom", 5, (0, 40), numType="int"),
        }
        self.currentMode = "Break"
        self.previewGlyph = None

        self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode)
        for i, mode in enumerate(self.modes):
            setattr(self.w, mode, Group((120, 15, -15, -15)))
            modeGroup = getattr(self.w, mode)
            modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u">", callback=self.apply)
            modeGroup.infoBox = Box((0, 0, -50, 35))
            modeGroup.info = TextBox((10, 8, -50, 20), "No selection")
            if i > 0:
                modeGroup.show(False)

        self.w.Break.radius = ParameterSliderTextInput(
            self.parameters["radius"], (0, 60, -25, 25), title="Radius", callback=self.makePreviewGlyph
        )
        self.w.Break.roundness = ParameterSliderTextInput(
            self.parameters["roundness"], (0, 95, -25, 25), title="Roundness", callback=self.makePreviewGlyph
        )

        self.w.Pit.depth = ParameterSliderTextInput(
            self.parameters["depth"], (0, 50, -25, 25), title="Depth", callback=self.makePreviewGlyph
        )
        self.w.Pit.breadth = ParameterSliderTextInput(
            self.parameters["breadth"], (0, 80, -25, 25), title="Breadth", callback=self.makePreviewGlyph
        )
        self.w.Pit.bottom = ParameterSliderTextInput(
            self.parameters["bottom"], (0, 110, -25, 25), title="bottom", callback=self.makePreviewGlyph
        )

        addObserver(self, "preview", "draw")
        addObserver(self, "preview", "drawInactive")
        addObserver(self, "previewSolid", "drawPreview")
        addObserver(self, "makePreviewGlyph", "mouseDown")
        addObserver(self, "makePreviewGlyph", "mouseDragged")
        addObserver(self, "makePreviewGlyph", "keyDown")
        addObserver(self, "makePreviewGlyph", "keyUp")
        addObserver(self, "setControls", "mouseUp")
        addObserver(self, "setControls", "selectAll")
        addObserver(self, "setControls", "deselectAll")
        addObserver(self, "setControls", "currentGlyphChanged")
        self.w.bind("close", self.windowClose)
        self.setControls()
        self.w.open()
Пример #32
0
class MoveGlyphWindow:
    '''Move the current glyph using sliders.'''
    def __init__(self, glyph):

        # if glyph is None, show a message
        if glyph is None:
            Message('no glyph selected',
                    title='moveTool',
                    informativeText='Please select one glyph first!')
            return

        # store the glyph and initial move values as object attributes
        self.glyph = glyph
        self.moveX = 0

        # create a floating window
        self.w = FloatingWindow((200, 74), "move %s" % self.glyph.name)

        # add a slider for moving in the x axis
        self.w.sliderX = Slider((10, 10, -10, 22),
                                value=0,
                                maxValue=200,
                                minValue=-200,
                                callback=self.adjust)

        # open the window
        self.w.open()

    def adjust(self, sender):

        # get the current x and y values from the sliders
        valueX = self.w.sliderX.get()

        # calculate actual move distance
        x = self.moveX - valueX

        # move the glyph
        self.glyph.moveBy((x, y))

        # update saved values
        self.moveX = valueX

        # print the current move distance
        print(self.moveX)
Пример #33
0
    def __init__(self, glyph):

        # if glyph is None, show a message
        # store the glyph and initial move values as object attributes
        self.w = FloatingWindow((200, 64), "move "+str(labelslider))
        for labelslider in BuildLabelsList(f):
            # create a floating window
            # add a slider for moving in the x axis
            self.g = glyph
            self.moveX = 0
            self.label= labelslider
            self.w.labelslider = Slider(
                    (10, 10, -10, 22),
                    value=0, maxValue=100, minValue=-100,
                    callback=self.adjust)

            # open the window
            self.w.button = Button((15, -35, -15, 20), "Done")
            self.w.open()
Пример #34
0
class MoveGlyphWindow:

    '''Move the current glyph using sliders.'''

    def __init__(self, glyph):

        # if glyph is None, show a message
        # store the glyph and initial move values as object attributes
        self.w = FloatingWindow((200, 64), "move "+str(labelslider))
        for labelslider in BuildLabelsList(f):
            # create a floating window
            # add a slider for moving in the x axis
            self.g = glyph
            self.moveX = 0
            self.label= labelslider
            self.w.labelslider = Slider(
                    (10, 10, -10, 22),
                    value=0, maxValue=100, minValue=-100,
                    callback=self.adjust)

            # open the window
            self.w.button = Button((15, -35, -15, 20), "Done")
            self.w.open()

    def adjust(self, sender):

        # get the current x and y values from the sliders
        valueX = self.w.labelslider.get()

        # calculate actual move distance
        x = self.moveX - valueX

        # move the glyph
        for contour in self.g:
            for point in counter.points:
                if point.labels is 'CROSSBAR':
                    point.moveBy((x, 0))

        # update saved values
        self.moveX = valueX

        # print the current move distance
        print(self.moveX)
Пример #35
0
 def __init__(self):
     NSUserDefaults.standardUserDefaults().registerDefaults_({"ToucheWindowHeight":340})
     self.windowHeight = NSUserDefaults.standardUserDefaults().integerForKey_("ToucheWindowHeight")
     self.minWindowHeight = 340
     if self.windowHeight < self.minWindowHeight:
         self.windowHeight = self.minWindowHeight
     self.closedWindowHeight = 100
     self.w = FloatingWindow((180, self.windowHeight), u'Touché!', minSize=(180,340), maxSize=(250,898))
     self.w.bind("resize", self.windowResized)
     self.isResizing = False
     p = 10
     w = 160
     
     # options
     self.w.options = Group((0, 0, 180, 220))
     
     buttons = {
         "checkSelBtn": {"text": "Check selected glyphs", "callback": self.checkSel, "y": p},
     }
     for button, data in buttons.iteritems():
         setattr(self.w.options, button, 
         Button((p, data["y"], w - 22, 22), data["text"], callback=data["callback"], sizeStyle="small"))
         
     self.w.options.zeroCheck = CheckBox((p, 35, w, 20), "Ignore zero-width glyphs", value=True, sizeStyle="small")
     self.w.options.progress = ProgressSpinner((w - 8, 13, 16, 16), sizeStyle="small")
     
     # results
     self.w.results = Group((0, 220, 180, -0))
     self.w.results.show(False)
     
     textBoxes = {"stats": -34, "result": -18}
     for box, y in textBoxes.iteritems():
         setattr(self.w.results, box, TextBox((p, y, w, 14), "", sizeStyle="small"))
         
     # list and preview 
     self.w.outputList = List((0,58,-0,-40),
         [{"left glyph": "", "right glyph": ""}], columnDescriptions=[{"title": "left glyph", "width": 90}, {"title": "right glyph"}],
         showColumnTitles=False, allowsMultipleSelection=False, enableDelete=False, selectionCallback=self.showPair)
     self.w.outputList._setColumnAutoresizing()
     self._resizeWindow(False)
     self.w.open()
    def __init__(self):
        self.modifiedGlyph = None
        self.w = FloatingWindow((400, 170), 'Corner Tool')
        self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor())
        self.modes = ['Break', 'Build','Pit']
        self.objectTypes = {'Build':'Segment', 'Break':'Corner point', 'Pit':'Corner point'}
        self.parameters = {
            'radius': VanillaSingleValueParameter('radius', 20, (-200, 200), numType='int'),
            'roundness': VanillaSingleValueParameter('roundness', 1.25, (0, 4), numType='float'),
            'depth': VanillaSingleValueParameter('depth', 30, (-100, 100), numType='int'),
            'breadth': VanillaSingleValueParameter('breadth', 30, (0, 150), numType='int'),
            'bottom': VanillaSingleValueParameter('bottom', 5, (0, 40), numType='int')
        }
        self.currentMode = 'Break'
        self.previewGlyph = None

        self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode)
        for i, mode in enumerate(self.modes):
            setattr(self.w, mode, Group((120, 15, -15, -15)))
            modeGroup = getattr(self.w, mode)
            modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u'>', callback=self.apply)
            modeGroup.infoBox = Box((0, 0, -50, 35))
            modeGroup.info = TextBox((10, 8, -50, 20), 'No selection')
            if i > 0: modeGroup.show(False)

        self.w.Break.radius = ParameterSliderTextInput(self.parameters['radius'], (0, 60, -25, 25), title='Radius', callback=self.makePreviewGlyph)
        self.w.Break.roundness = ParameterSliderTextInput(self.parameters['roundness'], (0, 95, -25, 25), title='Roundness', callback=self.makePreviewGlyph)

        self.w.Pit.depth = ParameterSliderTextInput(self.parameters['depth'], (0, 50, -25, 25), title='Depth', callback=self.makePreviewGlyph)
        self.w.Pit.breadth = ParameterSliderTextInput(self.parameters['breadth'], (0, 80, -25, 25), title='Breadth', callback=self.makePreviewGlyph)
        self.w.Pit.bottom = ParameterSliderTextInput(self.parameters['bottom'], (0, 110, -25, 25), title='bottom', callback=self.makePreviewGlyph)

        addObserver(self, 'preview', 'draw')
        addObserver(self, 'preview', 'drawInactive')
        addObserver(self, 'makePreviewGlyph', 'mouseDown')
        addObserver(self, 'makePreviewGlyph', 'mouseDragged')
        addObserver(self, 'makePreviewGlyph', 'keyDown')
        addObserver(self, 'makePreviewGlyph', 'keyUp')
        addObserver(self, 'setControls', 'mouseUp')
        addObserver(self, 'setControls', 'selectAll')
        addObserver(self, 'setControls', 'deselectAll')
        addObserver(self, 'setControls', 'currentGlyphChanged')
        self.w.bind('close', self.windowClose)
        self.setControls()
        self.w.open()
Пример #37
0
 def __init__(self):
     NSUserDefaults.standardUserDefaults().registerDefaults_({"ToucheWindowHeight":340})
     self.windowHeight = NSUserDefaults.standardUserDefaults().integerForKey_("ToucheWindowHeight")
     self.minWindowHeight = 340
     if self.windowHeight < self.minWindowHeight:
         self.windowHeight = self.minWindowHeight
     self.closedWindowHeight = 100
     self.w = FloatingWindow((180, self.windowHeight), u'Touché!', minSize=(180,340), maxSize=(250,898))
     self.w.bind("resize", self.windowResized)
     self.isResizing = False
     p = 10
     w = 160
     
     # options
     self.w.options = Group((0, 0, 180, 220))
     
     buttons = {
         "checkSelBtn": {"text": "Check selected glyphs", "callback": self.checkSel, "y": p},
     }
     for button, data in buttons.iteritems():
         setattr(self.w.options, button, 
         Button((p, data["y"], w - 22, 22), data["text"], callback=data["callback"], sizeStyle="small"))
         
     self.w.options.zeroCheck = CheckBox((p, 35, w, 20), "Ignore zero-width glyphs", value=True, sizeStyle="small")
     self.w.options.progress = ProgressSpinner((w - 8, 13, 16, 16), sizeStyle="small")
     
     # results
     self.w.results = Group((0, 220, 180, -0))
     self.w.results.show(False)
     
     textBoxes = {"stats": -34, "result": -18}
     for box, y in textBoxes.iteritems():
         setattr(self.w.results, box, TextBox((p, y, w, 14), "", sizeStyle="small"))
         
     # list and preview 
     self.w.outputList = List((0,58,-0,-40),
         [{"left glyph": "", "right glyph": ""}], columnDescriptions=[{"title": "left glyph", "width": 90}, {"title": "right glyph"}],
         showColumnTitles=False, allowsMultipleSelection=False, enableDelete=False, selectionCallback=self.showPair)
     self.w.outputList._setColumnAutoresizing()
     self._resizeWindow(False)
     self.w.open()
 def __init__(self):
     self.glyphOrder = []
     self.orderFileName = ''
     self.formats = ['otf', 'ttf', 'pfa']
     self.format = 'otf'
     self.decompose = True
     self.overlap = True
     self.autohint = True
     self.release = True
     
     self.w = FloatingWindow((200,270), "Generate", minSize=(200,270),)
     self.w.getEncoding = Button((10, 10, 180, 20), 'Get .enc file', callback=self.getEncodingCallback)
     self.w.viewEncoding = Button((10, 75, 180, 20), 'View encoding', callback=self.viewEncodingCallback)
     self.w.line = HorizontalLine((12, 103, -12, 1))
     
     self.w.formatLabel    = TextBox((15, 117, 60, 20), "Format")
     self.w.formatChoice   = PopUpButton((70, 115, 80, 20), self.formats, callback=self.formatCallback)
     self.w.decomposeCheck = CheckBox((20, 141, -10, 20), "Decompose", callback=self.decomposeCallback, value=self.decompose)
     self.w.overlapCheck   = CheckBox((20, 161, -10, 20), "Remove Overlap", callback=self.overlapCallback, value=self.overlap)
     self.w.autohintCheck  = CheckBox((20, 181, -10, 20), "Autohint", callback=self.autohintCallback, value=self.autohint)
     self.w.releaseCheck   = CheckBox((20, 201, -10, 20), "Release Mode", callback=self.releaseCallback, value=self.release)
     self.w.generate = Button((10, 232, 180, 20), 'Generate Font', callback=self.generateCallback)
 
     self.w.decomposeCheck.enable(False)
     
     self.w.viewEncoding.enable(False)
     self.w.formatChoice.enable(False)
     self.w.overlapCheck.enable(False)
     self.w.autohintCheck.enable(False)
     self.w.releaseCheck.enable(False)
     self.w.generate.enable(False)
     
     self.d = Drawer((170, 400), self.w, preferredEdge="right")
     self.d.text = TextEditor((10, 10, -10, -10), readOnly=True)
     
     self.d.open()
     self.d.toggle()
     self.w.open()
	def __init__(self):
		flushAlign = 76
		firstRowY = 12
		rowOffsetY = 30
		firstCheckY = 135
		checkOffsetY = 27
		rightMarginX = -12
		self.windowWidth = 410
		self.windowHeightWithoutOptions = 45
		self.windowHeightWithOptions = 280
		self.scriptIsRTL = False

		windowPos = getExtensionDefault("%s.%s" % (extensionKey, "windowPos"))
		if not windowPos:
			windowPos = (100, 100)

		self.optionsVisible = getExtensionDefault("%s.%s" % (extensionKey, "optionsVisible"))
		if self.optionsVisible:
			optionsButtonSign = '-'
			windowHeight = self.windowHeightWithOptions
		else:
			self.optionsVisible = False # needs to be set because the first time the extension runs self.optionsVisible will be None
			optionsButtonSign = '+'
			windowHeight = self.windowHeightWithoutOptions

		self.chars = getExtensionDefault("%s.%s" % (extensionKey, "chars"))
		if not self.chars:
			self.chars = ''

		self.sliderValue = getExtensionDefault("%s.%s" % (extensionKey, "sliderValue"))
		if not self.sliderValue:
			self.sliderValue = 25

		self.scriptsIndex = getExtensionDefault("%s.%s" % (extensionKey, "scriptsIndex"))
		if not self.scriptsIndex:
			self.scriptsIndex = 0

		self.langsIndex = getExtensionDefault("%s.%s" % (extensionKey, "langsIndex"))
		if not self.langsIndex:
			self.langsIndex = 0


		self.w = FloatingWindow((windowPos[0], windowPos[1], self.windowWidth, windowHeight), "adhesiontext")

		# 1st row
		self.w.labelChars = TextBox((10, firstRowY, flushAlign, 20), "Characters:", alignment="right")
		self.w.chars = EditText((flushAlign +15, firstRowY -1, 199, 22), self.chars, callback=self.charsCallback)
		self.w.button = Button((300, firstRowY, 68, 20), "Get text", callback=self.buttonCallback)
		self.w.spinner = FixedSpinner((325, firstRowY, 20, 20), displayWhenStopped=False)
		self.w.optionsButton = SquareButton((378, firstRowY +1, 18, 18), optionsButtonSign, sizeStyle="small", callback=self.optionsCallback)
		# set the initial state of the button according to the content of the chars EditText
		if len(self.w.chars.get()): self.w.button.enable(True)
		else: self.w.button.enable(False)
		# keep track of the content of chars EditText
		self.previousChars = self.w.chars.get()

		# 2nd row
		self.w.labelWords = TextBox((10, firstRowY + rowOffsetY, flushAlign, 20), "Words:", alignment="right")
		self.w.wordCount = TextBox((flushAlign +12, firstRowY + rowOffsetY, 40, 20), alignment="left")
		self.w.slider = Slider((flushAlign +47, firstRowY + rowOffsetY +1, 165, 20), value=self.sliderValue, minValue=5, maxValue=200, callback=self.sliderCallback)
		# set the initial wordCount value according to the position of the slider
		self.w.wordCount.set(int(self.w.slider.get()))

		# 3rd row
		self.w.labelScripts = TextBox((10, firstRowY + rowOffsetY *2, flushAlign, 20), "Script:", alignment="right")
		self.w.scriptsPopup = PopUpButton((flushAlign +15, firstRowY + rowOffsetY *2, 150, 20), scriptsNameList, callback=self.scriptsCallback)
		self.w.scriptsPopup.set(self.scriptsIndex)

		# 4th row
		self.w.labelLangs = TextBox((10, firstRowY + rowOffsetY *3, flushAlign, 20), "Language:", alignment="right")
		self.w.langsPopup = PopUpButton((flushAlign +15, firstRowY + rowOffsetY *3, 150, 20), [])
		# set the initial list of languages according to the script value
		self.w.langsPopup.setItems(langsNameDict[scriptsNameList[self.w.scriptsPopup.get()]])
		self.w.langsPopup.set(self.langsIndex)

		self.punctCheck = getExtensionDefault("%s.%s" % (extensionKey, "punctCheck"))
		if not self.punctCheck:
			self.punctCheck = 0

		self.figsCheck = getExtensionDefault("%s.%s" % (extensionKey, "figsCheck"))
		if not self.figsCheck:
			self.figsCheck = 0

		self.figsPopup = getExtensionDefault("%s.%s" % (extensionKey, "figsPopup"))
		if not self.figsPopup:
			self.figsPopup = 0

		self.trimCheck = getExtensionDefault("%s.%s" % (extensionKey, "trimCheck"))
		if not self.trimCheck:
			self.trimCheck = 0

		self.caseCheck = getExtensionDefault("%s.%s" % (extensionKey, "caseCheck"))
		if not self.caseCheck:
			self.caseCheck = 0

		self.casingCheck = getExtensionDefault("%s.%s" % (extensionKey, "casingCheck"))
		if not self.casingCheck:
			self.casingCheck = 0

		self.casingPopup = getExtensionDefault("%s.%s" % (extensionKey, "casingPopup"))
		if not self.casingPopup:
			self.casingPopup = 0

		# 1st checkbox
		self.w.punctCheck = CheckBox((flushAlign +15, firstCheckY, 130, 20), "Add punctuation")
		self.w.punctCheck.set(self.punctCheck)

		# 2nd checkbox
		self.w.figsCheck = CheckBox((flushAlign +15, firstCheckY + checkOffsetY, 120, 20), "Insert numbers", callback=self.figsCallback)
		self.w.figsCheck.set(self.figsCheck)
		self.w.figsPopup = PopUpButton((210, firstCheckY + checkOffsetY, 90, 20), figOptionsList)
		self.w.figsPopup.set(self.figsPopup)
		# enable or disable the figure options PopUp depending on the figures CheckBox
		if scriptsNameList[self.w.scriptsPopup.get()] in enableFigOptionList:
			self.w.figsPopup.show(True)
			if self.w.figsCheck.get():
				self.w.figsPopup.enable(True)
			else:
				self.w.figsPopup.enable(False)
		else:
			self.w.figsPopup.show(False)

		# 3rd checkbox
		self.w.trimCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *2, 120, 20), "Trim accents")
		self.w.trimCheck.set(self.trimCheck)
		if scriptsNameList[self.w.scriptsPopup.get()] in enableTrimCheckList:
			self.w.trimCheck.enable(True)
		else:
			self.w.trimCheck.enable(False)

		# 4th checkbox
		self.w.caseCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *3, 120, 20), "Ignore casing")
		self.w.caseCheck.set(self.caseCheck)
		if scriptsNameList[self.w.scriptsPopup.get()] in enableCaseCheckList:
			self.w.caseCheck.enable(True)
		else:
			self.w.caseCheck.enable(False)

		# 5th checkbox
		self.w.casingCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *4, 115, 20), "Change casing", callback=self.casingCallback)
		self.w.casingCheck.set(self.casingCheck)
		if scriptsNameList[self.w.scriptsPopup.get()] in enableCaseCheckList:
			self.w.casingCheck.enable(True)
		else:
			self.w.casingCheck.enable(False)
		self.w.casingPopup = PopUpButton((210, firstCheckY + checkOffsetY *4, 90, 20), casingNameList)
		self.w.casingPopup.set(self.casingPopup)
		# enable or disable the casing PopUp depending on the casing CheckBox
		if self.w.casingCheck.get() and self.w.casingCheck.isEnable():
			self.w.casingPopup.enable(True)
		else:
			self.w.casingPopup.enable(False)

		self.nsTextField = self.w.chars.getNSTextField()
		self.w.setDefaultButton(self.w.button)
		self.w.bind("close", self.windowClose)
		self.w.open()
		self.w.makeKey()
class WurstSchreiber(object):

    def __init__(self):

        self.draw = False
        self.swap = True

        self.radius = getExtensionDefault(
            "%s.%s" % (WurstSchreiberDefaultKey, "radius"), 60)

        color = NSColor.colorWithCalibratedRed_green_blue_alpha_(1, 0, 0, .5)
        colorValue = getExtensionDefaultColor(
            "%s.%s" % (WurstSchreiberDefaultKey, "color"), color)

        self.w = FloatingWindow((150, 170), "WurstSchreiber")
        x = 15
        y = 15
        self.w.preview = CheckBox(
            (x, y, -x, 20),
            "Preview",
            callback=self.previewChanged,
            value=True)
        y+=30
        self.w.slider = SliderGroup(
            (x, y, -x, 22), 0, 100, self.radius, callback=self.sliderChanged)
        y+=35
        self.w.color = ColorWell(
            (x, y, -x, 40), callback=self.colorChanged, color=colorValue)
        y+=55
        self.w.button = Button(
            (x, y, -x, 20), "Trace!", callback=self.traceButton)
        addObserver(self, "drawWurst", "drawBackground")
        self.w.bind("close", self.closing)
        self.w.open()

    def closing(self, sender):
        removeObserver(self, "drawBackground")

    def previewChanged(self, sender):
        UpdateCurrentGlyphView()

    def sliderChanged(self, sender):
        self.radius = int(sender.get())
        setExtensionDefault(
            "%s.%s" % (WurstSchreiberDefaultKey, "radius"), self.radius)
        UpdateCurrentGlyphView()

    def colorChanged(self, sender):
        setExtensionDefaultColor(
            "%s.%s" % (WurstSchreiberDefaultKey, "color"), sender.get())
        UpdateCurrentGlyphView()

    def getColor(self):
        color = self.w.color.get()
        return color.getRed_green_blue_alpha_(None, None, None, None)

    def traceButton(self, sender):
        if self.w.preview.get():
            self.draw = True
            UpdateCurrentGlyphView()

    def drawWurst(self, sender):
        if self.w.preview.get():
            radius = self.radius
            draw = self.draw
            r,g,b,a = self.getColor()
            fill(r,g,b,a)
            glyph = CurrentGlyph()
            pen = WurstPen(None, radius, draw)
            glyph.draw(pen)
            if self.draw:
                glyph.prepareUndo("WurstTrace")
                if self.swap:
                    glyph.getLayer("background").clear()
                    glyph.swapToLayer("background")
                glyph.appendGlyph(pen.glyphcopy)
                self.draw = False
                self.w.preview.set(False)
                glyph.performUndo()
            glyph.update()
class CornerController:

    def __init__(self):
        self.modifiedGlyph = None
        self.w = FloatingWindow((400, 170), 'Corner Tool')
        self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor())
        self.modes = ['Break', 'Build','Pit']
        self.objectTypes = {'Build':'Segment', 'Break':'Corner point', 'Pit':'Corner point'}
        self.parameters = {
            'radius': VanillaSingleValueParameter('radius', 20, (-200, 200), numType='int'),
            'roundness': VanillaSingleValueParameter('roundness', 1.25, (0, 4), numType='float'),
            'depth': VanillaSingleValueParameter('depth', 30, (-100, 100), numType='int'),
            'breadth': VanillaSingleValueParameter('breadth', 30, (0, 150), numType='int'),
            'bottom': VanillaSingleValueParameter('bottom', 5, (0, 40), numType='int')
        }
        self.currentMode = 'Break'
        self.previewGlyph = None

        self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode)
        for i, mode in enumerate(self.modes):
            setattr(self.w, mode, Group((120, 15, -15, -15)))
            modeGroup = getattr(self.w, mode)
            modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u'>', callback=self.apply)
            modeGroup.infoBox = Box((0, 0, -50, 35))
            modeGroup.info = TextBox((10, 8, -50, 20), 'No selection')
            if i > 0: modeGroup.show(False)

        self.w.Break.radius = ParameterSliderTextInput(self.parameters['radius'], (0, 60, -25, 25), title='Radius', callback=self.makePreviewGlyph)
        self.w.Break.roundness = ParameterSliderTextInput(self.parameters['roundness'], (0, 95, -25, 25), title='Roundness', callback=self.makePreviewGlyph)

        self.w.Pit.depth = ParameterSliderTextInput(self.parameters['depth'], (0, 50, -25, 25), title='Depth', callback=self.makePreviewGlyph)
        self.w.Pit.breadth = ParameterSliderTextInput(self.parameters['breadth'], (0, 80, -25, 25), title='Breadth', callback=self.makePreviewGlyph)
        self.w.Pit.bottom = ParameterSliderTextInput(self.parameters['bottom'], (0, 110, -25, 25), title='bottom', callback=self.makePreviewGlyph)

        addObserver(self, 'preview', 'draw')
        addObserver(self, 'preview', 'drawInactive')
        addObserver(self, 'makePreviewGlyph', 'mouseDown')
        addObserver(self, 'makePreviewGlyph', 'mouseDragged')
        addObserver(self, 'makePreviewGlyph', 'keyDown')
        addObserver(self, 'makePreviewGlyph', 'keyUp')
        addObserver(self, 'setControls', 'mouseUp')
        addObserver(self, 'setControls', 'selectAll')
        addObserver(self, 'setControls', 'deselectAll')
        addObserver(self, 'setControls', 'currentGlyphChanged')
        self.w.bind('close', self.windowClose)
        self.setControls()
        self.w.open()

    def changeMode(self, sender):
        index = sender.get()
        previousModeGroup = getattr(self.w, self.currentMode)
        previousModeGroup.show(False)
        self.currentMode = self.modes[index]
        modeGroup = getattr(self.w, self.currentMode)
        modeGroup.show(True)
        self.setControls()

    def setControls(self, notification=None):
        mode = self.currentMode
        selection = self.getSelection()
        modeGroup = getattr(self.w, mode)
        if not len(selection):
            modeGroup.apply.enable(False)
            modeGroup.info.set('No selection (%ss)'%(self.objectTypes[mode].lower()))
        elif len(selection):
            modeGroup.apply.enable(True)
            info = '%s valid %s'%(len(selection), self.objectTypes[mode].lower())
            if len(selection) > 1: info += 's'
            modeGroup.info.set(info)
        self.makePreviewGlyph()

    def getSelection(self, notification=None):
        glyph = CurrentGlyph()
        if len(glyph.selection) == 0:
            return []
        elif len(glyph.selection) > 0:
            iG = IntelGlyph(glyph)
            if self.currentMode == 'Build':
                selection = iG.getSelection(True)
            elif self.currentMode in ['Break', 'Pit']:
                selection = [point for point in iG.getSelection() if (point.segmentType is not None) and (abs(point.turn()) > pi/18)]
            return selection

    def preview(self, notification):
        sc = notification['scale']
        if self.previewGlyph is not None:
            self.previewGlyph.drawPreview(sc, styleFill=True, showNodes=False, strokeWidth=2, fillColor=cornerOutlineSoftColor, strokeColor=cornerOutlineStrongColor)

    def makePreviewGlyph(self, sender=None):
        if (sender is not None) and isinstance(sender, dict):
            if sender.has_key('notificationName') and sender['notificationName'] == 'mouseDragged':
                g = sender['glyph']
                if not len(g.selection):
                    return
        self.previewGlyph = self.makeCornerGlyph()
        UpdateCurrentGlyphView()

    def makeCornerGlyph(self, sender=None):
        mode = self.currentMode
        if mode == 'Build':
            cornerGlyph = self.buildCorners()
        elif mode == 'Break':
            cornerGlyph = self.breakCorners()
        elif mode == 'Pit':
            cornerGlyph = self.pitCorners()
        return cornerGlyph

    def buildCorners(self):
        g = CurrentGlyph()
        iG = IntelGlyph(g)
        for contour in iG:
            segments = contour.collectSegments()['selection']
            l = len(segments)
            lines, curves = self.checkComposition(segments)
            if l > 1 and lines and curves:
                segments = [segment for segment in segments if len(segment) == 4]
            elif l > 1 and lines and not curves:
                segments = segments[:1] + segments[-1:]
            for segment in reversed(segments):
                contour.buildCorner(segment)
        return iG

    def breakCorners(self):
        g = CurrentGlyph()
        iG = IntelGlyph(g)
        radius = self.parameters['radius'].get()
        roundness = self.parameters['roundness'].get()
        for contour in iG:
            selection = contour.getSelection()
            for point in selection:
                contour.breakCorner(point, radius, velocity=roundness)
            contour.correctSmoothness()
        return iG

    def pitCorners(self):
        g = CurrentGlyph()
        iG = IntelGlyph(g)
        depth = self.parameters['depth'].get()
        breadth = self.parameters['breadth'].get()
        bottom = self.parameters['bottom'].get()
        for contour in iG:
            selection = contour.getSelection()
            for point in selection:
                contour.pitCorner(point, depth, breadth, bottom)
            contour.removeOverlappingPoints()
            contour.correctSmoothness()
        return iG

    def apply(self, sender):
        targetGlyph = CurrentGlyph()
        modifiedGlyph = self.makeCornerGlyph()
        targetGlyph.prepareUndo('un.round')
        targetGlyph.clearContours()
        for p in targetGlyph.selection:
            p.selected = False
        pen = targetGlyph.getPointPen()
        modifiedGlyph.drawPoints(pen)
        targetGlyph.performUndo()
        targetGlyph.update()

    def checkComposition(self, segmentsList):
        lines = 0
        curves = 0
        for segment in segmentsList:
            if len(segment) == 2:
                lines += 1
            elif len(segment) == 4:
                curves += 1
        return lines, curves

    def windowClose(self, notification):
        removeObserver(self, 'draw')
        removeObserver(self, 'drawInactive')
        removeObserver(self, 'mouseUp')
        removeObserver(self, 'mouseDown')
        removeObserver(self, 'mouseDragged')
        removeObserver(self, 'keyDown')
        removeObserver(self, 'keyUp')
        removeObserver(self, 'selectAll')
        removeObserver(self, 'deselectAll')
        removeObserver(self, 'currentGlyphChanged')
class GenerateWithOrder(object):
    """A simple extension to generate font with order from a FL Encoding file """
    def __init__(self):
        self.glyphOrder = []
        self.orderFileName = ''
        self.formats = ['otf', 'ttf', 'pfa']
        self.format = 'otf'
        self.decompose = True
        self.overlap = True
        self.autohint = True
        self.release = True
        
        self.w = FloatingWindow((200,270), "Generate", minSize=(200,270),)
        self.w.getEncoding = Button((10, 10, 180, 20), 'Get .enc file', callback=self.getEncodingCallback)
        self.w.viewEncoding = Button((10, 75, 180, 20), 'View encoding', callback=self.viewEncodingCallback)
        self.w.line = HorizontalLine((12, 103, -12, 1))
        
        self.w.formatLabel    = TextBox((15, 117, 60, 20), "Format")
        self.w.formatChoice   = PopUpButton((70, 115, 80, 20), self.formats, callback=self.formatCallback)
        self.w.decomposeCheck = CheckBox((20, 141, -10, 20), "Decompose", callback=self.decomposeCallback, value=self.decompose)
        self.w.overlapCheck   = CheckBox((20, 161, -10, 20), "Remove Overlap", callback=self.overlapCallback, value=self.overlap)
        self.w.autohintCheck  = CheckBox((20, 181, -10, 20), "Autohint", callback=self.autohintCallback, value=self.autohint)
        self.w.releaseCheck   = CheckBox((20, 201, -10, 20), "Release Mode", callback=self.releaseCallback, value=self.release)
        self.w.generate = Button((10, 232, 180, 20), 'Generate Font', callback=self.generateCallback)
    
        self.w.decomposeCheck.enable(False)
        
        self.w.viewEncoding.enable(False)
        self.w.formatChoice.enable(False)
        self.w.overlapCheck.enable(False)
        self.w.autohintCheck.enable(False)
        self.w.releaseCheck.enable(False)
        self.w.generate.enable(False)
        
        self.d = Drawer((170, 400), self.w, preferredEdge="right")
        self.d.text = TextEditor((10, 10, -10, -10), readOnly=True)
        
        self.d.open()
        self.d.toggle()
        self.w.open()

    def process_enc(self, p):
        order = []
        
        f = open(p)
        for line in f:
            if line.startswith(('#', '%')):
                pass
            else:
                l = line.split()
                if len(l[0]) != 0:
                    for i in l:
                        if not i.startswith(('#', '%', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) and len(i) != 0:
                            order.append(i)
        f.close()
        
        self.glyphOrder = order

                
    def getEncodingCallback(self, sender):
        getFile(parentWindow=self.w, fileTypes=['enc', 'Enc'], resultCallback=self.processEncodingCallback)

    def viewEncodingCallback(self, sender):
        if not self.d.isOpen():
            t = "\n".join(self.glyphOrder)
            self.d.text.set(t)
        self.d.toggle()

    def processEncodingCallback(self, sender):
        if sender[0] is not None:
            fn = os.path.split(sender[0])[1]
            self.process_enc(sender[0])
            self.w.encodingTitle = TextBox((15, 34, 180, 17), "Encoding File:", alignment="left")
            self.w.encodingFileTitle = TextBox((15, 52, 180, 17), fn, alignment="left")
            
            self.w.viewEncoding.enable(True)
            self.w.formatChoice.enable(True)
            self.w.overlapCheck.enable(True)
            self.w.autohintCheck.enable(True)
            self.w.releaseCheck.enable(True)
            self.w.generate.enable(True)
            
    def formatCallback(self, sender):
        self.format = self.formats[sender.get()]
        if self.format == 'otf' or self.format == 'pfa':
            self.decompose = True
            self.w.decomposeCheck.enable(False)
            self.w.decomposeCheck.set(True)
        else:
            self.w.decomposeCheck.enable(True)

    def decomposeCallback(self, sender):
        if sender.get() == 0:
            self.decompose = False
        else:
            self.decompose = True

    def overlapCallback(self, sender):
        if sender.get() == 0:
            self.overlap = False
        else:
            self.overlap = True

    def autohintCallback(self, sender):
        if sender.get() == 0:
            self.autohint = False
        else:
            self.autohint = True

    def releaseCallback(self, sender):
        if sender.get() == 0:
            self.release = False
        else:
            self.release = True
            
    def generateCallback(self, sender):
        font = CurrentFont()
        d,f = os.path.split(font.path)
        f = f[:-3] + self.format
        putFile(messageText="Save Font", directory=d, fileName=f, parentWindow=self.w, resultCallback=self.processGenerateCallback)
        
    def processGenerateCallback(self, sender):
        path = sender
        font = CurrentFont()
        font.generate(path, self.format, decompose=self.decompose, autohint=self.autohint, releaseMode=self.release, glyphOrder=self.glyphOrder)
Пример #43
0
class ToucheTool():
    
    def __init__(self):
        NSUserDefaults.standardUserDefaults().registerDefaults_({"ToucheWindowHeight":340})
        self.windowHeight = NSUserDefaults.standardUserDefaults().integerForKey_("ToucheWindowHeight")
        self.minWindowHeight = 340
        if self.windowHeight < self.minWindowHeight:
            self.windowHeight = self.minWindowHeight
        self.closedWindowHeight = 100
        self.w = FloatingWindow((180, self.windowHeight), u'Touché!', minSize=(180,340), maxSize=(250,898))
        self.w.bind("resize", self.windowResized)
        self.isResizing = False
        p = 10
        w = 160
        
        # options
        self.w.options = Group((0, 0, 180, 220))
        
        buttons = {
            "checkSelBtn": {"text": "Check selected glyphs", "callback": self.checkSel, "y": p},
        }
        for button, data in buttons.iteritems():
            setattr(self.w.options, button, 
            Button((p, data["y"], w - 22, 22), data["text"], callback=data["callback"], sizeStyle="small"))
            
        self.w.options.zeroCheck = CheckBox((p, 35, w, 20), "Ignore zero-width glyphs", value=True, sizeStyle="small")
        self.w.options.progress = ProgressSpinner((w - 8, 13, 16, 16), sizeStyle="small")
        
        # results
        self.w.results = Group((0, 220, 180, -0))
        self.w.results.show(False)
        
        textBoxes = {"stats": -34, "result": -18}
        for box, y in textBoxes.iteritems():
            setattr(self.w.results, box, TextBox((p, y, w, 14), "", sizeStyle="small"))
            
        # list and preview 
        self.w.outputList = List((0,58,-0,-40),
            [{"left glyph": "", "right glyph": ""}], columnDescriptions=[{"title": "left glyph", "width": 90}, {"title": "right glyph"}],
            showColumnTitles=False, allowsMultipleSelection=False, enableDelete=False, selectionCallback=self.showPair)
        self.w.outputList._setColumnAutoresizing()
        self._resizeWindow(False)
        self.w.open()
    
    
    # callbacks
        
    def checkAll(self, sender=None):
        self.check(useSelection=False)
        
    def checkSel(self, sender=None):
        self.check(useSelection=True)
        
    def check(self, useSelection):
        self._resizeWindow(enlarge=False)
        self.checkFont(useSelection=useSelection, excludeZeroWidth=self.w.options.zeroCheck.get())
    
    def showPair(self, sender=None):
        try:
            index = sender.getSelection()[0]
            glyphs = [self.f[gName] for gName in self.touchingPairs[index]]
            ActiveFont = self.f._font
            EditViewController = ActiveFont.currentTab
            if EditViewController is None:
                tabText = "/%s/%s" %(glyphs[0].name, glyphs[1].name)
                ActiveFont.newTab(tabText)
            else:
                textStorage = EditViewController.graphicView()
                if not hasattr(textStorage, "replaceCharactersInRange_withString_"): # compatibility with API change in 2.5
                    textStorage = EditViewController.graphicView().textStorage()
                LeftChar = ActiveFont.characterForGlyph_(glyphs[0]._object)
                RightChar = ActiveFont.characterForGlyph_(glyphs[1]._object)
                if LeftChar != 0 and RightChar != 0:
                    selection = textStorage.selectedRange()
                    if selection.length < 2:
                        selection.length = 2
                        if selection.location > 0:
                            selection.location -= 1
                    
                    NewString = ""
                    if LeftChar < 0xffff and RightChar < 0xffff:
                        NewString = u"%s%s" % (unichr(LeftChar), unichr(RightChar))
                    else:
                        print "Upper plane codes are not supported yet"
                    
                    textStorage.replaceCharactersInRange_withString_(selection, NewString)
                    selection.length = 0
                    selection.location += 1
                    textStorage.setSelectedRange_(selection)
            #self.w.preview.set(glyphs)
        except IndexError:
            pass
    
                
    # checking
        
    def _hasSufficientWidth(self, g):
        # to ignore combining accents and the like
        if self.excludeZeroWidth:
            # also skips 1-unit wide glyphs which many use instead of 0
            if g.width < 2 or g._object.subCategory == "Nonspacing":
                return False
        return True
    
    def _trimGlyphList(self, glyphList):
        newGlyphList = []
        for g in glyphList:
            if g.box is not None and self._hasSufficientWidth(g):
                newGlyphList.append(g)
        return newGlyphList
    
    def windowResized(self, window):
        posSize = self.w.getPosSize()
        Height = posSize[3]
        if Height > self.closedWindowHeight and self.isResizing is False:
            print "set new Height", Height
            NSUserDefaults.standardUserDefaults().setInteger_forKey_(Height, "ToucheWindowHeight")
            self.windowHeight = Height
    
    def _resizeWindow(self, enlarge=True):
        posSize = self.w.getPosSize()
        if enlarge:
            self.w.results.show(True)
            self.w.outputList.show(True)
            targetHeight = self.windowHeight
            if targetHeight < 340:
                targetHeight = 340
        else:
            self.w.results.show(False)
            self.w.outputList.show(False)
            targetHeight = self.closedWindowHeight
        self.isResizing = True
        self.w.setPosSize((posSize[0], posSize[1], posSize[2], targetHeight))
        self.isResizing = False
    
    # ok let's do this

    def checkFont(self, useSelection=False, excludeZeroWidth=True):
        f = CurrentFont()
        if f is not None:
            # initialize things
            self.w.options.progress.start()
            time0 = time.time()
            self.excludeZeroWidth = excludeZeroWidth
            self.f = f
    
            glyphNames = f.selection if useSelection else f.keys()
            glyphList = [f[x] for x in glyphNames]
            glyphList = self._trimGlyphList(glyphList)
            
            self.touchingPairs = Touche(f).findTouchingPairs(glyphList)
        
            # display output
            self.w.results.stats.set("%d glyphs checked" % len(glyphList))
            self.w.results.result.set("%d touching pairs found" % len(self.touchingPairs))
            self.w.results.show(True)
            
            outputList = [{"left glyph": g1, "right glyph": g2} for (g1, g2) in self.touchingPairs]
            self.w.outputList.set(outputList)
            if len(self.touchingPairs) > 0:
                self.w.outputList.setSelection([0])
            
            #self.w.preview.setFont(f)
            self.w.options.progress.stop()
            self._resizeWindow(enlarge=True)
        
            time1 = time.time()
            print u'Touché: finished checking %d glyphs in %.2f seconds' % (len(glyphList), time1-time0)
            
        else:
            Message(u'Touché: Can’t find a font to check')
Пример #44
0
class spacingObserver(object):
    
    def __init__(self):
        self.enableGroupSpacing = False
        self.popupOpen = False
        addObserver(self, 'glyphEditCallback', 'spaceCenterKeyDown')
        addObserver(self, 'glyphEditedCallback', 'spaceCenterKeyUp')
        addObserver(self, 'spaceCenterOpenCallback', 'spaceCenterDidOpen')
        addObserver(self, 'fontOpenCallback', 'fontDidOpen')
        self.previousMargins = {'left': 0, 'right': 0}

    def processMetricsGroups(self, baseGlyph=None):
            
        for groupName in self.metricsGroups:
            
            if (baseGlyph is None) and len(self.font.groups[groupName]) > 0:
                baseGlyph = self.font.groups[groupName][0]
                self.previousMargins['left'] = self.font[baseGlyph].angledLeftMargin
                self.previousMargins['right'] = self.font[baseGlyph].angledRightMargin
            
            if (metricsPrefix in groupName) and (baseGlyph in self.font.groups[groupName]):
                if (leftIndicator in groupName) and (self.previousMargins['left'] != self.font[baseGlyph].angledLeftMargin):
                    self.setGroupSpacing(baseGlyph, self.font.groups[groupName], 'Left')                    
                elif (rightIndicator in groupName) and (self.previousMargins['right'] != self.font[baseGlyph].angledRightMargin):    
                    self.setGroupSpacing(baseGlyph, self.font.groups[groupName], 'Right') 
    

    def setGroupSpacing(self, baseGlyphName, group, side):
        
        for glyphName in group:
            
            baseGlyph = self.font[baseGlyphName]
            targetGlyph = self.font[glyphName]

            if glyphName is not baseGlyphName:
        
                if (len(targetGlyph.components) > 0) and (side == 'Left'):
                    for component in targetGlyph.components:
                        if component.baseGlyph in group:
                            component.move((self.previousMargins['left']-baseGlyph.angledLeftMargin, 0))

                self.setSidebearing(baseGlyph, targetGlyph, side)

            elif glyphName is baseGlyphName:

                if (len(baseGlyph.components) > 0) and (side == 'Left'):
                    for component in baseGlyph.components:
                        if component.baseGlyph in group:
                            component.move((self.previousMargins['left']-baseGlyph.angledLeftMargin, 0))

            targetGlyph.update()
                    
    def setSidebearing(self, baseGlyph, targetGlyph, side):
        baseMargin = getattr(baseGlyph, 'angled' + side + 'Margin')
        targetMargin = getattr(targetGlyph, 'angled' + side + 'Margin')
        
        if targetMargin != baseMargin:
            setattr(targetGlyph, 'angled' + side + 'Margin', baseMargin)

                    
    def getMetricsGroups(self, notification=None):
        self.font = CurrentFont()            
        if self.font is not None:
            self.metricsGroups = [group for group in self.font.groups.keys() if metricsPrefix in group and leftIndicator in group or rightIndicator in group]         
            if (notification is not None) and (self.enableGroupSpacing == True):
                self.processMetricsGroups()
         

    def enableGroupSpacingCallback(self, sender):
        self.enableGroupSpacing = sender.get()
 
    def glyphEditCallback(self, notification):

        edGlyph = notification['glyph']
        self.previousMargins = {'width': edGlyph.width, 'left': edGlyph.angledLeftMargin, 'right': edGlyph.angledRightMargin}

    def glyphEditedCallback(self, notification):
        
        if self.enableGroupSpacing == True:
        
            edGlyph = notification['glyph']
            
            if self.font != CurrentFont():
                self.getMetricsGroups()
            
            self.processMetricsGroups(edGlyph.name)   
        

    def spaceCenterOpenCallback(self, notification):
        if (not self.popupOpen) and (len(self.metricsGroups) > 0):
            self.w = FloatingWindow((160, 36), 'Group Spacing')
            self.w.activateGroups = CheckBox((9, -27, 151, 18), "Activate Group spacing", value=self.enableGroupSpacing, callback=self.enableGroupSpacingCallback, sizeStyle="small")
            self.w.bind('close', self.windowCloseCallback)
            self.w.open()
            self.popupOpen = True

    def windowCloseCallback(self, notification):
        self.popupOpen = False

    def fontOpenCallback(self, notification):
        font = notification['font']
        font.groups.addObserver(self, 'getMetricsGroups', 'Groups.Changed')
        self.getMetricsGroups(notification)
Пример #45
0
 def __init__(self):
     
     # Preferences
     self._drawing = getExtensionDefault(self.DEFAULTKEY_DRAW, True)
     self._fill = getExtensionDefault(self.DEFAULTKEY_FILL, True)
     self._stroke = getExtensionDefault(self.DEFAULTKEY_STROKE, True)
     self._points = getExtensionDefault(self.DEFAULTKEY_POINTS, True)
     
     self._fillColor = getExtensionDefaultColor(self.DEFAULTKEY_FILLCOLOR, self.FALLBACK_FILLCOLOR)
     self._strokeColor = getExtensionDefaultColor(self.DEFAULTKEY_STROKECOLOR, self.FALLBACK_STROKECOLOR)
     self._pointsColor = getExtensionDefaultColor(self.DEFAULTKEY_POINTSCOLOR, self.FALLBACK_POINTSCOLOR)
     
     self._alignment = getExtensionDefault(self.DEFAULTKEY_ALIGNMENT, 0)
     self._kerning = getExtensionDefault(self.DEFAULTKEY_KERNING, 1)
     self._floating = getExtensionDefault(self.DEFAULTKEY_FLOATING, 1)
     
     # User preferences
     self._onCurvePointsSize = getDefault("glyphViewOncurvePointsSize") # typo, should be: OnCurve
     self._offCurvePointsSize = getDefault("glyphViewOffCurvePointsSize")
     self._strokeWidth = getDefault("glyphViewStrokeWidth")
     
     w, h = 400, 195
     x = y = 10
     
     self.initAllFonts()
     
     self.w = FloatingWindow((w, h), "Overlay UFOs")
     self.w.draw = CheckBox((x, y, 95, 18), "Draw", callback=self.drawCallback, value=self._drawing, sizeStyle="small")
     x += 60
     self.w.fill = CheckBox((x, y, 95, 18), "Fill", callback=self.fillCallback, value=self._fill, sizeStyle="small")
     x += 40
     self.w.fillColor = ColorWell((x, y, 45, 20), callback=self.fillColorCallback, color=self._fillColor)
     x += 60
     self.w.stroke = CheckBox((x, y, 95, 18), "Stroke", callback=self.strokeCallback, value=self._stroke, sizeStyle="small")
     x += 60
     self.w.strokeColor = ColorWell((x, y, 45, 20), callback=self.strokeColorCallback, color=self._strokeColor)
     x += 60
     self.w.points = CheckBox((x, y, 95, 18), "Points", callback=self.pointsCallback, value=self._points, sizeStyle="small")
     x += 60
     self.w.pointsColor = ColorWell((x, y, 45, 20), callback=self.pointsColorCallback, color=self._pointsColor)
     x, y = 10, 40
     self.w.alignText = TextBox((x, y, 250, 15), "Alignment:", sizeStyle="small")
     y += 18
     self.w.alignment = RadioGroup((x, y, 80, 55), ['Left', 'Center', 'Right'], isVertical=True, callback=self.alignmentCallback, sizeStyle="small")
     self.w.alignment.set(self._alignment)
     y += 62
     self.w.kerning = CheckBox((x, y, 100, 10), "Show kerning", callback=self.kerningCallback, value=self._kerning, sizeStyle="mini")
     y += 18
     self.w.floating = CheckBox((x, y, 100, 10), "Floating Window", callback=self.floatingCallback, value=self._floating, sizeStyle="mini")
     y += 25
     self.w.resetDefaults = Button((x, y, 85, 14), "Reset settings", callback=self.resetSettingsCallback, sizeStyle="mini")
     x, y = 110, 40
     self.w.fontList = List((x, y, 240, 55), self.getFontItems(), 
         columnDescriptions=self.getListDescriptor(), showColumnTitles=False,
         selectionCallback=None, doubleClickCallback=self.fontListCallback,
         allowsMultipleSelection=True, allowsEmptySelection=True,
         drawVerticalLines=False, drawHorizontalLines=True,
         drawFocusRing=False, rowHeight=16
     )
     y += 55
     self.w.hiddenFontList = List((x, y, 240, 55), self.getHiddenFontItems(), 
         columnDescriptions=self.getListDescriptor(), showColumnTitles=False,
         selectionCallback=None, doubleClickCallback=self.hiddenFontListCallback,
         allowsMultipleSelection=True, allowsEmptySelection=True,
         drawVerticalLines=False, drawHorizontalLines=True,
         drawFocusRing=False, rowHeight=16
     )
     self._selectionChanging = False
     self.w.fontList.setSelection([]) # unselect
     y += 65
     self.w.contextLeft = EditText((x, y, 90, 20), callback=self.contextCallback, continuous=True, placeholder="Left", sizeStyle="small")
     self.w.contextCurrent = EditText((x+95, y, 50, 20), callback=self.contextCallback, continuous=True, placeholder="?", sizeStyle="small")
     self.w.contextRight = EditText((x+150, y, 90, 20), callback=self.contextCallback, continuous=True, placeholder="Right", sizeStyle="small")
     x, y = 360, 100
     self.w.addFonts = Button((x, y, 30, 20), "+", callback=self.addHiddenFontsCallback, sizeStyle="regular")
     y += 25
     self.w.removeFonts = Button((x, y, 30, 20), unichr(8722), callback=self.removeHiddenFontsCallback, sizeStyle="regular")
             
     # Observers
     addObserver(self, "fontDidOpen", "fontDidOpen")
     addObserver(self, "fontWillClose", "fontWillClose") # fontDidClose?
     addObserver(self, "draw", "drawInactive")
     addObserver(self, "draw", "draw")
     
     # Prepare and open window
     self.setWindowLevel()
     self.setUpBaseWindowBehavior()
     self.w.open()
Пример #46
0
	def __init__(self):
		self.font = CurrentFont()
		self.glyph = CurrentGlyph()
		self.upm = self.font.info.unitsPerEm
		self.glyphPreviewCacheDict = {} # key: glyph name -- value: list containing assembled glyphs
		self.anchorsOnMarksDict = {} # key: anchor name -- value: list of mark glyph names
		self.anchorsOnBasesDict = {} # key: anchor name -- value: list of base glyph names
		self.marksDict = {} # key: mark glyph name -- value: anchor name (NOTE: It's expected that each mark glyph only has one type of anchor)
		self.fillAnchorsAndMarksDicts()
		self.glyphNamesList = [] # list of glyph names that will be displayed in the UI list
		self.selectedGlyphNamesList = [] # list of glyph names selected in the UI list
		self.extraGlyphsList = [] # list of the glyph objects that should be inserted before and after the accented glyphs

		self.Blue, self.Alpha = 1, 0.6

		self.font.naked().addObserver(self, "fontWasModified", "Font.Changed")
		addObserver(self, "_fontWillClose", "fontWillClose")
		addObserver(self, "_currentFontChanged", "fontResignCurrent")
		addObserver(self, "_currentGlyphChanged", "currentGlyphChanged")
		addObserver(self, "_drawFill", "draw")
		addObserver(self, "_drawFill", "drawInactive")
		addObserver(self, "_previewFill", "drawPreview")
		addObserver(self, "_drawGlyphs", "draw") # observer for the draw event
		addObserver(self, "_drawGlyphs", "drawInactive") # draw the glyphs when the glyph window is not in focus
		addObserver(self, "_drawGlyphs", "drawPreview")

		integerNumFormatter = NSNumberFormatter.alloc().init()
		integerNumFormatter.setAllowsFloats_(False)
		integerNumFormatter.setGeneratesDecimalNumbers_(False)

		intPosMinZeroNumFormatter = NSNumberFormatter.alloc().init()
		intPosMinZeroNumFormatter.setAllowsFloats_(False)
		intPosMinZeroNumFormatter.setGeneratesDecimalNumbers_(False)
		intPosMinZeroNumFormatter.setMinimum_(NSNumber.numberWithInt_(0))

		intPosMinOneNumFormatter = NSNumberFormatter.alloc().init()
		intPosMinOneNumFormatter.setAllowsFloats_(False)
		intPosMinOneNumFormatter.setGeneratesDecimalNumbers_(False)
		intPosMinOneNumFormatter.setMinimum_(NSNumber.numberWithInt_(1))

		self.textSize = getExtensionDefault("%s.%s" % (extensionKey, "textSize"))
		if not self.textSize:
			self.textSize = 150

		self.lineHeight = getExtensionDefault("%s.%s" % (extensionKey, "lineHeight"))
		if not self.lineHeight:
			self.lineHeight = 200

		self.extraSidebearings = getExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings"))
		if not self.extraSidebearings:
			self.extraSidebearings = [0, 0]

		self.extraGlyphs = getExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs"))
		if not self.extraGlyphs:
			self.extraGlyphs = ''

		posSize = getExtensionDefault("%s.%s" % (extensionKey, "posSize"))
		if not posSize:
			posSize = (100, 100, 1200, 400)

		self.calibrateMode = getExtensionDefault("%s.%s" % (extensionKey, "calibrateMode"))
		if not self.calibrateMode:
			self.calibrateMode = False

		calibrateModeStrings = getExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings"))
		if not calibrateModeStrings:
			calibrateModeStrings = {
				'group1.baseInput': 'dotlessi o s',
				'group1.markInput': 'dieresis circumflex macron breve caron',
				'group2.baseInput': 'I O S',
				'group2.markInput': 'dieresis.cap circumflex.cap macron.cap breve.cap caron.cap',
				'group3.baseInput': 'I.sc O.sc S.sc',
				'group3.markInput': 'dieresis circumflex macron breve caron',
				'group4.baseInput': '',
				'group4.markInput': '',
			}

		# -- Window --
		self.w = FloatingWindow(posSize, extensionName, minSize=(500, 400))
		self.w.fontList = List((10, 10, 190, -41), self.glyphNamesList, selectionCallback=self.listSelectionCallback)
		if roboFontVersion < '1.7':
			self.w.fontList.getNSTableView().sizeToFit() # use the full width of the column
		self.w.fontList.show(not self.calibrateMode)
		self.w.lineView = MultiLineView((210, 10, -10, -41),
							pointSize = self.textSize,
							lineHeight = self.lineHeight,
							displayOptions={"Beam" : False, "displayMode" : "Multi Line"}
							)

		# -- Calibration Mode --
		baseLabel = "Bases"
		markLabel = "Marks"
		width, height = 190, 140
		self.cm = Group((0, 0, 0, 0))
		# ---
		self.cm.group1 = Group((5, height*0, width, height-10))
		self.cm.group1.baseLabel = TextBox((0, 0, width, 20), baseLabel)
		self.cm.group1.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group1.baseInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group1.markLabel = TextBox((0, 50, width, 20), markLabel)
		self.cm.group1.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group1.markInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group1.divider = HorizontalLine((0, -1, -0, 1))
		# ---
		self.cm.group2 = Group((5, height*1, width, height-10))
		self.cm.group2.baseLabel = TextBox((0, 0, width, 20), baseLabel)
		self.cm.group2.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group2.baseInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group2.markLabel = TextBox((0, 50, width, 20), markLabel)
		self.cm.group2.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group2.markInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group2.divider = HorizontalLine((0, -1, -0, 1))
		# ---
		self.cm.group3 = Group((5, height*2, width, height-10))
		self.cm.group3.baseLabel = TextBox((0, 0, width, 20), baseLabel)
		self.cm.group3.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group3.baseInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group3.markLabel = TextBox((0, 50, width, 20), markLabel)
		self.cm.group3.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group3.markInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group3.divider = HorizontalLine((0, -1, -0, 1))
		# ---
		self.cm.group4 = Group((5, height*3, width, height-10))
		self.cm.group4.baseLabel = TextBox((0, 0, width, 20), baseLabel)
		self.cm.group4.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group4.baseInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group4.markLabel = TextBox((0, 50, width, 20), markLabel)
		self.cm.group4.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group4.markInput'], callback=self.updateCalibrateMode, continuous=False)
		# ---
		view = DefconAppKitTopAnchoredNSView.alloc().init()
		view.addSubview_(self.cm.getNSView())
		view.setFrame_(((0, 0), (width+10, height*4-23)))
		self.cm.setPosSize((0, 0, width+10, height*4-22))
		self.w.scrollView = ScrollView((5, 10, width+10, -41), view, drawsBackground=False, hasHorizontalScroller=False)
		self.w.scrollView.getNSScrollView().setBorderType_(NSNoBorder)
		self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1) # NSScrollElasticityNone
		self.w.scrollView.show(self.calibrateMode)

		# -- Footer --
		self.w.calibrateModeCheck = CheckBox((10, -32, 200, -10), "Calibration Mode", callback=self.calibrateModeCallback, value=self.calibrateMode)
		self.w.textSizeLabel = TextBox((210, -30, 100, -10), "Text Size")
		self.w.textSize = EditText((270, -32, 35, -10), self.textSize, callback=self.textSizeCallback, continuous=False, formatter=intPosMinOneNumFormatter)
		self.w.lineHeightLabel = TextBox((320, -30, 100, -10), "Line Height")
		self.w.lineHeight = EditText((395, -32, 35, -10), self.lineHeight, callback=self.lineHeightCallback, continuous=False, formatter=integerNumFormatter)
		self.w.extraSidebearingsLabel = TextBox((446, -30, 180, -10), "Extra Sidebearings")
		self.w.extraSidebearingsChar  = TextBox((602, -30, 20, -10), "&")
		self.w.extraSidebearingLeft  = EditText((567, -32, 35, -10), self.extraSidebearings[0], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter)
		self.w.extraSidebearingRight = EditText((614, -32, 35, -10), self.extraSidebearings[1], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter)
		self.w.extraGlyphsLabel = TextBox((665, -30, 180, -10), "Extra Glyphs")
		self.w.extraGlyphs = EditText((749, -32, -10, -10), self.extraGlyphs, callback=self.extraGlyphsCallback, continuous=False)

		# trigger the initial state and contents of the window
		self.extraGlyphsCallback() # this will call self.updateExtensionWindow()

		self.w.bind("close", self.windowClose)
		self.w.open()
		self.w.makeKey()
Пример #47
0
class OverlayUFOs(BaseWindowController):
    
    DEFAULTKEY = "com.fontbureau.overlayUFO"
    DEFAULTKEY_DRAW = "%s.draw" % DEFAULTKEY
    DEFAULTKEY_FILL = "%s.fill" % DEFAULTKEY
    DEFAULTKEY_FILLCOLOR = "%s.fillColor" % DEFAULTKEY
    DEFAULTKEY_STROKE = "%s.stroke" % DEFAULTKEY
    DEFAULTKEY_STROKECOLOR = "%s.strokeColor" % DEFAULTKEY
    DEFAULTKEY_POINTS = "%s.points" % DEFAULTKEY
    DEFAULTKEY_POINTSCOLOR = "%s.pointsColor" % DEFAULTKEY
    DEFAULTKEY_ALIGNMENT = "%s.alignment" % DEFAULTKEY
    DEFAULTKEY_KERNING = "%s.kerning" % DEFAULTKEY
    DEFAULTKEY_FLOATING = "%s.floating" % DEFAULTKEY
    
    FALLBACK_FILLCOLOR = NSColor.colorWithCalibratedRed_green_blue_alpha_(0, 0.3, 1, .1)
    FALLBACK_STROKECOLOR = NSColor.colorWithCalibratedRed_green_blue_alpha_(0, 0.3, 1, .5)
    FALLBACK_POINTSCOLOR = NSColor.colorWithCalibratedRed_green_blue_alpha_(0, 0.3, 1, .5)
    
    def getListDescriptor(self): 
        return [
            dict(title="Status", key="status", width=10, cell=SmallTextListCell(), editable=False), 
            dict(title="Name", key="name", width=230, cell=SmallTextListCell(), editable=False), 
        ]
    
    def __init__(self):
        
        # Preferences
        self._drawing = getExtensionDefault(self.DEFAULTKEY_DRAW, True)
        self._fill = getExtensionDefault(self.DEFAULTKEY_FILL, True)
        self._stroke = getExtensionDefault(self.DEFAULTKEY_STROKE, True)
        self._points = getExtensionDefault(self.DEFAULTKEY_POINTS, True)
        
        self._fillColor = getExtensionDefaultColor(self.DEFAULTKEY_FILLCOLOR, self.FALLBACK_FILLCOLOR)
        self._strokeColor = getExtensionDefaultColor(self.DEFAULTKEY_STROKECOLOR, self.FALLBACK_STROKECOLOR)
        self._pointsColor = getExtensionDefaultColor(self.DEFAULTKEY_POINTSCOLOR, self.FALLBACK_POINTSCOLOR)
        
        self._alignment = getExtensionDefault(self.DEFAULTKEY_ALIGNMENT, 0)
        self._kerning = getExtensionDefault(self.DEFAULTKEY_KERNING, 1)
        self._floating = getExtensionDefault(self.DEFAULTKEY_FLOATING, 1)
        
        # User preferences
        self._onCurvePointsSize = getDefault("glyphViewOncurvePointsSize") # typo, should be: OnCurve
        self._offCurvePointsSize = getDefault("glyphViewOffCurvePointsSize")
        self._strokeWidth = getDefault("glyphViewStrokeWidth")
        
        w, h = 400, 195
        x = y = 10
        
        self.initAllFonts()
        
        self.w = FloatingWindow((w, h), "Overlay UFOs")
        self.w.draw = CheckBox((x, y, 95, 18), "Draw", callback=self.drawCallback, value=self._drawing, sizeStyle="small")
        x += 60
        self.w.fill = CheckBox((x, y, 95, 18), "Fill", callback=self.fillCallback, value=self._fill, sizeStyle="small")
        x += 40
        self.w.fillColor = ColorWell((x, y, 45, 20), callback=self.fillColorCallback, color=self._fillColor)
        x += 60
        self.w.stroke = CheckBox((x, y, 95, 18), "Stroke", callback=self.strokeCallback, value=self._stroke, sizeStyle="small")
        x += 60
        self.w.strokeColor = ColorWell((x, y, 45, 20), callback=self.strokeColorCallback, color=self._strokeColor)
        x += 60
        self.w.points = CheckBox((x, y, 95, 18), "Points", callback=self.pointsCallback, value=self._points, sizeStyle="small")
        x += 60
        self.w.pointsColor = ColorWell((x, y, 45, 20), callback=self.pointsColorCallback, color=self._pointsColor)
        x, y = 10, 40
        self.w.alignText = TextBox((x, y, 250, 15), "Alignment:", sizeStyle="small")
        y += 18
        self.w.alignment = RadioGroup((x, y, 80, 55), ['Left', 'Center', 'Right'], isVertical=True, callback=self.alignmentCallback, sizeStyle="small")
        self.w.alignment.set(self._alignment)
        y += 62
        self.w.kerning = CheckBox((x, y, 100, 10), "Show kerning", callback=self.kerningCallback, value=self._kerning, sizeStyle="mini")
        y += 18
        self.w.floating = CheckBox((x, y, 100, 10), "Floating Window", callback=self.floatingCallback, value=self._floating, sizeStyle="mini")
        y += 25
        self.w.resetDefaults = Button((x, y, 85, 14), "Reset settings", callback=self.resetSettingsCallback, sizeStyle="mini")
        x, y = 110, 40
        self.w.fontList = List((x, y, 240, 55), self.getFontItems(), 
            columnDescriptions=self.getListDescriptor(), showColumnTitles=False,
            selectionCallback=None, doubleClickCallback=self.fontListCallback,
            allowsMultipleSelection=True, allowsEmptySelection=True,
            drawVerticalLines=False, drawHorizontalLines=True,
            drawFocusRing=False, rowHeight=16
        )
        y += 55
        self.w.hiddenFontList = List((x, y, 240, 55), self.getHiddenFontItems(), 
            columnDescriptions=self.getListDescriptor(), showColumnTitles=False,
            selectionCallback=None, doubleClickCallback=self.hiddenFontListCallback,
            allowsMultipleSelection=True, allowsEmptySelection=True,
            drawVerticalLines=False, drawHorizontalLines=True,
            drawFocusRing=False, rowHeight=16
        )
        self._selectionChanging = False
        self.w.fontList.setSelection([]) # unselect
        y += 65
        self.w.contextLeft = EditText((x, y, 90, 20), callback=self.contextCallback, continuous=True, placeholder="Left", sizeStyle="small")
        self.w.contextCurrent = EditText((x+95, y, 50, 20), callback=self.contextCallback, continuous=True, placeholder="?", sizeStyle="small")
        self.w.contextRight = EditText((x+150, y, 90, 20), callback=self.contextCallback, continuous=True, placeholder="Right", sizeStyle="small")
        x, y = 360, 100
        self.w.addFonts = Button((x, y, 30, 20), "+", callback=self.addHiddenFontsCallback, sizeStyle="regular")
        y += 25
        self.w.removeFonts = Button((x, y, 30, 20), unichr(8722), callback=self.removeHiddenFontsCallback, sizeStyle="regular")
                
        # Observers
        addObserver(self, "fontDidOpen", "fontDidOpen")
        addObserver(self, "fontWillClose", "fontWillClose") # fontDidClose?
        addObserver(self, "draw", "drawInactive")
        addObserver(self, "draw", "draw")
        
        # Prepare and open window
        self.setWindowLevel()
        self.setUpBaseWindowBehavior()
        self.w.open()
    
    def setWindowLevel(self):
        if self._floating:
            self.w._window.setLevel_(NSFloatingWindowLevel)
        else:
            self.w._window.setLevel_(NSNormalWindowLevel)
            
    def windowCloseCallback(self, sender):
        removeObserver(self, "fontDidOpen")
        removeObserver(self, "fontWillClose")
        removeObserver(self, "drawInactive")
        removeObserver(self, "draw")
        self.updateView()
        super(OverlayUFOs, self).windowCloseCallback(sender)
    
    def updateView(self):
        UpdateCurrentGlyphView()
    
    def initAllFonts(self):
        fonts = []
        for font in AllFonts():
            fonts.append({"font": font, "status": u"•"})
        self.fonts = fonts
        self.hiddenFonts = []
            
    def getFontName(self, font):
        if font.document():
            name = font.document().displayName()
        else:
            name = font.fileName.split("/")[-1]
        return name
    
    def getHiddenFontItems(self):
        hiddenFonts = self.hiddenFonts
        hiddenFontItems = self.getItems(hiddenFonts)
        return hiddenFontItems
    
    def getFontItems(self):
        fonts = self.fonts
        fontItems = self.getItems(fonts)
        return fontItems
    
    def getItems(self, fonts):
        items = []
        uniqueNames = {}
        for f in fonts:
            font = f["font"]
            status = f["status"]
            path = font.path
            name = self.getFontName(font)
            if not uniqueNames.has_key(name):
                uniqueNames[name] = []
            uniqueNames[name].append(path)
            paths = uniqueNames[name]
            if len(paths) > 1:
                prefix = commonprefix(paths)
                if prefix:
                    suffix = " ...%s" % path[len(prefix):]
                else:
                    suffix = " %s" % path
                name += suffix
            items.append({"status": status, "name": name})
        return items
    
    def getActiveFonts(self):
        fonts = self.fonts + self.hiddenFonts
        activeFonts = []
        for font in fonts:
            if font["status"]:
                activeFonts.append(font["font"])
        return activeFonts
    
    def getContexts(self):
        return self.w.contextLeft.get(), self.w.contextCurrent.get(), self.w.contextRight.get()
    
    def getAlignment(self):
        index = self._alignment
        if index == 0:
            return 'left'
        elif index == 1:
            return 'center'
        elif index == 2:
            return 'right'
    
    def getKernValue(self, nakedFont, leftGlyph, rightGlyph):
        if not leftGlyph or not rightGlyph:
            return 0
        if not self._kerning:
            return 0
        return nakedFont.flatKerning.get((leftGlyph.name, rightGlyph.name)) or 0
    
    def draw(self, info):
        
        if not self._drawing:
            return
            
        glyph = info.get("glyph")
        drawingScale = info.get('scale')
        
        if glyph is None:
            return
            
        current = glyph.getParent()
        fonts = self.getActiveFonts()
        
        for font in fonts:
            
            nakedFont = font.naked()
            
            contextLeft, contextCurrent, contextRight = self.getContexts()
            contextLeft = splitText(contextLeft or '', nakedFont.unicodeData or '')
            contextLeft = [font[gname] for gname in contextLeft if gname in font.keys()]
            contextRight = splitText(contextRight or '', nakedFont.unicodeData or '')
            contextRight = [font[gname] for gname in contextRight if gname in font.keys()]
            contextCurrent = splitText(contextCurrent or '', nakedFont.unicodeData or '')
            if len(contextCurrent) > 0:
                contextCurrent = [font[gname] for gname in [contextCurrent[0]] if gname in font.keys()]
                if len(contextCurrent) > 0:
                    sourceGlyph = contextCurrent[0]
                else:
                    sourceGlyph = None
            elif glyph.name in font.keys():
                sourceGlyph = font[glyph.name]
                contextCurrent = [sourceGlyph]
            else:
                sourceGlyph = None
                contextCurrent = []
            
            save()
            
            self._fillColor.setFill()
            self._strokeColor.setStroke()
            scale(current.info.unitsPerEm/float(font.info.unitsPerEm))
            
            # Draw left context
            previousGlyph = sourceGlyph
            contextLeft.reverse()
            totalWidth = 0
            for i, cbGlyph in enumerate(contextLeft):
                kernValue = self.getKernValue(nakedFont, cbGlyph, previousGlyph) # right to left
                translate(-cbGlyph.width-kernValue, 0)
                totalWidth += cbGlyph.width + kernValue
                glyphBezierPath = cbGlyph.naked().getRepresentation("defconAppKit.NSBezierPath")
                if self._fill:
                    glyphBezierPath.fill()
                if self._stroke:
                    glyphBezierPath.setLineWidth_(self._strokeWidth*drawingScale)
                    strokePixelPath(glyphBezierPath)
                previousGlyph = cbGlyph
            translate(totalWidth, 0)
            
            # Draw current context or current glyph 
            if contextCurrent:
                previousGlyph = None
                alignment = self.getAlignment()
                if alignment == 'left':
                    offset = 0
                elif alignment == 'center':
                    offset = (glyph.width - contextCurrent[0].width)/2                                        
                elif alignment == 'right':
                    offset = glyph.width - contextCurrent[0].width                                     
                totalWidth = offset
                translate(totalWidth, 0)
            
            for i, cbGlyph in enumerate(contextCurrent):
                #if cbGlyph == glyph:
                #    continue # Don't show if is current glyph
                kernValue = self.getKernValue(nakedFont, previousGlyph, cbGlyph)
                translate(kernValue, 0)
                glyphBezierPath = cbGlyph.naked().getRepresentation("defconAppKit.NSBezierPath")
                if self._fill:
                    glyphBezierPath.fill()
                if self._stroke:
                    glyphBezierPath.setLineWidth_(self._strokeWidth*drawingScale)
                    strokePixelPath(glyphBezierPath)
                if self._points:
                    self.drawPoints(cbGlyph, info['scale'])
                translate(cbGlyph.width, 0)
                totalWidth += cbGlyph.width + kernValue
                previousGlyph = cbGlyph
            translate(-totalWidth, 0)
            
            # Draw right context
            translate(glyph.width)
            totalWidth = glyph.width
            for i, cbGlyph in enumerate(contextRight):
                kernValue = self.getKernValue(nakedFont, previousGlyph, cbGlyph)
                translate(kernValue, 0)
                glyphBezierPath = cbGlyph.naked().getRepresentation("defconAppKit.NSBezierPath")
                if self._fill:
                    glyphBezierPath.fill()
                if self._stroke:
                    glyphBezierPath.setLineWidth_(self._strokeWidth*drawingScale)
                    strokePixelPath(glyphBezierPath)
                translate(cbGlyph.width, 0)
                totalWidth += cbGlyph.width + kernValue
                previousGlyph = cbGlyph
                
            restore()
    
    def drawPoints(self, glyph, scale):
        save()
        _onCurveSize = self._onCurvePointsSize * scale
        _offCurveSize = self._offCurvePointsSize * scale
        _strokeWidth = self._strokeWidth * scale
        
        self._pointsColor.set()
        
        path = NSBezierPath.bezierPath()
        offCurveHandlesPath = NSBezierPath.bezierPath()
        pointsData = glyph.getRepresentation("doodle.OutlineInformation")
        
        for point1, point2 in pointsData["bezierHandles"]:
            offCurveHandlesPath.moveToPoint_(point1)
            offCurveHandlesPath.lineToPoint_(point2)

        for point in pointsData.get("offCurvePoints"):
            (x, y) = point["point"]
            path.appendBezierPathWithOvalInRect_(NSMakeRect(x - _offCurveSize, y - _offCurveSize, _offCurveSize * 2, _offCurveSize * 2))
            
        for point in pointsData.get("onCurvePoints"):
            (x, y) = point["point"]
            path.appendBezierPathWithRect_(NSMakeRect(x - _onCurveSize, y - _onCurveSize, _onCurveSize * 2, _onCurveSize * 2))
            
        path.fill()
        offCurveHandlesPath.setLineWidth_(_strokeWidth)
        strokePixelPath(offCurveHandlesPath)
        restore()

    def fontDidOpen(self, event):
        font = event["font"]
        self.fonts.append({"font": font, "status": u"•"})
        self.w.fontList.set(self.getFontItems())
        self.updateView()
    
    def fontWillClose(self, event):
        # not always working... try from path or name?
        closingFont = event["font"]
        for i, font in enumerate(self.fonts):
            if font["font"] == closingFont:
                del self.fonts[i]
                item = self.w.fontList.get()[i]
                self.w.fontList.remove(item)
                break
        self.updateView()
    
    def fontListCallback(self, sender):
        fonts = self.fonts
        self.listCallback(sender, fonts)

    def hiddenFontListCallback(self, sender):
        fonts = self.hiddenFonts
        self.listCallback(sender, fonts)
            
    def listCallback(self, sender, fonts):
        for index in sender.getSelection():
            item = sender.get()[index]
            font = fonts[index]
            if item["status"]:
                item["status"] = font["status"] = ""
            else:
                item["status"] = font["status"] = u"•"
        self.updateView()
    
    def contextCallback(self, sender):
        self.updateView()
    
    def drawCallback(self, sender):
        drawing = sender.get()
        setExtensionDefault(self.DEFAULTKEY_DRAW, drawing)
        self._drawing = drawing
        self.updateView()
    
    def fillCallback(self, sender):
        fill = sender.get()
        setExtensionDefault(self.DEFAULTKEY_FILL, fill)
        self._fill = fill
        self.updateView()
    
    def fillColorCallback(self, sender):
        fillColor = sender.get()
        setExtensionDefaultColor(self.DEFAULTKEY_FILLCOLOR, fillColor)
        self._fillColor = fillColor
        self.updateView()
    
    def strokeCallback(self, sender):
        stroke = sender.get()
        setExtensionDefault(self.DEFAULTKEY_STROKE, stroke)
        self._stroke = stroke
        self.updateView()
    
    def strokeColorCallback(self, sender):
        strokeColor = sender.get()
        setExtensionDefaultColor(self.DEFAULTKEY_STROKECOLOR, strokeColor)
        self._strokeColor = strokeColor
        self.updateView()
    
    def pointsCallback(self, sender):
        points = sender.get()
        setExtensionDefault(self.DEFAULTKEY_POINTS, points)
        self._points = points
        self.updateView()
    
    def pointsColorCallback(self, sender):
        pointsColor = sender.get()
        setExtensionDefaultColor(self.DEFAULTKEY_POINTSCOLOR, pointsColor)
        self._pointsColor = pointsColor
        self.updateView()
    
    def alignmentCallback(self, sender):
        alignment = sender.get()
        setExtensionDefault(self.DEFAULTKEY_ALIGNMENT, alignment)
        self._alignment = alignment
        self.updateView()
    
    def kerningCallback(self, sender):
        kerning = sender.get()
        setExtensionDefault(self.DEFAULTKEY_KERNING, kerning)
        self._kerning = kerning
        self.updateView()

    def floatingCallback(self, sender):
        floating = sender.get()
        setExtensionDefault(self.DEFAULTKEY_FLOATING, floating)
        self._floating = floating
        self.setWindowLevel()
        
    def resetSettingsCallback(self, sender):
        drawing = True
        fill = True
        fillColor = self.FALLBACK_FILLCOLOR
        stroke = True
        strokeColor = self.FALLBACK_STROKECOLOR
        points = True
        pointsColor = self.FALLBACK_POINTSCOLOR
        alignment = 0
        kerning = True
        floating = True
        
        setExtensionDefault(self.DEFAULTKEY_DRAW, drawing)
        setExtensionDefault(self.DEFAULTKEY_FILL, fill)
        setExtensionDefaultColor(self.DEFAULTKEY_FILLCOLOR, fillColor)
        setExtensionDefault(self.DEFAULTKEY_STROKE, stroke)
        setExtensionDefaultColor(self.DEFAULTKEY_STROKECOLOR, strokeColor)
        setExtensionDefault(self.DEFAULTKEY_POINTS, points)
        setExtensionDefaultColor(self.DEFAULTKEY_POINTSCOLOR, pointsColor)
        setExtensionDefault(self.DEFAULTKEY_ALIGNMENT, alignment)
        setExtensionDefault(self.DEFAULTKEY_KERNING, kerning)
        setExtensionDefault(self.DEFAULTKEY_FLOATING, floating)
        
        self.w.draw.set(drawing)
        self.w.fill.set(fill)
        self.w.fillColor.set(fillColor)
        self.w.stroke.set(stroke)
        self.w.strokeColor.set(strokeColor)
        self.w.points.set(points)
        self.w.pointsColor.set(strokeColor)
        self.w.alignment.set(alignment)
        self.w.kerning.set(kerning)
        self.w.floating.set(floating)
        
        self._drawing = drawing
        self._fill = fill
        self._fillColor = fillColor
        self._stroke = stroke
        self._strokeColor = strokeColor
        self._points = points
        self._pointsColor = strokeColor
        self._alignment = alignment
        self._kerning = kerning
        self._floating = floating
        
        self.updateView()

    def addHiddenFontsCallback(self, sender):
        fonts = OpenFont(None, False)
        if fonts is None:
            return
        if not isinstance(fonts, list): # make sure it's a list
            fonts = [fonts] 
        paths = [font["font"].path for font in self.hiddenFonts]
        for font in fonts:
            if font.path in paths:
                continue # already open
            self.hiddenFonts.append({"font": font, "status": u"•"})
        self.w.hiddenFontList.set(self.getHiddenFontItems())
        self.updateView()
    
    def removeHiddenFontsCallback(self, sender):
        hiddenFontList = self.w.hiddenFontList.get()
        selection = self.w.hiddenFontList.getSelection()
        for i in reversed(selection):
            del self.hiddenFonts[i]
            item = hiddenFontList[i]
            self.w.hiddenFontList.remove(item)
        self.updateView()
Пример #48
0
class AdjustAnchors(BaseWindowController):

	def __init__(self):
		self.font = CurrentFont()
		self.glyph = CurrentGlyph()
		self.upm = self.font.info.unitsPerEm
		self.glyphPreviewCacheDict = {} # key: glyph name -- value: list containing assembled glyphs
		self.anchorsOnMarksDict = {} # key: anchor name -- value: list of mark glyph names
		self.anchorsOnBasesDict = {} # key: anchor name -- value: list of base glyph names
		self.marksDict = {} # key: mark glyph name -- value: anchor name (NOTE: It's expected that each mark glyph only has one type of anchor)
		self.fillAnchorsAndMarksDicts()
		self.glyphNamesList = [] # list of glyph names that will be displayed in the UI list
		self.selectedGlyphNamesList = [] # list of glyph names selected in the UI list
		self.extraGlyphsList = [] # list of the glyph objects that should be inserted before and after the accented glyphs

		self.Blue, self.Alpha = 1, 0.6

		self.font.naked().addObserver(self, "fontWasModified", "Font.Changed")
		addObserver(self, "_fontWillClose", "fontWillClose")
		addObserver(self, "_currentFontChanged", "fontResignCurrent")
		addObserver(self, "_currentGlyphChanged", "currentGlyphChanged")
		addObserver(self, "_drawFill", "draw")
		addObserver(self, "_drawFill", "drawInactive")
		addObserver(self, "_previewFill", "drawPreview")
		addObserver(self, "_drawGlyphs", "draw") # observer for the draw event
		addObserver(self, "_drawGlyphs", "drawInactive") # draw the glyphs when the glyph window is not in focus
		addObserver(self, "_drawGlyphs", "drawPreview")

		integerNumFormatter = NSNumberFormatter.alloc().init()
		integerNumFormatter.setAllowsFloats_(False)
		integerNumFormatter.setGeneratesDecimalNumbers_(False)

		intPosMinZeroNumFormatter = NSNumberFormatter.alloc().init()
		intPosMinZeroNumFormatter.setAllowsFloats_(False)
		intPosMinZeroNumFormatter.setGeneratesDecimalNumbers_(False)
		intPosMinZeroNumFormatter.setMinimum_(NSNumber.numberWithInt_(0))

		intPosMinOneNumFormatter = NSNumberFormatter.alloc().init()
		intPosMinOneNumFormatter.setAllowsFloats_(False)
		intPosMinOneNumFormatter.setGeneratesDecimalNumbers_(False)
		intPosMinOneNumFormatter.setMinimum_(NSNumber.numberWithInt_(1))

		self.textSize = getExtensionDefault("%s.%s" % (extensionKey, "textSize"))
		if not self.textSize:
			self.textSize = 150

		self.lineHeight = getExtensionDefault("%s.%s" % (extensionKey, "lineHeight"))
		if not self.lineHeight:
			self.lineHeight = 200

		self.extraSidebearings = getExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings"))
		if not self.extraSidebearings:
			self.extraSidebearings = [0, 0]

		self.extraGlyphs = getExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs"))
		if not self.extraGlyphs:
			self.extraGlyphs = ''

		posSize = getExtensionDefault("%s.%s" % (extensionKey, "posSize"))
		if not posSize:
			posSize = (100, 100, 1200, 400)

		self.calibrateMode = getExtensionDefault("%s.%s" % (extensionKey, "calibrateMode"))
		if not self.calibrateMode:
			self.calibrateMode = False

		calibrateModeStrings = getExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings"))
		if not calibrateModeStrings:
			calibrateModeStrings = {
				'group1.baseInput': 'dotlessi o s',
				'group1.markInput': 'dieresis circumflex macron breve caron',
				'group2.baseInput': 'I O S',
				'group2.markInput': 'dieresis.cap circumflex.cap macron.cap breve.cap caron.cap',
				'group3.baseInput': 'I.sc O.sc S.sc',
				'group3.markInput': 'dieresis circumflex macron breve caron',
				'group4.baseInput': '',
				'group4.markInput': '',
			}

		# -- Window --
		self.w = FloatingWindow(posSize, extensionName, minSize=(500, 400))
		self.w.fontList = List((10, 10, 190, -41), self.glyphNamesList, selectionCallback=self.listSelectionCallback)
		if roboFontVersion < '1.7':
			self.w.fontList.getNSTableView().sizeToFit() # use the full width of the column
		self.w.fontList.show(not self.calibrateMode)
		self.w.lineView = MultiLineView((210, 10, -10, -41),
							pointSize = self.textSize,
							lineHeight = self.lineHeight,
							displayOptions={"Beam" : False, "displayMode" : "Multi Line"}
							)

		# -- Calibration Mode --
		baseLabel = "Bases"
		markLabel = "Marks"
		width, height = 190, 140
		self.cm = Group((0, 0, 0, 0))
		# ---
		self.cm.group1 = Group((5, height*0, width, height-10))
		self.cm.group1.baseLabel = TextBox((0, 0, width, 20), baseLabel)
		self.cm.group1.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group1.baseInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group1.markLabel = TextBox((0, 50, width, 20), markLabel)
		self.cm.group1.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group1.markInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group1.divider = HorizontalLine((0, -1, -0, 1))
		# ---
		self.cm.group2 = Group((5, height*1, width, height-10))
		self.cm.group2.baseLabel = TextBox((0, 0, width, 20), baseLabel)
		self.cm.group2.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group2.baseInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group2.markLabel = TextBox((0, 50, width, 20), markLabel)
		self.cm.group2.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group2.markInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group2.divider = HorizontalLine((0, -1, -0, 1))
		# ---
		self.cm.group3 = Group((5, height*2, width, height-10))
		self.cm.group3.baseLabel = TextBox((0, 0, width, 20), baseLabel)
		self.cm.group3.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group3.baseInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group3.markLabel = TextBox((0, 50, width, 20), markLabel)
		self.cm.group3.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group3.markInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group3.divider = HorizontalLine((0, -1, -0, 1))
		# ---
		self.cm.group4 = Group((5, height*3, width, height-10))
		self.cm.group4.baseLabel = TextBox((0, 0, width, 20), baseLabel)
		self.cm.group4.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group4.baseInput'], callback=self.updateCalibrateMode, continuous=False)
		self.cm.group4.markLabel = TextBox((0, 50, width, 20), markLabel)
		self.cm.group4.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group4.markInput'], callback=self.updateCalibrateMode, continuous=False)
		# ---
		view = DefconAppKitTopAnchoredNSView.alloc().init()
		view.addSubview_(self.cm.getNSView())
		view.setFrame_(((0, 0), (width+10, height*4-23)))
		self.cm.setPosSize((0, 0, width+10, height*4-22))
		self.w.scrollView = ScrollView((5, 10, width+10, -41), view, drawsBackground=False, hasHorizontalScroller=False)
		self.w.scrollView.getNSScrollView().setBorderType_(NSNoBorder)
		self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1) # NSScrollElasticityNone
		self.w.scrollView.show(self.calibrateMode)

		# -- Footer --
		self.w.calibrateModeCheck = CheckBox((10, -32, 200, -10), "Calibration Mode", callback=self.calibrateModeCallback, value=self.calibrateMode)
		self.w.textSizeLabel = TextBox((210, -30, 100, -10), "Text Size")
		self.w.textSize = EditText((270, -32, 35, -10), self.textSize, callback=self.textSizeCallback, continuous=False, formatter=intPosMinOneNumFormatter)
		self.w.lineHeightLabel = TextBox((320, -30, 100, -10), "Line Height")
		self.w.lineHeight = EditText((395, -32, 35, -10), self.lineHeight, callback=self.lineHeightCallback, continuous=False, formatter=integerNumFormatter)
		self.w.extraSidebearingsLabel = TextBox((446, -30, 180, -10), "Extra Sidebearings")
		self.w.extraSidebearingsChar  = TextBox((602, -30, 20, -10), "&")
		self.w.extraSidebearingLeft  = EditText((567, -32, 35, -10), self.extraSidebearings[0], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter)
		self.w.extraSidebearingRight = EditText((614, -32, 35, -10), self.extraSidebearings[1], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter)
		self.w.extraGlyphsLabel = TextBox((665, -30, 180, -10), "Extra Glyphs")
		self.w.extraGlyphs = EditText((749, -32, -10, -10), self.extraGlyphs, callback=self.extraGlyphsCallback, continuous=False)

		# trigger the initial state and contents of the window
		self.extraGlyphsCallback() # this will call self.updateExtensionWindow()

		self.w.bind("close", self.windowClose)
		self.w.open()
		self.w.makeKey()


	def calibrateModeCallback(self, sender):
		self.calibrateMode = not self.calibrateMode
		self.w.fontList.show(not sender.get())
		self.w.scrollView.show(self.calibrateMode)
		self.updateExtensionWindow()


	def textSizeCallback(self, sender):
		try: # in case the user submits an empty field
			self.textSize = int(sender.get())
		except: # reset to the previous value
			NSBeep()
			self.sender.set(self.textSize)
		self.w.lineView.setPointSize(self.textSize)


	def lineHeightCallback(self, sender):
		try:
			self.lineHeight = int(sender.get())
		except:
			NSBeep()
			self.sender.set(self.lineHeight)
		self.w.lineView.setLineHeight(self.lineHeight)


	def extraSidebearingsCallback(self, sender):
		left = self.w.extraSidebearingLeft
		right = self.w.extraSidebearingRight
		try:
			self.extraSidebearings = [int(left.get()), int(right.get())]
		except:
			NSBeep()
			left.set(self.extraSidebearings[0])
			right.set(self.extraSidebearings[1])
		self.extraGlyphsCallback() # this will call self.updateExtensionWindow()


	def extraGlyphsCallback(self, *sender):
		del self.extraGlyphsList[:] # empty the list
		self.extraGlyphs = self.w.extraGlyphs.get()
		glyphNamesList = self.extraGlyphs.split()
		for gName in glyphNamesList:
			try:
				extraGlyph = self.font[gName]
				# must create a new glyph in order to be able to increase the sidebearings without modifying the font
				newGlyph = RGlyph()
				newGlyph.setParent(self.font)
				# must use deepAppend because the extra glyph may have components (which will cause problems to the MultiLineView)
				newGlyph = self.deepAppendGlyph(newGlyph, extraGlyph)
				newGlyph.width = extraGlyph.width
			except RoboFontError:
				continue
			newGlyph.leftMargin += self.extraSidebearings[0]
			newGlyph.rightMargin += self.extraSidebearings[1]
			self.extraGlyphsList.append(newGlyph)
		self.glyphPreviewCacheDict.clear()
		self.updateExtensionWindow()


	def windowClose(self, sender):
		self.font.naked().removeObserver(self, "Font.Changed")
		removeObserver(self, "fontWillClose")
		removeObserver(self, "fontResignCurrent")
		removeObserver(self, "currentGlyphChanged")
		removeObserver(self, "draw")
		removeObserver(self, "drawInactive")
		removeObserver(self, "drawPreview")
		self.saveExtensionDefaults()


	def getCalibrateModeStrings(self):
		calibrateModeStringsDict = {}
		for i in range(1,5):
			group = getattr(self.cm, "group%d" % i)
			calibrateModeStringsDict["group%d.baseInput" % i] = group.baseInput.get()
			calibrateModeStringsDict["group%d.markInput" % i] = group.markInput.get()
		return calibrateModeStringsDict


	def saveExtensionDefaults(self):
		setExtensionDefault("%s.%s" % (extensionKey, "posSize"), self.w.getPosSize())
		setExtensionDefault("%s.%s" % (extensionKey, "textSize"), self.textSize)
		setExtensionDefault("%s.%s" % (extensionKey, "lineHeight"), self.lineHeight)
		setExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings"), self.extraSidebearings)
		setExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs"), self.extraGlyphs)
		setExtensionDefault("%s.%s" % (extensionKey, "calibrateMode"), self.calibrateMode)
		setExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings"), self.getCalibrateModeStrings())


	def _previewFill(self, info):
		self.Blue, self.Alpha = 0, 1


	def _drawFill(self, info):
		self.Blue, self.Alpha = 1, 0.6


	def _fontWillClose(self, info):
		"""
			Close the window when the last font is closed
		"""
		if len(AllFonts()) < 2:
			self.windowClose(self)
			self.w.close()


	def _currentFontChanged(self, info):
		self.font.naked().removeObserver(self, "Font.Changed")
		self.font = CurrentFont()
		self.font.naked().addObserver(self, "fontWasModified", "Font.Changed")
		self.fillAnchorsAndMarksDicts()
		del self.glyphNamesList[:]
		del self.selectedGlyphNamesList[:]
		self.updateExtensionWindow()


	def _currentGlyphChanged(self, info):
		self.updateExtensionWindow()


	def fontWasModified(self, info):
		OutputWindow().clear()
		self.fillAnchorsAndMarksDicts()
		del self.glyphNamesList[:]
		del self.selectedGlyphNamesList[:]
		self.updateExtensionWindow()


	def deepAppendGlyph(self, glyph, gToAppend, offset=(0,0)):
		if not gToAppend.components:
			glyph.appendGlyph(gToAppend, offset)
		else:
			for component in gToAppend.components:
				compGlyph = self.font[component.baseGlyph].copy()

				# handle component transformations
				componentTransformation = component.transformation
				# when undoing a paste anchor or a delete anchor action, RoboFont returns component.transformation as a list instead of a tuple
				if type(componentTransformation) is list:
					componentTransformation = tuple(componentTransformation)
				if componentTransformation != (1, 0, 0, 1, 0, 0): # if component is skewed and/or is shifted
					matrix = componentTransformation[0:4]
					if matrix != (1, 0, 0, 1): # if component is skewed
						transformObj = Identity.transform(matrix + (0, 0)) # ignore the original component's shifting values
						compGlyph.transform(transformObj)

				glyph.appendGlyph(compGlyph, map(sum, zip(component.offset, offset))) # add the two tuples of offset
			for contour in gToAppend:
				glyph.appendContour(contour, offset)

		# if the assembled glyph still has components, recursively remove and replace them 1-by-1 by the glyphs they reference
		if glyph.components:
			nestedComponent = glyph.components[-1] # start from the end
			glyph.removeComponent(nestedComponent)
			glyph = self.deepAppendGlyph(glyph, self.font[nestedComponent.baseGlyph], nestedComponent.offset)

		return glyph


	def updateCalibrateMode(self, *sender):
		glyphsList = []
		newLine = self.w.lineView.createNewLineGlyph()

		# cycle thru the UI Groups and collect the strings
		for i in range(1,5):
			group = getattr(self.cm, "group%d" % i)
			baseGlyphsNamesList = group.baseInput.get().split()
			markGlyphsNamesList = group.markInput.get().split()

			# iterate thru the base+mark combinations
			for gBaseName, gMarkName in product(baseGlyphsNamesList, markGlyphsNamesList):
				newGlyph = RGlyph()
				newGlyph.setParent(self.font)
				# skip invalid glyph names
				try:
					baseGlyph = self.font[gBaseName]
					markGlyph = self.font[gMarkName]
				except RoboFontError:
					continue
				# append base glyph
				newGlyph = self.deepAppendGlyph(newGlyph, baseGlyph)
				# append mark glyph
				newGlyph = self.deepAppendGlyph(newGlyph, markGlyph, self.getAnchorOffsets(baseGlyph, markGlyph))
				# set the advanced width
				dfltSidebearings = self.upm * .05 # 5% of the UPM
				newGlyph.leftMargin = dfltSidebearings + self.extraSidebearings[0]
				newGlyph.rightMargin = dfltSidebearings + self.extraSidebearings[1]
				# append the assembled glyph to the list
				glyphsList.extend(self.extraGlyphsList)
				glyphsList.append(newGlyph)

			# add line break, if both input fields have content
			if baseGlyphsNamesList and markGlyphsNamesList:
				glyphsList.extend(self.extraGlyphsList)
				glyphsList.append(newLine)

		# update the contents of the MultiLineView
		self.w.lineView.set(glyphsList)


	def updateExtensionWindow(self):
		if self.calibrateMode:
			self.updateCalibrateMode()
			return

		if CurrentGlyph() is not None: # NOTE: CurrentGlyph() will return zero (its length), so "is not None" is necessary
			self.glyph = CurrentGlyph()
			self.glyphNamesList = self.makeGlyphNamesList(self.glyph)
			self.updateListView()
			currentGlyphName = self.glyph.name

			# base glyph + accent combinations preview
			# first check if there's a cached glyph
			if currentGlyphName in self.glyphPreviewCacheDict:
				self.w.lineView.set(self.glyphPreviewCacheDict[currentGlyphName])

			# assemble the glyphs
			else:
				glyphsList = []
				for glyphNameInUIList in self.glyphNamesList:
					newGlyph = RGlyph()
					newGlyph.setParent(self.font)

					# the glyph in the UI list is a mark
					if glyphNameInUIList in self.marksDict:
						markGlyph = self.font[glyphNameInUIList]

						# append base glyph
						newGlyph = self.deepAppendGlyph(newGlyph, self.glyph)
						# append mark glyph
						newGlyph = self.deepAppendGlyph(newGlyph, markGlyph, self.getAnchorOffsets(self.glyph, markGlyph))

						# set the advanced width
						if self.glyph.width < 10: # combining marks or other glyphs with a small advanced width
							newGlyph.leftMargin = self.upm * .05 # 5% of the UPM
							newGlyph.rightMargin = newGlyph.leftMargin
						else:
							newGlyph.width = self.glyph.width

					# the glyph in the UI list is a base
					else:
						baseGlyph = self.font[glyphNameInUIList]

						# append base glyph
						newGlyph = self.deepAppendGlyph(newGlyph, baseGlyph)
						# append mark glyph
						newGlyph = self.deepAppendGlyph(newGlyph, self.glyph, self.getAnchorOffsets(baseGlyph, self.glyph))

						# set the advanced width
						if self.glyph.width < 10: # combining marks or other glyphs with a small advanced width
							newGlyph.leftMargin = self.upm * .05
							newGlyph.rightMargin = newGlyph.leftMargin
						else:
							newGlyph.width = baseGlyph.width

					# pad the new glyph if it has too much overhang
					if newGlyph.leftMargin < self.upm * .15:
						newGlyph.leftMargin = self.upm * .05
					if newGlyph.rightMargin < self.upm * .15:
						newGlyph.rightMargin = self.upm * .05

					# add extra sidebearings
						newGlyph.leftMargin += self.extraSidebearings[0]
						newGlyph.rightMargin += self.extraSidebearings[1]

					# one last check for making sure the new glyph can be displayed
					if not newGlyph.components:
						glyphsList.extend(self.extraGlyphsList)
						glyphsList.append(newGlyph)
					else:
						print "Combination with mark glyph %s can't be previewed because it contains component %s." % (glyphNameInUIList, newGlyph.components[0].baseGlyph)

				glyphsList.extend(self.extraGlyphsList)
				self.w.lineView.set(glyphsList)

				# add to the cache
				self.glyphPreviewCacheDict[currentGlyphName] = glyphsList
		else:
			self.w.lineView.set([])


	def listSelectionCallback(self, sender):
		selectedGlyphNamesList = []
		for index in sender.getSelection():
			selectedGlyphNamesList.append(self.glyphNamesList[index])
		self.selectedGlyphNamesList = selectedGlyphNamesList
		self.updateGlyphView()


	def updateGlyphView(self):
		# update the current glyph view
		UpdateCurrentGlyphView()


	def fillAnchorsAndMarksDicts(self):
		# reset all the dicts
		self.glyphPreviewCacheDict.clear()
		self.anchorsOnMarksDict.clear()
		self.anchorsOnBasesDict.clear()
		self.marksDict.clear()
		markGlyphsWithMoreThanOneAnchorTypeList = []

		for glyphName in self.font.glyphOrder:
			glyphAnchorsList = self.font[glyphName].anchors
			for anchor in glyphAnchorsList:
				if anchor.name[0] == '_':
					anchorName = anchor.name[1:]
					# add to AnchorsOnMarks dictionary
					if anchorName not in self.anchorsOnMarksDict:
						self.anchorsOnMarksDict[anchorName] = [glyphName]
					else:
						tempList = self.anchorsOnMarksDict[anchorName]
						tempList.append(glyphName)
						self.anchorsOnMarksDict[anchorName] = tempList
					# add to Marks dictionary
					if glyphName not in self.marksDict:
						self.marksDict[glyphName] = anchorName
					else:
						if glyphName not in markGlyphsWithMoreThanOneAnchorTypeList:
							markGlyphsWithMoreThanOneAnchorTypeList.append(glyphName)
				else:
					anchorName = anchor.name
					# add to AnchorsOnBases dictionary
					if anchorName not in self.anchorsOnBasesDict:
						self.anchorsOnBasesDict[anchorName] = [glyphName]
					else:
						tempList = self.anchorsOnBasesDict[anchorName]
						tempList.append(glyphName)
						self.anchorsOnBasesDict[anchorName] = tempList

		if markGlyphsWithMoreThanOneAnchorTypeList:
			for glyphName in markGlyphsWithMoreThanOneAnchorTypeList:
				print "ERROR: Glyph %s has more than one type of anchor." % glyphName


	def makeGlyphNamesList(self, glyph):
		glyphNamesList = []
		markGlyphIsAbleToBeBase = False
		if glyph is not None: # NOTE: "if glyph" will return zero (its length), so "is not None" is necessary
			# assemble the list for the UI list
			for anchor in glyph.anchors:
				anchorName = anchor.name
				if anchorName in self.anchorsOnMarksDict:
					glyphNamesList.extend(self.anchorsOnMarksDict[anchorName])
				elif anchorName[1:] in self.anchorsOnBasesDict: # skips the leading underscore
					glyphNamesList.extend(self.anchorsOnBasesDict[anchorName[1:]])

			# for mark glyphs, test if they're able to get other mark glyphs attached to them
			# this will (correctly) prevent the UI list from including glyph names that cannot be displayed with the current glyph
			if glyph.name in self.marksDict:
				for anchor in glyph.anchors:
					if anchor.name[0] != '_': # the current mark glyph has anchors that allow it to be a base for other marks
						markGlyphIsAbleToBeBase = True
						break
				# remove marks from the glyph list if the current mark glyph can't work as a base
				if not markGlyphIsAbleToBeBase:
					for glyphName in glyphNamesList[::-1]: # iterate from the end of the list
						if glyphName in self.marksDict:
							glyphNamesList.remove(glyphName)

		return glyphNamesList


	def updateListView(self):
		self.w.fontList.set(self.glyphNamesList)


	def getAnchorOffsets(self, canvasGlyph, glyphToDraw):
		# the current glyph is a mark
		if canvasGlyph.name in self.marksDict:
			# glyphToDraw is also a mark (mark-to-mark case)
			if glyphToDraw.name in self.marksDict:
				# pick the (mark glyph) anchor to draw on
				for anchor in canvasGlyph.anchors:
					if anchor.name[0] != '_':
						anchorName = anchor.name
						markAnchor = anchor
						break
				# pick the (base glyph) anchor to draw on
				for anchor in glyphToDraw.anchors:
					try:
						if anchor.name == '_'+ anchorName:
							baseAnchor = anchor
							break
					except UnboundLocalError:
						continue
			# glyphToDraw is not a mark
			else:
				# pick the (mark glyph) anchor to draw on
				for anchor in canvasGlyph.anchors:
					if anchor.name[0] == '_':
						anchorName = anchor.name[1:]
						markAnchor = anchor
						break
				# pick the (base glyph) anchor to draw on
				for anchor in glyphToDraw.anchors:
					try:
						if anchor.name == anchorName:
							baseAnchor = anchor
							break
					except UnboundLocalError:
						continue

			try:
				offsetX = markAnchor.x - baseAnchor.x
				offsetY = markAnchor.y - baseAnchor.y
			except UnboundLocalError:
				offsetX = 0
				offsetY = 0

		# the current glyph is a base
		else:
			try:
				anchorName = self.marksDict[glyphToDraw.name]
			except KeyError:
				anchorName = None

			if anchorName:
				# pick the (base glyph) anchor to draw on
				for anchor in canvasGlyph.anchors:
					if anchor.name == anchorName:
						baseAnchor = anchor
						break
				# pick the (mark glyph) anchor to draw on
				for anchor in glyphToDraw.anchors:
					if anchor.name == '_'+ anchorName:
						markAnchor = anchor
						break

			try:
				offsetX = baseAnchor.x - markAnchor.x
				offsetY = baseAnchor.y - markAnchor.y
			except UnboundLocalError:
				offsetX = 0
				offsetY = 0

		return (offsetX, offsetY)


	def _drawGlyphs(self, info):
		""" draw stuff in the glyph window view """
		translateBefore = (0, 0)

		for glyphName in self.selectedGlyphNamesList:
			glyphToDraw = self.font[glyphName]

			# determine the offset of the anchors
			offset = self.getAnchorOffsets(self.glyph, glyphToDraw)

			# set the offset of the drawing
			translate(offset[0] - translateBefore[0], offset[1] - translateBefore[1])

			# record the shift amounts (these are needed for resetting the drawing position when more than one mark is selected on the list)
			translateBefore = offset

			# set the fill & stroke
			fill(0, 0, self.Blue, self.Alpha)
			strokeWidth(None)

			# draw it
			mojoPen = MojoDrawingToolsPen(glyphToDraw, self.font)
			glyphToDraw.draw(mojoPen)
			mojoPen.draw()
class CornerController:
    def __init__(self):
        self.modifiedGlyph = None
        self.w = FloatingWindow((400, 170), "Corner Tool")
        self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor())
        self.modes = ["Break", "Build", "Pit"]
        self.objectTypes = {"Build": "Segment", "Break": "Corner point", "Pit": "Corner point"}
        self.parameters = {
            "radius": VanillaSingleValueParameter("radius", 20, (-200, 200), numType="int"),
            "roundness": VanillaSingleValueParameter("roundness", 1.25, (0, 4), numType="float"),
            "depth": VanillaSingleValueParameter("depth", 30, (-100, 100), numType="int"),
            "breadth": VanillaSingleValueParameter("breadth", 30, (0, 150), numType="int"),
            "bottom": VanillaSingleValueParameter("bottom", 5, (0, 40), numType="int"),
        }
        self.currentMode = "Break"
        self.previewGlyph = None

        self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode)
        for i, mode in enumerate(self.modes):
            setattr(self.w, mode, Group((120, 15, -15, -15)))
            modeGroup = getattr(self.w, mode)
            modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u">", callback=self.apply)
            modeGroup.infoBox = Box((0, 0, -50, 35))
            modeGroup.info = TextBox((10, 8, -50, 20), "No selection")
            if i > 0:
                modeGroup.show(False)

        self.w.Break.radius = ParameterSliderTextInput(
            self.parameters["radius"], (0, 60, -25, 25), title="Radius", callback=self.makePreviewGlyph
        )
        self.w.Break.roundness = ParameterSliderTextInput(
            self.parameters["roundness"], (0, 95, -25, 25), title="Roundness", callback=self.makePreviewGlyph
        )

        self.w.Pit.depth = ParameterSliderTextInput(
            self.parameters["depth"], (0, 50, -25, 25), title="Depth", callback=self.makePreviewGlyph
        )
        self.w.Pit.breadth = ParameterSliderTextInput(
            self.parameters["breadth"], (0, 80, -25, 25), title="Breadth", callback=self.makePreviewGlyph
        )
        self.w.Pit.bottom = ParameterSliderTextInput(
            self.parameters["bottom"], (0, 110, -25, 25), title="bottom", callback=self.makePreviewGlyph
        )

        addObserver(self, "preview", "draw")
        addObserver(self, "preview", "drawInactive")
        addObserver(self, "previewSolid", "drawPreview")
        addObserver(self, "makePreviewGlyph", "mouseDown")
        addObserver(self, "makePreviewGlyph", "mouseDragged")
        addObserver(self, "makePreviewGlyph", "keyDown")
        addObserver(self, "makePreviewGlyph", "keyUp")
        addObserver(self, "setControls", "mouseUp")
        addObserver(self, "setControls", "selectAll")
        addObserver(self, "setControls", "deselectAll")
        addObserver(self, "setControls", "currentGlyphChanged")
        self.w.bind("close", self.windowClose)
        self.setControls()
        self.w.open()

    def changeMode(self, sender):
        index = sender.get()
        previousModeGroup = getattr(self.w, self.currentMode)
        previousModeGroup.show(False)
        self.currentMode = self.modes[index]
        modeGroup = getattr(self.w, self.currentMode)
        modeGroup.show(True)
        self.setControls()

    def setControls(self, notification=None):
        mode = self.currentMode
        selection = self.getSelection()
        modeGroup = getattr(self.w, mode)
        if not len(selection):
            modeGroup.apply.enable(False)
            modeGroup.info.set("No selection (%ss)" % (self.objectTypes[mode].lower()))
        elif len(selection):
            modeGroup.apply.enable(True)
            info = "%s valid %s" % (len(selection), self.objectTypes[mode].lower())
            if len(selection) > 1:
                info += "s"
            modeGroup.info.set(info)
        self.makePreviewGlyph()

    def getSelection(self, notification=None):
        glyph = CurrentGlyph()
        if len(glyph.selection) == 0:
            return []
        elif len(glyph.selection) > 0:
            iG = IntelGlyph(glyph)
            if self.currentMode == "Build":
                selection = iG.getSelection(True)
            elif self.currentMode in ["Break", "Pit"]:
                selection = [
                    point
                    for point in iG.getSelection()
                    if (point.segmentType is not None) and (abs(point.turn()) > pi / 18)
                ]
            return selection

    def preview(self, notification):
        sc = notification["scale"]
        if self.previewGlyph is not None:
            self.previewGlyph.drawPreview(
                sc,
                styleFill=True,
                showNodes=False,
                strokeWidth=2,
                fillColor=cornerOutlineSoftColor,
                strokeColor=cornerOutlineStrongColor,
            )

    def previewSolid(self, notification):
        sc = notification["scale"]
        if self.previewGlyph is not None:
            self.previewGlyph.drawPreview(sc, plain=True)

    def makePreviewGlyph(self, sender=None):
        if (sender is not None) and isinstance(sender, dict):
            if sender.has_key("notificationName") and sender["notificationName"] == "mouseDragged":
                g = sender["glyph"]
                if not len(g.selection):
                    return
        self.previewGlyph = self.makeCornerGlyph()
        UpdateCurrentGlyphView()

    def makeCornerGlyph(self, sender=None):
        mode = self.currentMode
        if mode == "Build":
            cornerGlyph = self.buildCorners()
        elif mode == "Break":
            cornerGlyph = self.breakCorners()
        elif mode == "Pit":
            cornerGlyph = self.pitCorners()
        return cornerGlyph

    def buildCorners(self):
        g = CurrentGlyph()
        iG = IntelGlyph(g)
        for contour in iG:
            segments = contour.collectSegments()["selection"]
            l = len(segments)
            lines, curves = self.checkComposition(segments)
            if l > 1 and lines and curves:
                segments = [segment for segment in segments if len(segment) == 4]
            elif l > 1 and lines and not curves:
                segments = segments[:1] + segments[-1:]
            for segment in reversed(segments):
                contour.buildCorner(segment)
        return iG

    def breakCorners(self):
        g = CurrentGlyph()
        iG = IntelGlyph(g)
        radius = self.parameters["radius"].get()
        roundness = self.parameters["roundness"].get()
        for contour in iG:
            selection = contour.getSelection()
            for point in selection:
                contour.breakCorner(point, radius, velocity=roundness)
            contour.correctSmoothness()
        return iG

    def pitCorners(self):
        g = CurrentGlyph()
        iG = IntelGlyph(g)
        depth = self.parameters["depth"].get()
        breadth = self.parameters["breadth"].get()
        bottom = self.parameters["bottom"].get()
        for contour in iG:
            selection = contour.getSelection()
            for point in selection:
                contour.pitCorner(point, depth, breadth, bottom)
            contour.removeOverlappingPoints()
            contour.correctSmoothness()
        return iG

    def apply(self, sender):
        targetGlyph = CurrentGlyph()
        modifiedGlyph = self.makeCornerGlyph()
        targetGlyph.prepareUndo("un.round")
        targetGlyph.clearContours()
        for p in targetGlyph.selection:
            p.selected = False
        pen = targetGlyph.getPointPen()
        modifiedGlyph.drawPoints(pen)
        targetGlyph.performUndo()
        targetGlyph.update()

    def checkComposition(self, segmentsList):
        lines = 0
        curves = 0
        for segment in segmentsList:
            if len(segment) == 2:
                lines += 1
            elif len(segment) == 4:
                curves += 1
        return lines, curves

    def windowClose(self, notification):
        removeObserver(self, "draw")
        removeObserver(self, "drawInactive")
        removeObserver(self, "drawPreview")
        removeObserver(self, "mouseUp")
        removeObserver(self, "mouseDown")
        removeObserver(self, "mouseDragged")
        removeObserver(self, "keyDown")
        removeObserver(self, "keyUp")
        removeObserver(self, "selectAll")
        removeObserver(self, "deselectAll")
        removeObserver(self, "currentGlyphChanged")
class Adhesiontext(BaseWindowController):

	def __init__(self):
		flushAlign = 76
		firstRowY = 12
		rowOffsetY = 30
		firstCheckY = 135
		checkOffsetY = 27
		rightMarginX = -12
		self.windowWidth = 410
		self.windowHeightWithoutOptions = 45
		self.windowHeightWithOptions = 280
		self.scriptIsRTL = False

		windowPos = getExtensionDefault("%s.%s" % (extensionKey, "windowPos"))
		if not windowPos:
			windowPos = (100, 100)

		self.optionsVisible = getExtensionDefault("%s.%s" % (extensionKey, "optionsVisible"))
		if self.optionsVisible:
			optionsButtonSign = '-'
			windowHeight = self.windowHeightWithOptions
		else:
			self.optionsVisible = False # needs to be set because the first time the extension runs self.optionsVisible will be None
			optionsButtonSign = '+'
			windowHeight = self.windowHeightWithoutOptions

		self.chars = getExtensionDefault("%s.%s" % (extensionKey, "chars"))
		if not self.chars:
			self.chars = ''

		self.sliderValue = getExtensionDefault("%s.%s" % (extensionKey, "sliderValue"))
		if not self.sliderValue:
			self.sliderValue = 25

		self.scriptsIndex = getExtensionDefault("%s.%s" % (extensionKey, "scriptsIndex"))
		if not self.scriptsIndex:
			self.scriptsIndex = 0

		self.langsIndex = getExtensionDefault("%s.%s" % (extensionKey, "langsIndex"))
		if not self.langsIndex:
			self.langsIndex = 0


		self.w = FloatingWindow((windowPos[0], windowPos[1], self.windowWidth, windowHeight), "adhesiontext")

		# 1st row
		self.w.labelChars = TextBox((10, firstRowY, flushAlign, 20), "Characters:", alignment="right")
		self.w.chars = EditText((flushAlign +15, firstRowY -1, 199, 22), self.chars, callback=self.charsCallback)
		self.w.button = Button((300, firstRowY, 68, 20), "Get text", callback=self.buttonCallback)
		self.w.spinner = FixedSpinner((325, firstRowY, 20, 20), displayWhenStopped=False)
		self.w.optionsButton = SquareButton((378, firstRowY +1, 18, 18), optionsButtonSign, sizeStyle="small", callback=self.optionsCallback)
		# set the initial state of the button according to the content of the chars EditText
		if len(self.w.chars.get()): self.w.button.enable(True)
		else: self.w.button.enable(False)
		# keep track of the content of chars EditText
		self.previousChars = self.w.chars.get()

		# 2nd row
		self.w.labelWords = TextBox((10, firstRowY + rowOffsetY, flushAlign, 20), "Words:", alignment="right")
		self.w.wordCount = TextBox((flushAlign +12, firstRowY + rowOffsetY, 40, 20), alignment="left")
		self.w.slider = Slider((flushAlign +47, firstRowY + rowOffsetY +1, 165, 20), value=self.sliderValue, minValue=5, maxValue=200, callback=self.sliderCallback)
		# set the initial wordCount value according to the position of the slider
		self.w.wordCount.set(int(self.w.slider.get()))

		# 3rd row
		self.w.labelScripts = TextBox((10, firstRowY + rowOffsetY *2, flushAlign, 20), "Script:", alignment="right")
		self.w.scriptsPopup = PopUpButton((flushAlign +15, firstRowY + rowOffsetY *2, 150, 20), scriptsNameList, callback=self.scriptsCallback)
		self.w.scriptsPopup.set(self.scriptsIndex)

		# 4th row
		self.w.labelLangs = TextBox((10, firstRowY + rowOffsetY *3, flushAlign, 20), "Language:", alignment="right")
		self.w.langsPopup = PopUpButton((flushAlign +15, firstRowY + rowOffsetY *3, 150, 20), [])
		# set the initial list of languages according to the script value
		self.w.langsPopup.setItems(langsNameDict[scriptsNameList[self.w.scriptsPopup.get()]])
		self.w.langsPopup.set(self.langsIndex)

		self.punctCheck = getExtensionDefault("%s.%s" % (extensionKey, "punctCheck"))
		if not self.punctCheck:
			self.punctCheck = 0

		self.figsCheck = getExtensionDefault("%s.%s" % (extensionKey, "figsCheck"))
		if not self.figsCheck:
			self.figsCheck = 0

		self.figsPopup = getExtensionDefault("%s.%s" % (extensionKey, "figsPopup"))
		if not self.figsPopup:
			self.figsPopup = 0

		self.trimCheck = getExtensionDefault("%s.%s" % (extensionKey, "trimCheck"))
		if not self.trimCheck:
			self.trimCheck = 0

		self.caseCheck = getExtensionDefault("%s.%s" % (extensionKey, "caseCheck"))
		if not self.caseCheck:
			self.caseCheck = 0

		self.casingCheck = getExtensionDefault("%s.%s" % (extensionKey, "casingCheck"))
		if not self.casingCheck:
			self.casingCheck = 0

		self.casingPopup = getExtensionDefault("%s.%s" % (extensionKey, "casingPopup"))
		if not self.casingPopup:
			self.casingPopup = 0

		# 1st checkbox
		self.w.punctCheck = CheckBox((flushAlign +15, firstCheckY, 130, 20), "Add punctuation")
		self.w.punctCheck.set(self.punctCheck)

		# 2nd checkbox
		self.w.figsCheck = CheckBox((flushAlign +15, firstCheckY + checkOffsetY, 120, 20), "Insert numbers", callback=self.figsCallback)
		self.w.figsCheck.set(self.figsCheck)
		self.w.figsPopup = PopUpButton((210, firstCheckY + checkOffsetY, 90, 20), figOptionsList)
		self.w.figsPopup.set(self.figsPopup)
		# enable or disable the figure options PopUp depending on the figures CheckBox
		if scriptsNameList[self.w.scriptsPopup.get()] in enableFigOptionList:
			self.w.figsPopup.show(True)
			if self.w.figsCheck.get():
				self.w.figsPopup.enable(True)
			else:
				self.w.figsPopup.enable(False)
		else:
			self.w.figsPopup.show(False)

		# 3rd checkbox
		self.w.trimCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *2, 120, 20), "Trim accents")
		self.w.trimCheck.set(self.trimCheck)
		if scriptsNameList[self.w.scriptsPopup.get()] in enableTrimCheckList:
			self.w.trimCheck.enable(True)
		else:
			self.w.trimCheck.enable(False)

		# 4th checkbox
		self.w.caseCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *3, 120, 20), "Ignore casing")
		self.w.caseCheck.set(self.caseCheck)
		if scriptsNameList[self.w.scriptsPopup.get()] in enableCaseCheckList:
			self.w.caseCheck.enable(True)
		else:
			self.w.caseCheck.enable(False)

		# 5th checkbox
		self.w.casingCheck = CheckBoxPlus((flushAlign +15, firstCheckY + checkOffsetY *4, 115, 20), "Change casing", callback=self.casingCallback)
		self.w.casingCheck.set(self.casingCheck)
		if scriptsNameList[self.w.scriptsPopup.get()] in enableCaseCheckList:
			self.w.casingCheck.enable(True)
		else:
			self.w.casingCheck.enable(False)
		self.w.casingPopup = PopUpButton((210, firstCheckY + checkOffsetY *4, 90, 20), casingNameList)
		self.w.casingPopup.set(self.casingPopup)
		# enable or disable the casing PopUp depending on the casing CheckBox
		if self.w.casingCheck.get() and self.w.casingCheck.isEnable():
			self.w.casingPopup.enable(True)
		else:
			self.w.casingPopup.enable(False)

		self.nsTextField = self.w.chars.getNSTextField()
		self.w.setDefaultButton(self.w.button)
		self.w.bind("close", self.windowClose)
		self.w.open()
		self.w.makeKey()

	def windowClose(self, sender):
		self.saveExtensionDefaults()

	def saveExtensionDefaults(self):
		setExtensionDefault("%s.%s" % (extensionKey, "windowPos"), self.w.getPosSize()[0:2])
		setExtensionDefault("%s.%s" % (extensionKey, "optionsVisible"), self.optionsVisible)
		setExtensionDefault("%s.%s" % (extensionKey, "chars"), self.w.chars.get())
		setExtensionDefault("%s.%s" % (extensionKey, "sliderValue"), int(self.w.slider.get()))
		setExtensionDefault("%s.%s" % (extensionKey, "scriptsIndex"), int(self.w.scriptsPopup.get()))
		setExtensionDefault("%s.%s" % (extensionKey, "langsIndex"), int(self.w.langsPopup.get()))
		setExtensionDefault("%s.%s" % (extensionKey, "punctCheck"), self.w.punctCheck.get())
		setExtensionDefault("%s.%s" % (extensionKey, "figsCheck"), self.w.figsCheck.get())
		setExtensionDefault("%s.%s" % (extensionKey, "figsPopup"), self.w.figsPopup.get())
		setExtensionDefault("%s.%s" % (extensionKey, "trimCheck"), self.w.trimCheck.get())
		setExtensionDefault("%s.%s" % (extensionKey, "caseCheck"), self.w.caseCheck.get())
		setExtensionDefault("%s.%s" % (extensionKey, "casingCheck"), self.w.casingCheck.get())
		setExtensionDefault("%s.%s" % (extensionKey, "casingPopup"), self.w.casingPopup.get())

	def buttonCallback(self, sender):
		sender.enable(False)
		self.w.spinner.start()
		self.getText()
		self.w.spinner.stop()
		sender.enable(True)

	def optionsCallback(self, sender):
		sign = sender.getTitle()
		if sign == "+":
			sender.setTitle("-")
			self.w.resize(self.windowWidth, self.windowHeightWithOptions, animate=True)
			self.optionsVisible = True
		else:
			sender.setTitle("+")
			self.w.resize(self.windowWidth, self.windowHeightWithoutOptions, animate=True)
			self.optionsVisible = False

	def charsCallback(self, sender):
		charsContent = sender.get()
		if len(charsContent):
			self.w.button.enable(True)
			nsTextView = self.nsTextField.currentEditor() # NOTE: the field editor is only available when NSTextField is in editing mode.

			# when only one glyph is selected and copied, the contents of the clipboard are the glyph's XML
			# instead of its unicode character or its name; therefore, post-process the pasted content.
			if xmlHeader in charsContent:
				caretIndex = charsContent.index(xmlHeader)
				codepointString = re_glyphUnicode.search(charsContent)
				glyphName = re_glyphName.search(charsContent)

				if codepointString:
					replacement = unichr(eval('0x' + codepointString.group(1)))
				elif glyphName:
					replacement = '/' + glyphName.group(1)
				else:
					replacement = ''

				# replace the glyph's XML by its unicode character or its name
				self.w.chars.set(re_glyph.sub(replacement, charsContent))
				# restore the location of the caret
				location = caretIndex + len(replacement)
				nsTextView.setSelectedRange_((location, 0))
				# update the variable
				charsContent = sender.get()

			caretIndex = nsTextView.selectedRanges()[0].rangeValue().location

			# Limit the number of characters
			numeralWasFound = self.stringHasNumeral(charsContent)
			if len(charsContent) > maxChars or numeralWasFound:
				NSBeep()
				if numeralWasFound:
					self.showMessage("Sorry, numerals are not allowed.", "")
				else:
					self.showMessage("You've reached the maximum \rnumber of characters.", "The limit is %d." % maxChars)
				# restore the content of chars EditText to the previous string
				sender.set(self.previousChars)
				# restore the focus on the chars EditText and restore the location of the caret
				caretIndexAdjust = len(self.previousChars) - len(charsContent)
				self.w.getNSWindow().makeFirstResponder_(self.nsTextField)
				nsTextView.setSelectedRange_((caretIndex + caretIndexAdjust, 0))

			# update the stored string
			self.previousChars = sender.get()

		else:
			self.w.button.enable(False)

	def sliderCallback(self, sender):
		self.w.wordCount.set(int(sender.get()))

	def scriptsCallback(self, sender):
		self.w.langsPopup.setItems(langsNameDict[scriptsNameList[sender.get()]])
		# toggle RTL/LTR
		if scriptsNameList[sender.get()] in rightToLeftList:
			self.scriptIsRTL = True
			self.nsTextField.setBaseWritingDirection_(NSWritingDirectionRightToLeft)
			self.nsTextField.setAlignment_(NSRightTextAlignment)
		else:
			self.scriptIsRTL = False
			self.nsTextField.setBaseWritingDirection_(NSWritingDirectionLeftToRight)
			self.nsTextField.setAlignment_(NSLeftTextAlignment)
		# restore the focus on the chars EditText
		self.w.getNSWindow().makeFirstResponder_(self.nsTextField)
		# toggle figsPopup
		if scriptsNameList[sender.get()] in enableFigOptionList:
			self.w.figsPopup.show(True)
			if self.w.figsCheck.get():
				self.w.figsPopup.enable(True)
			else:
				self.w.figsPopup.enable(False)
		else:
			self.w.figsPopup.show(False)
		# toggle trimCheck
		if scriptsNameList[sender.get()] in enableTrimCheckList:
			self.w.trimCheck.enable(True)
		else:
			self.w.trimCheck.enable(False)
		# toggle caseCheck and casingCheck
		if scriptsNameList[sender.get()] in enableCaseCheckList:
			self.w.caseCheck.enable(True)
			self.w.casingCheck.enable(True)
			if self.w.casingCheck.get():
				self.w.casingPopup.enable(True)
		else:
			self.w.caseCheck.enable(False)
			self.w.casingCheck.enable(False)
			self.w.casingPopup.enable(False)

	def figsCallback(self, sender):
		if sender.get():
			self.w.figsPopup.enable(True)
		else:
			self.w.figsPopup.enable(False)

	def casingCallback(self, sender):
		if sender.get():
			self.w.casingPopup.enable(True)
		else:
			self.w.casingPopup.enable(False)

	def stringHasNumeral(self, string):
		if re_numeral.search(string):
			return True
		return False

	def isConnected(self):
		try:
			urlopen(url, timeout=3)
			return True
		except URLError:
			pass
		return False

	def getText(self):
		if CurrentFont() is None:
			NSBeep()
			self.showMessage("Open a font first.", "")
			return

		if not self.isConnected():
			NSBeep()
			self.showMessage("Required internet connection not found.", "")
			return

		values = {'chars' : self.w.chars.get().encode('utf-8'),
				  'script' : scriptsTagDict[scriptsNameList[self.w.scriptsPopup.get()]],
				  'tb' : langsTagDict[langsNameDict[scriptsNameList[self.w.scriptsPopup.get()]][self.w.langsPopup.get()]] }

		if self.w.punctCheck.get():
			values['punct'] = True
		if self.w.figsCheck.get():
			values['figs'] = True
			if self.w.figsPopup.isVisible():
				figsOptTagsList = ["dflt", "locl"]
				values['figsOpt'] = figsOptTagsList[self.w.figsPopup.get()]
		if self.w.trimCheck.get() and self.w.trimCheck.isEnable():
			values['trim'] = True
		if self.w.caseCheck.get() and self.w.caseCheck.isEnable():
			values['case'] = True
		if self.w.casingCheck.get() and self.w.casingCheck.isEnable():
			values['casing'] = casingNameList[self.w.casingPopup.get()].lower()

		data = urlencode(values)
		data = data.encode('utf-8')
		print(data)
		request = Request(url, data)
		response = urlopen(request)
		text = response.read()
		textU = unicode(text, 'utf-8')

		if (msgStr in textU):
			textU = textU.replace(msgStr, "")
			NSBeep()
			self.showMessage(textU, "")
			return

		elif (wrnStr in textU):
			resultIndex = textU.find(rsltStr)
			secmsgIndex = textU.find(sndStr)
			frstmsgU = textU[:secmsgIndex].replace(wrnStr, "")
			scndmsgU = textU[secmsgIndex:resultIndex].replace(sndStr, "")
			textU = textU[resultIndex:].replace(rsltStr, "")
			NSBeep()
			self.showMessage(frstmsgU, scndmsgU)

		textList = textU.split()
		trimmedText = ' '.join(textList[:int(self.w.slider.get())])

		if CurrentSpaceCenter() is None:
			OpenSpaceCenter(CurrentFont(), newWindow=False)

		sp = CurrentSpaceCenter()
		print(trimmedText)
		sp.setRaw(trimmedText)

		# Toggle RTL-LTR
		try:
			sp.setLeftToRight(not self.scriptIsRTL)
			sp.setInputWritingDirection('Right to Left' if self.scriptIsRTL else 'Left to Right')
		except AttributeError:
			pass

		return
Пример #51
0
class RedArrowErrorFilter():

    def __init__(self):
        self.errorList = [
            'Extremum',
            'Mixed cubic and quadratic segments',
            'Fractional Coordinates',
            'Fractional transformation',
            'Incorrect smooth connection',
            'Empty segment',
            'Vector on closepath',
            'Collinear vectors',
            'Semi-horizontal vector',
            'Semi-vertical vector',
            'Zero handle',
        ]
        self.errorList.insert(0, "select Red Arrow Error")
        self.heightOfTool = 360
        self.widthOfTool = 200 
        self.w = FloatingWindow((self.widthOfTool, self.heightOfTool), "Red Arrow Error Filter") ### FloatingWindow
        #self.w.text = TextBox((10, 5, -10, 16), "...", sizeStyle='regular')       
        self.w.select_test = PopUpButton((10, 10, -10, 16), self.errorList, sizeStyle='regular', callback=self.select_test)
        self.w.extremumToleranceText = TextBox((10, 35, -25, 18), "Extremum Tolerance", sizeStyle='small')       
        self.w.extremumToleranceInput = EditText((160, 35, -10, 18), "2", sizeStyle='small')       

        self.w.smooth_connection_max_distance_Text = TextBox((10, 57, -25, 18), "Smooth Connect max_dist", sizeStyle='small')       
        self.w.smooth_connection_max_distance_Input = EditText((160, 55, -10, 18), "4", sizeStyle='small')

        self.w.collinear_vectors_max_distance_Text = TextBox((10, 77, -25, 18), "Collinear Vectors max_dist", sizeStyle='small')       
        self.w.collinear_vectors_max_distance_Input = EditText((160, 75, -10, 18), "2", sizeStyle='small')        
        
        self.w.report = EditText((10, 100, -10, -10), "...", sizeStyle='regular')       
        self.w.report.enable(False)

        self.count = []
        self.report = []
        self.w.open()


    def select_test(self, sender):
        
        # options
        try: 
            extremumTolerance = int(self.w.extremumToleranceInput.get())
        except ValueError:
            self.w.extremumToleranceInput.set(2)
            extremumTolerance = 2
        try: 
            smooth_connection_max_distance_Input = int(self.w.smooth_connection_max_distance_Input.get())
        except ValueError:
            self.w.smooth_connection_max_distance_Input.set(4)
            smooth_connection_max_distance_Input = 4     
        try: 
            collinear_vectors_max_distance_Input = int(self.w.collinear_vectors_max_distance_Input.get())
        except ValueError:
            self.w.collinear_vectors_max_distance_Input.set(2)
            collinear_vectors_max_distance_Input = 2 
        
        options = {
        "extremum_calculate_badness": True,
        "extremum_ignore_badness_below": extremumTolerance,
        "smooth_connection_max_distance": smooth_connection_max_distance_Input,
        "fractional_ignore_point_zero": True,
        "collinear_vectors_max_distance": collinear_vectors_max_distance_Input,
        }


        # a random number to change the mark color
        #randomNumber = random.random()
        # check if a font is open or not
        if CurrentFont():
            font = CurrentFont()
            glyphnames = CurrentFont().keys()
        else:
            self.w.report.set("Open a Font")
            return
        # start the outline test
        selection = []
        otp = OutlineTestPen(CurrentFont(), options)
        for n in glyphnames:
            otp.errors = []
            g = font[n]
            g.drawPoints(otp)
            if otp.errors:
                for e in otp.errors:
                    # convert error object to string
                    errorString = str(e).split(" ")[0]
                    # if the first part of error string = the first part of selection from PopUp                    
                    if errorString == str(sender.getItems()[sender.get()]).split(" ")[0]:
                        #g.mark = (1, randomNumber, 0.6, 1)
                        selection.append(g.name)
                        #print(e)
        font.selection = selection
        # output of glyphs with errors in UI
        result = dict((x,selection.count(x)) for x in set(selection))
        formattedResult = '  '.join("%s=%r" % (key,val) for (key,val) in sorted(result.items()))
        self.w.report.set(formattedResult)