Exemplo n.º 1
0
 def __createDockingSide(self, position):
     '''
         creates dockbar, which are next to the  edges of the content view
     '''
     dockingSideObj = Group(self.dockingRectPosSizes[position],
                            blendingMode=None)
     objBarView = dockingSideObj.getNSView()
     objBarView.dockingSidePositionName = position
     objBarView.setWantsLayer_(True)
     objBarView.layer().setBackgroundColor_(NSColor.clearColor().CGColor())
     objName = f"{position}_dockbar"
     setattr(self, objName, dockingSideObj)
Exemplo n.º 2
0
    def __init__(self, posSize, gridActive, ctrlsAmount, activeCtrls,
                 offgridActive, callback):
        Group.__init__(self, posSize)
        assert activeCtrls <= ctrlsAmount

        self.ctrlHeight = posSize[3]
        self.gridActive = gridActive
        self.ctrlsAmount = ctrlsAmount
        self.activeCtrls = activeCtrls
        self.offgridActive = offgridActive
        self.gridIndexes = [
            '{:d}'.format(integer) for integer in range(1, ctrlsAmount + 1)
        ]
        self.callback = callback

        self.gridsDB = [{
            'horizontal': False,
            'vertical': False,
            'step': None,
            'color': color
        } for color in GRID_COLOR_INIT]

        jumpin_Y = 4
        self.gridActiveCheck = CheckBox(
            (0, jumpin_Y, NET_WIDTH * .6,
             vanillaControlsSize['CheckBoxRegularHeight']),
            "Show grids",
            value=self.gridActive,
            callback=self.gridActiveCheckCallback)

        for eachI in range(1, ctrlsAmount + 1):
            jumpin_Y += vanillaControlsSize[
                'EditTextRegularHeight'] + MARGIN_VER
            gridCtrl = SingleGridController(
                (0, jumpin_Y, NET_WIDTH,
                 vanillaControlsSize['EditTextRegularHeight']),
                index=eachI,
                isVertical=False,
                isHorizontal=False,
                step=None,
                gridColor=GRID_COLOR_INIT[eachI - 1],
                callback=self.gridCtrlCallback)
            gridCtrl.enable(self.gridActive)
            setattr(self, 'grid{:0>2}'.format(eachI), gridCtrl)

        jumpin_Y += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER
        self.showOffgridCheck = CheckBox(
            (0, jumpin_Y, NET_WIDTH,
             vanillaControlsSize['CheckBoxRegularHeight']),
            "Show offgrid points",
            value=self.offgridActive,
            callback=self.showOffgridCheckCallback)
Exemplo n.º 3
0
 def __init__(self, posSize, text, minValue, maxValue, value, callback):
     Group.__init__(self, posSize)
     self.text = TextBox((0, 0, -0, 20), text)
     self.slider = Slider((2, 20, -60, 17),
                          minValue=minValue,
                          maxValue=maxValue,
                          value=value,
                          sizeStyle="small",
                          callback=self.sliderChanged)
     self.edit = EditText((-40, 15, -0, 22),
                          text=str(value),
                          placeholder=str(value),
                          callback=self.editChanged)
     self.callback = callback
Exemplo n.º 4
0
class LoadedDockingGroup(EmptyDockingGroup):
    '''
        DockedWindowView
        group that represents docked windows
    '''
    def __init__(self, dockingWindow):
        self._dockingWindow = dockingWindow

        testPosSize = (0, 0, -0, -0)  ### TEST
        blendingMode = None  # ? check what exacly it does
        super(LoadedDockingGroup, self).__init__(posSize=testPosSize,
                                                 blendingMode=blendingMode)

        self._nsObject.setWantsLayer_(True)
        self._nsObject.layer().setBorderWidth_(1)
        self._nsObject.layer().setBorderColor_(NSColor.gridColor().CGColor())
        self.__addTitleView()
        self.__addContentView()
        self.__transferDockedContent()

    def __addTitleView(self):
        self._titleView = Group((0, 0, -0, titleHeight))
        self._dockingWindow.getTitle()
        self._titleView.title = TextBox((0, 0, -0, titleHeight),
                                        self._dockingWindow.getTitle(),
                                        sizeStyle='mini',
                                        alignment='center')
        self._titleView.undockBtn = GradientButton(
            (-titleHeight, 0, titleHeight, titleHeight),
            title="❏",
            bordered=False,
            callback=self._undock,
            sizeStyle='mini')
        self._titleView.getNSView().setWantsLayer_(True)
        self._titleView.getNSView().layer().setBackgroundColor_(
            NSColor.gridColor().CGColor())

    def __addContentView(self):
        self._contentView = Group((0, titleHeight, -0, -0))

    def __transferDockedContent(self):
        for objName in self._dockingWindow.__dict__:
            obj = getattr(self._dockingWindow, objName)
            if isinstance(obj, VanillaBaseObject):
                setattr(self._contentView, objName, obj)
                # I don't know if it is a proper way to change the posi

    def _undock(self, sender):
        print("undock not implemented yet")
Exemplo n.º 5
0
    def __init__(self, posSize, openedFontPaths, lftNeighborActive,
                 lftFontPath, lftGlyphName, cntNeighborActive, cntFontPath,
                 cntGlyphName, rgtNeighborActive, rgtFontPath, rgtGlyphName,
                 callback):

        Group.__init__(self, posSize)
        self.callback = callback
        self.ctrlHeight = posSize[3]

        self.neighborsDB = {}
        self.neighborsDB['lft'] = [
            lftNeighborActive, lftFontPath, lftGlyphName
        ]
        self.neighborsDB['cnt'] = [
            cntNeighborActive, cntFontPath, cntGlyphName
        ]
        self.neighborsDB['rgt'] = [
            rgtNeighborActive, rgtFontPath, rgtGlyphName
        ]

        jumpin_X = 0
        self.lftController = SingleNeighborController(
            (jumpin_X, 0, 60, self.ctrlHeight),
            'Left',
            isActive=lftNeighborActive,
            openedFontPaths=openedFontPaths,
            activeFontPath=lftFontPath,
            activeGlyphName=lftGlyphName,
            callback=self.lftControllerCallback)

        jumpin_X += 60 + MARGIN_HOR
        self.cntController = SingleNeighborController(
            (jumpin_X, 0, 60, self.ctrlHeight),
            'Center',
            isActive=cntNeighborActive,
            openedFontPaths=openedFontPaths,
            activeFontPath=cntFontPath,
            activeGlyphName=cntGlyphName,
            callback=self.cntControllerCallback)

        jumpin_X += 60 + MARGIN_HOR
        self.rgtController = SingleNeighborController(
            (jumpin_X, 0, 60, self.ctrlHeight),
            'Right',
            isActive=rgtNeighborActive,
            openedFontPaths=openedFontPaths,
            activeFontPath=rgtFontPath,
            activeGlyphName=rgtGlyphName,
            callback=self.rgtControllerCallback)
 def __init__(self, posSize, minValue, maxValue, value, callback):
     Group.__init__(self, posSize)
     self.slider = Slider(
         (2, 3, -55, 17),
         minValue=minValue,
         maxValue=maxValue,
         value=value,
         sizeStyle="regular",
         callback=self.sliderChanged)
     self.edit = EditText(
         (-40, 0, -0, 22),
         text=str(value),
         placeholder=str(value),
         callback=self.editChanged)
     self.callback = callback
    def __init__(self):
        self.w = Window((300, 100))
        self.w.inner = Group((10, 10, -10, -10))

        p1 = VanillaSingleValueParameter('main', 10, (0, 100), 'int')
        p2 = VanillaSingleValueParameter('ratio',
                                         10, (0, 100),
                                         'int',
                                         master=p1,
                                         mode='ratio',
                                         dissociable=True)
        p3 = VanillaSingleValueParameter('offset',
                                         10, (0, 100),
                                         'int',
                                         master=p1,
                                         mode='offset',
                                         dissociable=True)

        self.w.inner.p1 = ParameterSliderTextInput(p1, (0, 0, -0, 22),
                                                   'master')
        self.w.inner.p2 = ParameterSliderTextInput(p2, (0, 25, -0, 22),
                                                   'ratio')
        self.w.inner.p3 = ParameterSliderTextInput(p3, (0, 50, -0, 22),
                                                   'offset')
        self.w.open()
