Exemple #1
0
 def __init__(self, posSize, glyphNamesToDisplay, verticalMode, fontsOrder,
              callback):
     super(SpacingMatrix, self).__init__(posSize)
     self.glyphNamesToDisplay = glyphNamesToDisplay
     self.fontsOrder = fontsOrder
     self.verticalMode = verticalMode
     self.callback = callback
     self.canvas = CanvasGroup((0, 0, 0, 0), delegate=self)
Exemple #2
0
    def __init__(self, posSize, displayedWord, canvasScalingFactor, fontObj,
                 isKerningDisplayActive, areVerticalLettersDrawn,
                 areGroupsShown, areCollisionsShown, isSidebearingsActive,
                 isCorrectionActive, isMetricsActive, isColorsActive,
                 isSymmetricalEditingOn, isSwappedEditingOn, indexPair):

        super(WordDisplay, self).__init__(posSize)

        self.fontObj = fontObj
        self.displayedWord = displayedWord
        self.displayedPairs = buildPairsFromString(self.displayedWord,
                                                   self.fontObj)
        self.indexPair = indexPair

        if indexPair is not None:
            self.activePair = self.displayedPairs[self.indexPair]
        else:
            self.activePair = None

        self.canvasScalingFactor = canvasScalingFactor
        self.isKerningDisplayActive = isKerningDisplayActive
        self.areVerticalLettersDrawn = areVerticalLettersDrawn
        self.areGroupsShown = areGroupsShown
        self.areCollisionsShown = areCollisionsShown
        self.isSidebearingsActive = isSidebearingsActive
        self.isCorrectionActive = isCorrectionActive
        self.isMetricsActive = isMetricsActive
        self.isColorsActive = isColorsActive

        self.isSymmetricalEditingOn = isSymmetricalEditingOn
        self.isSwappedEditingOn = isSwappedEditingOn

        self.ctrlWidth, self.ctrlHeight = posSize[2], posSize[3]

        self.checkPairsQuality()
        self.wordCanvasGroup = CanvasGroup((0, 0, 0, 0), delegate=self)
Exemple #3
0
 def __init__(self):
     self.dotSize = 10
     self.glyphs = None
     self.result = None
     self.pointer = None
     self.snap = 5 # snap distance
     self.snapped = None    # index of which point we're snapping on
     self.orientation = 0.3
     self.glyphScale = 0.18
     self.glyphs = [None, None, None]
     self.mGlyphs = None
     self.startDrag = None
     self.p1 = self.p2 = self.p3 = None
     s = 400
     self.w = vanilla.Window((s,s), "3nterpolation",minSize=(250,250))
     self.w.c = CanvasGroup((0,0,0,0), delegate=self)
     self.w.bind('resize', self.resize)
     self.w.open()
     self.resize()
     self.w.c.update()
Exemple #4
0
class SpacingMatrix(Group):

    lineViewSelectedGlyph = None
    activeGlyph = None
    activeSide = None
    activeElement = None

    def __init__(self, posSize, glyphNamesToDisplay, verticalMode, fontsOrder,
                 callback):
        super(SpacingMatrix, self).__init__(posSize)
        self.glyphNamesToDisplay = glyphNamesToDisplay
        self.fontsOrder = fontsOrder
        self.verticalMode = verticalMode
        self.callback = callback
        self.canvas = CanvasGroup((0, 0, 0, 0), delegate=self)

    def setGlyphNamesToDisplay(self, glyphNamesToDisplay):
        self.glyphNamesToDisplay = glyphNamesToDisplay
        self.refreshActiveElements()

        if hasattr(self.canvas, 'activeEdit') is True:
            self.canvas.activeEdit.show(False)

    def setVerticalMode(self, verticalMode):
        self.verticalMode = verticalMode

    def setFontsOrder(self, fontsOrder):
        self.fontsOrder = fontsOrder

    def adjustSize(self, size):
        width, height = size
        x, y = self.getPosSize()[0:2]
        self.setPosSize((x, y, width, height))
        self.canvas.resize(width, height)
        self.update()

    def refreshActiveElements(self):
        self.activeGlyph = None
        self.activeSide = None
        self.activeElement = None
        self.update()

    def _killActiveEdit(self):
        if hasattr(self.canvas, 'activeEdit') is True:
            delattr(self.canvas, 'activeEdit')

    def mouseDown(self, notification):
        self._killActiveEdit()

        # origin is bottom left of the window, here we adjust the coordinates to the canvas
        pointerX, pointerY = notification.locationInWindow(
        ).x - MARGIN_LFT, notification.locationInWindow().y - MARGIN_HALFROW

        # translate abs coordinates to element indexes
        xRatio = pointerX / SPACING_COL_WIDTH
        indexGlyphName = int(xRatio)
        if indexGlyphName >= len(self.glyphNamesToDisplay):
            indexGlyphName = None
        # more on the left or more on the right?
        if round(xRatio % 1, 0) == 0:
            self.activeSide = 'lft'
        else:
            self.activeSide = 'rgt'

        if pointerY < len(self.fontsOrder
                          ) * vanillaControlsSize['EditTextSmallHeight'] * 2:
            yRatio = pointerY / (vanillaControlsSize['EditTextSmallHeight'] *
                                 2)

            # it starts counting from the bottom, so I have to subtract the result from the length of the fonts order attribute
            indexFont = len(self.fontsOrder) - int(yRatio)

            # here I try to understand which ctrl has been clicked
            if round(yRatio % 1, 0) == 0:
                self.activeElement = 'margins'
            else:
                self.activeElement = 'width'
        else:
            indexFont = None

        # here I init a ctrl for changing metrics
        if indexGlyphName is None or indexFont is None:
            self.activeGlyph = None
            return None

        else:
            # we skip the fake .newLine glyphs
            if self.glyphNamesToDisplay[indexGlyphName] == '.newLine':
                return None

            # this is the glyph which should be addressed by the active ctrl
            self.activeGlyph = self.fontsOrder[indexFont - 1][
                self.glyphNamesToDisplay[indexGlyphName]]

            # how wide the ctrls? it depends
            if self.activeElement == 'margins':
                activeEditWidth = SPACING_COL_WIDTH / 2.
            else:
                activeEditWidth = SPACING_COL_WIDTH

            # origin of vanilla ctrls is top left, but indexes are already ok for this, I guess
            if self.activeElement == 'margins' and self.activeSide == 'rgt':
                activeEditX = indexGlyphName * SPACING_COL_WIDTH + SPACING_COL_WIDTH / 2.
            else:
                activeEditX = indexGlyphName * SPACING_COL_WIDTH

            if self.activeElement == 'margins':
                activeEditY = indexFont * vanillaControlsSize[
                    'EditTextSmallHeight'] * 2
            else:
                activeEditY = indexFont * vanillaControlsSize[
                    'EditTextSmallHeight'] * 2 - vanillaControlsSize[
                        'EditTextSmallHeight']

            # here I choose the value to display in the ctrl
            if self.activeElement == 'width':
                activeValue = self.activeGlyph.width
            else:
                if self.activeSide == 'lft':
                    activeValue = self.activeGlyph.leftMargin
                else:
                    activeValue = self.activeGlyph.rightMargin

            self.canvas.activeEdit = CustomEditText(
                (activeEditX, activeEditY, activeEditWidth,
                 vanillaControlsSize['EditTextSmallHeight']),
                sizeStyle='small',
                continuous=False,
                text='{:d}'.format(int(round(activeValue, 0))),
                callback=self.activeEditCallback)
            self.canvas.activeEdit.centerAlignment()

    def activeEditCallback(self, sender):
        if self.activeGlyph and self.activeSide and self.activeElement:
            ctrlValue = sender.get()

            if self.verticalMode is False:
                glyphsToModify = [self.activeGlyph]
            else:
                glyphsToModify = [
                    ff[self.activeGlyph.name] for ff in self.fontsOrder
                    if ff[self.activeGlyph.name].name == self.activeGlyph.name
                ]

            try:
                # using glyph reference
                if ctrlValue in self.activeGlyph.getParent().glyphOrder:
                    for eachGlyph in glyphsToModify:
                        sourceGlyph = eachGlyph.getParent()[ctrlValue]
                        if self.activeElement == 'width':
                            eachGlyph.width = sourceGlyph.width
                        else:
                            if self.activeSide == 'lft':
                                eachGlyph.leftMargin = sourceGlyph.leftMargin
                            else:
                                eachGlyph.rightMargin = sourceGlyph.rightMargin

                # using a numerical value
                else:
                    value = int(ctrlValue)
                    for eachGlyph in glyphsToModify:
                        if self.activeElement == 'width':
                            eachGlyph.width = value
                        else:
                            if self.activeSide == 'lft':
                                eachGlyph.leftMargin = value
                            else:
                                eachGlyph.rightMargin = value

            except ValueError:
                self.canvas.activeEdit.set('')  # temp

        self._killActiveEdit()
        self.callback(self)
        self.update()

    def update(self):
        self.canvas.update()

    def draw(self):
        try:
            dt.save()
            dt.font(SYSTEM_FONT_NAME)
            dt.fontSize(CAPTION_BODY_SIZE)
            for indexGlyphName, eachGlyphName in enumerate(
                    self.glyphNamesToDisplay):

                # in this way it does not draw what's outside the canvas frame!
                if SPACING_COL_WIDTH * indexGlyphName > self.getPosSize()[2]:
                    continue

                self._drawMatrixColumn(eachGlyphName)
                dt.translate(SPACING_COL_WIDTH, 0)

                self._setBoxQualities()
                dt.line((0, 0), (0, self.getPosSize()[3]))

            dt.restore()

        except Exception, error:
            print traceback.format_exc()
    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