Exemplo n.º 8
0
 def __addTitleView(self):
     self._titleView = Group((0, 0, -0, titleHeight))
     self._dockingWindow.getTitle()
     self._titleView.title = TextBox((0, 0, -0, titleHeight),
                                     self._dockingWindow.getTitle(),
                                     sizeStyle='mini',
                                     alignment='center')
     self._titleView.undockBtn = GradientButton(
         (-titleHeight, 0, titleHeight, titleHeight),
         title="❏",
         bordered=False,
         callback=self._undock,
         sizeStyle='mini')
     self._titleView.getNSView().setWantsLayer_(True)
     self._titleView.getNSView().layer().setBackgroundColor_(
         NSColor.gridColor().CGColor())
Exemplo n.º 9
0
    def showWindow_(self, sender):
        try:
            from vanilla import Group, Slider, TextBox, Window
            self.windowWidth = 300
            self.windowHeight = 240

            self.w = Window((self.windowWidth, self.windowWidth),
                            "Rotate View",
                            minSize=(self.windowWidth, self.windowWidth + 20))

            self.w.Preview = RoatatePreview((0, 0, -0, -60))
            self.w.controlBox = Group((0, -60, -0, -0))
            self.w.controlBox.slider = Slider((10, 6, -10, 23),
                                              tickMarkCount=17,
                                              callback=self.sliderCallback,
                                              value=0,
                                              minValue=-360,
                                              maxValue=360)
            self.w.controlBox.textBox = TextBox((10, -25, -10, 22),
                                                text="0.00°",
                                                alignment="center")
            self.w.controlBox.slider.getNSSlider().setEnabled_(False)

            self.w.open()
            self.changeGlyph_(None)
            Glyphs.addCallback(
                self.changeGlyph_, UPDATEINTERFACE
            )  #will be called on ever change to the interface
        except:
            print(traceback.format_exc())
Exemplo n.º 10
0
 def __init__(self):
     self.w = Window((300, 500), minSize=(200, 100))
     y = 10
     self.w.g = Group((0, 0, 0, 0))
     for i, tag in enumerate(["liga", "calt", "dlig", "smcp", "kern", "locl"]):
         setattr(self.w.g, f"tag{i}", TagView((10, y, 60, 20), tag, None, self.callback))
         y += 26
     self.w.open()
    def __init__(self):
        self.filters = PenBallFiltersManager()
        self.filters.loadFiltersFromJSON('/'.join([LOCALPATH, JSONFILE]))
        self.glyphNames = []
        self.observedGlyphs = []
        self.cachedFont = RFont(showUI=False)
        self.currentFont = CurrentFont()
        filtersList = self.filters.keys()
        if len(filtersList) > 0:
            self.currentFilterName = filtersList[0]
        else:
            self.currentFilterName = None
        self.fill = True

        self.observers = [
            ('fontChanged', 'fontBecameCurrent'),
            ('fontChanged', 'fontDidOpen'),
            ('fontChanged', 'fontDidClose'),
        ]

        self.w = Window((100, 100, 800, 500), 'PenBall Wizard v{0}'.format(__version__), minSize=(500, 400))
        self.w.filtersPanel = Group((0, 0, 300, -0))
        self.w.filtersPanel.filtersList = List((0, 0, -0, -40), filtersList, selectionCallback=self.filterSelectionChanged, doubleClickCallback=self.filterEdit, allowsMultipleSelection=False, allowsEmptySelection=False, rowHeight=22)
        self.w.filtersPanel.controls = Group((0, -40, -0, 0))
        self.w.filtersPanel.addFilter = SquareButton((0, -40, 100, 40), 'Add filter', sizeStyle='small', callback=self.addFilter)
        self.w.filtersPanel.addFilterChain = SquareButton((100, -40, 100, 40), 'Add operations', sizeStyle='small', callback=self.addFilterChain)
        self.w.filtersPanel.removeFilter = SquareButton((-100, -40, 100, 40), 'Remove filter', sizeStyle='small', callback=self.removeFilter)
        self.w.textInput = EditText((300, 0, -90, 22), '', callback=self.stringInput)
        self.w.generate = SquareButton((-90, 0, 90, 22), 'Generate', callback=self.generateGlyphsToFont, sizeStyle='small')
        self.w.preview = MultiLineView((300, 22, -0, -0))
        self.w.switchFillStroke = SquareButton((-75, -40, 60, 25), 'Stroke', callback=self.switchFillStroke, sizeStyle='small')
        displayStates = self.w.preview.getDisplayStates()
        for key in ['Show Metrics','Upside Down','Stroke','Beam','Inverse','Water Fall','Multi Line']:
            displayStates[key] = False
        for key in ['Fill','Single Line']:
            displayStates[key] = True
        self.w.preview.setDisplayStates(displayStates)

        for callback, event in self.observers:
            addObserver(self, callback, event)

        self.updateControls()

        self.w.bind('close', self.end)
        self.launchWindow()
        self.w.open()
Exemplo n.º 12
0
    def __init__(self, posSize, title, options, chosenOption, sizeStyle, callback):
        Group.__init__(self, posSize)
        self.callback = callback
        self.options = options
        width = posSize[2]
        height = posSize[3]

        self.caption = TextBox((0, 2, width*.5, height),
                               title,
                               sizeStyle=sizeStyle,
                               alignment='right')

        self.combo = ComboBox((width*.5, 0, width*.5-1, height),
                              options,
                              continuous=False,
                              sizeStyle=sizeStyle,
                              callback=self.comboCallback)
        self.combo.set(chosenOption)
Exemplo n.º 13
0
    def __init__(self, posSize, index, isVertical, isHorizontal, step,
                 gridColor, callback):
        Group.__init__(self, posSize)

        # from arguments to attributes
        self.ctrlX, self.ctrlY, self.ctrlWidth, self.ctrlHeight = posSize
        self.index = index
        self.isVertical = isVertical
        self.isHorizontal = isHorizontal
        self.step = step
        self.gridColor = gridColor
        self.callback = callback

        # ctrls
        jumpin_X = 12
        self.indexText = TextBox(
            (jumpin_X, 0, 16, vanillaControlsSize['TextBoxRegularHeight']),
            '{:d})'.format(index))
        jumpin_X += self.indexText.getPosSize()[2]

        self.stepCtrl = EditText(
            (jumpin_X, 0, 38, vanillaControlsSize['EditTextRegularHeight']),
            callback=self.stepCtrlCallback)
        jumpin_X += self.stepCtrl.getPosSize()[2] + 16

        self.isHorizontalCheck = CheckBox(
            (jumpin_X, 0, 32, vanillaControlsSize['CheckBoxRegularHeight']),
            "H",
            value=self.isHorizontal,
            callback=self.isHorizontalCheckCallback)
        jumpin_X += self.isHorizontalCheck.getPosSize()[2] + 2

        self.isVerticalCheck = CheckBox(
            (jumpin_X, 0, 32, vanillaControlsSize['CheckBoxRegularHeight']),
            "V",
            value=self.isVertical,
            callback=self.isVerticalCheckCallback)
        jumpin_X += self.isVerticalCheck.getPosSize()[2] + 10

        self.whichColorWell = ColorWell(
            (jumpin_X, 0, 46, self.ctrlHeight),
            color=NSColor.colorWithCalibratedRed_green_blue_alpha_(*gridColor),
            callback=self.whichColorWellCallback)
Exemplo n.º 14
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 _testWind():
     win = Window((20, 200, 200, 270),
                  minSize=(200, 270),
                  title="Docked Window Demo")
     win.color = Group((0, 0, -0, -0))
     win.color.txt = TextBox((0, 0, -0, -0),
                             f"demo window {globals()['testNum']}",
                             alignment='center')
     globals()['testNum'] = globals()['testNum'] + 1
     # win.color.getNSView().setWantsLayer_(True)
     # win.color.getNSView().layer().setBackgroundColor_(color.CGColor())
     # win.btn = GradientButton((10, 10, 50, 50),
     #                          title="❏", sizeStyle='regular')
     return win
Exemplo n.º 16
0
    def __init__(self, posSize, sqrActive, bcpLengthActive, callback):
        Group.__init__(self, posSize)

        self.ctrlHeight = posSize[3]
        self.sqrActive = sqrActive
        self.bcpLengthActive = bcpLengthActive
        self.callback = callback

        jumpin_Y = 2
        self.sqrCheck = CheckBox(
            (0, jumpin_Y, NET_WIDTH,
             vanillaControlsSize['CheckBoxRegularHeight']),
            "Show squarings",
            value=self.sqrActive,
            callback=self.sqrCheckCallback)

        jumpin_Y += vanillaControlsSize['CheckBoxRegularHeight']
        self.bcpLengthCheck = CheckBox(
            (0, jumpin_Y, NET_WIDTH,
             vanillaControlsSize['CheckBoxRegularHeight']),
            "Show bcp length",
            value=self.bcpLengthActive,
            callback=self.bcpLengthCheckCallback)
Exemplo n.º 17
0
    def __init__(self, posSize, title, isActive, openedFontPaths,
                 activeFontPath, activeGlyphName, callback):
        Group.__init__(self, posSize)
        self.isActive = isActive
        self.openedFontPaths = openedFontPaths
        self.activeFontPath = activeFontPath
        self.activeGlyphName = activeGlyphName
        self.callback = callback
        ctrlWidth = posSize[2]

        # ui
        jumpingY = 4
        self.isActiveCheck = CheckBox(
            (0, jumpingY, ctrlWidth,
             vanillaControlsSize['CheckBoxRegularHeight']),
            title,
            value=self.isActive,
            callback=self.isActiveCallback)

        jumpingY += vanillaControlsSize['CheckBoxRegularHeight'] + 2
        self.fontPop = PopUpButton(
            (1, jumpingY, ctrlWidth - 1,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            makeFontList(openedFontPaths),
            callback=self.fontPopCallback)

        jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER

        if self.activeFontPath == CURRENT_FONT_REPR:
            activeFont = CurrentFont()
        else:
            activeFont = getOpenedFontFromPath(AllFonts(), self.activeFontPath)
        self.glyphPop = PopUpButton(
            (1, jumpingY, ctrlWidth - 1,
             vanillaControlsSize['ComboBoxRegularHeight']),
            makeGlyphList(activeFont),
            callback=self.glyphPopCallback)
Exemplo n.º 18
0
    def initUI(self):
        self.prevSelection = [0]
        w, h = self.minSize
        self.w = HUDFloatingWindow((0, 0, w, h),self.windowTitle,minSize=self.minSize,autosaveName=key)
        self.w.getNSWindow().setHasShadow_(False)

        columnInfo = [
                dict(title='icon', cell=ImageListCell(), width=self.rowHeight+self.rowHeight/8),
                dict(title='tool', cell=VerticallyCenteredTextFieldCell('mini'), editable=False),
                dict(title='active', cell=CheckBoxListCell(), editable=True, width=17),
            ]

        self.w.palette = Group((0,0,-0,-0))
        self.w.palette.list = List((0,0,-0,-66),[], columnDescriptions=columnInfo, rowHeight=self.rowHeight, selectionCallback=self.selectionCallback,showColumnTitles=False, allowsEmptySelection=True, allowsMultipleSelection=False, drawHorizontalLines=True,drawFocusRing=True,editCallback=self.listChangedCallback)#,dragSettings=dict(type=toolOrderDragType, callback=self.dragCallback), selfDropSettings=dict(type=toolOrderDragType, operation=NSDragOperationMove, callback=self.dropListSelfCallback))
        self.selectionCallback(self.w.palette.list)
        self.w.palette.openSettings = GradientButton((5,-66+5,-5,-5),imageNamed=NSImageNameActionTemplate,sizeStyle='mini',callback=self.openSettingsCallback)
        self.w.settings = Group((-self.settingsWidth,0,self.settingsWidth,-0))
        columnInfo = [

                dict(title='hotkey', editable=True),
                dict(title='modifier',cell=PopUpButtonListCell(self.modifiers), binding="selectedValue")
            ]
        self.w.settings.list = List((5,0,-0,-66),[], columnDescriptions=columnInfo, rowHeight=self.rowHeight, showColumnTitles=False, allowsEmptySelection=True, allowsMultipleSelection=False, drawVerticalLines=True, drawFocusRing=True,editCallback=self.hotkeyEditCallback)
        self.w.settings.hideToolbar = CheckBox((5,-66+5,-5,15),'hide toolbar',sizeStyle='mini', callback=self.hideToolbarCallback,value=self.hideToolbar)
        # self.w.settings.sortDefaulr = SquareButton((self.settingsWidth/2+2.5,-66+5,-5,15),'sort default bar',sizeStyle='mini',callback=self.sortDefaultToolsCallback)
        self.w.settings.showOnLaunchChB = CheckBox((5,-44+5,-5,15),'show on launch',sizeStyle='mini', callback=self.showOnLaunchCallback,value=self.showOnLaunch)
        self.w.settings.exportBtn = SquareButton((5,-22+2,self.settingsWidth/2-5-2.5,15),'export prefs',sizeStyle='mini',callback=self.exportImportCallback)
        self.w.settings.importBtn = SquareButton((self.settingsWidth/2+2.5,-22+2,-5,15),'import prefs',sizeStyle='mini',callback=self.exportImportCallback)
        self.w.settings.show(False)
        self.hideToolbarCallback(self.w.settings.hideToolbar)
        self._rebuildToolPalette()
        self.w.palette.list.setSelection(self.prevSelection)
        self.w.bind('close', self.windowClose)
        self.w.bind('resize', self.windowResize)
        self.windowResize(self.w)
        self.w.open()
    def __init__(self, font):
        self.font = font
        self.recipients = FontRecipients(self.font)

        if 'pm.ghostlines.ghostlines.registry_token' in self.font.lib:
            self.roster_token = self.font.lib[
                'pm.ghostlines.ghostlines.registry_token']
        else:
            self.roster_token = None

        self.window.content = Group((15, 15, -15, -15))
        self.window.content.font_name_label = TextBox((0, 0, -0, 22),
                                                      "Font Name",
                                                      sizeStyle="small")
        self.window.content.font_name = TextBox((0, 19, -0, 22),
                                                self.font.info.familyName)
        self.window.content.font_author_label = TextBox((0, 55, -0, 22),
                                                        "Designer",
                                                        sizeStyle="small")
        self.window.content.font_author = TextBox(
            (0, 74, -0, 22), self.font.info.openTypeNameDesigner)

        self.window.content.recipients_label = TextBox((0, 114, -15, 22),
                                                       "Subscribers",
                                                       sizeStyle="small")
        self.window.content.recipients = List((0, 135, -0, 190),
                                              self.recipients,
                                              drawFocusRing=False,
                                              allowsEmptySelection=True)
        self.window.content.recipients.setSelection([])

        self.window.content.roster_label = TextBox((0, 350, -15, 22),
                                                   "Application Page",
                                                   sizeStyle="small")
        self.window.content.roster_status = TextBox((0, 370, -15, 22),
                                                    self.roster_status)

        self.window.content.confirmation_button = Button((0, -24, 0, 24),
                                                         "Complete Migration",
                                                         callback=self.migrate)

        self.window.content.explainer = TextBox(
            (0, 405, -15, 66),
            "A new font entry will be created on Ghostlines with the details above. Any pending applicants will be retained if you have activated that feature.",
            sizeStyle="small")

        self.window.setDefaultButton(self.window.content.confirmation_button)
    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()
Exemplo n.º 21
0
    def loadPlugin(self):
        self.menuName = "Italic Extremes"
        self.actionButtonLabel = 'Add Nodes'
        self.keyboardShortcut = None
        windowWidth = 300
        windowHeight = 120
        m, h, yPos = 10, 18, 10
        self.w = FloatingWindow((windowWidth, windowHeight))
        self.w.group = Group((0, 0, windowWidth, windowHeight))
        self.w.group.angle = EditText((m, yPos, -50, h),
                                      "",
                                      placeholder='Angles',
                                      sizeStyle='small',
                                      callback=self.editAngles_callback,
                                      continuous=True)
        self.w.group.refresh = Button((-40, yPos, -m, h),
                                      u"↺",
                                      callback=self.revertAngles_callback)
        yPos += m + h
        self.w.group.tabs = Tabs((m, yPos, -m, -m),
                                 ["Add slanted nodes", "Add H/V extremes"],
                                 callback=self.tab_callback)
        self.tab1 = self.w.group.tabs[0]
        self.tab1.removeV = CheckBox((m, 0, -m, h),
                                     "Delete vertical extremes",
                                     sizeStyle='small',
                                     value=False,
                                     callback=self.removeV_callback)
        yPos = h
        self.tab1.removeH = CheckBox((m, yPos, -m, h),
                                     "Delete horizontal extremes",
                                     sizeStyle='small',
                                     value=False,
                                     callback=self.removeH_callback)
        self.tab2 = self.w.group.tabs[1]
        yPos = 0
        self.tab2.removeI = CheckBox((m, yPos, -m, h),
                                     "Delete slanted nodes",
                                     sizeStyle='small',
                                     value=False,
                                     callback=self.removeI_callback)

        self.dialog = self.w.group.getNSView()
Exemplo n.º 22
0
    def showWindow_(self, sender):
        try:
            from vanilla import Group, Slider, TextBox, Window
            self.windowWidth = 300
            self.windowHeight = 240

            self.w = Window((self.windowWidth, self.windowWidth),
                            "Rotate View",
                            minSize=(self.windowWidth, self.windowWidth))
            window = self.w.getNSWindow()
            window.setStyleMask_(window.styleMask()
                                 | NSFullSizeContentViewWindowMask)
            try:  # only available in 10.10
                window.setTitlebarAppearsTransparent_(True)
            except:
                pass
            #window.toolbar = nil;
            window.setMovableByWindowBackground_(True)

            self.w.Preview = RoatatePreview((0, 0, -0, -28))
            self.w.controlBox = Group((0, -28, -0, -0))
            self.w.controlBox.slider = Slider((10, 2, -55, 28),
                                              tickMarkCount=17,
                                              callback=self.sliderCallback,
                                              value=0,
                                              minValue=-360,
                                              maxValue=360)
            self.w.controlBox.textBox = TextBox((-55, -23, -5, -3),
                                                text="0°",
                                                alignment="center")
            self.w.controlBox.slider.getNSSlider().setEnabled_(False)

            self.w.open()
            self.changeGlyph_(None)
            Glyphs.addCallback(
                self.changeGlyph_, UPDATEINTERFACE
            )  #will be called on ever change to the interface
        except:
            print(traceback.format_exc())
Exemplo n.º 23
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()
    def updateControls(self):
        if self.currentFilterName is not None:
            if hasattr(self.w.filtersPanel, 'controls'):
                delattr(self.w.filtersPanel, 'controls')
            currentFilter = self.filters[self.currentFilterName]
            self.w.filtersPanel.controls = Group((0, 0, 0, 0))
            hasSubfilters = self.filters.hasSubfilters(self.currentFilterName)

            if hasSubfilters:
                argumentBlocks = [(subfilterName, self.filters[subfilterName].arguments) for subfilterName, mode, source in currentFilter.subfilters]
            else:
                argumentBlocks = [(currentFilter.name, currentFilter.arguments)]

            gap = 5
            height = gap
            end = 0
            lineheight = 27
            top = 35
            boxes = 0

            for j, (filterName, arguments)  in enumerate(argumentBlocks):
                if len(arguments) > 0:
                    blockfilterName = '{0}{1}'.format(filterName, j)
                    setattr(self.w.filtersPanel.controls, blockfilterName, Box((5, 5, 0, 0)))
                    block = getattr(self.w.filtersPanel.controls, blockfilterName)
                    if hasSubfilters:
                        _, filterMode, filterSource = currentFilter.subfilters[j]
                        modes = '({0}) [{1}]'.format(filterMode, filterSource)
                        block.modes = TextBox((-150, 11, -8, 12), modes, alignment='right', sizeStyle='mini')
                    block.title = TextBox((8, 8, -150, 22), filterName.upper())
                    start = height
                    boxHeight = top

                    for i, (arg, value) in enumerate(arguments.items()):
                        valueType = None

                        if hasSubfilters:
                            argumentName = currentFilter.joinSubfilterArgumentName(filterName, arg, j)
                            if argumentName in currentFilter.arguments:
                                value = currentFilter.arguments[argumentName]
                            else:
                                value = self.filters[filterName].arguments[argumentName]
                                currentFilter.setArgumentValue(argumentName, value)
                        else:
                            argumentName = arg

                        limits = currentFilter.getLimits(argumentName)
                        if limits is None: limits = (0, 100)

                        if isinstance(value, bool):
                            setattr(block, arg, CheckBox((8, top + (i*lineheight), -8, 22), arg, value=value, callback=self.setArgumentValue, sizeStyle='small'))
                            valueType = 'bool'
                        elif isinstance(value, (str, unicode)):
                            setattr(block, arg, EditText((8, top + (i*lineheight), -8, 22), value, callback=self.setArgumentValue, sizeStyle='small'))
                        elif isinstance(value, (int, float)):
                            parameter = VanillaSingleValueParameter(arg, value, limits=limits)
                            setattr(block, arg, ParameterSliderTextInput(parameter, (8, top + (i*lineheight), -8, 22), title=arg, callback=self.setArgumentValue))

                        control = getattr(block, arg)
                        control.name = argumentName
                        control.type = valueType

                        boxHeight += lineheight

                    boxHeight += 12
                    block.setPosSize((5, start, -5, boxHeight))
                    height += boxHeight + gap

            height += 40

            self.w.filtersPanel.filtersList.setPosSize((0, 0, -0, -height))
            self.w.filtersPanel.controls.setPosSize((0, -height, -0, -45))
Exemplo n.º 25
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()
Exemplo n.º 26
0
    def __init__(self, font, document=None):
        self.font = font

        self.note_draft_storage = LibStorage(self.font.lib,
                                             "releaseNotesDraft")
        self.license_storage = LibStorage(self.font.lib, "licenseFilepath")
        self.family_id_storage = LibStorage(self.font.lib, "fontFamilyId")

        self.subscribers = self.font_family["subscribers"]

        if document is not None:
            self.window.assignToDocument(document)

        self.window.background = Background((301, -52, 299, 52), alpha=0.05)

        self.window.release_info = Group((315, 15, 270, -15))

        self.window.release_info.font_name_label = TextBox((0, 0, -0, 22),
                                                           "Font Name",
                                                           sizeStyle="small")
        self.window.release_info.font_name = TextBox((0, 19, -0, 22),
                                                     self.font_family["name"])
        self.window.release_info.font_author_label = TextBox((0, 60, -0, 22),
                                                             "Designer",
                                                             sizeStyle="small")
        self.window.release_info.font_author = TextBox(
            (0, 79, -0, 22), self.font_family["designer_name"])
        self.window.release_info.version_label = TextBox((0, 120, -0, 22),
                                                         "Version Number",
                                                         sizeStyle="small")
        self.window.release_info.version = TextBox((0, 139, -0, 22),
                                                   self.font_version)

        self.window.release_info.notes_field_label = TextBox((0, 176, -0, 22),
                                                             "Release Notes",
                                                             sizeStyle="small")
        self.window.release_info.notes_field = NotesEditor(
            (0, 198, -0, 175), draft_storage=self.note_draft_storage)

        self.window.release_info.license_field_label = TextBox(
            (0, 393, -0, 22), "Attach License", sizeStyle="small")
        self.window.release_info.license_field = FileUploadField(
            (0, 410, -0, 22), storage=self.license_storage)

        self.window.release_info.send_button = CounterButton(
            (0, -24, -0, 24), ("Send Release to All", "Send Release to {}"),
            callback=self.send)

        self.window.release_subscriber_divider = VerticalLine((300, 0, 1, -0))

        self.window.subscriber_info = Group((15, 15, 270, -15))

        self.window.subscriber_info.subscribers_label = TextBox(
            (0, 0, -0, 22), "Subscribers", sizeStyle="small")
        self.window.subscriber_info.subscribers = List(
            (0, 22, -0, 205),
            self.subscribers,
            columnDescriptions=[{
                "title": "Name",
                "key": "name",
                "editable": False
            }, {
                "title": "Email Address",
                "key": "email_address",
                "editable": False
            }],
            selectionCallback=self.update_send_button)
        self.window.subscriber_info.subscribers.setSelection([])

        self.window.subscriber_info.subscribers_tip = TextBox(
            (0, 238, -0, 14),
            "cmd+click to select subset",
            alignment="right",
            sizeStyle="small")

        self.window.subscriber_info.show_subscriber_sheet_button = Button(
            (0, 233, 30, 24), "+", callback=self.show_subscriber_sheet)
        self.window.subscriber_info.remove_subscriber_button = Button(
            (40, 233, 30, 24), "-", callback=self.remove_subscriber)

        self.window.subscriber_info.applicants = \
            ApplicantList((0, 280, 270, 210),
                          self.font_family["applicant_roster"],
                          self.family_id_storage.retrieve(),
                          after_approve=self.refresh_subscribers)

        self.window.release_releases_divider = VerticalLine((600, 0, 1, -0))

        self.window.releases_info = Group((615, 15, 270, -15))

        self.window.releases_info.log_label = TextBox((0, 0, -0, 22),
                                                      "Releases",
                                                      sizeStyle="small")
        self.window.releases_info.log = \
            ReleaseLog((0, 22, -0, -0),
                       self.font_family["releases"][::-1],
                       columnDescriptions=[
                      {
                          "title": "Created",
                          "key": "created_at",
                          "editable": False
                      }, {
                          "title": "Version",
                          "key": "version",
                          "editable": False,
                          "width": 50
                      }, {
                          "title": "# subs.",
                          "key": "subscriber_count",
                          "editable": False,
                          "width": 50
                      }
                  ])

        self.resize_window_for_releases()
        self.window.bind("became main", self.fetch_applicants)
Exemplo n.º 27
0
    def settings(self):
        from vanilla import Group, Slider, TextBox, Window
        self.name = 'Scrawl'
        self.slider_value = 1  # current slider value

        # Create Vanilla window and group with controls
        viewWidth = 266
        viewHeight = 42
        self.sliderMenuView = Window((viewWidth, viewHeight))
        self.sliderMenuView.group = Group((0, 0, viewWidth, viewHeight))
        self.w = self.sliderMenuView.group
        y = 0
        self.w.text = TextBox((20, y, -20, 17), "%s Pen Size" % self.name)
        y += 18
        self.w.pen_size = Slider(
            (20, y, -60, 24),
            minValue=1,
            maxValue=256,
            value=float(self.slider_value),
            tickMarkCount=0,
            # stopOnTickMarks = False,
            # continuuous = True,
            callback=self.slider_callback,
            sizeStyle="small",
        )
        self.w.pen_size_text = TextBox((-50, y + 3, -20, 17),
                                       "%s" % default_pen_size)

        self.generalContextMenus = [
            {
                "view": self.sliderMenuView.group.getNSView()
            },
            {
                "name":
                Glyphs.localize({
                    'en': u'Delete Scrawl',
                    'de': u'Gekritzel löschen'
                }),
                "action":
                self.delete_data
            },
            {
                "name":
                Glyphs.localize({
                    'en':
                    u'Save Scrawl To Background Image',
                    'de':
                    u'Gekritzel als Hintergrundbild speichern'
                }),
                "action":
                self.save_background
            },
            # {
            #     "name": Glyphs.localize({
            #         'en': u'Save current size as master default',
            #         'de': u'Aktuelle Größe als Master-Standard speichern'
            #     }),
            #     "action": self.save_background
            # },
        ]
        self.keyboardShortcut = 'c'
        self.pen_size = default_pen_size
        self.pixel_size = default_pixel_size
        self.pixel_ratio = default_pixel_ratio
        self.rect = NSMakeRect(0, 0, 1000, 1000)
        self.data = None
        self.prev_location = None
        self.erase = False
        self.mouse_position = None
        self.layer = None
        self.needs_save = False
        self.current_layer = self.get_current_layer()
Exemplo n.º 28
0
    def __init__(self):
        self.locations = [
            'User Agents', 'Global Agents', 'Global Daemons', 'System Agents',
            'System Daemons'
        ]
        self.listItems = []
        self.selected = {}

        # Preferences
        self.homedir = os.path.expanduser('~')
        self.prefsFolder = self.homedir + "/Library/Preferences/"
        self.prefsFile = "de.nelsonfritsch.unicron.plist"

        if os.path.isfile(self.prefsFolder + self.prefsFile):
            self.prefs = self._loadPrefs(self)
        else:
            self.prefs = dict(showSystemWarning=True, windowStyle='System')
            self._savePrefs(self)

        # Preferences Window
        self.prefsWindow = Window((300, 105), 'Preferences')

        self.styles = ['System', 'Light', 'Dark']
        self.prefsWindow.styleTxt = TextBox((10, 10, -10, 20), "Window Style:")
        self.prefsWindow.style = PopUpButton((30, 35, -10, 20),
                                             self.styles,
                                             callback=self.prefsSetStyle)

        self.prefsWindow.restore = Button((10, 75, -10, 20),
                                          'Restore Warnings',
                                          callback=self.prefsRestoreWarnings)

        # Main Window
        minsize = 285
        self.w = Window((minsize, 400),
                        'Unicron',
                        closable=True,
                        fullSizeContentView=True,
                        titleVisible=False,
                        minSize=(minsize, minsize),
                        maxSize=(600, 1200),
                        autosaveName="UnicronMainWindow")

        self.pathList = NSPopUpButton.alloc().initWithFrame_(
            ((0, 0), (160, 20)))
        self.pathList.addItemsWithTitles_(self.locations)

        refreshIcon = NSImage.alloc().initWithSize_((32, 32))
        sourceImage = NSImage.imageNamed_(NSImageNameRefreshTemplate)

        w, h = sourceImage.size()

        if w > h:
            diffx = 0
            diffy = w - h
        else:
            diffx = h - w
            diffy = 0

        maxSize = max([w, h])
        refreshIcon.lockFocus()
        sourceImage.drawInRect_fromRect_operation_fraction_(
            NSMakeRect(diffx, diffy + 4, 22, 22),
            NSMakeRect(0, 0, maxSize, maxSize), NSCompositeSourceOver, 1)
        refreshIcon.unlockFocus()
        refreshIcon.setTemplate_(True)

        toolbarItems = [
            dict(itemIdentifier="Daemons",
                 label="Daemons",
                 toolTip="Daemon Group",
                 view=self.pathList,
                 callback=self.populateList),
            dict(itemIdentifier="image",
                 label="Image",
                 imageObject=refreshIcon,
                 callback=self.populateList),
        ]
        self.w.addToolbar("Unicron Toolbar",
                          toolbarItems=toolbarItems,
                          displayMode="icon")

        self.w.blend = Group((0, 0, 0, 0), blendingMode='behindWindow')

        self.listColumnDescriptions = [{
            'title': '',
            'key': 'image',
            'width': 25,
            'typingSensitive': True,
            'allowsSorting': True,
            'cell': ImageListCell()
        }, {
            'title': 'Name',
            'key': 'name',
            'typingSensitive': True,
            'allowsSorting': True,
        }]
        self.rowHeight = 20
        self.w.list = List((0, 37, -0, 0),
                           items=self.listItems,
                           columnDescriptions=self.listColumnDescriptions,
                           showColumnTitles=True,
                           allowsEmptySelection=True,
                           allowsMultipleSelection=False,
                           autohidesScrollers=True,
                           drawFocusRing=False,
                           rowHeight=self.rowHeight,
                           selectionCallback=self._selectionCallback,
                           menuCallback=self._menuCallback)

        self.w.list._nsObject.setBorderType_(NSNoBorder)

        self.w.statusbar = Group((0, -26, 0, 0), blendingMode='behindWindow')
        self.w.statusbar.border = HorizontalLine((0, 0, 0, 1))

        self.w.counter = TextBox((16, -20, -16, 15),
                                 '',
                                 alignment='center',
                                 sizeStyle='small')
        self.populateList(self)
        self.w.rowIndicator = Group((0, 0, 0, 10))

        self.prefsSetStyle(self)

        self.w.open()
Exemplo n.º 29
0
 def __addContentView(self):
     self._contentView = Group((0, titleHeight, -0, -0))
Exemplo n.º 30
0
    def __init__(self):
        self.w = Window((180, 340),
                        u'Touché!',
                        minSize=(180, 340),
                        maxSize=(1000, 898))
        p = 10
        w = 160

        # options
        self.w.options = Group((0, 0, 180, 220))

        buttons = {
            "checkSelBtn": {
                "text": "Check selected glyphs\nfor touching pairs",
                "callback": self.checkSel,
                "y": p
            },
            "checkAllBtn": {
                "text": "Check entire font\n(can take several minutes!)",
                "callback": self.checkAll,
                "y": 60
            }
        }
        for button, data in buttons.items():
            setattr(
                self.w.options, button,
                SquareButton((p, data["y"], w, 40),
                             data["text"],
                             callback=data["callback"],
                             sizeStyle="small"))

        self.w.options.zeroCheck = CheckBox((p, 108, w, 20),
                                            "Ignore zero-width glyphs",
                                            value=True,
                                            sizeStyle="small")
        self.w.options.progress = ProgressSpinner((82, 174, 16, 16),
                                                  sizeStyle="small")

        # results
        self.w.results = Group((0, 220, 180, -0))
        self.w.results.show(False)

        textBoxes = {"stats": 24, "result": 42}
        for box, y in textBoxes.items():
            setattr(self.w.results, box,
                    TextBox((p, y, w, 14), "", sizeStyle="small"))

        moreButtons = {
            "spaceView": {
                "text": "View all in Space Center",
                "callback": self.showAllPairs,
                "y": 65
            },
            "exportTxt": {
                "text": "Export as MM pair list",
                "callback": self.exportPairList,
                "y": 90
            }
        }
        for button, data in moreButtons.items():
            setattr(
                self.w.results, button,
                SquareButton((p, data["y"], w, 20),
                             data["text"],
                             callback=data["callback"],
                             sizeStyle="small"))

        # list and preview
        self.w.outputList = List((180, 0, 188, -0), [{
            "left glyph": "",
            "right glyph": ""
        }],
                                 columnDescriptions=[{
                                     "title": "left glyph"
                                 }, {
                                     "title": "right glyph"
                                 }],
                                 showColumnTitles=False,
                                 allowsMultipleSelection=False,
                                 enableDelete=False,
                                 selectionCallback=self.showPair)
        self.w.preview = MultiLineView((368, 0, -0, -0), pointSize=256)

        self.w.open()
Exemplo n.º 31
0
    def __init__(self):
        self.font = CurrentFont()
        self.glyph = CurrentGlyph()
        self.upm = self.font.info.unitsPerEm
        self.rf3 = int(roboFontVersion.split(".")[0]) >= 3
        if self.rf3:
            self.layer = CurrentLayer()
        # key: glyph name -- value: list containing assembled glyphs
        self.glyphPreviewCacheDict = {}
        # key: anchor name -- value: list of mark glyph names
        self.anchorsOnMarksDict = {}
        # key: anchor name -- value: list of base glyph names
        self.anchorsOnBasesDict = {}
        self.CXTanchorsOnBasesDict = {}
        # key: mark glyph name -- value: anchor name
        # NOTE: It's expected that each mark glyph only has one type of anchor
        self.marksDict = {}
        self.fillAnchorsAndMarksDicts()
        # list of glyph names that will be displayed in the UI list
        self.glyphNamesList = []
        # list of glyph names selected in the UI list
        self.selectedGlyphNamesList = []
        # list of the glyph objects that should be inserted
        # before and after the accented glyphs
        self.extraGlyphsList = []

        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")
        # observer for the draw event
        addObserver(self, "_drawGlyphs", "draw")
        # draw the glyphs when the glyph window is not in focus
        addObserver(self, "_drawGlyphs", "drawInactive")
        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':
            # use the full width of the column
            self.w.fontList.getNSTableView().sizeToFit()
        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"
                                        })
        self.w.lineView.setFont(self.font)
        # -- 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)
        # NSScrollElasticityNone
        self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1)
        self.w.scrollView.show(self.calibrateMode)

        # -- Footer --
        self.w.footer = Group((10, -32, -10, -10))
        self.w.footer.calibrateModeCheck = CheckBox(
            (0, 0, 200, -0),
            "Calibration Mode",
            callback=self.calibrateModeCallback,
            value=self.calibrateMode)
        self.w.footer.textSizeLabel = TextBox((200, 2, 100, -0), "Text Size")
        self.w.footer.textSize = EditText((260, 0, 35, -0),
                                          self.textSize,
                                          callback=self.textSizeCallback,
                                          continuous=False,
                                          formatter=intPosMinOneNumFormatter)
        self.w.footer.lineHeightLabel = TextBox((310, 2, 100, -0),
                                                "Line Height")
        self.w.footer.lineHeight = EditText((385, 0, 35, -0),
                                            self.lineHeight,
                                            callback=self.lineHeightCallback,
                                            continuous=False,
                                            formatter=integerNumFormatter)
        self.w.footer.extraSidebearingsLabel = TextBox((436, 2, 180, -0),
                                                       "Extra Sidebearings")
        self.w.footer.extraSidebearingsChar = TextBox((592, 2, 20, -0), "&")
        self.w.footer.extraSidebearingLeft = EditText(
            (557, 0, 35, -0),
            self.extraSidebearings[0],
            callback=self.extraSidebearingsCallback,
            continuous=False,
            formatter=intPosMinZeroNumFormatter)
        self.w.footer.extraSidebearingRight = EditText(
            (604, 0, 35, -0),
            self.extraSidebearings[1],
            callback=self.extraSidebearingsCallback,
            continuous=False,
            formatter=intPosMinZeroNumFormatter)
        self.w.footer.extraGlyphsLabel = TextBox((655, 2, 180, -0),
                                                 "Extra Glyphs")
        self.w.footer.extraGlyphs = EditText((739, 0, -0, -0),
                                             self.extraGlyphs,
                                             callback=self.extraGlyphsCallback,
                                             continuous=False)

        # trigger the initial state and contents of the window
        self.extraGlyphsCallback()  # calls self.updateExtensionWindow()

        self.w.bind("close", self.windowClose)
        self.w.open()
        self.w.makeKey()