class GlyphMetricsUI(object):
    def __init__(self):
        # debug
        windowname = 'Debug Glyph Metrics UI'
        windows = [w for w in NSApp().orderedWindows() if w.isVisible()]
        for window in windows:
            print(window.title())
            if window.title() == windowname:
                window.close()
        if debug == True:
            self.debug = Window((333, 33), windowname)
            self.debug.bind('close', self.windowSideuiClose)
            self.debug.open()
        # setup
        self.showButtons = False
        self.sbui = None
        # add interface
        addObserver(self, 'addInterface', 'glyphWindowWillOpen')
        addObserver(self, 'updateSelfWindow', 'currentGlyphChanged')
        # toggle visibility of tool ui
        addObserver(self, 'showSideUIonDraw', 'draw')
        addObserver(self, 'hideSideUIonPreview', 'drawPreview')
        # remove UI and window manager when glyph window closes
        # addObserver(self, "observerGlyphWindowWillClose", "glyphWindowWillClose")
        # subscribe to glyph changes
        addObserver(self, "viewDidChangeGlyph", "viewDidChangeGlyph")

    # def observerGlyphWindowWillClose(self, notification):
    #     self.window = notification['window']
    #     self.cleanup(self.window)
    #     del windowViewManger[notification['window']]
    #     del lll[notification['window']]
    #     del ccc[notification['window']]
    #     del rrr[notification['window']]

    def windowSideuiClose(self, sender):
        self.window.removeGlyphEditorSubview(self.sbui)
        removeObserver(self, 'glyphWindowWillOpen')
        removeObserver(self, 'glyphWindowWillClose')
        removeObserver(self, 'glyphWindowWillClose')
        removeObserver(self, 'currentGlyphChanged')
        removeObserver(self, 'draw')
        removeObserver(self, 'drawPreview')
        removeObserver(self, 'viewDidChangeGlyph')

    def cleanup(self, w):
        try:
            w.removeGlyphEditorSubview(self.sbui)
        except:
            return

    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

    def updateSelfWindow(self, notification):
        self.window = CurrentGlyphWindow()
        self.buildMatchBase()
        self.updateValues()

    def showSideUIonDraw(self, notification):
        self.sbWatcher()
        sbui = windowViewManger.get(self.window)
        if sbui is not None:
            sbui.show(True)

    def hideSideUIonPreview(self, notification):
        sbui = windowViewManger.get(self.window)
        if sbui is not None:
            sbui.show(False)

    def updateValues(self, notification=None):
        try:
            g = self.window.getGlyph()
            f = g.font
            sbui = windowViewManger.get(self.window)
            sbui.L.Ltext.set(str(g.angledLeftMargin))
            sbui.R.Rtext.set(str(g.angledRightMargin))
            sbui.C.Ctext.set(str(g.width))
        except Exception as e:
            # if debug == True:
            #     print('Exception updateValues', e)
            return

    # hack sidebearings changed observer
    # used when things redraw
    def sbWatcherInitialize(self):
        g = self.window.getGlyph()
        f = g.font
        if g is not None:
            lll[self.window] = g.angledLeftMargin
            ccc[self.window] = g.width
            rrr[self.window] = g.angledRightMargin

    def sbWatcher(self):
        g = CurrentGlyph()
        if g is not None:
            f = g.font
            if lll[self.window] != None and ccc[self.window] != None and rrr[
                    self.window] != None:
                if lll[self.window] != g.angledLeftMargin or ccc[
                        self.window] != g.width or rrr[
                            self.window] != g.angledRightMargin:
                    lll[self.window] = g.angledLeftMargin
                    ccc[self.window] = g.width
                    rrr[self.window] = g.angledRightMargin
                    self.updateValues()
                    self.buildMatchBase()

    def setSB(self, sender):
        changeAttribute = sender.getPlaceholder()
        g = self.window.getGlyph()
        f = g.font
        v = sender.get()
        if is_number(v):
            if debug == True:
                print('value is a number')
            g.prepareUndo('Change ' + changeAttribute + ' SB')
            setattr(g, changeAttribute, float(v))
            g.performUndo()
            self.updateValues()
        elif v in f:
            if debug == True:
                print('value is a glyph')
            g.prepareUndo('Change ' + changeAttribute + ' SB')
            sb = getattr(f[v], changeAttribute)
            setattr(g, changeAttribute, sb)
            g.performUndo()
            self.updateValues()
        else:
            if debug == True:
                print('value is not a number or a glyph')
            return

    def setLminus(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('➖ Left SB')
        g.angledLeftMargin += -1 * unit
        g.performUndo()
        self.updateValues()

    def setLround(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Round Left SB')
        g.angledLeftMargin = int(unit *
                                 round(float(g.angledLeftMargin) / unit))
        g.performUndo()
        self.updateValues()

    def setLplus(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('➕ Left SB')
        g.angledLeftMargin += unit
        g.performUndo()
        self.updateValues()

    def setLright(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Copy Right SB')
        g.angledLeftMargin = g.angledRightMargin
        g.performUndo()
        self.updateValues()

    def setLmatch(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Match Left SB')
        f = g.font
        gmatch = sender.getTitle()
        if f[gmatch] is not None:
            g.angledLeftMargin = f[gmatch].angledLeftMargin
        g.performUndo()
        self.updateValues()

    def setRminus(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('➖ Right SB')
        g.angledRightMargin += -1 * unit
        g.performUndo()
        self.updateValues()

    def setRround(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Round Right SB')
        g.angledRightMargin = int(unit *
                                  round(float(g.angledRightMargin) / unit))
        g.performUndo()
        self.updateValues()

    def setRplus(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('➕ Right SB')
        g.angledRightMargin += unit
        g.performUndo()
        self.updateValues()

    def setRmatch(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Match Right SB')
        gmatch = sender.getTitle()
        f = g.font
        if f[gmatch] is not None:
            g.angledRightMargin = f[gmatch].angledRightMargin
        g.performUndo()
        self.updateValues()

    def setRleft(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Copy Left SB')
        g.angledRightMargin = g.angledLeftMargin
        g.performUndo()
        self.updateValues()

    def setCminus(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('➖ Width')
        # use whole units, not floats
        oldwidth = g.width
        leftby = unit
        g.angledLeftMargin += -1 * leftby
        g.width = oldwidth - unit * 2
        g.performUndo()
        self.updateValues()

    def setCround(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Round Width')
        g.width = int(unit * round(float(g.width) / unit))
        g.performUndo()
        self.updateValues()

    def setCcenter(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Center on Width')
        # use whole units, not floats
        padding = g.angledLeftMargin + g.angledRightMargin
        gwidth = g.width
        g.angledLeftMargin = int(padding / 2)
        g.width = gwidth
        g.performUndo()
        self.updateValues()

    def setCplus(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('➕ Width')
        # use whole units, not floats
        oldwidth = g.width
        leftby = unit
        g.angledLeftMargin += leftby
        g.width = oldwidth + unit * 2
        g.performUndo()
        self.updateValues()

    def setCmatch(self, sender):
        g = self.window.getGlyph()
        if g is None:
            return
        g.prepareUndo('Match Width')
        f = g.font
        gmatch = sender.getTitle()
        if f[gmatch] is not None:
            g.width = f[gmatch].width
        g.performUndo()
        self.updateValues()

    def flatButt(self, this, match=False):
        this = this.getNSButton()
        this.setBezelStyle_(buttstyle)
        this.setBordered_(False)
        this.setWantsLayer_(True)
        this.setBackgroundColor_(NSColor.whiteColor())
        if match == True:
            this.setBackgroundColor_(
                NSColor.colorWithCalibratedRed_green_blue_alpha_(
                    .9, 1, .85, 1))

    def buildMatchBase(self, notification=None):
        self.newheight = height
        try:
            g = self.window.getGlyph()
            f = g.font
            # remove old buttons
            for i in range(10):
                if hasattr(self.sbui.L, 'buttobj_%s' % i):
                    delattr(self.sbui.L, 'buttobj_%s' % i)
                    delattr(self.sbui.R, 'buttobj_%s' % i)
                    delattr(self.sbui.C, 'buttobj_%s' % i)

            # add button for each component
            self.uniquecomponents = []
            for c in g.components:
                if c.baseGlyph not in self.uniquecomponents:
                    self.uniquecomponents.append(c.baseGlyph)

            for i, c in enumerate(self.uniquecomponents):
                row = i + 1
                yy = -height * (row + 1) - 3

                xywh = (0, yy, width * 5.5 + (gap * 4), height)
                buttobj = Button(xywh,
                                 c,
                                 sizeStyle='mini',
                                 callback=self.setLmatch)
                setattr(self.sbui.L, 'buttobj_%s' % i, buttobj)
                this = getattr(self.sbui.L, 'buttobj_%s' % i)
                this.getNSButton().setAlignment_(NSTextAlignmentLeft)
                this.getNSButton().setToolTip_('Match LSB of ' + c)

                xywh = (-width * 5.5 - (gap * 4), yy, width * 5.5 + (gap * 4),
                        height)
                buttobj = Button(xywh,
                                 c,
                                 sizeStyle='mini',
                                 callback=self.setRmatch)
                setattr(self.sbui.R, 'buttobj_%s' % i, buttobj)
                this = getattr(self.sbui.R, 'buttobj_%s' % i)
                this.getNSButton().setAlignment_(NSTextAlignmentRight)
                this.getNSButton().setToolTip_('Match RSB of ' + c)

                xywh = ((dfltLwidth / 2) - (width * 2.75 + (gap * 2)), yy,
                        width * 5.5 + (gap * 4), height)
                buttobj = Button(xywh,
                                 c,
                                 sizeStyle='mini',
                                 callback=self.setCmatch)
                setattr(self.sbui.C, 'buttobj_%s' % i, buttobj)
                this = getattr(self.sbui.C, 'buttobj_%s' % i)
                this.getNSButton().setToolTip_('Match Width of ' + c)

            for i, c in enumerate(self.uniquecomponents):
                try:
                    this = getattr(self.sbui.L, 'buttobj_%s' % i)
                    # hide if hidden
                    if self.showButtons == False:
                        this.show(False)
                    # check if metrics match base glyphs
                    if int(f[c].angledLeftMargin) == int(g.angledLeftMargin):
                        self.flatButt(this, True)
                    else:
                        self.flatButt(this)

                    this = getattr(self.sbui.R, 'buttobj_%s' % i)
                    if self.showButtons == False:
                        this.show(False)
                    if int(f[c].angledRightMargin) == int(g.angledRightMargin):
                        self.flatButt(this, True)
                    else:
                        self.flatButt(this)

                    this = getattr(self.sbui.C, 'buttobj_%s' % i)
                    if self.showButtons == False:
                        this.show(False)
                    if f[c].width == g.width:
                        self.flatButt(this, True)
                    else:
                        self.flatButt(this)

                except Exception as e:
                    return

            # change height of canvas to fit buttons
            self.newheight = height * (len(self.uniquecomponents) + 2)
            newy = -55 - height * (len(self.uniquecomponents))
            self.sbui.setPosSize((margin, newy, -margin, self.newheight))
            self.sbui.L.setPosSize((0, 0, dfltLwidth, self.newheight))
            self.sbui.R.setPosSize(
                (-dfltRwidth, 0, dfltRwidth, self.newheight))
            winX, winY, winW, winH = self.window.getVisibleRect()
            winW = winW - margin * 5
            offsetcenter = (winW / 2) - (width * 2.25)
            self.sbui.C.setPosSize(
                (offsetcenter, 0, width * 5 + 12, self.newheight))

        except Exception as e:
            return

    #############################################
    # watch for glyph changes
    #############################################

    def viewDidChangeGlyph(self, notification):
        self.glyph = CurrentGlyph()
        self.unsubscribeGlyph()
        self.subscribeGlyph()
        self.glyphChanged()

    def subscribeGlyph(self):
        self.glyph.addObserver(self, 'glyphChanged', 'Glyph.Changed')

    def unsubscribeGlyph(self):
        if self.glyph is None:
            return
        self.glyph.removeObserver(self, 'Glyph.Changed')

    def glyphChanged(self, notification=None):
        self.updateValues()
Exemple #7
0
class WordDisplay(Group):
    def __init__(self, posSize, displayedWord, canvasScalingFactor, fontObj,
                 isKerningDisplayActive, areVerticalLettersDrawn,
                 areGroupsShown, areCollisionsShown, isSidebearingsActive,
                 isCorrectionActive, isMetricsActive, isColorsActive,
                 isSymmetricalEditingOn, isSwappedEditingOn, indexPair):

        super(WordDisplay, self).__init__(posSize)

        self.fontObj = fontObj
        self.displayedWord = displayedWord
        self.displayedPairs = buildPairsFromString(self.displayedWord,
                                                   self.fontObj)
        self.indexPair = indexPair

        if indexPair is not None:
            self.activePair = self.displayedPairs[self.indexPair]
        else:
            self.activePair = None

        self.canvasScalingFactor = canvasScalingFactor
        self.isKerningDisplayActive = isKerningDisplayActive
        self.areVerticalLettersDrawn = areVerticalLettersDrawn
        self.areGroupsShown = areGroupsShown
        self.areCollisionsShown = areCollisionsShown
        self.isSidebearingsActive = isSidebearingsActive
        self.isCorrectionActive = isCorrectionActive
        self.isMetricsActive = isMetricsActive
        self.isColorsActive = isColorsActive

        self.isSymmetricalEditingOn = isSymmetricalEditingOn
        self.isSwappedEditingOn = isSwappedEditingOn

        self.ctrlWidth, self.ctrlHeight = posSize[2], posSize[3]

        self.checkPairsQuality()
        self.wordCanvasGroup = CanvasGroup((0, 0, 0, 0), delegate=self)

    def checkPairsQuality(self):
        for eachPair in self.displayedPairs:
            status, pairsDB = checkPairConflicts(eachPair, self.fontObj)
            if status is False:
                print 'conflicting pairs'
                print 'please check the DB:', pairsDB

    def getActivePair(self):
        return self.activePair

    def switchGlyphFromGroup(self, location, indexPair):
        assert location in ['left', 'right']

        if self.activePair is None:
            self.setActivePairIndex(indexPair)

        if location == 'left':
            theElem, otherElem = self.activePair
        else:
            otherElem, theElem = self.activePair
        groupReference = whichGroup(theElem, location, self.fontObj)

        if self.areGroupsShown is True and groupReference is not None:
            nextElemIndex = (self.fontObj.groups[groupReference].index(theElem)
                             + 1) % len(self.fontObj.groups[groupReference])
            if location == 'left':
                self.activePair = self.fontObj.groups[groupReference][
                    nextElemIndex], otherElem
            else:
                self.activePair = otherElem, self.fontObj.groups[
                    groupReference][nextElemIndex]
            self.wordCanvasGroup.update()

    def setSwappedEditingMode(self, value):
        self.isSwappedEditingOn = value

    def setSymmetricalEditingMode(self, value):
        self.isSymmetricalEditingOn = value

    def setGraphicsBooleans(self, isKerningDisplayActive,
                            areVerticalLettersDrawn, areGroupsShown,
                            areCollisionsShown, isSidebearingsActive,
                            isCorrectionActive, isMetricsActive,
                            isColorsActive):
        self.isKerningDisplayActive = isKerningDisplayActive
        self.areVerticalLettersDrawn = areVerticalLettersDrawn
        self.areGroupsShown = areGroupsShown
        self.areCollisionsShown = areCollisionsShown
        self.isSidebearingsActive = isSidebearingsActive
        self.isCorrectionActive = isCorrectionActive
        self.isMetricsActive = isMetricsActive
        self.isColorsActive = isColorsActive

    def adjustSize(self, posSize):
        x, y, width, height = posSize
        self.setPosSize((x, y, width, height))
        self.wordCanvasGroup.setPosSize((0, 0, width, height))
        self.wordCanvasGroup.resize(width, height)
        self.wordCanvasGroup.update()

    def setDisplayedWord(self, displayedWord):
        previousLength = len(self.displayedPairs)
        self.displayedWord = displayedWord
        self.displayedPairs = buildPairsFromString(self.displayedWord,
                                                   self.fontObj)
        if self.indexPair is not None:
            self.setActivePairIndex(self.indexPair)
        self.checkPairsQuality()

    def setScalingFactor(self, scalingFactor):
        self.canvasScalingFactor = scalingFactor

    def setActivePairIndex(self, indexPair):
        self.indexPair = indexPair
        if self.indexPair is not None:
            try:
                self.activePair = self.displayedPairs[self.indexPair]
            except IndexError:
                self.activePair = self.displayedPairs[-1]
                self.indexPair = len(self.displayedPairs) - 1
        else:
            self.activePair = None

    def setCtrlSize(self, ctrlWidth, ctrlHeight):
        self.ctrlWidth = ctrlWidth
        self.ctrlHeight = ctrlHeight

    def _drawColoredCorrection(self, correction):
        dt.save()

        if correction > 0:
            dt.fill(*LIGHT_GREEN)
        else:
            dt.fill(*LIGHT_RED)
        dt.rect(0, self.fontObj.info.descender, correction,
                self.fontObj.info.unitsPerEm)
        dt.restore()

    def _drawMetricsCorrection(self, correction):
        dt.save()
        dt.fill(*BLACK)
        dt.stroke(None)
        dt.translate(
            0,
            self.fontObj.info.unitsPerEm + self.fontObj.info.descender + 100)
        dt.scale(1 /
                 (self.ctrlHeight /
                  (self.canvasScalingFactor * self.fontObj.info.unitsPerEm)))
        dt.font(SYSTEM_FONT_NAME)
        dt.fontSize(BODY_SIZE)
        textWidth, textHeight = dt.textSize('{:+d}'.format(correction))
        dt.textBox('{:+d}'.format(correction),
                   (-textWidth / 2., -textHeight / 2., textWidth, textHeight),
                   align='center')
        dt.restore()

    def _drawGlyphOutlines(self, glyphName):
        dt.save()
        dt.fill(*BLACK)
        dt.stroke(None)
        glyphToDisplay = self.fontObj[glyphName]
        dt.drawGlyph(glyphToDisplay)
        dt.restore()

    def _drawMetricsData(self, glyphName, offset):
        dt.save()
        glyphToDisplay = self.fontObj[glyphName]
        dt.translate(0, self.fontObj.info.descender)
        reverseScalingFactor = 1 / (
            self.ctrlHeight /
            (self.canvasScalingFactor * self.fontObj.info.unitsPerEm))

        if self.isSidebearingsActive is True:
            dt.fill(None)
            dt.stroke(*BLACK)
            dt.strokeWidth(reverseScalingFactor)
            dt.line((0, 0), (0, -offset * reverseScalingFactor))
            dt.line((glyphToDisplay.width, 0),
                    (glyphToDisplay.width, -offset * reverseScalingFactor))
        dt.restore()

        dt.save()
        dt.translate(0, self.fontObj.info.descender)
        dt.translate(0, -offset * reverseScalingFactor)
        dt.fill(*BLACK)

        dt.stroke(None)
        dt.font(SYSTEM_FONT_NAME)
        dt.fontSize(BODY_SIZE * reverseScalingFactor)

        textWidth, textHeight = dt.textSize(u'{}'.format(glyphToDisplay.width))
        dt.textBox(u'{:d}'.format(int(glyphToDisplay.width)),
                   (0, 0, glyphToDisplay.width, textHeight * 2),
                   align='center')
        dt.textBox(u'\n{:d}'.format(int(glyphToDisplay.leftMargin)),
                   (0, 0, glyphToDisplay.width / 2., textHeight * 2),
                   align='center')
        dt.textBox(u'\n{:d}'.format(int(glyphToDisplay.rightMargin)),
                   (glyphToDisplay.width / 2., 0, glyphToDisplay.width / 2.,
                    textHeight * 2),
                   align='center')
        dt.restore()

    def _drawBaseline(self, glyphName):
        glyphToDisplay = self.fontObj[glyphName]

        dt.save()
        dt.stroke(*BLACK)
        dt.fill(None)
        # reversed scaling factor
        dt.strokeWidth(
            1 / (self.ctrlHeight /
                 (self.canvasScalingFactor * self.fontObj.info.unitsPerEm)))
        dt.line((0, 0), (glyphToDisplay.width, 0))
        dt.restore()

    def _drawSidebearings(self, glyphName):
        glyphToDisplay = self.fontObj[glyphName]

        dt.save()
        dt.stroke(*BLACK)
        dt.fill(None)

        # reversed scaling factor
        dt.strokeWidth(
            1 / (self.ctrlHeight /
                 (self.canvasScalingFactor * self.fontObj.info.unitsPerEm)))

        dt.fill(*LIGHT_GRAY)
        dt.line(
            (0, self.fontObj.info.descender),
            (0, self.fontObj.info.descender + self.fontObj.info.unitsPerEm))
        dt.line((glyphToDisplay.width, self.fontObj.info.descender),
                (glyphToDisplay.width,
                 self.fontObj.info.descender + self.fontObj.info.unitsPerEm))

        dt.restore()

    def _drawCursor(self, correction, pairKind):
        assert pairKind in ('gr2gr', 'gr2gl', 'gl2gr',
                            'gl2gl') or pairKind is None

        dt.save()

        if pairKind is None:
            lftColor = NON_KERNED_COLOR
            rgtColor = NON_KERNED_COLOR

        elif pairKind == 'gr2gr':
            lftColor = GROUP_COLOR
            rgtColor = GROUP_COLOR

        elif pairKind == 'gr2gl':
            lftColor = GROUP_COLOR
            rgtColor = GLYPH_COLOR

        elif pairKind == 'gl2gr':
            lftColor = GLYPH_COLOR
            rgtColor = GROUP_COLOR
        else:
            lftColor = GLYPH_COLOR
            rgtColor = GLYPH_COLOR

        lftGlyphName, rgtGlyphName = self.activePair
        lftGlyph = self.fontObj[lftGlyphName]
        rgtGlyph = self.fontObj[rgtGlyphName]

        lftCursorWidth = lftGlyph.width / 2. + correction / 2.
        rgtCursorWidth = rgtGlyph.width / 2. + correction / 2.
        cursorHeight = 50  # upm

        # lft
        dt.fill(*lftColor)
        dt.rect(-lftGlyph.width / 2. - correction,
                self.fontObj.info.descender - cursorHeight + cursorHeight / 2.,
                lftCursorWidth, cursorHeight)

        # rgt
        dt.fill(*rgtColor)
        dt.rect(-correction / 2.,
                self.fontObj.info.descender - cursorHeight + cursorHeight / 2.,
                rgtCursorWidth, cursorHeight)
        dt.restore()

    def _drawGlyphOutlinesFromGroups(self, aPair, kerningReference,
                                     correction):
        prevGlyphName, eachGlyphName = aPair
        if kerningReference is not None:
            lftReference, rgtReference = kerningReference
        else:
            lftReference = whichGroup(prevGlyphName, 'left', self.fontObj)
            rgtReference = whichGroup(eachGlyphName, 'right', self.fontObj)

        prevGlyph, eachGlyph = self.fontObj[prevGlyphName], self.fontObj[
            eachGlyphName]
        reverseScalingFactor = 1 / (
            self.ctrlHeight /
            (self.canvasScalingFactor * self.fontObj.info.unitsPerEm))

        # _L__ group
        if lftReference:
            if lftReference.startswith('@MMK_L_'):
                dt.save()
                dt.fill(*LAYERED_GLYPHS_COLOR)
                groupContent = self.fontObj.groups[lftReference]
                if len(groupContent) > 1:
                    for eachGroupSibling in groupContent:
                        if eachGroupSibling != prevGlyphName:
                            glyphToDisplay = self.fontObj[eachGroupSibling]
                            dt.save()
                            dt.translate(
                                -glyphToDisplay.width, 0
                            )  # back, according to his width, otherwise it does not coincide
                            dt.drawGlyph(glyphToDisplay)
                            dt.restore()

                dt.fill(*BLACK)  # caption
                dt.translate(-prevGlyph.width,
                             0)  # we need a caption in the right place
                dt.font(SYSTEM_FONT_NAME)
                dt.fontSize(GROUP_NAME_BODY_SIZE * reverseScalingFactor)
                textWidth, textHeight = dt.textSize(lftReference)
                dt.text(lftReference,
                        (glyphToDisplay.width / 2. - textWidth / 2.,
                         -GROUP_NAME_BODY_SIZE * reverseScalingFactor * 2))
                dt.restore()

        # _R__ group
        if rgtReference:
            if rgtReference.startswith('@MMK_R_'):
                dt.save()
                dt.translate(correction, 0)
                dt.fill(*LAYERED_GLYPHS_COLOR)
                groupContent = self.fontObj.groups[rgtReference]

                if len(groupContent) > 1:
                    for eachGroupSibling in groupContent:
                        if eachGroupSibling != eachGlyphName:
                            glyphToDisplay = self.fontObj[eachGroupSibling]
                            dt.drawGlyph(glyphToDisplay)

                dt.fill(*BLACK)
                dt.font(SYSTEM_FONT_NAME)
                dt.fontSize(GROUP_NAME_BODY_SIZE * reverseScalingFactor)
                textWidth, textHeight = dt.textSize(rgtReference)
                dt.text(rgtReference,
                        (glyphToDisplay.width / 2. - textWidth / 2.,
                         -GROUP_NAME_BODY_SIZE * reverseScalingFactor * 2))
                dt.restore()

    def _drawCollisions(self, aPair):
        dt.save()

        correction, kerningReference, pairKind = getCorrection(
            aPair, self.fontObj)

        if kerningReference is None:
            lftName, rgtName = aPair
        else:
            lftName, rgtName = kerningReference

        lftGlyphs = []
        if lftName.startswith('@MMK') is True:
            lftGlyphs = self.fontObj.groups[lftName]
        else:
            lftGlyphs = [lftName]

        rgtGlyphs = []
        if rgtName.startswith('@MMK') is True:
            rgtGlyphs = self.fontObj.groups[rgtName]
        else:
            rgtGlyphs = [rgtName]

        dt.fontSize(COLLISION_BODY_SIZE)

        breakCycle = False
        for eachLftName in lftGlyphs:
            for eachRgtName in rgtGlyphs:
                isTouching = checkIfPairOverlaps(self.fontObj[eachLftName],
                                                 self.fontObj[eachRgtName])
                if isTouching:
                    dt.text(u'💥', (0, 0))
                    breakCycle = True
                    break

            if breakCycle is True:
                break
        dt.restore()

    def _drawException(self, aPair, correction):
        lftGlyphName, rgtGlyphName = aPair
        lftGlyph, rgtGlyph = self.fontObj[lftGlyphName], self.fontObj[
            rgtGlyphName]

        dt.save()
        dt.fill(None)
        dt.stroke(*LIGHT_GRAY)
        dt.strokeWidth(20)

        # calc wiggle line
        pt1 = Point(-lftGlyph.width, 0)
        pt2 = Point(rgtGlyph.width + correction, 0)
        wigglePoints = calcWiggle(pt1, pt2, 100, 100, .65)

        # draw wiggle line
        dt.newPath()
        dt.moveTo(wigglePoints[0])
        for eachBcpOut, eachBcpIn, eachAnchor in wigglePoints[1:]:
            dt.curveTo(eachBcpOut, eachBcpIn, eachAnchor)
        dt.drawPath()

        dt.restore()

    def draw(self):

        try:
            glyphsToDisplay = splitText(self.displayedWord,
                                        self.fontObj.naked().unicodeData)

            # if the user switches the glyphs from the groups
            # here we have to arrange the list of glyphnames properly
            if self.activePair is not None:
                lftName, rgtName = self.activePair
                glyphsToDisplay[self.indexPair] = lftName
                glyphsToDisplay[self.indexPair + 1] = rgtName

            # here we draw
            dt.save()

            # this is for safety reason, user should be notified about possible unwanted kerning corrections
            if self.isSwappedEditingOn is True:
                dt.save()
                dt.fill(*FLIPPED_BACKGROUND_COLOR)
                dt.rect(0, 0, self.ctrlWidth, self.ctrlHeight)
                dt.restore()

            if self.isSymmetricalEditingOn is True:
                dt.save()
                dt.fill(*SYMMETRICAL_BACKGROUND_COLOR)
                dt.rect(0, 0, self.ctrlWidth, self.ctrlHeight)
                dt.restore()

            dt.scale(
                self.ctrlHeight /
                (self.canvasScalingFactor * self.fontObj.info.unitsPerEm)
            )  # the canvas is virtually scaled according to self.canvasScalingFactor value and canvasSize
            dt.translate(TEXT_MARGIN, 0)

            # group glyphs
            dt.translate(0, 600)

            if self.areGroupsShown is True:
                dt.save()
                prevGlyphName = None
                for indexChar, eachGlyphName in enumerate(glyphsToDisplay):
                    eachGlyph = self.fontObj[eachGlyphName]

                    # this is for kerning
                    if indexChar > 0:
                        correction, kerningReference, pairKind = getCorrection(
                            (prevGlyphName, eachGlyphName), self.fontObj)

                        if kerningReference:
                            exceptionStatus, doesExists, exceptionParents = isPairException(
                                kerningReference, self.fontObj)
                            if exceptionStatus is True:
                                self._drawException(
                                    (prevGlyphName, eachGlyphName), correction)

                        if (indexChar - 1) == self.indexPair:
                            if correction is None:
                                offsetCorrection = 0
                            else:
                                offsetCorrection = correction
                            self._drawGlyphOutlinesFromGroups(
                                (prevGlyphName, eachGlyphName),
                                kerningReference, offsetCorrection)

                        if correction and correction != 0 and self.isKerningDisplayActive:
                            dt.translate(correction, 0)

                    dt.translate(eachGlyph.width, 0)
                    prevGlyphName = eachGlyphName
                dt.restore()

            # background loop
            dt.save()
            glyphsToDisplayTotalWidth = 0
            prevGlyphName = None
            for indexChar, eachGlyphName in enumerate(glyphsToDisplay):
                eachGlyph = self.fontObj[eachGlyphName]

                # this is for kerning
                if indexChar > 0:
                    correction, kerningReference, pairKind = getCorrection(
                        (prevGlyphName, eachGlyphName), self.fontObj)
                    if self.isKerningDisplayActive and correction is not None:
                        if correction != 0 and self.isColorsActive is True:
                            self._drawColoredCorrection(correction)

                        if self.isCorrectionActive is True:
                            self._drawMetricsCorrection(correction)

                        dt.translate(correction, 0)
                        glyphsToDisplayTotalWidth += correction

                    if (indexChar - 1) == self.indexPair:
                        if correction is None:
                            offsetCorrection = 0
                        else:
                            offsetCorrection = correction
                        self._drawCursor(offsetCorrection, pairKind)

                # # draw metrics info
                if self.isMetricsActive is True:
                    self._drawMetricsData(eachGlyphName, 52)

                if self.isSidebearingsActive is True:
                    self._drawBaseline(eachGlyphName)
                    self._drawSidebearings(eachGlyphName)

                dt.translate(eachGlyph.width, 0)
                glyphsToDisplayTotalWidth += eachGlyph.width
                prevGlyphName = eachGlyphName
            dt.restore()

            # foreground loop
            dt.save()
            prevGlyphName = None
            for indexChar, eachGlyphName in enumerate(glyphsToDisplay):
                eachGlyph = self.fontObj[eachGlyphName]

                # this is for kerning
                if indexChar > 0:
                    correction, kerningReference, pairKind = getCorrection(
                        (prevGlyphName, eachGlyphName), self.fontObj)

                    if correction and correction != 0 and self.isKerningDisplayActive:
                        dt.translate(correction, 0)

                self._drawGlyphOutlines(eachGlyphName)
                dt.translate(eachGlyph.width, 0)

                prevGlyphName = eachGlyphName
            dt.restore()

            # collisions loop
            if self.areCollisionsShown is True:
                dt.save()
                prevGlyphName = None
                for indexChar, eachGlyphName in enumerate(glyphsToDisplay):
                    eachGlyph = self.fontObj[eachGlyphName]

                    if indexChar > 0:
                        correction, kerningReference, pairKind = getCorrection(
                            (prevGlyphName, eachGlyphName), self.fontObj)
                        if correction and correction != 0 and self.isKerningDisplayActive:
                            dt.translate(correction, 0)

                        if (indexChar - 1) == self.indexPair:
                            self._drawCollisions(
                                (prevGlyphName, eachGlyphName))

                    dt.translate(eachGlyph.width, 0)
                    prevGlyphName = eachGlyphName

                dt.restore()

            # main restore, it wraps the three loops
            dt.restore()

            if self.areVerticalLettersDrawn is True:
                # separate from the rest, we put the vertical letters
                dt.save()
                # we push the matrix forward
                dt.translate(self.ctrlWidth, 0)
                # then we rotate
                dt.rotate(90)
                # then we scale, but how much? a quarter of the main lettering
                dt.scale(
                    self.ctrlHeight /
                    (self.canvasScalingFactor * self.fontObj.info.unitsPerEm) *
                    .25)
                # the reference is the baseline, so we have to put some air below the letters
                dt.translate(0, 600)  # upm value
                # let's define the graphics
                dt.fill(*BLACK)
                dt.stroke(None)
                # then we draw, we need a prevGlyphName in order to get kerning correction
                prevGlyphName = None
                # we iterate on the letters we need to draw + a space as a margin
                for indexChar, eachGlyphName in enumerate(['space'] +
                                                          glyphsToDisplay):
                    # accessing the glyph obj
                    eachGlyph = self.fontObj[eachGlyphName]
                    # if it isn't the first letter...
                    if indexChar > 0:
                        # ... we grab the kerning correction from the pair
                        correction, kerningReference, pairKind = getCorrection(
                            (prevGlyphName, eachGlyphName), self.fontObj)
                        # if there is any correction...
                        if correction and correction != 0 and self.isKerningDisplayActive:
                            # ... we apply it to the transformation matrix
                            dt.translate(correction, 0)
                    # then we draw the outlines
                    self._drawGlyphOutlines(eachGlyphName)
                    # and we move the transformation matrix according to glyph width
                    dt.translate(eachGlyph.width, 0)
                    # then we load the glyph to the prevGlyphName
                    prevGlyphName = eachGlyphName
                # restoring the vertical drawing
                dt.restore()

        except Exception:
            print traceback.format_exc()
Exemple #8
0
    def __init__(self, posSize, interface, sheet):
        super(DesignFrame, self).__init__(posSize)
        self.ui = interface
        self.s = sheet

        y = 10
        self.EM_Dimension_title = TextBox((10,y,200,20), 
                "EM Dimension (FU)", 
                sizeStyle = "small")
        self.EM_DimensionX_title = TextBox((145,y,20,20), 
                "X:", 
                sizeStyle = "small")
        self.EM_DimensionX_editText = EditText((160,y-3,45,20), 
                self.s.EM_Dimension_X, 
                callback = self.EM_DimensionX_editText_callback,
                sizeStyle = "small")
        self.EM_DimensionY_title = TextBox((235,y,20,20), 
                "Y:", 
                sizeStyle = "small")
        self.EM_DimensionY_editText = EditText((250,y-3,45,20), 
                self.s.EM_Dimension_Y,  
                callback = self.EM_DimensionY_editText_callback,
                sizeStyle = "small")
        y += 30
        self.characterFace_title = TextBox((10,y,200,20), 
                "Character Face (EM%)", 
                sizeStyle = "small")
        self.characterFacePercent_title = TextBox((208,y,30,20), 
                "%", 
                sizeStyle = "small")
        self.characterFace_editText = EditText((160,y-3,45,20), 
                self.s.characterFace,
                callback = self.characterFace_editText_callback,
                sizeStyle = "small")
        y += 30
        self.overshoot_title = TextBox((10,y,200,20), 
                "Overshoot (FU)", 
                sizeStyle = "small")
        self.overshootOutside_title = TextBox((110,y,70,20), 
                "Outside:", 
                sizeStyle = "small")
        self.overshootOutside_editText = EditText((160,y-3,45,20), 
                self.s.overshootOutsideValue, 
                callback = self.overshootOutside_editText_callback,
                sizeStyle = "small")
        self.overshootInside_title = TextBox((210,y,60,20), 
                "Inside:", 
                sizeStyle = "small")
        self.overshootInside_editText = EditText((250,y-3,45,20), 
                self.s.overshootInsideValue,  
                callback = self.overshootInside_editText_callback,
                sizeStyle = "small")
        y += 30
        self.horizontalLine_title = TextBox((10,y,140,20), 
                "Horizontal Line (EM%)", 
                sizeStyle = "small")
        self.horizontalLine_slider = Slider((160,y-3 ,135,20), 
                minValue = 0, maxValue = 50, value = 0, 
                sizeStyle = "small",
                callback = self._horizontalLine_slider_callback)
        y += 30
        self.verticalLine_title = TextBox((10,y,140,20), 
                "Vertical Line (EM%)", 
                sizeStyle = "small")
        self.verticalLine_slider = Slider((160,y-3 ,135,20), 
                minValue = 0, maxValue = 50, value = 0, 
                sizeStyle = "small",
                callback = self._verticalLine_slider_callback)
        y += 30
        self.customsFrames_title = TextBox((10,y,200,20), 
                "Customs Frames (EM%):", 
                sizeStyle = "small")
        y += 20
        slider = SliderListCell()

        self.customsFrames_list = List((10,y,285,-30),
                self.s.customsFrames,
                columnDescriptions = [{"title": "Name", "width" : 75}, 
                                    {"title": "Values", "width" : 200, "cell": slider}],
                editCallback = self._customsFrames_list_editCallback,
                drawFocusRing = False)  
        self.addCustomsFrames_button = Button((170,-28,62,-10),
                "+",
                callback = self._addCustomsFrames_button_callback,
                sizeStyle="small")
        self.removeCustomsFrames_button = Button((232,-28,62,-10),
                "-",
                callback = self._removeCustomsFrames_button_callback,
                sizeStyle="small")
        self.s.translateX,self.s.translateY = 0, 0
        self.canvas = CanvasGroup((-295,10,-10,-10), 
                delegate=ProjectCanvas(self.s, "DesignFrame", self))

        self.s.w.bind('close', self.windowWillClose)
        self.observer()
Exemple #9
0
class DesignFrame(Group):

    def __init__(self, posSize, interface, sheet):
        super(DesignFrame, self).__init__(posSize)
        self.ui = interface
        self.s = sheet

        y = 10
        self.EM_Dimension_title = TextBox((10,y,200,20), 
                "EM Dimension (FU)", 
                sizeStyle = "small")
        self.EM_DimensionX_title = TextBox((145,y,20,20), 
                "X:", 
                sizeStyle = "small")
        self.EM_DimensionX_editText = EditText((160,y-3,45,20), 
                self.s.EM_Dimension_X, 
                callback = self.EM_DimensionX_editText_callback,
                sizeStyle = "small")
        self.EM_DimensionY_title = TextBox((235,y,20,20), 
                "Y:", 
                sizeStyle = "small")
        self.EM_DimensionY_editText = EditText((250,y-3,45,20), 
                self.s.EM_Dimension_Y,  
                callback = self.EM_DimensionY_editText_callback,
                sizeStyle = "small")
        y += 30
        self.characterFace_title = TextBox((10,y,200,20), 
                "Character Face (EM%)", 
                sizeStyle = "small")
        self.characterFacePercent_title = TextBox((208,y,30,20), 
                "%", 
                sizeStyle = "small")
        self.characterFace_editText = EditText((160,y-3,45,20), 
                self.s.characterFace,
                callback = self.characterFace_editText_callback,
                sizeStyle = "small")
        y += 30
        self.overshoot_title = TextBox((10,y,200,20), 
                "Overshoot (FU)", 
                sizeStyle = "small")
        self.overshootOutside_title = TextBox((110,y,70,20), 
                "Outside:", 
                sizeStyle = "small")
        self.overshootOutside_editText = EditText((160,y-3,45,20), 
                self.s.overshootOutsideValue, 
                callback = self.overshootOutside_editText_callback,
                sizeStyle = "small")
        self.overshootInside_title = TextBox((210,y,60,20), 
                "Inside:", 
                sizeStyle = "small")
        self.overshootInside_editText = EditText((250,y-3,45,20), 
                self.s.overshootInsideValue,  
                callback = self.overshootInside_editText_callback,
                sizeStyle = "small")
        y += 30
        self.horizontalLine_title = TextBox((10,y,140,20), 
                "Horizontal Line (EM%)", 
                sizeStyle = "small")
        self.horizontalLine_slider = Slider((160,y-3 ,135,20), 
                minValue = 0, maxValue = 50, value = 0, 
                sizeStyle = "small",
                callback = self._horizontalLine_slider_callback)
        y += 30
        self.verticalLine_title = TextBox((10,y,140,20), 
                "Vertical Line (EM%)", 
                sizeStyle = "small")
        self.verticalLine_slider = Slider((160,y-3 ,135,20), 
                minValue = 0, maxValue = 50, value = 0, 
                sizeStyle = "small",
                callback = self._verticalLine_slider_callback)
        y += 30
        self.customsFrames_title = TextBox((10,y,200,20), 
                "Customs Frames (EM%):", 
                sizeStyle = "small")
        y += 20
        slider = SliderListCell()

        self.customsFrames_list = List((10,y,285,-30),
                self.s.customsFrames,
                columnDescriptions = [{"title": "Name", "width" : 75}, 
                                    {"title": "Values", "width" : 200, "cell": slider}],
                editCallback = self._customsFrames_list_editCallback,
                drawFocusRing = False)  
        self.addCustomsFrames_button = Button((170,-28,62,-10),
                "+",
                callback = self._addCustomsFrames_button_callback,
                sizeStyle="small")
        self.removeCustomsFrames_button = Button((232,-28,62,-10),
                "-",
                callback = self._removeCustomsFrames_button_callback,
                sizeStyle="small")
        self.s.translateX,self.s.translateY = 0, 0
        self.canvas = CanvasGroup((-295,10,-10,-10), 
                delegate=ProjectCanvas(self.s, "DesignFrame", self))

        self.s.w.bind('close', self.windowWillClose)
        self.observer()

    def update(self):
        self.canvas.update()
        UpdateCurrentGlyphView()

    def EM_DimensionX_editText_callback(self, sender):
        try: self.s.EM_Dimension_X = int(sender.get())        
        except: sender.set(self.s.EM_Dimension_X)
        self.update()

    def EM_DimensionY_editText_callback(self, sender):
        try: self.s.EM_Dimension_Y = int(sender.get())        
        except: sender.set(self.s.EM_Dimension_Y)
        self.update()

    def characterFace_editText_callback(self, sender):
        try:
            value = int(sender.get())
            if 0 <= value <= 100:
                self.s.characterFace = value        
            else:
                sender.set(self.s.characterFace)
        except: sender.set(self.s.characterFace)
        self.update()

    def overshootOutside_editText_callback(self, sender):
        try: self.s.overshootOutsideValue = int(sender.get())
        except: sender.set(self.s.overshootOutsideValue)
        self.update()

    def overshootInside_editText_callback(self, sender):
        try: self.s.overshootInsideValue = int(sender.get())        
        except: sender.set(self.s.overshootInsideValue)
        self.update()

    def _horizontalLine_slider_callback(self, sender):
        self.s.horizontalLine = int(sender.get())
        self.update()

    def _verticalLine_slider_callback(self, sender):
        self.s.verticalLine = int(sender.get())
        self.update()

    def _customsFrames_list_editCallback(self, sender):
        self.s.customsFrames = sender.get()
        self.update()

    def _addCustomsFrames_button_callback(self, sender):
        name = "Frame%i"%len(self.s.customsFrames)
        self.s.customsFrames.append({"Name":name})
        self.customsFrames_list.set(self.s.customsFrames)
        self.update()

    def _removeCustomsFrames_button_callback(self, sender):
        # Get the customsFrames list selection
        sel = self.customsFrames_list.getSelection()
        if not sel: return
        # Delete the selection from the customsFrames
        self.s.customsFrames = [e for i, e in enumerate(self.s.customsFrames) if i not in sel]
        self.customsFrames_list.set(self.s.customsFrames)
        self.update()

    def draw(self, info):
        if self.s.glyph is None: return
        s = info['scale']
        strokeWidth(.6*s)
        DesignFrameDrawer(self.s).draw()

    def windowWillClose(self, sender):
        self.observer(remove=True)
        
    def observer(self, remove = False):
        if not remove:
            addObserver(self, "draw", "draw")
            addObserver(self, "draw", "drawInactive")
            return
        removeObserver(self, "draw")
        removeObserver(self, "drawInactive")
Exemple #10
0
    def __init__(self, willOpen=True):
        super(SidebearingsLinker, self).__init__()

        # collecting fonts
        self.allFonts = AllFonts()
        if self.allFonts != []:
            self.selectedFont = self.allFonts[0]

        # interface
        self.w = FloatingWindow((PLUGIN_WIDTH, PLUGIN_HEIGHT), PLUGIN_TITLE)

        jumpingY = MARGIN_VER
        self.w.fontPopUp = PopUpButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            getNamesFrom(self.allFonts),
            callback=self.fontPopUpCallback)

        jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_ROW
        self.w.canvas = CanvasGroup(
            (MARGIN_HOR, jumpingY, NET_WIDTH, CANVAS_HEIGHT), delegate=self)

        jumpingY += CANVAS_HEIGHT + MARGIN_ROW
        linksColumnDescriptions = [{
            "title": "left",
            'key': 'lft',
            'width': LIST_WIDE_COL
        }, {
            "title": "active",
            "cell": CheckBoxListCell(),
            'key': 'lftActive',
            'width': LIST_NARROW_COL
        }, {
            "title": "glyph",
            'key': 'servant',
            'width': LIST_WIDE_COL,
            "editable": False
        }, {
            "title": "active",
            "cell": CheckBoxListCell(),
            'key': 'rgtActive',
            'width': LIST_NARROW_COL
        }, {
            "title": "right",
            'key': 'rgt',
            'width': LIST_WIDE_COL
        }]

        if self.selectedFont is not None:
            links = loadLinksFromFont(self.selectedFont)
        else:
            links = []

        self.w.linksList = List(
            (MARGIN_HOR, jumpingY, NET_WIDTH, 200),
            links,
            showColumnTitles=False,
            allowsMultipleSelection=False,
            drawVerticalLines=True,
            columnDescriptions=linksColumnDescriptions,
            selectionCallback=self.selectionLinksListCallback,
            editCallback=self.editLinksListCallback)

        if self.selectedFont is not None:
            self.w.linksList.setSelection([0])
            self.currentRow = self.w.linksList[0]
            self.matchDisplayedSubscriptions()

        jumpingY += self.w.linksList.getPosSize()[3] + MARGIN_ROW
        buttonWidth = (NET_WIDTH - MARGIN_HOR) / 2
        self.w.linkAllButton = SquareButton(
            (MARGIN_HOR, jumpingY, buttonWidth,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Link All',
            callback=self.linkAllButtonCallback)

        self.w.unlockAllButton = SquareButton(
            (MARGIN_HOR * 2 + buttonWidth, jumpingY, buttonWidth,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Unlink All',
            callback=self.unlockAllButtonCallback)

        jumpingY += vanillaControlsSize[
            'ButtonRegularHeight'] * 1.5 + MARGIN_ROW
        self.w.separationLineOne = HorizontalLine(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['HorizontalLineThickness']))

        jumpingY += MARGIN_ROW
        self.w.pushIntoFontButton = SquareButton(
            (MARGIN_HOR, jumpingY, buttonWidth,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Push into font',
            callback=self.pushIntoFontButtonCallback)
        self.w.pushIntoFontButton.enable(False)

        self.w.clearLibsButton = SquareButton(
            (MARGIN_HOR * 2 + buttonWidth, jumpingY, buttonWidth,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Clear Libs',
            callback=self.clearLibsButtonCallback)

        jumpingY += vanillaControlsSize[
            'ButtonRegularHeight'] * 1.5 + MARGIN_ROW
        self.w.loadFromTable = SquareButton(
            (MARGIN_HOR, jumpingY, buttonWidth,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Load from table',
            callback=self.loadFromTableCallback)
        self.w.loadFromTable.enable(True)

        self.w.exportTable = SquareButton(
            (MARGIN_HOR * 2 + buttonWidth, jumpingY, buttonWidth,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Export table',
            callback=self.exportTableCallback)
        self.w.exportTable.enable(True)

        jumpingY += vanillaControlsSize[
            'ButtonRegularHeight'] * 1.5 + MARGIN_VER * 2
        self.w.resize(PLUGIN_WIDTH, jumpingY)

        self.setUpBaseWindowBehavior()

        if self.selectedFont is not None:
            self.matchSubscriptions()
            result = askYesNo('Warning',
                              'Do you want to align servants to masters?')
            if bool(result) is True:
                self._alignServantsToMasters()

        addObserver(self, "drawOnGlyphCanvas", "draw")
        addObserver(self, "drawOnGlyphCanvas", "drawInactive")
        addObserver(self, 'fontDidOpenCallback', 'fontDidOpen')
        addObserver(self, 'fontDidCloseCallback', 'fontDidClose')
        if willOpen is True:
            self.w.open()
Exemple #11
0
    def __init__(self):
        self.w = FloatingWindow((400, 450), "Tracer", minSize=(400, 400))

        middle = 130
        gap = 15
        y = 10
        self.w.thresholdText = TextBox((10, y + 1, middle, 22),
                                       "Threshold:",
                                       alignment="right")
        self.w.threshold = Slider((middle + gap, y, -10, 22),
                                  minValue=0,
                                  maxValue=1,
                                  value=.2,
                                  continuous=False,
                                  callback=self.makePreview)

        y += 30
        self.w.blurText = TextBox((10, y + 1, middle, 22),
                                  "Blur:",
                                  alignment="right")
        self.w.blur = Slider((middle + gap, y, -10, 22),
                             minValue=0,
                             maxValue=30,
                             value=0,
                             continuous=False,
                             callback=self.makePreview)
        y += 30
        self.w.invert = CheckBox((middle + gap, y + 2, -10, 22),
                                 "Invert",
                                 callback=self.makePreview)
        y += 30
        self.w.turdsizeText = TextBox((10, y + 1, middle, 22),
                                      "Suppress Speckles:",
                                      alignment="right")
        self.w.turdsize = Slider((middle + gap, y, -10, 22),
                                 minValue=0,
                                 maxValue=30,
                                 value=2,
                                 continuous=False,
                                 callback=self.makePreview)
        y += 30
        self.w.opttoleranceText = TextBox((10, y + 1, middle, 22),
                                          "Tolerance:",
                                          alignment="right")
        self.w.opttolerance = Slider((middle + gap, y, -10, 22),
                                     minValue=0,
                                     maxValue=2,
                                     value=0.2,
                                     continuous=False,
                                     callback=self.makePreview)

        y += 25
        _y = -40
        self.w.preview = CanvasGroup((0, y, -0, _y), delegate=self)
        self._previewImage = None
        self._previewGlyph = None

        _y = -30
        self.w.trace = Button((-100, _y, -10, 22),
                              "Trace",
                              callback=self.trace)
        self.w.traceFont = Button((-210, _y, -110, 22),
                                  "Trace Font",
                                  callback=self.traceFont)
        self.w.update = Button((-300, _y, -220, 22),
                               "Update",
                               callback=self.makePreview)
        self.w.showPreview = CheckBox((10, _y, 100, 22),
                                      "Preview",
                                      value=True,
                                      callback=self.makePreview)

        self.w.setDefaultButton(self.w.trace)
        self.makePreview()
        self.w.open()
    def __init__(self, posSize, interface, sheet):
        super(ReferenceViewer, self).__init__(posSize)
        self.ui = interface
        self.s = sheet

        self.FontList_comboBox = ComboBox((10, 10, 130, 18),
                                          Global.fontsList.get(),
                                          sizeStyle='small')
        self.FontList_comboBox.set(Global.fontsList.get()[0])

        self.addReferenceFont_button = Button(
            (150, 9, 70, 20),
            "Add",
            sizeStyle="small",
            callback=self._addReferenceFont_button_callback)

        self.removeReference_button = Button(
            (225, 9, 70, 20),
            "Remove",
            sizeStyle="small",
            callback=self._removeReference_button_callback)

        self.s.reference_list_selection = []
        self.reference_list = List(
            (10, 35, 285, 125),
            self.s.referenceViewerList,
            columnDescriptions=[{
                "title": "Font"
            }],
            selectionCallback=self._reference_list_selectionCallback,
            drawFocusRing=False)

        self.settings = Group((10, 170, 295, -0))
        self.settings.show(0)

        y = 3

        self.settings.size_title = TextBox((0, y, 100, 20),
                                           "Size (FU)",
                                           sizeStyle="small")
        self.settings.size_editText = EditText(
            (-60, y - 3, -10, 20),
            "",
            sizeStyle="small",
            callback=self._size_editText_callback)

        self.settings.size_slider = Slider((90, y - 3, -65, 20),
                                           minValue=0,
                                           maxValue=1000,
                                           value=250,
                                           sizeStyle="small",
                                           callback=self._size_slider_callback)

        y += 30
        self.settings.color_title = TextBox((0, y, 100, 20),
                                            "Color (FU)",
                                            sizeStyle="small")
        self.settings.color_colorWell = ColorWell(
            (90, y - 3, -10, 20),
            callback=self._color_editText_callback,
            color=NSColor.grayColor())

        self.canvas = CanvasGroup(
            (-295, 10, -10, -10),
            delegate=ProjectCanvas(self.s, "ReferenceViewer", self))

        self.s.w.bind('close', self.windowWillClose)
        self.observer()
class ReferenceViewer(Group):
    def __init__(self, posSize, interface, sheet):
        super(ReferenceViewer, self).__init__(posSize)
        self.ui = interface
        self.s = sheet

        self.FontList_comboBox = ComboBox((10, 10, 130, 18),
                                          Global.fontsList.get(),
                                          sizeStyle='small')
        self.FontList_comboBox.set(Global.fontsList.get()[0])

        self.addReferenceFont_button = Button(
            (150, 9, 70, 20),
            "Add",
            sizeStyle="small",
            callback=self._addReferenceFont_button_callback)

        self.removeReference_button = Button(
            (225, 9, 70, 20),
            "Remove",
            sizeStyle="small",
            callback=self._removeReference_button_callback)

        self.s.reference_list_selection = []
        self.reference_list = List(
            (10, 35, 285, 125),
            self.s.referenceViewerList,
            columnDescriptions=[{
                "title": "Font"
            }],
            selectionCallback=self._reference_list_selectionCallback,
            drawFocusRing=False)

        self.settings = Group((10, 170, 295, -0))
        self.settings.show(0)

        y = 3

        self.settings.size_title = TextBox((0, y, 100, 20),
                                           "Size (FU)",
                                           sizeStyle="small")
        self.settings.size_editText = EditText(
            (-60, y - 3, -10, 20),
            "",
            sizeStyle="small",
            callback=self._size_editText_callback)

        self.settings.size_slider = Slider((90, y - 3, -65, 20),
                                           minValue=0,
                                           maxValue=1000,
                                           value=250,
                                           sizeStyle="small",
                                           callback=self._size_slider_callback)

        y += 30
        self.settings.color_title = TextBox((0, y, 100, 20),
                                            "Color (FU)",
                                            sizeStyle="small")
        self.settings.color_colorWell = ColorWell(
            (90, y - 3, -10, 20),
            callback=self._color_editText_callback,
            color=NSColor.grayColor())

        self.canvas = CanvasGroup(
            (-295, 10, -10, -10),
            delegate=ProjectCanvas(self.s, "ReferenceViewer", self))

        self.s.w.bind('close', self.windowWillClose)
        self.observer()

    def update(self):
        self.canvas.update()
        UpdateCurrentGlyphView()

    def _addReferenceFont_button_callback(self, sender):
        font = self.FontList_comboBox.get()
        if font is None or font == "": return

        # Default values
        new_elem = {
            "font": font,
            "size": 400,
            "x": -500,
            "y": 40,
            "color": (0, 0, 0, .56)
        }

        self.s.referenceViewerSettings.append(new_elem)
        self.s.referenceViewerList.append({"Font": font})
        self.reference_list.set(self.s.referenceViewerList)
        self.reference_list.setSelection([len(self.s.referenceViewerList) - 1])
        self.update()

    def _removeReference_button_callback(self, sender):
        sel = self.reference_list.getSelection()
        if sel is None: return

        def remove(l):
            return [e for i, e in enumerate(l) if i not in sel]

        self.s.referenceViewerSettings = remove(self.s.referenceViewerSettings)
        self.s.referenceViewerList = remove(self.s.referenceViewerList)

        self.reference_list.set(self.s.referenceViewerList)
        self.reference_list.setSelection([len(self.s.referenceViewerList) - 1])
        self.update()

    def _reference_list_selectionCallback(self, sender):
        self.s.reference_list_selection = sender.getSelection()
        if not self.s.reference_list_selection:
            self.settings.show(0)
            return
        self.settings.show(1)
        settings = self.s.referenceViewerSettings[
            self.s.reference_list_selection[0]]
        self.settings.size_editText.set(settings["size"])
        self.settings.size_slider.set(settings["size"])
        colors = settings["color"]
        color = NSColor.colorWithCalibratedRed_green_blue_alpha_(
            colors[0], colors[1], colors[2], colors[3])
        self.settings.color_colorWell.set(color)

    def _size_editText_callback(self, sender):
        if not self.s.reference_list_selection: return
        size = self.s.referenceViewerSettings[
            self.s.reference_list_selection[0]]["size"]
        try:
            size = int(sender.get())
        except:
            sender.set(size)
        self.s.referenceViewerSettings[
            self.s.reference_list_selection[0]]["size"] = size
        self.settings.size_slider.set(size)
        self.update()

    def _size_slider_callback(self, sender):
        if not self.s.reference_list_selection: return
        self.s.referenceViewerSettings[
            self.s.reference_list_selection[0]]["size"] = int(sender.get())
        self.settings.size_editText.set(self.s.referenceViewerSettings[
            self.s.reference_list_selection[0]]["size"])
        self.update()

    def _color_editText_callback(self, sender):
        if not self.s.reference_list_selection: return
        color = sender.get()
        self.s.referenceViewerSettings[
            self.s.reference_list_selection[0]]["color"] = (
                color.redComponent(),
                color.greenComponent(),
                color.blueComponent(),
                color.alphaComponent(),
            )
        self.update()

    def draw(self, info):
        if self.s.glyph is None: return
        if self.s.glyph.name.startswith("uni"):
            txt = chr(int(self.s.glyph.name[3:7], 16))
        elif self.s.glyph.unicode:
            txt = chr(self.s.glyph.unicode)
        else:
            txt = ""
        ReferenceViewerDraw(self.s, txt)

    def windowWillClose(self, sender):
        self.observer(remove=True)

    def observer(self, remove=False):
        if not remove:
            addObserver(self, "draw", "draw")
            addObserver(self, "draw", "drawInactive")
            return
        removeObserver(self, "draw")
        removeObserver(self, "drawInactive")