Exemplo n.º 32
0
class AdjustAnchors(BaseWindowController):
    def __init__(self):
        self.font = CurrentFont()
        self.glyph = CurrentGlyph()
        self.upm = self.font.info.unitsPerEm
        self.rf3 = int(roboFontVersion.split(".")[0]) >= 3
        if self.rf3:
            self.layer = CurrentLayer()
        # key: glyph name -- value: list containing assembled glyphs
        self.glyphPreviewCacheDict = {}
        # key: anchor name -- value: list of mark glyph names
        self.anchorsOnMarksDict = {}
        # key: anchor name -- value: list of base glyph names
        self.anchorsOnBasesDict = {}
        self.CXTanchorsOnBasesDict = {}
        # key: mark glyph name -- value: anchor name
        # NOTE: It's expected that each mark glyph only has one type of anchor
        self.marksDict = {}
        self.fillAnchorsAndMarksDicts()
        # list of glyph names that will be displayed in the UI list
        self.glyphNamesList = []
        # list of glyph names selected in the UI list
        self.selectedGlyphNamesList = []
        # list of the glyph objects that should be inserted
        # before and after the accented glyphs
        self.extraGlyphsList = []

        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")
        # observer for the draw event
        addObserver(self, "_drawGlyphs", "draw")
        # draw the glyphs when the glyph window is not in focus
        addObserver(self, "_drawGlyphs", "drawInactive")
        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':
            # use the full width of the column
            self.w.fontList.getNSTableView().sizeToFit()
        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"
                                        })
        self.w.lineView.setFont(self.font)
        # -- 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)
        # NSScrollElasticityNone
        self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1)
        self.w.scrollView.show(self.calibrateMode)

        # -- Footer --
        self.w.footer = Group((10, -32, -10, -10))
        self.w.footer.calibrateModeCheck = CheckBox(
            (0, 0, 200, -0),
            "Calibration Mode",
            callback=self.calibrateModeCallback,
            value=self.calibrateMode)
        self.w.footer.textSizeLabel = TextBox((200, 2, 100, -0), "Text Size")
        self.w.footer.textSize = EditText((260, 0, 35, -0),
                                          self.textSize,
                                          callback=self.textSizeCallback,
                                          continuous=False,
                                          formatter=intPosMinOneNumFormatter)
        self.w.footer.lineHeightLabel = TextBox((310, 2, 100, -0),
                                                "Line Height")
        self.w.footer.lineHeight = EditText((385, 0, 35, -0),
                                            self.lineHeight,
                                            callback=self.lineHeightCallback,
                                            continuous=False,
                                            formatter=integerNumFormatter)
        self.w.footer.extraSidebearingsLabel = TextBox((436, 2, 180, -0),
                                                       "Extra Sidebearings")
        self.w.footer.extraSidebearingsChar = TextBox((592, 2, 20, -0), "&")
        self.w.footer.extraSidebearingLeft = EditText(
            (557, 0, 35, -0),
            self.extraSidebearings[0],
            callback=self.extraSidebearingsCallback,
            continuous=False,
            formatter=intPosMinZeroNumFormatter)
        self.w.footer.extraSidebearingRight = EditText(
            (604, 0, 35, -0),
            self.extraSidebearings[1],
            callback=self.extraSidebearingsCallback,
            continuous=False,
            formatter=intPosMinZeroNumFormatter)
        self.w.footer.extraGlyphsLabel = TextBox((655, 2, 180, -0),
                                                 "Extra Glyphs")
        self.w.footer.extraGlyphs = EditText((739, 0, -0, -0),
                                             self.extraGlyphs,
                                             callback=self.extraGlyphsCallback,
                                             continuous=False)

        # trigger the initial state and contents of the window
        self.extraGlyphsCallback()  # calls 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 Exception:  # 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 Exception:
            NSBeep()
            self.sender.set(self.lineHeight)
        self.w.lineView.setLineHeight(self.lineHeight)

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

    def extraGlyphsCallback(self, *sender):
        del self.extraGlyphsList[:]  # empty the list
        self.extraGlyphs = self.w.footer.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()
                if self.rf3:
                    newGlyph.layer = self.layer
                else:
                    newGlyph.font = newGlyph.getParent()
                # 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 Exception:
                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.w.lineView.setFont(self.font)
        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:
                # avoid traceback in the case where the selected glyph is
                # referencing a component whose glyph is not in the font
                if component.baseGlyph not in self.font.keys():
                    print("WARNING: %s is referencing a glyph named %s, which "
                          "does not exist in the font." %
                          (self.font.selection[0], component.baseGlyph))
                    continue

                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 component is skewed and/or is shifted
                if componentTransformation != (1, 0, 0, 1, 0, 0):
                    matrix = componentTransformation[0:4]
                    if matrix != (1, 0, 0, 1):  # if component is skewed
                        # ignore the original component's shifting values
                        transformObj = Identity.transform(matrix + (0, 0))
                        compGlyph.transform(transformObj)

                # add the two tuples of offset
                glyph.appendGlyph(
                    compGlyph, tuple(map(sum, zip(component.offset, 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()
                if self.rf3:
                    newGlyph.layer = self.layer
                else:
                    newGlyph.font = newGlyph.getParent()
                # skip invalid glyph names
                try:
                    baseGlyph = self.font[gBaseName]
                    markGlyph = self.font[gMarkName]
                except Exception:
                    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 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

        # NOTE: CurrentGlyph() will return zero (its length),
        # so "is not None" is necessary
        if CurrentGlyph() is not None:
            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:
                    # trim the contextual portion of the UI glyph name
                    # and keep track of it
                    if CONTEXTUAL_ANCHOR_TAG in glyphNameInUIList:
                        cxtTagIndex = glyphNameInUIList.find(
                            CONTEXTUAL_ANCHOR_TAG)
                        glyphNameCXTportion = glyphNameInUIList[cxtTagIndex:]
                        # this line must be last!
                        glyphNameInUIList = glyphNameInUIList[:cxtTagIndex]
                    else:
                        glyphNameCXTportion = ''

                    newGlyph = RGlyph()
                    if self.rf3:
                        newGlyph.layer = self.layer
                    else:
                        newGlyph.font = newGlyph.getParent()

                    # 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,
                                                  glyphNameCXTportion))

                        # set the advanced width
                        # combining marks or other glyphs with
                        # a small advanced width
                        if self.glyph.width < 10:
                            newGlyph.leftMargin = self.upm * .05  # 5% of 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
                        # combining marks or other glyphs with
                        # a small advanced width
                        if self.glyph.width < 10:
                            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 + glyphNameCXTportion,
                               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):
        UpdateCurrentGlyphView()

    def fillAnchorsAndMarksDicts(self):
        # reset all the dicts
        self.glyphPreviewCacheDict.clear()
        self.anchorsOnMarksDict.clear()
        self.anchorsOnBasesDict.clear()
        self.CXTanchorsOnBasesDict.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
                    if CONTEXTUAL_ANCHOR_TAG in anchorName:
                        # add to AnchorsOnBases dictionary
                        if anchorName not in self.CXTanchorsOnBasesDict:
                            self.CXTanchorsOnBasesDict[anchorName] = [
                                glyphName
                            ]
                        else:
                            tempList = self.CXTanchorsOnBasesDict[anchorName]
                            tempList.append(glyphName)
                            self.CXTanchorsOnBasesDict[anchorName] = tempList
                    else:
                        # 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
        # NOTE: "if glyph" will return zero (its length),
        # so "is not None" is necessary
        if glyph is not None:
            # assemble the list for the UI list
            for anchor in glyph.anchors:
                anchorName = anchor.name
                # the glyph selected is a base
                if anchorName in self.anchorsOnMarksDict:
                    glyphNamesList.extend(self.anchorsOnMarksDict[anchorName])
                # the glyph selected is a mark
                # skips the leading underscore
                elif anchorName[1:] in self.anchorsOnBasesDict:
                    glyphNamesList.extend(
                        self.anchorsOnBasesDict[anchorName[1:]])
                # the glyph selected is a base
                elif anchorName[0] != '_' and (anchorName
                                               in self.CXTanchorsOnBasesDict):
                    cxtTagIndex = anchorName.find(CONTEXTUAL_ANCHOR_TAG)
                    anchorNameNOTCXTportion = anchorName[:cxtTagIndex]
                    anchorNameCXTportion = anchorName[cxtTagIndex:]
                    # XXX here only the first mark glyph that has an anchor of
                    # the kind 'anchorNameNOTCXTportion' is considered.
                    # This is probably harmless, but...
                    glyphName = '%s%s' % (
                        self.anchorsOnMarksDict[anchorNameNOTCXTportion][0],
                        anchorNameCXTportion)
                    glyphNamesList.append(glyphName)

            # 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:
                    # the current mark glyph has anchors that
                    # allow it to be a base for other marks
                    if anchor.name[0] != '_':
                        markGlyphIsAbleToBeBase = True
                        break
                # remove marks from the glyph list if the
                # current mark glyph can't work as a base
                if not markGlyphIsAbleToBeBase:
                    # iterate from the end of the list
                    for glyphName in glyphNamesList[::-1]:
                        if glyphName in self.marksDict:
                            glyphNamesList.remove(glyphName)
        glyphNamesList.sort()
        return glyphNamesList

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

    def getAnchorOffsets(self,
                         canvasGlyph,
                         glyphToDraw,
                         anchorNameCXTportion=''):
        # 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 + anchorNameCXTportion:
                        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:
            # trim the contextual portion of the UI glyph name
            # and keep track of it
            if CONTEXTUAL_ANCHOR_TAG in glyphName:
                cxtTagIndex = glyphName.find(CONTEXTUAL_ANCHOR_TAG)
                glyphNameCXTportion = glyphName[cxtTagIndex:]
                glyphName = glyphName[:cxtTagIndex]  # this line must be last!
            else:
                glyphNameCXTportion = ''

            glyphToDraw = self.font[glyphName]

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

            # 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()
    def addInterface(self, notification):
        self.window = notification['window']
        # self.cleanup(self.window)

        # CONTAINER
        xywh = (margin, -55, -margin, height)
        self.sbui = CanvasGroup(xywh, delegate=CanvasStuff(self.window))

        # LEFT
        x, y, w, h = xywh = (0, -height, dfltLwidth, height)
        this = self.sbui.L = Group(xywh)

        # text input
        xywh = (x, y + 3, width * 1.5, height * .75)
        this.Ltext = EditText(xywh,
                              placeholder='angledLeftMargin',
                              sizeStyle='mini',
                              continuous=False,
                              callback=self.setSB)
        # quick mod buttons
        xywh = (x + width * 1.5 + (gap * 1), y, width, height)
        this.Lminus = Button(xywh,
                             iconminus,
                             sizeStyle='mini',
                             callback=self.setLminus)
        this.Lminus.getNSButton().setToolTip_('Adjust LSB -' + str(unit))
        xywh = (x + width * 2.5 + (gap * 2), y, width, height)
        this.Lplus = Button(xywh,
                            iconplus,
                            sizeStyle='mini',
                            callback=self.setLplus)
        this.Lplus.getNSButton().setToolTip_('Adjust LSB +' + str(unit))
        xywh = (x + width * 3.5 + (gap * 3), y, width, height)
        this.Lround = Button(xywh,
                             iconround,
                             sizeStyle='mini',
                             callback=self.setLround)
        this.Lround.getNSButton().setToolTip_('Round LSB to ' + str(unit))
        xywh = (x + width * 4.5 + (gap * 4), y, width, height)
        this.Lright = Button(xywh,
                             iconcopyR,
                             sizeStyle='mini',
                             callback=self.setLright)
        this.Lright.getNSButton().setToolTip_('Copy Right Value')
        # stylize
        this.Ltext.getNSTextField().setBezeled_(False)
        this.Ltext.getNSTextField().setBackgroundColor_(NSColor.clearColor())
        self.flatButt(this.Lminus)
        self.flatButt(this.Lplus)
        self.flatButt(this.Lround)
        self.flatButt(this.Lright)

        # RIGHT
        x, y, w, h = xywh = (-dfltRwidth, y, dfltRwidth, h)
        this = self.sbui.R = Group(xywh)
        # text input
        xywh = (-x - width * 1.5, y + 3, width * 1.5, height * .75)
        this.Rtext = EditText(xywh,
                              placeholder='angledRightMargin',
                              sizeStyle='mini',
                              continuous=False,
                              callback=self.setSB)
        # quick mod buttons
        xywh = (-x - width * 5.5 - (gap * 4), y, width, height)
        this.Rleft = Button(xywh,
                            iconcopyL,
                            sizeStyle='mini',
                            callback=self.setRleft)
        this.Rleft.getNSButton().setToolTip_('Copy Left Value')
        xywh = (-x - width * 4.5 - (gap * 3), y, width, height)
        this.Rround = Button(xywh,
                             iconround,
                             sizeStyle='mini',
                             callback=self.setRround)
        this.Rround.getNSButton().setToolTip_('Round RSB to ' + str(unit))
        xywh = (-x - width * 3.5 - (gap * 2), y, width, height)
        this.Rminus = Button(xywh,
                             iconminus,
                             sizeStyle='mini',
                             callback=self.setRminus)
        this.Rminus.getNSButton().setToolTip_('Adjust RSB -' + str(unit))
        xywh = (-x - width * 2.5 - (gap * 1), y, width, height)
        this.Rplus = Button(xywh,
                            iconplus,
                            sizeStyle='mini',
                            callback=self.setRplus)
        this.Rplus.getNSButton().setToolTip_('Adjust RSB +' + str(unit))
        # stylize
        this.Rtext.getNSTextField().setBezeled_(False)
        this.Rtext.getNSTextField().setBackgroundColor_(NSColor.clearColor())
        this.Rtext.getNSTextField().setAlignment_(NSTextAlignmentRight)
        self.flatButt(this.Rminus)
        self.flatButt(this.Rplus)
        self.flatButt(this.Rround)
        self.flatButt(this.Rleft)

        # CENTER
        winX, winY, winW, winH = self.window.getVisibleRect()
        winW = winW - margin * 5
        x, y, w, h = xywh = ((winW / 2) - (dfltCwidth / 2), y, dfltCwidth, h)
        this = self.sbui.C = Group(xywh)
        x = 0

        # text input
        c = (dfltCwidth / 2)
        xywh = (c - (width * .75), y + 3, width * 1.5, height * .75)
        this.Ctext = EditText(xywh,
                              placeholder='width',
                              sizeStyle='mini',
                              continuous=False,
                              callback=self.setSB)
        # quick mod buttons
        xywh = (c - (width * .75) - width * 2 - (gap * 2), y, width, height)
        this.Ccenter = Button(xywh,
                              iconcenter,
                              sizeStyle='mini',
                              callback=self.setCcenter)
        this.Ccenter.getNSButton().setToolTip_('Center on Width')
        xywh = (c - (width * .75) - width - (gap * 1), y, width, height)
        this.Cround = Button(xywh,
                             iconround,
                             sizeStyle='mini',
                             callback=self.setCround)
        this.Cround.getNSButton().setToolTip_('Round Width to ' + str(unit))
        xywh = (c + (width * .75) + (gap * 1), y, width, height)
        this.Cminus = Button(xywh,
                             iconminus,
                             sizeStyle='mini',
                             callback=self.setCminus)
        this.Cminus.getNSButton().setToolTip_('Adjust Width -' + str(2 * unit))
        xywh = (c + (width * .75) + width + (gap * 2), y, width, height)
        this.Cplus = Button(xywh,
                            iconplus,
                            sizeStyle='mini',
                            callback=self.setCplus)
        this.Cplus.getNSButton().setToolTip_('Adjust Width +' + str(2 * unit))
        # stylize
        this.Ctext.getNSTextField().setBezeled_(False)
        this.Ctext.getNSTextField().setBackgroundColor_(NSColor.clearColor())
        this.Ctext.getNSTextField().setAlignment_(NSTextAlignmentCenter)
        self.flatButt(this.Cminus)
        self.flatButt(this.Cplus)
        self.flatButt(this.Cround)
        self.flatButt(this.Ccenter)

        # hide
        self.sbui.L.Lminus.show(False)
        self.sbui.L.Lround.show(False)
        self.sbui.L.Lplus.show(False)
        self.sbui.L.Lright.show(False)
        self.sbui.R.Rminus.show(False)
        self.sbui.R.Rround.show(False)
        self.sbui.R.Rplus.show(False)
        self.sbui.R.Rleft.show(False)
        self.sbui.C.Cminus.show(False)
        self.sbui.C.Cround.show(False)
        self.sbui.C.Ccenter.show(False)
        self.sbui.C.Cplus.show(False)

        # make it real
        self.sbWatcherInitialize()
        self.window.addGlyphEditorSubview(self.sbui)
        self.updateValues()
        self.buildMatchBase()
        windowViewManger[self.window] = self.sbui