Пример #1
0
 class Test:
     def __init__(self):
         self.w = Window((400, 400), minSize=(300, 300))
         self.w.e = CodeEditor((0, 0, -0, -0),
                               t,
                               lexer=GlyphConstructionLexer())
         self.w.open()
Пример #2
0
    class SliderTest:
        def __init__(self):
            self.w = Window((300, 400),
                            "SliderTest",
                            autosaveName="SliderTestttt")
            # self.w.slider1 = SliderPlus((10, 10, -10, 50), "Slider 1", 0, 50, 100)
            # self.w.slider2 = SliderPlus((10, 60, -10, 50), "Slider 2", 0, 50, 100)
            info = [("abcd", "The alphabet"), ("xyz ", "The alphabet part 2"),
                    ("wdth", "Width"), ("wght", "Weight")]
            self.sliderInfo = {}
            for tag, label in info:
                self.sliderInfo[tag] = (label, 0, 50, 100)
            self.w.sliderGroup = SliderGroup(300,
                                             self.sliderInfo,
                                             continuous=True,
                                             callback=self.sliderGroupCallback)
            self.w.mutateButton = Button((10, -40, 80, 20),
                                         "Mutate",
                                         callback=self.mutateCallback)
            self.w.open()

        def sliderGroupCallback(self, sender):
            print(sender.get())

        def mutateCallback(self, sender):
            state = {}
            for tag, (label, minValue, defaultValue,
                      maxValue) in self.sliderInfo.items():
                v = minValue + (maxValue - minValue) * random()
                state[tag] = v
            self.w.sliderGroup.set(state)
class Preview:
    def __init__(self):
        ## create a window
        self.w = Window((400, 400), "Preview", minSize=(100, 100))

        ## add a GlyphPreview to the window
        self.w.preview = GlyphPreview((0, 0, -0, -0))

        ## set the currentGlyph
        self.setGlyph(CurrentGlyph())

        ## add an observer when the glyph changed in the glyph view
        addObserver(self, "_currentGlyphChanged", "currentGlyphChanged")

        ## bind a windows close callback to this object
        self.w.bind("close", self.windowClose)
        ## open the window
        self.w.open()

    def _currentGlyphChanged(self, info):
        ## notification callback when the glyph changed in the glyph view
        ## just set the new glyph in the glyph preview
        self.setGlyph(CurrentGlyph())

    def setGlyph(self, glyph):
        ## setting the glyph in the glyph Preview
        self.w.preview.setGlyph(glyph)

    def windowClose(self, sender):
        ## remove the observer if the window closes
        removeObserver(self, "_currentGlyphChanged")
Пример #4
0
class SymmetrifyDialog( object ):

	def buttonCallback( self, sender ):
		button = sender.getTitle()
		
		font.disableUpdateInterface()
		glyph.beginUndo()
		if button == 'S':
			rotate()
		if button == 'T':
			horiflip()
		if button == 'C':
			vertiflip()
		if button == 'H':
			bothflip()
		glyph.endUndo()
		font.enableUpdateInterface()
		
		self.w.close()

	def __init__( self, titles ):
		self.button = ''
		margin = 10
		size = 40
		self.w = Window( ( len( titles ) * ( margin + size ) + margin, 2 * margin + size ), "Symmetrify" )
		top = margin
		left = margin

		for title in titles:
			button = SquareButton( ( left, top, size, size ), title, callback = self.buttonCallback )
			setattr( self.w, title, button )
			left += size + margin

	def run( self ):
		self.w.open()
Пример #5
0
class BaseApp(object):
    u"""The BaseApp class implements generic functions for more specialize App classes.
    The main function of apps is to create applications (with window UI) that
    offers an interface to PageBot publication building scripts. This way
    apps can be stored and standalone desktop applications, offering more
    interactive feedback to non-scripting users. 
    Also it hides code form the user, just presenting a coherent set of choices,
    that then build into PDF documents, websites or identity stationary.
    """
    W, H = 400, 400
    PUBLICATION_CLASS = None  # Defined by inheriting publication App classes.

    def __init__(self):
        self.w = Window((100, 100, self.W, self.H), self.__class__.__name__)
        self.initialize()  # Initialize UI and Publication instance.
        self.w.open()  # Open the application window.

    def initialize(self):
        u"""To be implemente by inheriting app classes.
    	Should initialize the self._doc Publication instance.
    	"""
        self._doc = self.PUBLICATIONS_CLASS()
        self.buildUI(self._doc.getUIParameters())

    def build(self, sender=None):
        u"""Default behavior, building the publications. To be redefined by
    	inheriting classes if additional functions are needed."""
        self._doc.solve()
        fileName = self._doc.title.replace(' ', '_')
        self._doc.export('_export/%s.pdf' % fileName)
Пример #6
0
    class Test:

        def __init__(self):
            tagGroups = {"GSUB": {"aalt", "salt", "ss02", "ccmb", "ccmp", "liga", "dlig", "rvrn", "cpsp"},
                         "GPOS": {"kern", "mark", "mkmk", "cpsp", "ZZZZ"}}
            self.w = Window((300, 500), "TagTest", minSize=(200, 200), autosaveName="TempTagTesttt")
            self.tags = FeatureTagGroup(300, tagGroups, callback=self.tagsChanged)

            self.w.tagsScrollView = AligningScrollView((0, 0, 0, -50), self.tags, drawBackground=False,
                                                       borderType=AppKit.NSNoBorder)
            self.w.mutateButton = Button((10, -30, 100, 20), "Mutate", callback=self.mutate)
            self.w.repopulateButton = Button((120, -30, 100, 20), "Repopulate", callback=self.repopulate)
            self.w.open()

        def tagsChanged(self, sender):
            print(sender.get())

        def mutate(self, sender):
            state = self.tags.get()
            import random
            for i in range(3):
                k = random.choice(list(state))
                state[k] = random.choice([None, None, None, False, True])
            self.tags.set(state)

        def repopulate(self, sender):
            tagGroups = {"GSUB": {"salt", "ss02", "ccmb", "ccmp", "liga", "cpsp"},
                         "GPOS": {"kern", "mkmk", "cpsp"}}
            self.tags.setTags(tagGroups)
class ParameterTester:
    def __init__(self):
        self.w = Window((300, 100))
        self.w.inner = Group((10, 10, -10, -10))

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

        self.w.inner.p1 = ParameterSliderTextInput(p1, (0, 0, -0, 22),
                                                   'master')
        self.w.inner.p2 = ParameterSliderTextInput(p2, (0, 25, -0, 22),
                                                   'ratio')
        self.w.inner.p3 = ParameterSliderTextInput(p3, (0, 50, -0, 22),
                                                   'offset')
        self.w.open()
Пример #8
0
class SymmetrifyDialog(object):
    def buttonCallback(self, sender):
        self.button = sender.getTitle()
        self.w.close()

    def __init__(self, titles):
        self.button = ''
        margin = 10
        size = 40
        self.w = Window(
            (len(titles) * (margin + size) + margin, 2 * margin + size),
            "Symmetrify")
        top = margin
        left = margin

        for title in titles:
            button = SquareButton((left, top, size, size),
                                  title,
                                  callback=self.buttonCallback)
            setattr(self.w, title, button)
            left += size + margin

    def run(self):
        self.w.open()
        while not self.button:
            pass
        return self.button
class GlyphnameDialog( object):

	def __init__( self ):
		x = 10
		y = 10
		height = 20
		button_width = 30
		glyphname_width = 180
		gap = 6
		self.w = Window( ( x + button_width + gap + glyphname_width + gap + button_width + x, y + height + y ), "insert glyph" )
		self.w.center()
		self.w.glyphname = EditText( ( x, y, glyphname_width, height ), '')
		x += glyphname_width + gap
		self.w.alignleft = Button( ( x, y, button_width, height ), LEFT, callback = self.buttonCallback )
		x += button_width + gap
		self.w.alignright = Button( ( x, y, button_width, height ), RIGHT, callback = self.buttonCallback )
		self.w.setDefaultButton( self.w.alignleft )
		self.w.alignright.bind( "\x1b", [] )
		self.w.open()

	def buttonCallback( self, sender ):
		alignment = sender.getTitle()
		glyphname = self.w.glyphname.get()
		if not glyphname:
			self.w.close()
			return
		if len( glyphname ) == 1:
			uni = ord(glyphname)
			g = font.glyphForUnicode_("%.4X" % uni)
			if g:
				glyphname = g.name
		other_glyph = font.glyphs[ glyphname ]
		if not other_glyph:
			for glyph in font.glyphs:
				if glyph.name.startswith( glyphname ):
					other_glyph = glyph
					print 'Using', glyph.name
					break
			else:
				print 'No matching glyph found.'
				self.w.close()
				return
		
		selected_glyphs = set( [ layer.parent for layer in font.selectedLayers ] )
		
		for glyph in selected_glyphs:
			glyph.beginUndo()
			for layer in glyph.layers:
				# find other layer
				for other_layer in other_glyph.layers:
					if other_layer.name == layer.name:
						insert_paths( layer, other_layer, alignment )
						break
				else:
					if active_layerId == layer.layerId:
						insert_paths( layer, other_glyph.layers[layer.associatedMasterId], alignment )
			glyph.endUndo()
		self.w.close()
class InstanceInterpolationsReport(object):
    def __init__(self):
        self.w = Window((350, 600),
                        "Instance Interpolations Report",
                        minSize=(300, 450))
        self.w.textEditor = TextEditor((10, 10, -10, -10),
                                       text=text,
                                       readOnly=True)
        self.w.open()
Пример #11
0
    class DesignSpaceExplorerTest(object):

        def __init__(self, designSpace, previewCharacter="e"):
            from vanilla import Window
            from tnbits.toolparts.buildvariables.designspaceexplorer import DesignSpaceExplorer
            self.w = Window((1000, 500), "DesignSpace Explorer", minSize=(600, 300))
            self.w.designSpaceExplorer = DesignSpaceExplorer((0, 0, 0, 0), designSpace,
                previewCharacter=previewCharacter)
            self.w.open()
Пример #12
0
class CopyKerning:

    def __init__(self):
        if AllFonts() is None:
            from vanilla.dialogs import message
            message("No fonts open.", "Open or create a font to copy data to and fro.")
            return

        self.sourceFontList = AllFonts()
        self.destinationFontList = AllFonts()
        self.source_font = self.sourceFontList[0]
        self.destination_fonts = None
        self.groups = None
        self.kerning = None

        ## create a window
        self.w = Window((400, 500), "Copy Groups and Kerning", minSize=(500, 600))
        self.w.sourceTitle = TextBox((15, 20, 200, 20), "Source Font:")
        self.w.sourceFont = PopUpButton((15, 42, 340, 20), [f.info.familyName + ' ' + f.info.styleName for f in self.sourceFontList], callback=self.sourceCallback)
        self.w.desTitle = TextBox((15, 76, 200, 20), "Destination Fonts:")
        self.w.destinationFonts = FontList((15, 96, -15, -115), self.destinationFontList, selectionCallback=self.desCallback)
        self.w.copyButton = Button((-215, -40, 200, 20), 'Copy Groups & Kerning', callback=self.copyCallback)
        self.w.line = HorizontalLine((10, -60, -10, 1))
        self._updateDest()
        ## open the window
        self.w.open()

    def _updateDest(self):
        des = list(self.sourceFontList)
        des.remove(self.source_font)
        self.w.destinationFonts.set(des)

    def copyKerning(self, groups, kerning, source_font, destination_fonts):
        kerning = source_font.kerning.asDict()
        groups = source_font.groups
        for font in destination_fonts:
            font.groups.update(groups)
            font.kerning.update(kerning)

    def sourceCallback(self, sender):
        self.source_font = self.sourceFontList[sender.get()]
        self._updateDest()

    def desCallback(self, sender):
        self.destination_fonts = [sender.get()[x] for x in sender.getSelection()]

    def copyCallback(self, sender):
        self.sheet = Sheet((300, 50), self.w)
        self.sheet.bar = ProgressBar((10, 20, -10, 10), isIndeterminate=True, sizeStyle="small")
        self.sheet.open()
        self.sheet.bar.start()
        self.copyKerning(self.groups, self.kerning, self.source_font, self.destination_fonts)
        self.sheet.bar.stop()
        self.sheet.close()
        del self.sheet
        self.w.close()
Пример #13
0
class convertMasterToBraceLayers(object):
    def __init__(self):
        self.master_names = [m.name for m in Glyphs.font.masters][1:]

        item_height = 24.0
        w_width = 350.0
        w_height = item_height * 5
        margin = 10
        next_y = margin
        col_1_width = w_width - (margin * 2)
        item_height = 24

        self.w = Window((w_width, w_height), "Convert Master to Brace Layers")

        next_y = margin
        self.w.master_names_label = TextBox((margin, next_y + 2, col_1_width, item_height), "Master to Convert (Cannot be the first Master)", sizeStyle='regular')
        next_y += item_height
        self.w.master_names = PopUpButton((margin, next_y, col_1_width, item_height), self.master_names)
        next_y += item_height + margin
        selected_master_index = Glyphs.font.masters.index(Glyphs.font.selectedFontMaster)
        self.w.master_names.set(selected_master_index - 1)

        self.w.gobutton = Button((margin + (col_1_width / 4), next_y, col_1_width / 2, item_height), 'Add Brace Layers', callback=self.makeitso)

        self.w.setDefaultButton(self.w.gobutton)

        self.w.open()

    def makeitso(self, sender):
        self.w.close()

        Glyphs.font.disableUpdateInterface()

        selected_master_index = self.w.master_names.get() + 1
        selected_master = Glyphs.font.masters[selected_master_index]
        layer_name = '{{{}}}'.format(', '.join([bytes(x) for x in selected_master.axes]))
        master_to_attach_to = Glyphs.font.masters[selected_master_index - 1]

        for g in Glyphs.font.glyphs:
            for l in g.layers:
                if l.associatedMasterId == selected_master.id:
                    if l.isSpecialLayer:
                        l.associatedMasterId = master_to_attach_to.id
                        continue

                    newL = copy.copy(l)
                    newL.associatedMasterId = master_to_attach_to.id
                    newL.name = layer_name
                    g.layers.append(newL)

        del(Glyphs.font.masters[selected_master_index])

        Glyphs.font.enableUpdateInterface()
        Glyphs.showMacroWindow()
Пример #14
0
def userChecksInfoNote(font, fontState):
    window = Window((400, 400),"edit info.note", minSize=(100, 100))
    window.textEditor = TextEditor(posSize=(0, 0, 400, 300))
    noteContent = font.info.note or ""
    window.textEditor.set(noteContent)
    def handleCommit(s):
        editorContent = window.textEditor.get()
        window.close()
        commitInfoNote(editorContent, font, fontState)
    window.updateNoteButton = SquareButton(posSize=(0, 350, 100, 50), title="commit", callback=handleCommit)
    window.cancelButton = SquareButton(posSize=(110, 350, 130, 50), title="cancel operation", callback=lambda x: window.close())
    window.open()
Пример #15
0
 def openWindow(self, document):
     u"""
     Controls and paper view for a document.
     """
     self.windowSize = (document.width, document.height)
     w = Window(self.windowSize, minSize=(1, 1), maxSize=self.windowSize, closable=False)
     self.setPaper(w, document)
     self.setStatusBar(w, document)
     w.bind("should close", self.windowShouldCloseCallback)
     w.bind("close", self.windowCloseCallback)
     w.open()
     return w
Пример #16
0
    class Test:

        def __init__(self):
            self.w = Window((300, 500), minSize=(200, 100))
            y = 10
            self.w.g = Group((0, 0, 0, 0))
            for i, tag in enumerate(["liga", "calt", "dlig", "smcp", "kern", "locl"]):
                setattr(self.w.g, f"tag{i}", TagView((10, y, 60, 20), tag, None, self.callback))
                y += 26
            self.w.open()

        def callback(self, sender):
            print("---", sender.tag, sender.state)
class ParameterTester:
    
    def __init__(self):
        self.w = Window((300, 100))
        self.w.inner = Group((10, 10, -10, -10))
        
        p1 = VanillaSingleValueParameter('main', 10, (0, 100), 'int')
        p2 = VanillaSingleValueParameter('ratio', 10, (0, 100), 'int', master=p1, mode='ratio', dissociable=True)
        p3 = VanillaSingleValueParameter('offset', 10, (0, 100), 'int', master=p1, mode='offset', dissociable=True)
        
        self.w.inner.p1 = ParameterSliderTextInput(p1, (0, 0, -0, 22), 'master')
        self.w.inner.p2 = ParameterSliderTextInput(p2, (0, 25, -0, 22), 'ratio')
        self.w.inner.p3 = ParameterSliderTextInput(p3, (0, 50, -0, 22), 'offset')
        self.w.open()
Пример #18
0
class ExampleWindow:
    def __init__(self):
        self.w = Window((400, 400), minSize=(200, 200))
        self.w.canvas = Canvas((M, M, -M, -M), delegate=self)
        self.w.open()

    def draw(self, rect):
        #NSColor.redColor().set()
        yellowColor.set()
        for n in range(50):
            rgba(random(), random(), random())
            rect = NSMakeRect(n * 400 + M, n * 400 + M, M, M)
            path = NSBezierPath.bezierPathWithRect_(rect)
            path.fill()
Пример #19
0
class SymmetrifyDialog(object):
    def buttonCallback(self, sender):
        button = sender.getTitle()

        font.disableUpdateInterface()
        glyph.beginUndo()
        if button == 'S':
            rotate()
        if button == 'T':
            horiflip()
        if button == 'C':
            vertiflip()
        if button == 'H':
            bothflip()
        if button == '*':
            rotate5()
            horiflip()
            rotate5()
            horiflip()
            rotate5()
            horiflip()
            rotate5()
            horiflip()
        glyph.endUndo()
        font.enableUpdateInterface()

        self.w.close()

    def __init__(self, titles):
        self.button = ''
        margin = 10
        size = 40
        self.w = Window(
            (len(titles) * (margin + size) + margin, 2 * margin + size),
            "Symmetrify")
        top = margin
        left = margin

        for title in titles:
            button = SquareButton((left, top, size, size),
                                  title,
                                  callback=self.buttonCallback)
            setattr(self.w, title, button)
            left += size + margin

    def run(self):
        self.w.open()
Пример #20
0
class DBFinalTool:
    def __init__(self):
        self.glyph = None # Typical RoboFont function
        self.updating = False
        
        pad = 10
        leading = 32
        y = pad
        w = 300
        h = 400
        buttonWidth = 100
        buttonHeight = 48
        
        self.w = Window((100, 100, w, h), 'Final tool window')
                    
        self.w.bind('close', self.windowCloseCallback)
        self.w.open()
        
    def windowCloseCallback(self, sender):
        print('removeObservers')
Пример #21
0
class VarFontTextEditor:
    def __init__(self):
        self.fontName = "Bitcount Grid Single"
        fnt = getFont(self.fontName)
        axesInfo = getAxisInfo(fnt)

        self.w = Window((500, 400), "Test", minSize=(300, 200))
        # self.w.button = Button((10, 10, 120, 24), "Click", callback=self.myCallback)
        y = 10
        self.sliderMapping = {}
        for index, axisInfo in enumerate(axesInfo):
            slider = Slider((10, y, 130, 24),
                            value=axisInfo['default'],
                            minValue=axisInfo['minValue'],
                            maxValue=axisInfo['maxValue'],
                            callback=self.sliderChanged)
            self.sliderMapping[slider] = axisInfo['tag']
            setattr(self.w, "slider_%s" % index, slider)
            y += 34

        self.w.textEditor = TextEditor((150, 0, 0, 0))

        attrs = {AppKit.NSFontAttributeName: fnt}
        self.w.textEditor._textView.setTypingAttributes_(attrs)
        self.w.open()

    def sliderChanged(self, sender):
        tag = self.sliderMapping[sender]
        location = {}
        for slider, tag in self.sliderMapping.items():
            location[tag] = slider.get()
        attrs = {
            AppKit.NSFontAttributeName: getFont(self.fontName,
                                                location=location)
        }
        stor = self.w.textEditor._textView.textStorage()
        stor.setAttributes_range_(attrs, (0, stor.length()))
Пример #22
0
class DrawBotViewer(object):
    def __init__(self):
        # create a window
        self.w = Window((400, 400), minSize=(200, 200))
        # add a slider
        self.w.slider = Slider((10, 10, -10, 22), callback=self.sliderCallback)
        # add a drawBox view
        self.w.drawBotCanvas = DrawView((0, 40, -0, -0))
        # draw something
        self.drawIt()
        # open the window
        self.w.open()

    def sliderCallback(self, sender):
        # slider chagned so redraw it
        self.drawIt()

    def drawIt(self):
        # get the value from the slider
        value = self.w.slider.get()
        print(value)
        # initiate a new drawing
        newDrawing()
        # add a page
        newPage(300, 300)
        # set a fill color
        fill(1, value / 100., 0)
        # draw a rectangle
        rect(10, 10, 100, 100)
        # set a font size
        fontSize(48 + value)
        # draw some text
        text("H", (10, 120))
        # get the pdf document
        pdfData = pdfImage()
        # set the pdf document into the canvas
        self.w.drawBotCanvas.setPDFDocument(pdfData)
Пример #23
0
class SymmetrifyDialog( object ):

	def buttonCallback( self, sender ):
		self.button = sender.getTitle()
		self.w.close()

	def __init__( self, titles ):
		self.button = ''
		margin = 10
		size = 40
		self.w = Window( ( len( titles ) * ( margin + size ) + margin, 2 * margin + size ), "Symmetrify" )
		top = margin
		left = margin

		for title in titles:
			button = SquareButton( ( left, top, size, size ), title, callback = self.buttonCallback )
			setattr( self.w, title, button )
			left += size + margin

	def run( self ):
		self.w.open()
		while not self.button:
			pass
		return self.button
Пример #24
0
class CopyGlyphs:

    def __init__(self):
        self.doMarkGlyphs = 0
        self.doOverwrite = 1
        self.sourceFontList = AllFonts()
        self.destinationFontList = AllFonts()
        self.source_font = self.sourceFontList[0]
        self.destination_fonts = None
        self.glyphs = None
        self.mark = NSColor.redColor()
        
        ## create a window
        self.w = Window((700, 500), "Copy Glyphs", minSize=(700, 500))
        self.w.sourceTitle = TextBox((15, 20, 200, 20), "Source Font:")
        self.w.sourceFont = PopUpButton((15, 42, -410, 20), [f.info.familyName + ' ' + f.info.styleName for f in self.sourceFontList], callback=self.sourceCallback)
        self.w.glyphs = GlyphCollectionView((16, 70, -410, -65), initialMode="list", enableDelete=False, allowDrag=False, selectionCallback=self.glyphCallback)
        self._sortGlyphs(self.source_font)
        self.w.desTitle = TextBox((-400, 20, 200, 20), "Destination Fonts:")
        self.w.destinationFonts = FontList((-400, 42, -15, -115), self.destinationFontList, selectionCallback=self.desCallback)
        self.w.overwrite = CheckBox((-395, -105, 130, 22), "Overwrite glyphs", callback=self.overwriteCallback, value=self.doOverwrite)
        self.w.markGlyphs = CheckBox((-395, -84, 100, 22), "Mark Glyphs", callback=self.markCallback, value=self.doMarkGlyphs)
        self.w.copyButton = Button((-115, -40, 100, 20), 'Copy Glyphs', callback=self.copyCallback)
        self.w.line = HorizontalLine((10, -50, -10, 1))
        self._updateDest()
        ## open the window
        self.w.open()
    
    def _updateDest(self):
        des = list(self.sourceFontList)
        des.remove(self.source_font)
        self.w.destinationFonts.set(des)
    
    def _sortGlyphs(self, font):
        gs = font.keys()
        gs.sort()
        self.w.glyphs.set([font[x] for x in gs])

    def _altName(self, font, glyph):
        name = glyph + '.copy'
        count = 1
        while name in font.keys():
            name = name + str(count)
            count += 1
        return name
        
    def copyGlyphs(self, glyphs, source_font, destination_fonts, overwrite, mark):
        for glyph in glyphs:
            for font in destination_fonts:
                if glyph in font.keys() and overwrite == 0:
                    n = self._altName(font, glyph)
                else:
                    n = glyph
                
                font.insertGlyph(source_font[glyph], name=n)
                
                if mark == 1:
                    font[n].mark = NSColorToRgba(self.mark)

    def overwriteCallback(self, sender):
        self.doOverwrite = sender.get()

    def markCallback(self, sender):
        self.doMarkGlyphs = sender.get()
        if self.doMarkGlyphs == 1:
            self.w.colorWell = ColorWell((-265, -85, 100, 23), callback=self.colorCallback, color=self.mark)
        else:
            del self.w.colorWell
        
    def colorCallback(self, sender):
        self.mark = sender.get()
    
    def sourceCallback(self, sender):
        self.source_font = self.sourceFontList[sender.get()]
        self._sortGlyphs(self.source_font)
        self._updateDest()
 
    def glyphCallback(self, sender):
        self.glyphs = [self.w.glyphs[x].name for x in sender.getSelection()]
        
    def desCallback(self, sender):
        self.destination_fonts = [sender.get()[x] for x in sender.getSelection()]
        
    def copyCallback(self, sender):
        self.sheet = Sheet((300, 50), self.w)
        self.sheet.bar = ProgressBar((10, 20, -10, 10), isIndeterminate=True, sizeStyle="small")
        self.sheet.open()
        self.sheet.bar.start()
        self.copyGlyphs(self.glyphs, self.source_font, self.destination_fonts, self.doOverwrite, self.doMarkGlyphs)
        self.sheet.bar.stop()
        self.sheet.close()
        del self.sheet
        self.w.close()
class GlyphnameDialog( object):

	def __init__( self ):
		x = 10
		y = 10
		height = 20
		button_width = 30
		glyphname_width = 180
		gap = 6
		self.w = Window( ( x + button_width + gap + glyphname_width + gap + button_width + x, y + height + y ), "insert glyph" )
		self.w.center()
		self.w.glyphname = EditText( ( x, y, glyphname_width, height ), '')
		x += glyphname_width + gap
		self.w.alignleft = Button( ( x, y, button_width, height ), LEFT, callback = self.buttonCallback )
		x += button_width + gap
		self.w.alignright = Button( ( x, y, button_width, height ), RIGHT, callback = self.buttonCallback )
		self.w.setDefaultButton( self.w.alignleft )
		self.w.alignright.bind( "\x1b", [] )
		self.w.open()

	def buttonCallback( self, sender ):
		title = sender.getTitle()
		glyphname = self.w.glyphname.get()
		if not glyphname:
			self.w.close()
			return
		if len( glyphname ) == 1:
			uni = ord(glyphname)
			g = font.glyphForUnicode_("%.4X" % uni)
			if g:
				glyphname = g.name
		other_glyph = font.glyphs[ glyphname ]
		if not other_glyph:
			for glyph in font.glyphs:
				if glyph.name.startswith( glyphname ):
					other_glyph = glyph
					print 'Using', glyph.name
					break
			else:
				print 'No matching glyph found.'
				self.w.close()
				return
		
		for layer in font.selectedLayers:
			glyph = layer.parent
			glyph.beginUndo()
			# deselect all
			for path in layer.paths:
				for node in path.nodes:
					layer.removeObjectFromSelection_( node )
			# find other layer
			for other_layer in other_glyph.layers:
				if other_layer.name == layer.name:
					# insert paths
					for path in other_layer.copyDecomposedLayer().paths:
						if title == RIGHT:
							shift = layer.width - other_layer.width
							for node in path.nodes:
								node.x = node.x + shift
						layer.paths.append( path )
						# select path
						layer.paths[-1].selected = True
					break
			glyph.endUndo()
		self.w.close()
Пример #26
0
from vanilla import Window, SquareButton, TextEditor
import vanilla
import mojo

def onSubmit(sender): 
    CurrentFont().info.note = window.textEditor.get()
    window.close()

if CurrentFont() is None:
    vanilla.dialogs.message("there is no current font, operation aborted")
else:
    window = Window((400, 400),"edit info.note", minSize=(100, 100))
    window.textEditor = TextEditor(posSize=(0, 0, 400, 300))
    noteContent = CurrentFont().info.note or ""
    window.textEditor.set(noteContent)
    window.updateNoteButton = SquareButton(posSize=(0, 350, 100, 50), title="update", callback=onSubmit)
    window.cancelButton = SquareButton(posSize=(110, 350, 100, 50), title="cancel", callback=lambda x: window.close())
    window.open()
Пример #27
0
class DBFinalTool:
    def __init__(self):
        self.glyph = None  # Typical RoboFont function
        self.updating = False

        pad = 10
        leading = 32
        y = pad
        w = 500
        h = 500
        c1 = 150
        c2 = 200
        bh = 24  # Button height
        leading = bh + pad / 2

        self.w = Window((100, 100, w, h), 'Final tool window', minSize=(w, h))
        self.w.fontList = List((pad, pad, c2, -w / 2), [],
                               doubleClickCallback=self.openFontCallback,
                               selectionCallback=self.update)

        y = pad
        self.w.fixTabWidths = Button((-c1 - pad, y, c1, bh),
                                     'Fix tab widths',
                                     callback=self.fixTabWidthsCallback)
        self.w.fixTabWidths.enable(False)

        y += leading
        self.w.fixNegativeWidths = Button(
            (-c1 - pad, y, c1, bh),
            'Fix negative widths',
            callback=self.fixNegativeWidthsCallback)
        self.w.fixNegativeWidths.enable(False)

        y += leading
        self.w.fixMissingComponentsWidths = Button(
            (-c1 - pad, y, c1, bh),
            'Fix missing components',
            callback=self.fixMissingComponentCallback)
        self.w.fixMissingComponentsWidths.enable(False)

        self.w.selectFolder = Button((-c1 - pad, -pad - bh, c1, bh),
                                     'Select fonts',
                                     callback=self.selectFontFolder)

        self.w.report = EditText((pad, -w / 2 + pad, -pad, -pad),
                                 readOnly=False)

        self.w.bind('close', self.windowCloseCallback)
        self.w.open()

        self.dirPath = self.selectFontFolder()

    def update(self, sender):
        """Do some UI status update work"""
        enable = len(self.w.fontList.getSelection()) > 0
        self.w.fixTabWidths.enable(enable)
        self.w.fixMissingComponentsWidths.enable(enable)
        self.w.fixNegativeWidths.enable(enable)

    def openFontCallback(self, sender):
        selectedFonts = []
        for index in self.w.fontList.getSelection():
            selectedFonts.append(self.w.fontList.get()[index])
        # Do something here with the fonts after double click
        # Open in RoboFont of Glyphs
        cmd = 'open'
        for selectedFont in selectedFonts:
            cmd += ' ' + self.dirPath + selectedFont
        #self.report(cmd)
        os.system(cmd)

    def selectFontFolder(self, sender=None):
        result = getFolder(messageText='Select fonts folder',
                           title='Select',
                           allowsMultipleSelection=False)
        if result:
            path = result[0]
            fontNames = []
            for filePath in os.listdir(path):
                if filePath.startswith('.') or not filePath.endswith('.ufo'):
                    continue
                fontNames.append(filePath)
            self.w.fontList.set(fontNames)
            return path + '/'
        return None

    def fixTabWidthsCallback(self, sender):
        self.clearReport()
        for index in self.w.fontList.getSelection():
            fontFile = self.w.fontList.get()[index]
            result = fixTabWidths(self.dirPath + fontFile)
            self.report('\n'.join(result))
            #self.report(self.dirPath )
            self.report('Done %s' % fontFile)

    def fixNegativeWidthsCallback(self, sender):
        self.clearReport()
        for index in self.w.fontList.getSelection():
            fontFile = self.w.fontList.get()[index]
            try:
                result = fixNegativeWidths(self.dirPath + fontFile)
                self.report('\n'.join(result))
            except:
                f = open(self.dirPath + 'error.txt', 'w')
                traceback.print_exc(file=f)
                f.close()
            self.report('Done %s\n' % fontFile)

    def fixMissingComponentCallback(self, sender):
        self.clearReport()
        for index in self.w.fontList.getSelection():
            fontFile = self.w.fontList.get()[index]
            result = fixMissingComponent(self.dirPath + fontFile)
            self.report('\n'.join(result))
            #self.report(self.dirPath )
            self.report('Done %s\n' % fontFile)

    def windowCloseCallback(self, sender):
        self.report('removeObservers')

    def clearReport(self):
        self.w.report.set('')

    def report(self, report):
        s = self.w.report.get()
        if s:
            s += '\n'
        self.w.report.set(s + str(report))
Пример #28
0
class makeItSo(object):
    def __init__(self):
        self.w = Window((550, 140), "Replace named Layer")
        self.w.editText = EditText((10, 15, -10, 22), placeholder="Layer Name", text='{170}')
        self.w.correct_path_direction = CheckBox((10, 50, -10, 18), "Correct Path Direction", value=True, sizeStyle='small')
        self.w.sync_metrics = CheckBox((210, 50, -10, 18), "Sync Metrics", value=True, sizeStyle='small')
        self.w.add_if_missing = CheckBox((10, 70, -10, 18), "Add layer if missing", value=True, sizeStyle='small')
        self.w.copybutton = Button((10, 100, -10, 17), "Replace layer", callback=self.buttonCallback)
        self.w.open()

    def buttonCallback(self, sender):
        self.w.close()

        target_font = Glyphs.font
        source_font = Glyphs.fonts[1]

        target_font.disableUpdateInterface()

        target_layer_name = self.w.editText.get()

        for source_glyph in source_font.glyphs:
            target_glyph = target_font.glyphs[source_glyph.name]
            if target_glyph is None:
                continue

            source_layer = source_glyph.layers[0]

            newL = copy.copy(source_layer)

            extant = True
            try:
                target_layer = [x for x in target_glyph.layers if x.name == target_layer_name][0]
                newL.associatedMasterId = target_layer.associatedMasterId
            except IndexError:
                if not self.w.add_if_missing.get():
                    continue
                source_weightValue = source_font.instances[0].weightValue
                mid = target_font.masters[0].id
                for m in target_font.masters:
                    if m.weightValue > source_weightValue:
                        break
                    mid = m.id
                newL.associatedMasterId = mid
                extant = False

            newL.name = target_layer_name
            for c in newL.components:
                c.automaticAlignment = False
                if target_font.glyphs[c.componentName] is None:
                    newLayerPaths = source_layer.copyDecomposedLayer()
                    newL.paths = newLayerPaths.paths
                    newL.components = []
                    break

            if self.w.correct_path_direction:
                newL.correctPathDirection()

            if extant:
                target_glyph.layers[target_layer.layerId] = newL
            else:
                target_glyph.layers.append(newL)

            if self.w.sync_metrics and extant:
                target_glyph.layers[target_layer.layerId].syncMetrics()

        target_font.enableUpdateInterface()
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()
Пример #30
0
class OCCToucheTool():
    def __init__(self):
        NSUserDefaults.standardUserDefaults().registerDefaults_(
            {"ToucheWindowHeight": 340})
        self.windowHeight = NSUserDefaults.standardUserDefaults(
        ).integerForKey_("ToucheWindowHeight")
        self.minWindowHeight = 340
        if self.windowHeight < self.minWindowHeight:
            self.windowHeight = self.minWindowHeight
        self.closedWindowHeight = 100
        self.w = Window((180, self.windowHeight),
                        u'2ché!',
                        minSize=(180, 340),
                        maxSize=(250, 898))
        self.w.bind("resize", self.windowResized)
        self.isResizing = False
        p = 10
        w = 160

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

        buttons = {
            "checkSelBtn": {
                "text": "Check selected glyphs",
                "callback": self.checkSel,
                "y": p
            },
        }
        for button, data in buttons.iteritems():
            setattr(
                self.w.options, button,
                Button((p, data["y"], w - 22, 22),
                       data["text"],
                       callback=data["callback"],
                       sizeStyle="small"))

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

        # Modification(Nic): prev / next buttons
        self.w.options.prevButton = Button((w + 22, 35, 10, 10),
                                           "Prev Button",
                                           callback=self.prevPair_)
        self.w.options.prevButton.bind("uparrow", [])

        self.w.options.nextButton = Button((w + 22, 35, 10, 10),
                                           "Next Button",
                                           callback=self.nextPair_)
        self.w.options.nextButton.bind("downarrow", [])

        # /Modification(Nic)

        # Modification(Nic): prev / next buttons

        self.w.options.decrementKerningHigh = Button(
            (w + 22, 35, 10, 10),
            "Decrement Kerning High",
            callback=self.decrementKerningByHigh_)
        self.w.options.decrementKerningHigh.bind("leftarrow", ["command"])

        self.w.options.decrementKerningLow = Button(
            (w + 22, 35, 10, 10),
            "Decrement Kerning Low",
            callback=self.decrementKerningByLow_)
        self.w.options.decrementKerningLow.bind("leftarrow", [])

        self.w.options.incrementKerningHigh = Button(
            (w + 22, 35, 10, 10),
            "Increment Kerning High",
            callback=self.incrementKerningByHigh_)
        self.w.options.incrementKerningHigh.bind("rightarrow", ["command"])

        self.w.options.incrementKerningLow = Button(
            (w + 22, 35, 10, 10),
            "Increment Kerning Low",
            callback=self.incrementKerningByLow_)
        self.w.options.incrementKerningLow.bind("rightarrow", [])

        # /Modification(Nic)

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

        textBoxes = {"stats": -34, "result": -18}
        for box, y in textBoxes.iteritems():
            setattr(self.w.results, box,
                    TextBox((p, y, w, 14), "", sizeStyle="small"))

        # list and preview
        self.w.outputList = List((0, 58, -0, -40), [{
            "left glyph": "",
            "right glyph": ""
        }],
                                 columnDescriptions=[{
                                     "title": "left glyph",
                                     "width": 90
                                 }, {
                                     "title": "right glyph"
                                 }],
                                 showColumnTitles=False,
                                 allowsMultipleSelection=False,
                                 enableDelete=False,
                                 selectionCallback=self.showPair)
        self.w.outputList._setColumnAutoresizing()
        self._resizeWindow(False)
        self.w.open()

    # callbacks

    # Modification(Nic): Incrementing and Decrementing the Pair Index in the list.

    def prevPair_(self, sender=None):
        currentIndices = self.w.outputList.getSelection()
        prevIndices = map(lambda i: max(i - 1, 0), currentIndices)
        if (len(self.w.outputList) > 0):
            self.w.outputList.setSelection(prevIndices)

    def nextPair_(self, sender=None):
        currentIndices = self.w.outputList.getSelection()
        nextIndices = map(lambda i: min(i + 1,
                                        len(self.w.outputList) - 1),
                          currentIndices)
        if (len(self.w.outputList) > 0):
            self.w.outputList.setSelection(nextIndices)

    # /Modification(Nic)

    # Modification(Nic): Incrementing and Decrementing the Pair Index in the list.

    def decrementKerningByLow_(self, sender=None):
        print('dec by low')
        currentIndices = self.w.outputList.getSelection()
        currentPair = self.w.outputList[currentIndices[0]]
        increment = Glyphs.intDefaults['GSKerningIncrementLow']
        self.bumpKerningForPair(currentPair['left glyph'],
                                currentPair['right glyph'], -increment)

    def decrementKerningByHigh_(self, sender=None):
        print('dec by high')
        currentIndices = self.w.outputList.getSelection()
        currentPair = self.w.outputList[currentIndices[0]]
        increment = Glyphs.intDefaults['GSKerningIncrementHigh']
        self.bumpKerningForPair(currentPair['left glyph'],
                                currentPair['right glyph'], -increment)

    def incrementKerningByLow_(self, sender=None):
        print('inc by low')
        currentIndices = self.w.outputList.getSelection()
        currentPair = self.w.outputList[currentIndices[0]]
        increment = Glyphs.intDefaults['GSKerningIncrementLow']
        self.bumpKerningForPair(currentPair['left glyph'],
                                currentPair['right glyph'], increment)

    def incrementKerningByHigh_(self, sender=None):
        print('inc by high')
        currentIndices = self.w.outputList.getSelection()
        currentPair = self.w.outputList[currentIndices[0]]
        increment = Glyphs.intDefaults['GSKerningIncrementHigh']
        self.bumpKerningForPair(currentPair['left glyph'],
                                currentPair['right glyph'], increment)

    # /Modification(Nic)

    # Modification(Nic): Routine to increment/decrement kerning properly
    def bumpKerningForPair(self, left, right, increment):
        leftGlyph, rightGlyph = Glyphs.font[left], Glyphs.font[right]
        k = Glyphs.font.kerningForPair(Glyphs.font.selectedFontMaster.id,
                                       leftGlyph.rightKerningKey,
                                       rightGlyph.leftKerningKey)
        if k > 10000: k = 0  # Glyphs uses MAXINT to signal no kerning.
        Glyphs.font.setKerningForPair(Glyphs.font.selectedFontMaster.id,
                                      leftGlyph.rightKerningKey,
                                      rightGlyph.leftKerningKey, k + increment)

    # Modification(Nic)

    def checkAll(self, sender=None):
        self.check(useSelection=False)

    def checkSel(self, sender=None):
        self.check(useSelection=True)

    def check(self, useSelection):
        self._resizeWindow(enlarge=False)
        self.checkFont(useSelection=useSelection,
                       excludeZeroWidth=self.w.options.zeroCheck.get())

    def showPair(self, sender=None):
        try:
            index = sender.getSelection()[0]
            glyphs = [self.f[gName] for gName in self.touchingPairs[index]]
            ActiveFont = self.f._font
            EditViewController = ActiveFont.currentTab
            if EditViewController is None:
                tabText = "/%s/%s" % (glyphs[0].name, glyphs[1].name)
                ActiveFont.newTab(tabText)
            else:
                textStorage = EditViewController.graphicView()
                if not hasattr(textStorage,
                               "replaceCharactersInRange_withString_"
                               ):  # compatibility with API change in 2.5
                    textStorage = EditViewController.graphicView().textStorage(
                    )
                LeftChar = ActiveFont.characterForGlyph_(glyphs[0]._object)
                RightChar = ActiveFont.characterForGlyph_(glyphs[1]._object)
                if LeftChar != 0 and RightChar != 0:
                    selection = textStorage.selectedRange()
                    if selection.length < 2:
                        selection.length = 2
                        if selection.location > 0:
                            selection.location -= 1

                    NewString = ""
                    if LeftChar < 0xffff and RightChar < 0xffff:
                        NewString = u"%s%s" % (unichr(LeftChar),
                                               unichr(RightChar))
                    else:
                        print "Upper plane codes are not supported yet"

                    textStorage.replaceCharactersInRange_withString_(
                        selection, NewString)
                    selection.length = 0
                    selection.location += 1
                    textStorage.setSelectedRange_(selection)
            #self.w.preview.set(glyphs)
        except IndexError:
            pass

    # checking

    def _hasSufficientWidth(self, g):
        # to ignore combining accents and the like
        if self.excludeZeroWidth:
            # also skips 1-unit wide glyphs which many use instead of 0
            if g.width < 2 or g._object.subCategory == "Nonspacing":
                return False
        return True

    def _trimGlyphList(self, glyphList):
        newGlyphList = []
        for g in glyphList:
            if g.box is not None and self._hasSufficientWidth(g):
                newGlyphList.append(g)
        return newGlyphList

    def windowResized(self, window):
        posSize = self.w.getPosSize()
        Height = posSize[3]
        if Height > self.closedWindowHeight and self.isResizing is False:
            print "set new Height", Height
            NSUserDefaults.standardUserDefaults().setInteger_forKey_(
                Height, "ToucheWindowHeight")
            self.windowHeight = Height

    def _resizeWindow(self, enlarge=True):
        posSize = self.w.getPosSize()
        if enlarge:
            self.w.results.show(True)
            self.w.outputList.show(True)
            targetHeight = self.windowHeight
            if targetHeight < 340:
                targetHeight = 340
        else:
            self.w.results.show(False)
            self.w.outputList.show(False)
            targetHeight = self.closedWindowHeight
        self.isResizing = True
        self.w.setPosSize((posSize[0], posSize[1], posSize[2], targetHeight))
        self.isResizing = False

    # ok let's do this

    def checkFont(self, useSelection=False, excludeZeroWidth=True):
        f = CurrentFont()
        if f is not None:
            # initialize things
            self.w.options.progress.start()
            time0 = time.time()
            self.excludeZeroWidth = excludeZeroWidth
            self.f = f

            glyphNames = f.selection if useSelection else f.keys()
            glyphList = [f[x] for x in glyphNames]
            glyphList = self._trimGlyphList(glyphList)

            self.touchingPairs = OCCTouche(f).findTouchingPairs(glyphList)

            # display output
            self.w.results.stats.set("%d glyphs checked" % len(glyphList))
            self.w.results.result.set("%d touching pairs found" %
                                      len(self.touchingPairs))
            self.w.results.show(True)

            outputList = [{
                "left glyph": g1,
                "right glyph": g2
            } for (g1, g2) in self.touchingPairs]
            self.w.outputList.set(outputList)
            if len(self.touchingPairs) > 0:
                self.w.outputList.setSelection([0])

            #self.w.preview.setFont(f)
            self.w.options.progress.stop()
            self._resizeWindow(enlarge=True)

            time1 = time.time()
            print u'2ché: finished checking %d glyphs in %.2f seconds' % (
                len(glyphList), time1 - time0)

        else:
            Message(u'2ché: Can’t find a font to check')
Пример #31
0
class SimpleFontWindow(BaseWindowController):

    def __init__(self, font):

        self._font = font

        if font.path:
            document = DoodleDocument.alloc().init()
            document.setFileURL_(NSURL.fileURLWithPath_(font.path))

            dc = NSDocumentController.sharedDocumentController()
            dc.addDocument_(document)

        self._canUpdateChangeCount = True

        self.w = Window((250, 500), "SimpleFontWindow", minSize=(200, 300))

        glyphs = sorted(font.keys())

        self.w.glyphs = List((0, 0, -0, -0), glyphs,
                             doubleClickCallback=self.openGlyph)

        toolbarItems = [
            dict(itemIdentifier="spaceCenter",
                 label="Space Center",
                 imageNamed="toolbarSpaceCenterAlternate",
                 callback=self.openSpaceCenter
                 ),
            dict(itemIdentifier="fontInfo",
                 label="Font Info",
                 imageNamed="toolbarFontInfo",
                 callback=self.openFontInfo
                 )
        ]
        self.w.addToolbar(toolbarIdentifier="SimpleToolbar",
                          toolbarItems=toolbarItems)

        windowController = self.w.getNSWindowController()
        windowController.setShouldCloseDocument_(True)
        self._font.UIdocument().addWindowController_(windowController)

        self._font.addObserver(self, "fontChanged", "Font.Changed")

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

        self.openFirstGlyph()

    def openGlyph(self, sender):
        sel = sender.getSelection()
        if sel:
            i = sel[0]
            name = sender[i]
            self._canUpdateChangeCount = False
            OpenGlyphWindow(self._font[name])
            self._canUpdateChangeCount = True

    def openSpaceCenter(self, sender):
        self._canUpdateChangeCount = False
        OpenSpaceCenter(self._font)
        self._canUpdateChangeCount = True

    def openFontInfo(self, sender):
        self._canUpdateChangeCount = False
        OpenFontInfoSheet(self._font, self.w)
        self._canUpdateChangeCount = True

    # notifications
    def fontChanged(self, notification):
        if self._canUpdateChangeCount:
            self._font.UIdocument().updateChangeCount_(0)

    # to make EditThatNextMaster work as needed

    def openFirstGlyph(self):

        glyphName = "A"

        if glyphName in font.keys():
            OpenGlyphWindow(self._font[glyphName])
Пример #32
0
class Dialogs(object):
    u"""
    New dialog creation, for dialog closing see Callbacks class.
    """

    # Start.

    def openStartWindow(self):
        u"""
        Offers a 'New' and 'Open...' button.
        """
        self.startDialog = Window(self.dialogSize, "Welcome", minSize=self.dialogSize, maxSize=self.dialogSize)
        self.startDialog.newText = TextBox((20, 60, 60, 30), "New")
        self.startDialog.newButton = Button((20, 100, 80, 20), "Create...", callback=self.new_)
        self.startDialog.openText = TextBox((160, 60, 60, 30), "Existing")
        self.startDialog.openButton = Button((160, 100, 60, 20), "Open...", callback=self.open_)
        self.startDialog.open()

    def closeStartDialog(self):
        u"""
        Closes and clears start dialog.
        """
        if not self.startDialog is None:
            self.startDialog.close()
            self.startDialog = None

    # Document.

    def openOpenDocumentDialog(self):
        u"""
        Open document dialog.
        """
        self.closeStartDialog()

        panel = NSOpenPanel.openPanel()
        panel.setCanChooseDirectories_(False)
        panel.setCanChooseFiles_(True)
        panel.setAllowsMultipleSelection_(False)
        panel.setAllowedFileTypes_(['wf'])

        if panel.runModal() == NSOKButton:
            added, document = self.model.openDocument(panel.filenames()[0])
            self.initDocument(added, document)

    def openNewDialog(self):
        u"""
        Opens the document canvas if it doesn't exist yet.
        """
        self.closeStartDialog()
        self.setDefaultDocumentValues()

        size = (400, 300)
        self.newDialog = w = Window(size, "New Document", minSize=size, maxSize=size)

        w.nameText = TextBox((20, 20, 180, 20), "Name")
        w.nameBox = EditText((200, 20, 180, 20), callback=self.newNameCallback)
        w.nameBox.set(self.documentValues['documentName'])

        w.sizeText = TextBox((20, 40, 180, 20), "Size")
        values = PaperSizes.getAllPaperSizes()
        w.sizeComboBox = ComboBox((200, 40, 180, 20), values, callback=self.newSizeCallback)
        w.sizeComboBox.set(self.defaultPaperSize)

        w.whText = TextBox((20, 60, 220, 20), u"w×h in ㎜")

        width, height = PaperSizes.getSize(self.defaultPaperSize, 'mm')

        w.width = EditText((200, 60, 80, 20), callback=self.newWidthCallback)
        w.width.set(width)

        w.x = TextBox((285, 60, 10, 20), u"×")
        w.dimensionBoxHeight = EditText((300, 60, 80, 20), callback=self.newHeightCallback)
        w.dimensionBoxHeight.set(height)

        w.okayButton = Button((240, 260, 60, 20), "Okay", callback=self.newOkayCallback)
        #w.okayButton.getNSButton().setEnabled_(False)
        w.cancelButton = Button((320, 260, 60, 20), "Cancel",
                callback=self.newCancelCallback)
        w.open()

    def closeOpenDialog(self):
        if not self.openDialog is None:
            self.openDialog.close()
            self.openDialog = None

    # Save dialog.

    def openSaveDialog(self):
        if not self.saveDialog is None:
            return

        self.saveDialog = Window(self.saveDialogSize, "Save", minSize=self.saveDialogSize,
                                    maxSize=self.saveDialogSize)
        self.saveDialog.saveText = TextBox((60, 20, 280, 60),
                "Save changes to the document %s?" % self.currentDocument.name)

        self.saveDialog.dontButton = Button((60, 70, 100, 20), "Don't Save",
                callback=self.saveDontCallback)

        self.saveDialog.cancelButton = Button((260, 70, 60, 20), "Cancel",
                callback=self.saveCloseCallback)

        self.saveDialog.doButton = Button((320, 70, 60, 20), "Save",
            callback=self.saveDoCallback)
        self.saveDialog.open()

    def closeSaveDialog(self):
        self.saveDocumentDialog.close()
        self.saveDocumentDialog = None

    # Close.

    def windowShouldCloseCallback(self, sender):
        window = self.getCurrentWindow()

        if sender == window:
            self.closeDocument_(sender)
Пример #33
0
class ToucheTool:
    def __init__(self):
        self.w = Window((180, 340), u"Touché!", minSize=(180, 340), maxSize=(1000, 898))
        p = 10
        w = 160

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

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

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

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

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

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

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

        self.w.open()

    # callbacks

    def checkAll(self, sender=None):
        self.check(useSelection=False)

    def checkSel(self, sender=None):
        self.check(useSelection=True)

    def check(self, useSelection):
        self.w.results.show(False)
        self._resizeWindow(enlarge=False)
        self.checkFont(useSelection=useSelection, excludeZeroWidth=self.w.options.zeroCheck.get())

    def showPair(self, sender=None):
        try:
            index = sender.getSelection()[0]
            glyphs = [self.f[gName] for gName in self.touchingPairs[index]]
            self.w.preview.set(glyphs)
        except IndexError:
            pass

    def showAllPairs(self, sender=None):
        # open all resulting pairs in Space Center
        rawString = ""
        for g1, g2 in self.touchingPairs:
            rawString += "/%s/%s/space" % (g1, g2)
        s = OpenSpaceCenter(self.f)
        s.setRaw(rawString)

    def exportPairList(self, sender=None):
        # Save the list of found touching pairs in a text file which can be read by MetricsMachine as a pair list
        path = PutFile("Choose save location", "TouchingPairs.txt")
        if path is not None:
            reportString = "#KPL:P: TouchingPairs\n"
            for g1, g2 in self.touchingPairs:
                reportString += "%s %s\n" % (g1, g2)
            fi = open(path, "w+")
            fi.write(reportString)
            fi.close()

    # checking

    def _hasSufficientWidth(self, g):
        # to ignore combining accents and the like
        if self.excludeZeroWidth:
            # also skips 1-unit wide glyphs which many use instead of 0
            if g.width < 2:
                return False
        return True

    def _trimGlyphList(self, glyphList):
        newGlyphList = []
        for g in glyphList:
            if g.box is not None and self._hasSufficientWidth(g):
                newGlyphList.append(g)
        return newGlyphList

    def _resizeWindow(self, enlarge=True):
        posSize = self.w.getPosSize()
        targetWidth = 700 if enlarge else 180
        self.w.setPosSize((posSize[0], posSize[1], targetWidth, posSize[3]))

    # ok let's do this

    def checkFont(self, useSelection=False, excludeZeroWidth=True):
        f = CurrentFont()
        if f is not None:
            # initialize things
            self.w.options.progress.start()
            time0 = time.time()
            self.excludeZeroWidth = excludeZeroWidth
            self.f = f

            glyphNames = f.selection if useSelection else f.keys()
            glyphList = [f[x] for x in glyphNames]
            glyphList = self._trimGlyphList(glyphList)

            self.touchingPairs = Touche(f).findTouchingPairs(glyphList)

            # display output
            self.w.results.stats.set("%d glyphs checked" % len(glyphList))
            self.w.results.result.set("%d touching pairs found" % len(self.touchingPairs))
            self.w.results.show(True)

            outputList = [{"left glyph": g1, "right glyph": g2} for (g1, g2) in self.touchingPairs]
            self.w.outputList.set(outputList)
            if len(self.touchingPairs) > 0:
                self.w.outputList.setSelection([0])
            else:
                self.w.preview.set("")

            outputButtons = [self.w.results.spaceView, self.w.results.exportTxt]
            for b in outputButtons:
                b.enable(False) if len(self.touchingPairs) == 0 else b.enable(True)
            self.w.preview.setFont(f)
            self.w.options.progress.stop()
            self._resizeWindow(enlarge=True)

            time1 = time.time()
            print u"Touché: finished checking %d glyphs in %.2f seconds" % (len(glyphList), time1 - time0)

        else:
            Message(u"Touché: Can’t find a font to check")
Пример #34
0
class GlyphnameDialog(object):
    def __init__(self):
        x = 10
        y = 10
        height = 20
        button_width = 30
        glyphname_width = 180
        gap = 6
        self.w = Window(
            (x + button_width + gap + glyphname_width + gap + button_width + x,
             y + height + y), "insert glyph")
        self.w.center()
        self.w.glyphname = EditText((x, y, glyphname_width, height), '')
        x += glyphname_width + gap
        self.w.alignleft = Button((x, y, button_width, height),
                                  LEFT,
                                  callback=self.buttonCallback)
        x += button_width + gap
        self.w.alignright = Button((x, y, button_width, height),
                                   RIGHT,
                                   callback=self.buttonCallback)
        self.w.setDefaultButton(self.w.alignleft)
        self.w.alignright.bind("\x1b", [])
        self.w.open()

    def buttonCallback(self, sender):
        title = sender.getTitle()
        glyphname = self.w.glyphname.get()
        if not glyphname:
            self.w.close()
            return
        if len(glyphname) == 1:
            uni = ord(glyphname)
            g = font.glyphForUnicode_("%.4X" % uni)
            if g:
                glyphname = g.name
        other_glyph = font.glyphs[glyphname]
        if not other_glyph:
            for glyph in font.glyphs:
                if glyph.name.startswith(glyphname):
                    other_glyph = glyph
                    break
            else:
                self.w.close()
                return

        for layer in font.selectedLayers:
            glyph = layer.parent
            glyph.beginUndo()
            # deselect all
            for path in layer.paths:
                for node in path.nodes:
                    layer.removeObjectFromSelection_(node)
            # find other layer
            for other_layer in other_glyph.layers:
                if other_layer.name == layer.name:
                    # insert paths
                    for path in other_layer.copyDecomposedLayer().paths:
                        if title == RIGHT:
                            shift = layer.width - other_layer.width
                            for node in path.nodes:
                                node.x = node.x + shift
                        layer.paths.append(path)
                        # select path
                        layer.paths[-1].selected = True
                    break
            glyph.endUndo()
        self.w.close()
class makeDisplay(object):
    def __init__(self):
        self.verboten = {
            'right': ['napostrophe', 'Omegadasiavaria'],
            'left': ['ldot', 'Ldot', 'ldot.sc', 'sigmafinal'],
            'both': ['*.tf', '*.tosf', '.notdef', 'NULL', 'CR']
        }
        self.category = None
        self.messages = []
        self.interpolated_fonts = dict()
        self.use_real = True
        self.use_selection = False
        self.ignore_red = False
        self.current_glyph = None
        self.leftside_kerning_groups = None
        self.rightside_kerning_groups = None
        self.all_kern_categories = self.get_all_kern_categories()
        self.categories_leftside = self.get_categorised_glyphs('left')
        self.categories_rightside = self.get_categorised_glyphs('right')

        item_height = 24.0
        w_width = 300.0
        w_height = item_height * (7 + len(self.all_kern_categories))
        margin = 10
        next_y = margin
        col_1_width = w_width - (margin * 2)
        item_height = 24

        radio_height = item_height * len(self.all_kern_categories)

        self.w = Window((w_width, w_height), "Make Kerning Strings")

        self.w.text_1 = TextBox((margin, next_y, w_width, item_height), "Kern with:", sizeStyle='regular')
        next_y += item_height
        self.w.radioCategories = RadioGroup((margin, next_y, col_1_width, radio_height), self.all_kern_categories, sizeStyle='regular')
        self.w.radioCategories.set(0)
        next_y += radio_height + margin

        self.w.use_real = CheckBox((margin, next_y, col_1_width, item_height), "Use real words", value=True, sizeStyle='regular')
        next_y += item_height

        self.w.use_selected = CheckBox((margin, next_y, col_1_width, item_height), "Use the selected glyphs verbatum", value=False, sizeStyle='regular')
        next_y += item_height

        self.w.ignore_red = CheckBox((margin, next_y, col_1_width, item_height), "Ignore red marked glyphs", value=False, sizeStyle='regular')
        next_y += item_height + margin

        self.w.gobutton = Button((margin + (col_1_width / 4), next_y, col_1_width / 2, item_height), 'Make Strings', callback=self.makeitso)

        self.w.setDefaultButton(self.w.gobutton)
        self.w.center()
        self.w.open()
        # self.makeitso(None)

    def sbuttonCallback(self, sender):
        self.s.close()

    @staticmethod
    def has_smallcaps():
        for g in Glyphs.font.glyphs:
            if g.subCategory == 'Smallcaps':
                return True

        return False

    def get_all_kern_categories(self):
        kcats = [
            'Uppercase',
            'Lowercase',
        ]
        if self.has_smallcaps:
            kcats.append('Smallcaps')
        kcats += [
            'Quotes',
            'Number',
            'Punctuation',
            'Other',
        ]
        return kcats

    def get_canonincal_kerning_glyph(self, layer, pair_side):
        g = layer.parent

        if self.use_selection:
            return g

        if pair_side == 'left':
            g = Glyphs.font.glyphs[layer.parent.rightKerningGroup] or layer.parent
        if pair_side == 'right':
            g = Glyphs.font.glyphs[layer.parent.leftKerningGroup] or layer.parent

        if g is None:
            g = layer.parent

        return g

    @staticmethod
    def make_list_unique(this_list):
        unique_list = []
        for x in this_list:
            if x in unique_list or x is None:
                continue
            unique_list.append(x)

        return unique_list

    def get_categorised_glyphs(self, side):
        # cats = defaultdict(lambda: defaultdict(list))
        cats = dict((k, defaultdict(list)) for k in self.all_kern_categories)
        for g in [x for x in Glyphs.font.glyphs if self.is_elligable(x)]:
            l = cats.get(g.category, cats.get(g.subCategory, cats['Other']))
            l[g.script].append(self.get_canonincal_kerning_glyph(g.layers[0], side))

        for cat in cats.keys():
            for script in cats[cat].keys():
                cats[cat][script] = self.make_list_unique(cats[cat][script])

        return cats

    def get_string(self, left_g, right_g):
        string = None

        if self.category == 'Quotes':
            cat = left_g.subCategory if left_g.subCategory != 'Other' else left_g.category
            pattern = _kerningStrings.patterns.get(left_g.script, _kerningStrings.patterns.get('latin')).get(cat + '-Quotes', '')
            strings = [pattern.format(right=right_g.name, left=left_g.name, qL=quote_pair[0], qR=quote_pair[1]).replace(' /', '/') for quote_pair in _kerningStrings.quotations]
            string = '  '.join(strings)

        if not string and self.use_real:
            base_name_left, _, suffix_left = left_g.name.partition('.')
            base_name_right, _, suffix_right = right_g.name.partition('.')

            potentials = [
                base_name_left + base_name_right,
                base_name_left + '/' + base_name_right,
                '/' + base_name_left + ' ' + base_name_right,
                '/' + base_name_left + '/' + base_name_right,
            ]
            for s in potentials:
                string = _kerningStrings.strings.get(s)
                if string:
                    break
                print(s)

        if not string:
            pattern = self.get_pattern(left_g, right_g)
            string = pattern.format(right=right_g.name, left=left_g.name).replace(' /', '/')

        if not string:
            string = '/' + left_g.name + '/' + right_g.name

        return string

    def get_category_for_glyph(self, glyph):
        if glyph.category in self.all_kern_categories:
            return glyph.category

        if glyph.subCategory in self.all_kern_categories:
            return glyph.subCategory

        if glyph.subCategory == 'Currancy':
            return 'Number'

        return 'Other'

    def get_pattern(self, main_glyph, other_glyph):
        scripts_patterns = _kerningStrings.patterns.get(main_glyph.script, {})
        # print(self.get_category_for_glyph(main_glyph))
        # print(self.get_category_for_glyph(main_glyph) + '-' + self.get_category_for_glyph(other_glyph), self.all_kern_categories)
        pattern = scripts_patterns.get(self.get_category_for_glyph(main_glyph) + '-' + self.get_category_for_glyph(other_glyph), '')

        if self.category == 'Number':
            suffix = ''.join(main_glyph.name.partition('.')[1:])
        else:
            suffix = ''

        try:
            pattern = pattern.format(
                suffix=suffix,
                left='{left}',
                right='{right}',
            )
        except KeyError:
            pass

        return pattern

    def is_elligable(self, glyph, side='both'):
        if self.ignore_red and glyph.color == 0:
            return False

        if not glyph.export:
            return False

        for vgn in self.verboten[side]:
            if re.match(vgn.replace('.', '\\.').replace('*', '.*'), glyph.name):
                return False
        return True

    def makeitso(self, sender):
        try:
            self.w.close()
        except AttributeError:
            pass
        self.category = self.all_kern_categories[self.w.radioCategories.get()]

        self.use_real = self.w.use_real.get()
        self.use_selection = self.w.use_selected.get()
        self.ignore_red = self.w.ignore_red.get()
        all_strings = []

        if self.category == 'Quotes':
            left_of_string_glyphs = self.make_list_unique([self.get_canonincal_kerning_glyph(sl, 'right') for sl in Glyphs.font.selectedLayers if self.is_elligable(sl.parent, 'right')])
            right_of_string_glyphs = self.make_list_unique([self.get_canonincal_kerning_glyph(sl, 'left') for sl in Glyphs.font.selectedLayers if self.is_elligable(sl.parent, 'left')])
            pairs = zip_longest(left_of_string_glyphs, right_of_string_glyphs)
            for p in pairs:
                gl, gr = p
                if gl is None:
                    gl = gr if gr in left_of_string_glyphs else left_of_string_glyphs[0]
                if gr is None:
                    gr = gl if gl in left_of_string_glyphs else right_of_string_glyphs[0]

                kerning_string = self.get_string(gl, gr)
                if kerning_string not in all_strings:
                    all_strings.append(kerning_string)

        else:
            # Holds kerning key glyphs that have been seen already, to avoid duplicates
            processed_main_glyphs_left = OrderedDict()
            processed_main_glyphs_right = OrderedDict()
            # print([(k, self.categories_rightside[k].keys()) for k in self.categories_rightside.keys()])
            for sl in Glyphs.font.selectedLayers:
                # Process the selected glyph on the left side
                main_g_left = self.get_canonincal_kerning_glyph(sl, 'left')
                pair_strings_left = []
                if self.is_elligable(main_g_left, 'left'):
                    if main_g_left.name not in processed_main_glyphs_left.keys():
                        processed_main_glyphs_left[main_g_left.name] = [sl.parent.name]
                        try:
                            if sl.parent.script:
                                other_glyphs_rightside = self.categories_rightside[self.category].get(sl.parent.script, self.categories_rightside[self.category].get(None))
                            else:
                                other_glyphs_rightside = self.categories_rightside[self.category].get(None, self.categories_rightside[self.category].get('latin'))
                        except KeyError:
                            other_glyphs_rightside = []
                        # print(self.category, self.categories_rightside.keys())
                        print(sl.parent.script, self.category, self.categories_rightside[self.category].keys())

                        for g in other_glyphs_rightside:
                            if not self.is_elligable(g, 'right'):
                                continue
                            other_g = self.get_canonincal_kerning_glyph(g.layers[sl.associatedMasterId], 'right')
                            kerning_string_left = self.get_string(main_g_left, other_g)
                            if kerning_string_left not in pair_strings_left:
                                pair_strings_left.append(kerning_string_left)
                    else:
                        processed_main_glyphs_left[main_g_left.name].append(sl.parent.name)

                    if pair_strings_left:
                        pair_strings_left.insert(0, main_g_left.name)

                # Process the selected glyph on the right side
                main_g_right = self.get_canonincal_kerning_glyph(sl, 'right')
                pair_strings_right = []
                if self.is_elligable(main_g_right, 'right'):
                    if main_g_right.name not in processed_main_glyphs_right.keys():
                        processed_main_glyphs_right[main_g_right.name] = [sl.parent.name]

                        if self.category == 'Quotes':
                            other_glyphs_leftside = [main_g_right]
                            main_g_right = self.get_canonincal_kerning_glyph(sl, 'left')
                        else:
                            if sl.parent.script:
                                other_glyphs_leftside = self.categories_leftside[self.category].get(sl.parent.script, self.categories_leftside[self.category].get(None, []))
                            else:
                                other_glyphs_leftside = self.categories_leftside[self.category].get(None, self.categories_leftside[self.category].get('latin', []))

                        for g in other_glyphs_leftside:
                            if not self.is_elligable(g, 'left'):
                                continue
                            other_g = self.get_canonincal_kerning_glyph(g.layers[sl.associatedMasterId], 'left')
                            kerning_string_right = self.get_string(other_g, main_g_right)
                            if kerning_string_right not in pair_strings_right:
                                pair_strings_right.append(kerning_string_right)
                    else:
                        processed_main_glyphs_right[main_g_right.name].append(sl.parent.name)

                    if pair_strings_right:
                        pair_strings_right.insert(0, main_g_right.name)

                left_string = '  '.join(self.make_list_unique(pair_strings_left))
                right_string = '  '.join(self.make_list_unique(pair_strings_right))
                if all([left_string, right_string]):
                    pair_strings = '\n'.join([left_string, right_string])
                else:
                    pair_strings = left_string or right_string

                # print(':', pair_strings, ':')

                if pair_strings:
                    all_strings.append(pair_strings)

        Glyphs.font.newTab('\n\n'.join(all_strings))
        Glyphs.font.currentTab.previewInstances = 'live'
        Glyphs.font.currentTab.scale = 0.065
        Glyphs.font.currentTab.textCursor = 3
        Glyphs.font.tool = 'TextTool'
Пример #36
0
class ScriptRunnerApp:
    """Wrapper class to bundle all document page typesetter and composition
    functions, generating export document."""
    def __init__(self):
        """
        Connects main window and output window for errors.
        """
        self.outputWindow = Window((400, 300), minSize=(1, 1), closable=True)
        self.outputWindow.outputView = OutPutEditor((0, 0, -0, -0),
                                                    readOnly=True)
        self.window = Window((800, 600), minSize=(1, 1), closable=True)
        self.window.drawView = DrawView((0, 32, -0, -0))
        self.scriptPath = None
        self.scriptFileName = None
        self.scriptName = None
        self.initialize()
        self.window.open()
        self.outputWindow.open()

    def getPath(self):
        """
        TODO: store in preferences.
        TODO: add example scripts to menu.
        TODO: remember name.
        """
        if self.scriptPath is not None:
            return self.scriptPath

    def initialize(self):
        """
        Sets up GUI contents.
        """
        self.buildTop()
        self.run()

    def buildTop(self):
        """Builds buttons at top.

        TODO: put in a group.
        """
        x = 4
        y = 4
        w = 100
        h = 24
        self.window.openFile = Button((x, y, w, h),
                                      'Open',
                                      sizeStyle='small',
                                      callback=self.openCallback)
        x += 110
        self.window.saveButton = Button((x, y, w, h),
                                        'Save',
                                        sizeStyle='small',
                                        callback=self.saveCallback)
        x += 110
        self.window.path = TextBox((x, y + 2, -40, h), '', sizeStyle='small')

    def run(self):
        """
        Runs the script code and writes PDF contents to drawView.
        """
        self.runCode()
        pdfDocument = self.getPageBotDocument()
        self.window.drawView.setPDFDocument(pdfDocument)

    def runCode(self):
        """
        Runs a PageBot script.
        """
        path = self.getPath()

        if path is None:
            return

        _drawBotDrawingTool.newDrawing()
        namespace = {}
        _drawBotDrawingTool._addToNamespace(namespace)

        # Creates a new standard output, catching all print statements and tracebacks.
        self.output = []
        self.stdout = StdOutput(self.output,
                                outputView=self.outputWindow.outputView)
        self.stderr = StdOutput(self.output,
                                isError=True,
                                outputView=self.outputWindow.outputView)

        # Calls DrawBot's ScriptRunner with above parameters.
        ScriptRunner(None,
                     path,
                     namespace=namespace,
                     stdout=self.stdout,
                     stderr=self.stderr)
        self.printErrors()

    def printErrors(self):
        for output in self.output:
            print(output[0])

    def getPageBotDocument(self):
        """Converts template drawn in memory to a PDF document."""
        context = getContextForFileExt('pdf')
        _drawBotDrawingTool._drawInContext(context)
        pdfDocument = _drawBotDrawingTool.pdfImage()
        return pdfDocument

    def saveCallback(self, sender):
        """Saves current template to a PDF file."""
        self.saveAs()

    def saveDoCallback(self, path):
        _drawBotDrawingTool.saveImage(path)

    def openCallback(self, sender):
        self.open()

    def terminate(self):
        pass

    def new(self):
        print('something new')

    def open(self):
        """Opens a different script by calling up the get file dialog."""
        paths = getFile(messageText='Please select your script',
                        title='Select a script.',
                        allowsMultipleSelection=False,
                        fileTypes=('py', ))

        if paths is not None:
            self.scriptPath = paths[0]
            self.scriptFileName = self.scriptPath.split('/')[-1]
            self.scriptName = self.scriptFileName.split('.')[0]
            self.window.path.set(self.scriptPath)
            self.run()

    def close(self):
        print('close something')

    def saveAs(self):
        if self.scriptPath is not None:
            doc = self.getPageBotDocument()
            putFile(messageText='Save PDF',
                    title='Save PDF as...',
                    fileName='%s.pdf' % self.scriptName,
                    parentWindow=self.window,
                    resultCallback=self.saveDoCallback)

    def save(self):
        print('save something')

    def cut(self):
        print('cut something')

    def copy(self):
        print('copy something')

    def paste(self):
        print('paste something')

    def delete(self):
        print('delete something')

    def undo(self):
        print('undo something')

    def redo(self):
        print('redo something')
Пример #37
0
class MM2SpaceCenter:
    def activateModule(self):
        addObserver(self, "MMPairChangedObserver",
                    "MetricsMachine.currentPairChanged")
        print('MM2SpaceCenter activated')

    def deactivateModule(self, sender):
        removeObserver(self, "MetricsMachine.currentPairChanged")
        print('MM2SpaceCenter deactivated')

    def __init__(self, ):
        self.font = metricsMachine.CurrentFont()
        self.pair = metricsMachine.GetCurrentPair()
        #self.wordlistPath = wordlistPath

        leftMargin = 10
        topMargin = 5
        yPos = 0
        lineHeight = 20

        yPos += topMargin

        self.messageText = 'MM2SpaceCenter activated 😎'

        self.wordCount = 20
        self.minLength = 3
        self.maxLength = 15

        self.activateModule()
        self.w = Window((250, 155), "MM2SpaceCenter")

        self.w.myTextBox = TextBox((leftMargin, yPos, -10, 17),
                                   self.messageText,
                                   sizeStyle="regular")

        yPos += (lineHeight * 1.2)

        topLineFields = {
            "wordCount": [0 + leftMargin, self.wordCount, 20],
            #"minLength": [108+leftMargin, self.minLength, 3],
            #"maxLength": [145+leftMargin, self.maxLength, 10],
        }
        topLineLabels = {
            "wcText": [31 + leftMargin, 78, 'words', 'left'],

            #"wcText": [31+leftMargin, 78, 'words with', 'left'],

            # "lenTextTwo": [133+leftMargin, 10, u'–', 'center'],
            #"lenTextThree": [176+leftMargin, -0, 'letters', 'left'],
        }

        # for label, values in topLineFields.items():
        #     setattr(self.w, label, EditText((values[0], 0+yPos, 28, 22), text=values[1], placeholder=str(values[2])))

        self.w.wordCount = EditText((0 + leftMargin, 0 + yPos, 28, 22),
                                    text=self.wordCount,
                                    placeholder=self.wordCount,
                                    callback=self.wordCountCallback)

        for label, values in topLineLabels.items():
            setattr(
                self.w, label,
                TextBox((values[0], 3 + yPos, values[1], 22),
                        text=values[2],
                        alignment=values[3]))

        yPos += lineHeight * 1.3

        self.loadDictionaries()

        # language selection
        languageOptions = list(self.languageNames)

        self.w.source = PopUpButton((leftMargin, yPos, 85, 20), [],
                                    sizeStyle="small",
                                    callback=self.changeSourceCallback)
        self.w.source.setItems(languageOptions)

        self.w.source.set(4)  #default to English for now
        self.source = None
        self.source = self.w.source.get(
        )  #get value, to use for other functions

        yPos += lineHeight * 1.2

        checkBoxSize = 18
        self.w.listOutput = CheckBox(
            (leftMargin, yPos, checkBoxSize, checkBoxSize),
            "",
            sizeStyle="small",
            callback=self.sortedCallback)
        self.w.listLabel = TextBox(
            (checkBoxSize + 5, yPos + 2, -leftMargin, checkBoxSize),
            "Output as list sorted by width",
            sizeStyle="small")

        yPos += lineHeight * 1.2

        checkBoxSize = 18
        self.w.openCloseContext = CheckBox(
            (leftMargin, yPos, checkBoxSize, checkBoxSize),
            "",
            sizeStyle="small",
            callback=self.sortedCallback)
        self.w.openCloseContextLabel = TextBox(
            (checkBoxSize + 5, yPos + 2, -leftMargin, checkBoxSize),
            "Show open+close context {n}",
            sizeStyle="small")

        yPos += lineHeight * 1.2

        self.w.mirroredPair = CheckBox(
            (leftMargin, yPos, checkBoxSize, checkBoxSize),
            "",
            sizeStyle="small",
            callback=self.sortedCallback)
        self.w.mirroredPairLabel = TextBox(
            (checkBoxSize + 5, yPos + 2, -leftMargin, checkBoxSize),
            "Show mirrored pair (LRL)",
            sizeStyle="small")

        self.sorted = self.w.listOutput.get()

        self.w.bind("close", self.deactivateModule)
        self.w.open()

    def sortedCallback(self, sender):
        self.sorted = self.w.listOutput.get()
        self.wordsForMMPair()

    def wordCountCallback(self, sender):
        #print ('old', self.wordCount)

        self.wordCount = self.w.wordCount.get() or 1

        #update space center
        self.wordsForMMPair()

    #from word-o-mat
    def loadDictionaries(self):
        """Load the available wordlists and read their contents."""
        self.dictWords = {}
        self.allWords = []
        self.outputWords = []

        self.textfiles = [
            'catalan', 'czech', 'danish', 'dutch', 'ukacd', 'finnish',
            'french', 'german', 'hungarian', 'icelandic', 'italian', 'latin',
            'norwegian', 'polish', 'slovak', 'spanish', 'vietnamese'
        ]
        self.languageNames = [
            'Catalan', 'Czech', 'Danish', 'Dutch', 'English', 'Finnish',
            'French', 'German', 'Hungarian', 'Icelandic', 'Italian', 'Latin',
            'Norwegian', 'Polish', 'Slovak', 'Spanish', 'Vietnamese syllables'
        ]

        #self.source = getExtensionDefault("com.cjtype.MM2SpaceCenter.source", 4)

        bundle = ExtensionBundle("MM2SpaceCenter")
        contentLimit = '*****'  # If word list file contains a header, start looking for content after this delimiter

        # read included textfiles
        for textfile in self.textfiles:
            path = bundle.getResourceFilePath(textfile)
            #print (path)
            with codecs.open(path, mode="r", encoding="utf-8") as fo:
                lines = fo.read()

            self.dictWords[textfile] = lines.splitlines(
            )  # this assumes no whitespace has to be stripped

            # strip header
            try:
                contentStart = self.dictWords[textfile].index(contentLimit) + 1
                self.dictWords[textfile] = self.dictWords[textfile][
                    contentStart:]
            except ValueError:
                pass

        # read user dictionary
        with open('/usr/share/dict/words', 'r') as userFile:
            lines = userFile.read()
        self.dictWords["user"] = lines.splitlines()

        #print ('load dicts')

    def changeSourceCallback(self, sender):
        """On changing source/wordlist, check if a custom word list should be loaded."""
        customIndex = len(self.textfiles) + 2
        if sender.get() == customIndex:  # Custom word list
            try:
                filePath = getFile(
                    title="Load custom word list",
                    messageText=
                    "Select a text file with words on separate lines",
                    fileTypes=["txt"])[0]
            except TypeError:
                filePath = None
                self.customWords = []
                print("Input of custom word list canceled, using default")
            if filePath is not None:
                with codecs.open(filePath, mode="r", encoding="utf-8") as fo:
                    lines = fo.read()
                # self.customWords = lines.splitlines()
                self.customWords = []
                for line in lines.splitlines():
                    w = line.strip()  # strip whitespace from beginning/end
                    self.customWords.append(w)

        self.source = self.w.source.get()

        #update space center
        self.wordsForMMPair()

        #print ('source changed')

    def sortWordsByWidth(self, wordlist):
        """Sort output word list by width."""
        f = self.font
        wordWidths = []

        for word in wordlist:
            unitCount = 0
            for char in word:
                try:
                    glyphWidth = f[char].width
                except:
                    try:
                        gname = self.glyphNamesForValues[char]
                        glyphWidth = f[gname].width
                    except:
                        glyphWidth = 0
                unitCount += glyphWidth
            # add kerning
            for i in range(len(word) - 1):
                pair = list(word[i:i + 2])
                unitCount += int(self.findKerning(pair))
            wordWidths.append(unitCount)

        wordWidths_sorted, wordlist_sorted = zip(*sorted(
            zip(wordWidths, wordlist)))  # thanks, stackoverflow
        return wordlist_sorted

    def findKerning(self, chars):
        """Helper function to find kerning between two given glyphs.
        This assumes MetricsMachine style group names."""

        markers = ["@MMK_L_", "@MMK_R_"]
        keys = [c for c in chars]

        for i in range(2):
            allGroups = self.font.groups.findGlyph(chars[i])
            if len(allGroups) > 0:
                for g in allGroups:
                    if markers[i] in g:
                        keys[i] = g
                        continue

        key = (keys[0], keys[1])
        if self.font.kerning.has_key(key):
            return self.font.kerning[key]
        else:
            return 0

    def MMPairChangedObserver(self, sender):
        #add code here for when myObserver is triggered
        currentPair = sender["pair"]
        if currentPair == self.pair:
            return

        self.pair = currentPair

        #print ('current MM pair changed', self.pair)
        self.wordsForMMPair()

        #pass

    # def getMetricsMachineController(self):
    #     # Iterate through ALL OBJECTS IN PYTHON!
    #     import gc
    #     for obj in gc.get_objects():
    #         if hasattr(obj, "__class__"):
    #             # Does this one have a familiar name? Cool. Assume that we have what we are looking for.
    #             if obj.__class__.__name__ == "MetricsMachineController":
    #                 return obj

    def setSpaceCenter(self, font, text):
        currentSC = CurrentSpaceCenter()
        if currentSC is None:
            print('opening space center, click back into MM window')
            OpenSpaceCenter(font, newWindow=False)
            currentSC = CurrentSpaceCenter()
        currentSC.setRaw(text)

    def randomly(self, seq):
        shuffled = list(seq)
        random.shuffle(shuffled)
        return iter(shuffled)

    def gname2char(self, f, gname):
        uni = f[gname].unicodes[0]
        char = chr(uni)
        return char

    def checkForUnencodedGname(self, font, gname):
        glyphIsEncoded = False

        escapeList = ['slash', 'backslash']

        if (not font[gname].unicodes) or (gname in escapeList):
            scString = '/' + gname + ' '
        else:
            scString = self.gname2char(font, gname)
            glyphIsEncoded = True

        return (scString, glyphIsEncoded)

    def getPairstring(self, pair):

        left, self.leftEncoded = self.checkForUnencodedGname(
            self.font, pair[0])
        right, self.rightEncoded = self.checkForUnencodedGname(
            self.font, pair[1])

        pairstring = left + right

        return pairstring

    #convert char gnames to chars to find words in dict
    def pair2char(self, pair):

        debug = False

        try:
            #print ('pair =', pair)
            left = self.gname2char(CurrentFont(), pair[0])
            right = self.gname2char(CurrentFont(), pair[1])
            pair_char = (left, right)
            return pair_char
        except:
            if debug == True:
                print("couldn't convert pair to chars")
            return pair

    def lcString(self, pairstring):
        string = 'non' + pairstring + 'nono' + pairstring + 'oo'
        return string

    def ucString(self, pairstring):
        string = 'HH' + pairstring + 'HOHO' + pairstring + 'OO'
        return string

    openClosePairs = {

        # initial/final punctuation (from https://www.compart.com/en/unicode/category/Pi and https://www.compart.com/en/unicode/category/Pf)
        "‚": "‘",
        "„": "“",
        "„": "”",
        "‘": "’",
        "‛": "’",
        "“": "”",
        "‟": "”",
        "‹": "›",
        "›": "‹",
        "«": "»",
        "»": "«",
        "⸂": "⸃",
        "⸄": "⸅",
        "⸉": "⸊",
        "⸌": "⸍",
        "⸜": "⸝",
        "⸠": "⸡",
        "”": "”",
        "’": "’",

        # Miscellaneous but common open/close pairs
        "'": "'",
        '"': '"',
        "¡": "!",
        "¿": "?",
        "←": "→",
        "→": "←",

        # opening/closing punctuation (from https://www.compart.com/en/unicode/category/Ps & https://www.compart.com/en/unicode/category/Pe)
        "(": ")",
        "[": "]",
        "{": "}",
        "༺": "༻",
        "༼": "༽",
        "᚛": "᚜",
        "‚": "‘",
        "„": "“",
        "⁅": "⁆",
        "⁽": "⁾",
        "₍": "₎",
        "⌈": "⌉",
        "⌊": "⌋",
        "〈": "〉",
        "❨": "❩",
        "❪": "❫",
        "❬": "❭",
        "❮": "❯",
        "❰": "❱",
        "❲": "❳",
        "❴": "❵",
        "⟅": "⟆",
        "⟦": "⟧",
        "⟨": "⟩",
        "⟪": "⟫",
        "⟬": "⟭",
        "⟮": "⟯",
        "⦃": "⦄",
        "⦅": "⦆",
        "⦇": "⦈",
        "⦉": "⦊",
        "⦋": "⦌",
        "⦍": "⦎",
        "⦏": "⦐",
        "⦑": "⦒",
        "⦓": "⦔",
        "⦕": "⦖",
        "⦗": "⦘",
        "⧘": "⧙",
        "⧚": "⧛",
        "⧼": "⧽",
        "⸢": "⸣",
        "⸤": "⸥",
        "⸦": "⸧",
        "⸨": "⸩",
        "〈": "〉",
        "《": "》",
        "「": "」",
        "『": "』",
        "【": "】",
        "〔": "〕",
        "〖": "〗",
        "〘": "〙",
        "〚": "〛",
        "〝": "〞",
        "⹂": "〟",
        "﴿": "﴾",
        "︗": "︘",
        "︵": "︶",
        "︷": "︸",
        "︹": "︺",
        "︻": "︼",
        "︽": "︾",
        "︿": "﹀",
        "﹁": "﹂",
        "﹃": "﹄",
        "﹇": "﹈",
        "﹙": "﹚",
        "﹛": "﹜",
        "﹝": "﹞",
        "(": ")",
        "[": "]",
        "{": "}",
        "⦅": "⦆",
        "「": "」",
    }

    def openCloseContext(self, pair):
        if self.w.openCloseContext.get() == True:

            # get unicodes to make sure we don’t show pairs that don’t exist in the font
            # TODO? may be better to move outside this function, if running it each time is slow. BUT it would have to listen for the CurrentFont to change.
            unicodesInFont = [
                u for glyph in CurrentFont() for u in glyph.unicodes
            ]

            left, self.leftEncoded = self.checkForUnencodedGname(
                self.font, pair[0])
            right, self.rightEncoded = self.checkForUnencodedGname(
                self.font, pair[1])

            openCloseString = ""

            for openClose in self.openClosePairs.items():
                # if both sides of pair are in an open+close pair, just add them
                if openClose[0] == left and openClose[1] == right:
                    openCloseString += left + right + " "
                # if the left is in an openClose pair and its companion is in the font, add them
                if openClose[0] == left and ord(
                        openClose[1]) in unicodesInFont:
                    openCloseString += left + right + self.openClosePairs[
                        left] + " "
                # if the right is in an openClose pair and its companion is in the font, add them
                if openClose[1] == right and ord(
                        openClose[0]) in unicodesInFont:
                    openCloseString += openClose[0] + left + right + " "
                else:
                    continue

            return openCloseString
        else:
            return ""

    # make mirrored pair to judge symmetry of kerns
    def pairMirrored(self, pair):
        if self.w.mirroredPair.get() == True:
            left, self.leftEncoded = self.checkForUnencodedGname(
                self.font, pair[0])
            right, self.rightEncoded = self.checkForUnencodedGname(
                self.font, pair[1])
            return left + right + left + " "
        else:
            return ""

    def wordsForMMPair(self, ):

        self.mixedCase = False

        ### temp comment out to check speed
        self.source = self.w.source.get()
        wordsAll = self.dictWords[self.textfiles[self.source]]

        #default values are hard coded for now
        #self.wordCount = self.getIntegerValue(self.w.wordCount)

        #v = self.getIntegerValue(self.w.wordCount)

        wordCountValue = int(self.wordCount)

        #print(v)

        #print ('self.wordCount', self.wordCount)

        #currently allows any word lenght, this could be customized later

        text = ''
        textList = []

        # try getting pairstring once in order to check if encoded
        pairstring = self.getPairstring(self.pair)

        #convert MM tuple into search pair to check uc, lc, mixed case. Maybe need a different var name here?
        pair2char = ''.join(self.pair2char(self.pair))

        #check Encoding

        #print (pairstring)

        #default value
        makeUpper = False

        if pair2char.isupper():
            #print (pairstring, 'upper')
            makeUpper = True
            #make lower for searching
            searchString = pair2char.lower()

        else:
            #print(pairstring, 'not upper')
            makeUpper = False
            searchString = pair2char
            pass

        #check for mixed case
        if self.pair2char(self.pair)[0].isupper():
            if self.pair2char(self.pair)[1].islower():
                if (self.leftEncoded == True) and (self.rightEncoded == True):
                    self.mixedCase = True

        try:
            currentSC = CurrentSpaceCenter()
            previousText = currentSC.getRaw()
        except:
            previousText = ''
            pass

        count = 0

        #self.usePhrases = False

        # more results for mixed case if we include lc words and capitalize
        if self.mixedCase == True:
            for word in self.randomly(wordsAll):

                # first look for words that are already mixed case
                if searchString in word:
                    #avoid duplicates
                    if not word in textList:

                        #print (word)
                        textList.append(word)
                        count += 1

                #then try capitalizing lowercase words
                if (searchString.lower() in word[:2]):
                    word = word.capitalize()
                    #avoid duplicates
                    if not word in textList:

                        #print (word)
                        textList.append(word)
                        count += 1

                #stop when you get enough results
                if count >= wordCountValue:
                    #print (text)

                    break

            pass

        else:
            for word in self.randomly(wordsAll):
                if searchString in word:

                    #avoid duplicates
                    if not word in textList:

                        #print (word)
                        textList.append(word)
                        count += 1

                #stop when you get enough results
                if count >= wordCountValue:
                    #print (text)

                    break

        if makeUpper == True:
            #make text upper again
            textList = list(text.upper() for text in textList)

        if not len(textList) == 0:
            #see if box is checked
            self.sorted = self.w.listOutput.get()

            #self.sorted = False
            if self.sorted == True:
                sortedText = self.sortWordsByWidth(textList)

                textList = sortedText

                joinString = "\\n"
                text = joinString.join([str(word) for word in textList])

                if self.w.mirroredPair.get(
                ) == True:  #if "start with mirrored pair" is checked, add this to text
                    text = self.pairMirrored(self.pair) + joinString + text
                if self.w.openCloseContext.get(
                ) == True:  # if "show open+close" is checked, add this to text
                    text = self.openCloseContext(self.pair) + text

            else:
                text = ' '.join([str(word) for word in textList])
                if self.w.mirroredPair.get(
                ) == True:  #if "start with mirrored pair" is checked, add this to text
                    text = self.pairMirrored(self.pair) + text
                if self.w.openCloseContext.get(
                ) == True:  # if "show open+close" is checked, add this to text
                    text = self.openCloseContext(self.pair) + text

        # if no words are found, show spacing string and previous text
        if len(text) == 0:

            #do i need to get pairstring again or can I used the previous one?
            #pairstring = self.getPairstring(self.pair)

            previousText = '\\n no words for pair ' + pairstring

            self.messageText = '😞 no words found: ' + pairstring
            self.w.myTextBox.set(self.messageText)

            if makeUpper == True:
                text = self.ucString(pairstring) + previousText
                if self.w.mirroredPair.get(
                ) == True:  #if "start with mirrored pair" is checked, add this to text
                    text = self.pairMirrored(self.pair) + text
                if self.w.openCloseContext.get(
                ) == True:  # if "show open+close" is checked, add this to text
                    text = self.openCloseContext(self.pair) + text

            else:
                text = self.lcString(pairstring) + previousText
                if self.w.mirroredPair.get(
                ) == True:  #if "start with mirrored pair" is checked, add this to text
                    text = self.pairMirrored(self.pair) + text
                if self.w.openCloseContext.get(
                ) == True:  # if "show open+close" is checked, add this to text
                    text = self.openCloseContext(self.pair) + text

            text = text.lstrip()  #remove whitespace
            self.setSpaceCenter(self.font, text)

        else:
            #set space center if words are found
            #not sure why there's always a /slash in from of the first word, added ' '+ to avoid losing the first word

            text = text.lstrip()  #remove whitespace

            self.setSpaceCenter(self.font, text)

            self.messageText = '😎 words found: ' + pairstring
            self.w.myTextBox.set(self.messageText)
Пример #38
0
class Unicron(object):
    def __init__(self):
        self.locations = [
            'User Agents', 'Global Agents', 'Global Daemons', 'System Agents',
            'System Daemons'
        ]
        self.listItems = []
        self.selected = {}

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

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

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

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

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

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

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

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

        w, h = sourceImage.size()

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

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

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

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

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

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

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

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

        self.prefsSetStyle(self)

        self.w.open()

    def prefsSetStyle(self, sender):
        style = self.prefsWindow.style.getItem()
        self._changePref(self, 'windowStyle', style)

        if style == 'System':
            style = NSUserDefaults.standardUserDefaults().stringForKey_(
                'AppleInterfaceStyle')
        if style == 'Dark':
            winAppearance = 'NSAppearanceNameVibrantDark'
        else:
            winAppearance = 'NSAppearanceNameVibrantLight'
        appearance = NSAppearance.appearanceNamed_(winAppearance)
        self.w._window.setAppearance_(appearance)
        self.prefsWindow._window.setAppearance_(appearance)

    def prefsRestoreWarnings(self, sender):
        self._changePref(self, 'showSystemWarning', True)

    def populateList(self, sender):
        self.selected.clear()
        self.w.list._removeSelection()
        item = self.pathList.titleOfSelectedItem()

        for i in range(len(self.w.list)):
            del self.w.list[0]

        thisItem = {}
        image = None
        id = os.getuid()
        systemWarning = "You should not edit or remove existing system's daemons. These jobs are required for a working macOS system."

        if item != 'Active Daemons':
            if item == 'User Agents':
                homedir = os.path.expanduser('~')
                path = homedir + '/Library/LaunchAgents'
                # If the folder doesn't exist in the user folder, create it
                try:
                    os.listdir(path)
                except:
                    os.mkdir(path)
            elif item == 'Global Agents':
                path = '/Library/LaunchAgents'
            elif item == 'Global Daemons':
                path = '/Library/LaunchDaemons'
            elif item == 'System Agents':
                path = '/System/Library/LaunchAgents'
                self._warning(self, systemWarning, "showSystemWarning")
            elif item == 'System Daemons':
                path = '/System/Library/LaunchDaemons'
                self._warning(self, systemWarning, "showSystemWarning")

            items = []
            files = os.listdir(path)
            count = 0

            for file in files:
                if file.endswith('.plist'):
                    file = file.replace('.plist', '')
                    try:
                        pid = launchd.LaunchdJob(file).pid
                    except:
                        pid = False
                    if launchd.LaunchdJob(file).exists() and pid != None:
                        image = NSImage.imageNamed_(NSImageNameStatusAvailable)
                    elif launchd.LaunchdJob(file).exists() and pid == None:
                        image = NSImage.imageNamed_(
                            NSImageNameStatusPartiallyAvailable)
                    else:
                        image = NSImage.imageNamed_(NSImageNameStatusNone)
                    state = True
                    thisItem['image'] = image
                    thisItem['name'] = file
                    self.w.list.append(thisItem)
                    count += 1
            self.w.counter.set(str(count) + ' Jobs')

    def _showInFinder(self, sender):
        file = self.selected['file']
        subprocess.call(['open', '-R', '%s' % file],
                        cwd='/',
                        shell=False,
                        universal_newlines=False)

    def _loadUnloadDaemon(self, sender, command):
        self.w.list.scrollToSelection()
        name = self.selected['name']
        path = self.selected['file']

        if bool(launchd.LaunchdJob(name).exists()):
            try:
                subprocess.call(
                    ['launchctl', 'unload', '%s' % path],
                    cwd='/',
                    shell=False,
                    universal_newlines=False)
            except:
                return
        else:
            try:
                subprocess.call(
                    ['launchctl', 'load', '%s' % path],
                    cwd='/',
                    shell=False,
                    universal_newlines=False)
            except:
                return

        self.populateList(self)

    def _removeDaemon(self, sender):
        self._loadUnloadDaemon(self, 'unload')
        self._loadUnloadDaemon(self, 'remove')

    # def addGroup(self, sender, key, value):

    def _selectionCallback(self, sender):
        try:
            if not self.w.list.getSelection():
                # Application did not finish loading yet
                pass
            else:
                # Get job name
                self.selected.clear()
                job = sender.get()[self.w.list.getSelection()[0]]
                self.selected['name'] = job['name']
                self.valueGroups = []
                # Get job path and file location
                item = self.pathList.titleOfSelectedItem()

                if 'User' in item:
                    import getpass
                    username = getpass.getuser()
                    user = username
                    path = '/Users/%s/Library/Launch' % username
                elif 'Global' in item:
                    user = '******'
                    path = '/Library/Launch'
                elif 'System' in item:
                    user = '******'
                    path = '/System/Library/Launch'
                if 'Agents' in item:
                    path += 'Agents/'
                else:
                    path += 'Daemons/'

                self.selected['path'] = path
                self.selected['file'] = str(self.selected['path'].replace(
                    ' ', '\ ')) + job['name'].replace(' ', '\ ') + '.plist'
                f = open(self.selected['file'], "r")
                self.selected['raw'] = str(f.read())
                self.selected['short'] = (
                    self.selected['name'][:32] + '…') if len(
                        self.selected['name']) > 32 else self.selected['name']
                # Get status
                if job['image'] == NSImage.imageNamed_(NSImageNameStatusNone):
                    status = None
                else:
                    status = 'Available'
                self.selected['status'] = status

                index = sender.getSelection()[0]
                relativeRect = sender.getNSTableView().rectOfRow_(index)

                self.pop = Popover((300, 100))

                self.pop.tabs = Tabs((20, 40, -20, -20),
                                     ["Editor", "Raw View"])
                self.pop.tabs._nsObject.setTabViewType_(NSNoTabsNoBorder)

                self.pop.tabBtn = SegmentedButton(
                    (10, 10, -10, 20),
                    [dict(title="Editor"),
                     dict(title="Raw View")],
                    callback=self._segmentPressed,
                    selectionStyle='one')
                self.pop.tabBtn.set(0)

                self.edit = self.pop.tabs[0]

                self.rawEdit = self.pop.tabs[1]
                self.rawEdit.editor = TextEditor((0, 0, -0, -45),
                                                 text=self.selected['raw'])

                self.selected['dict'] = launchd.plist.read(
                    self.selected['name'])

                # TODO: Add stackview to scrollview as group
                # Waiting for merge into master: https://github.com/robotools/vanilla/issues/132
                self.edit.stack = VerticalStackGroup((0, 0, -0, -45))

                for idx, (key, value) in enumerate(
                        sorted(self.selected['dict'].items())):
                    group = ValueGroup((0, 0, -0, -0),
                                       sender=self,
                                       key=key,
                                       value=value,
                                       idx=idx)
                    self.valueGroups.append(group)
                    self.edit.stack.addView(
                        self.valueGroups[idx], 300,
                        self.valueGroups[idx].getPosSize()[3])

                self.pop.save = Button((20, -50, -20, 40),
                                       "Save",
                                       callback=self._savePlist)
                self.pop.save.enable(False)
                self.pop.open(parentView=sender.getNSTableView(),
                              preferredEdge='right',
                              relativeRect=relativeRect)
        except:
            pass

    # TODO
    def _savePlist(self, sender):
        return

    def _segmentPressed(self, sender):
        self.pop.tabs.set(self.pop.tabBtn.get())

    def _menuCallback(self, sender):
        items = []

        items.append(dict(title=self.selected['short'], enabled=False))
        items.append("----")
        if self.selected['status'] == None:
            load, able = 'Load', 'Enable'
        else:
            load, able = 'Unload', 'Disable'

        loadCallback = partial(self._loadUnloadDaemon, command=load)
        ableCallback = partial(self._loadUnloadDaemon, command=able)
        items.append(dict(title=load, callback=loadCallback))
        items.append(dict(title=able, callback=ableCallback))
        items.append(dict(title="Show in Finder", callback=self._showInFinder))
        items.append(dict(title="Refresh list", callback=self.populateList))

        return items

    def _loadPrefs(self, sender):
        with open(self.prefsFolder + self.prefsFile, 'rb') as fp:
            self.prefs = plistlib.load(fp)
        return self.prefs

    def _savePrefs(self, sender):
        with open(self.prefsFolder + self.prefsFile, 'wb') as fp:
            plistlib.dump(self.prefs, fp)

    def _changePref(self, sender, key, value):
        self.prefs[key] = value
        self._savePrefs(self)

    def _warning(self, sender, warning, prefKey):
        if self.prefs.get(prefKey):
            self.warning = Sheet((400, 140), self.w)
            self.warning.img = ImageView((10, 10, 60, 60))
            self.warning.img.setImage(imageNamed=NSImageNameCaution)
            self.warning.txt = TextBox((70, 10, -10, -40),
                                       "Warning\n" + warning)

            callback = partial(self._changePref,
                               key=prefKey,
                               value=not self.prefs.get(prefKey))
            self.warning.check = CheckBox((70, 80, -10, 20),
                                          "Always show this warning",
                                          value=self.prefs.get(prefKey),
                                          callback=callback)

            self.warning.closeButton = Button((10, 110, -10, 20),
                                              "I understand",
                                              callback=self._closeWarning)
            self.warning.setDefaultButton(self.warning.closeButton)
            self.warning.center()
            self.w.list.enable(False)
            self.warning.open()

    def _closeWarning(self, sender):
        self.warning.close()
        self.w.list.enable(True)
        del self.warning
Пример #39
0
    script = 'fill(random(), random(), random())\nrect(10+random()*100, 10+random()*100, 200, 300)'
    newDrawing()
    namespace = DrawBotNamespace(_drawBotDrawingTool,
                                 _drawBotDrawingTool._magicVariables)
    _drawBotDrawingTool._addToNamespace(namespace)

    # Creates a new standard output, catching all print statements and tracebacks.
    stdout = StdOutput(output, outputView=outputWindow.outputView)
    stderr = StdOutput(output,
                       isError=True,
                       outputView=outputWindow.outputView)

    # Calls DrawBot's ScriptRunner with above parameters.
    ScriptRunner(script,
                 None,
                 namespace=namespace,
                 stdout=stdout,
                 stderr=stderr)
    _drawBotDrawingTool._drawInContext(context)
    pdfDocument = _drawBotDrawingTool.pdfImage()


if __name__ == '__main__':

    w = Window((10, 10, 400, 200), 'Window')
    w.button = Button((20, 20, 100, 30), 'Hit', callback=hitCallback)
    w.open()

    outputWindow = Window((500, 10, 400, 300), minSize=(1, 1), closable=True)
    outputWindow.outputView = OutPutEditor((0, 0, -0, -0), readOnly=True)
    outputWindow.open()
Пример #40
0
class CornersRounder(BaseWindowController):

    layerNames = []
    targetLayerName = None
    sourceLayerName = None

    roundingsData = None

    selectedFont = None
    allFonts = None

    def __init__(self):
        super(CornersRounder, self).__init__()

        self._initLogger()
        self.rounderLogger.info('we are on air! start: __init__()')

        self._updateFontsAttributes()
        if self.allFonts != []:
            self.selectedFont = self.allFonts[0]

        self._initRoundingsData()
        if self.selectedFont is not None:
            self.layerNames = ['foreground'] + self.selectedFont.layerOrder
            self.sourceLayerName = self.layerNames[0]
            self.targetLayerName = self.layerNames[0]

            if PLUGIN_LIB_NAME in self.selectedFont.lib:
                self.roundingsData = pullRoundingsDataFromFont(
                    self.selectedFont)

        self.w = Window((0, 0, PLUGIN_WIDTH, PLUGIN_HEIGHT), PLUGIN_TITLE)

        jumpingY = MARGIN_VER
        self.w.fontPopUp = PopUpButton(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            [os.path.basename(item.path) for item in self.allFonts],
            callback=self.fontPopUpCallback)

        jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER
        self.w.sepLineOne = HorizontalLine(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['HorizontalLineThickness']))

        jumpingY += MARGIN_VER
        for eachI in range(LABELS_AMOUNT):
            singleLabel = Label((MARGIN_HOR, jumpingY, NET_WIDTH,
                                 vanillaControlsSize['EditTextRegularHeight']),
                                attachCallback=self.attachCallback,
                                labelName='')

            setattr(self.w, 'label{:d}'.format(eachI), singleLabel)
            jumpingY += MARGIN_ROW + vanillaControlsSize[
                'EditTextRegularHeight']
        self._fromRoundingsData2LabelCtrls()

        jumpingY += MARGIN_ROW
        self.w.sepLineTwo = HorizontalLine(
            (MARGIN_HOR, jumpingY, NET_WIDTH,
             vanillaControlsSize['HorizontalLineThickness']))
        jumpingY += MARGIN_ROW * 2

        # tables
        labelListWdt = 78
        marginTable = 1
        angleListWdt = (NET_WIDTH - labelListWdt - marginTable * 3) // 3
        tableLineHeight = 16
        tableHgt = LABELS_AMOUNT * tableLineHeight + 33

        captionY = jumpingY
        captionOffset = 12
        jumpingY += vanillaControlsSize['TextBoxSmallHeight'] + MARGIN_ROW

        labelColumnDesc = [{"title": "labelName", 'editable': True}]
        jumpingX = MARGIN_HOR

        self.w.labelNameList = List(
            (jumpingX, jumpingY, labelListWdt, tableHgt), [],
            columnDescriptions=labelColumnDesc,
            showColumnTitles=True,
            editCallback=self.labelNameListCallback,
            rowHeight=tableLineHeight,
            drawHorizontalLines=True,
            drawVerticalLines=True,
            autohidesScrollers=True,
            allowsMultipleSelection=False)

        anglesColumnDesc = [{
            "title": "rad",
            'editable': True
        }, {
            "title": "bcp",
            'editable': True
        }]

        jumpingX += labelListWdt + marginTable
        self.w.fortyFiveCaption = TextBox(
            (jumpingX + captionOffset, captionY, angleListWdt,
             vanillaControlsSize['TextBoxSmallHeight']),
            u'45°',
            sizeStyle='small')

        self.w.fortyFiveList = List(
            (jumpingX, jumpingY, angleListWdt, tableHgt), [],
            columnDescriptions=anglesColumnDesc,
            showColumnTitles=True,
            rowHeight=tableLineHeight,
            editCallback=self.fortyFiveListCallback,
            drawHorizontalLines=True,
            drawVerticalLines=True,
            autohidesScrollers=True,
            allowsMultipleSelection=False)

        jumpingX += angleListWdt + marginTable
        self.w.ninetyCaption = TextBox(
            (jumpingX + captionOffset, captionY, angleListWdt,
             vanillaControlsSize['TextBoxSmallHeight']),
            u'90°',
            sizeStyle='small')

        self.w.ninetyList = List((jumpingX, jumpingY, angleListWdt, tableHgt),
                                 [],
                                 columnDescriptions=anglesColumnDesc,
                                 showColumnTitles=True,
                                 rowHeight=tableLineHeight,
                                 editCallback=self.ninetyListCallback,
                                 drawHorizontalLines=True,
                                 drawVerticalLines=True,
                                 autohidesScrollers=True,
                                 allowsMultipleSelection=False)

        jumpingX += angleListWdt + marginTable
        self.w.hundredThirtyFiveCaption = TextBox(
            (jumpingX + captionOffset, captionY, angleListWdt,
             vanillaControlsSize['TextBoxSmallHeight']),
            u'135°',
            sizeStyle='small')

        self.w.hundredThirtyFiveList = List(
            (jumpingX, jumpingY, angleListWdt, tableHgt), [],
            columnDescriptions=anglesColumnDesc,
            showColumnTitles=True,
            rowHeight=tableLineHeight,
            editCallback=self.hundredThirtyFiveListCallback,
            drawHorizontalLines=True,
            drawVerticalLines=True,
            autohidesScrollers=True,
            allowsMultipleSelection=False)
        self._fromRoundingsData2Lists()
        jumpingY += tableHgt + MARGIN_ROW * 2

        rgtX = MARGIN_HOR + NET_WIDTH * .52
        midWdt = NET_WIDTH * .48
        self.w.pushButton = SquareButton(
            (MARGIN_HOR, jumpingY, midWdt,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Push Data',
            callback=self.pushButtonCallback)
        self.w.clearLibButton = SquareButton(
            (rgtX, jumpingY, midWdt,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Clear Lib',
            callback=self.clearLibButtonCallback)

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

        self.w.sourceLayerCaption = TextBox(
            (MARGIN_HOR, jumpingY, midWdt,
             vanillaControlsSize['TextBoxRegularHeight']), 'source layer')
        self.w.targetLayerCaption = TextBox(
            (rgtX, jumpingY, midWdt,
             vanillaControlsSize['TextBoxRegularHeight']), 'target layer')

        jumpingY += vanillaControlsSize['TextBoxRegularHeight'] + MARGIN_ROW
        self.w.sourceLayerPopUp = PopUpButton(
            (MARGIN_HOR, jumpingY, midWdt,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            self.layerNames,
            callback=self.sourceLayerPopUpCallback)
        if self.layerNames and self.sourceLayerName:
            self.w.sourceLayerPopUp.set(
                self.layerNames.index(self.sourceLayerName))

        self.w.targetLayerCombo = ComboBox(
            (rgtX, jumpingY, midWdt,
             vanillaControlsSize['PopUpButtonRegularHeight']),
            self.layerNames,
            callback=self.targetLayerComboCallback)
        if self.layerNames and self.targetLayerName:
            self.w.targetLayerCombo.set(self.targetLayerName)

        jumpingY += vanillaControlsSize[
            'PopUpButtonRegularHeight'] + MARGIN_ROW * 4
        self.w.roundGlyphButton = SquareButton(
            (MARGIN_HOR, jumpingY, midWdt,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            u'Round Glyph (⌘+R)',
            callback=self.roundGlyphButtonCallback)
        self.w.roundGlyphButton.bind('r', ['command'])

        self.w.roundFontButton = SquareButton(
            (rgtX, jumpingY, midWdt,
             vanillaControlsSize['ButtonRegularHeight'] * 1.5),
            'Round Font',
            callback=self.roundFontButtonCallback)
        jumpingY += vanillaControlsSize[
            'ButtonRegularHeight'] * 1.5 + MARGIN_VER * 2

        self.w.resize(PLUGIN_WIDTH, jumpingY)

        self._checkPushButton()
        self._checkRoundButtons()
        self.setUpBaseWindowBehavior()
        addObserver(self, 'fontDidOpenCallback', 'fontDidOpen')
        addObserver(self, 'fontDidCloseCallback', 'fontDidClose')
        addObserver(self, '_keyDown', 'keyDown')
        self.w.open()

    # private methods
    def _initLogger(self):
        # create a logger
        self.rounderLogger = logging.getLogger('rounderLogger')
        self.rounderLogger.setLevel(logging.INFO)
        # create file handler which logs info messages
        fileHandle = logging.FileHandler('cornersRounderLogger.log')
        fileHandle.setLevel(logging.INFO)
        # create console handler with a higher log level, only errors
        # create formatter and add it to the handlers
        formatter = logging.Formatter(u'%(asctime)s – %(message)s')
        fileHandle.setFormatter(formatter)
        # add the handlers to the logger
        self.rounderLogger.addHandler(fileHandle)

    def _initRoundingsData(self):
        self.roundingsData = [
            makeRoundingsDataEmptyDict() for ii in range(LABELS_AMOUNT)
        ]

    def _updateFontsAttributes(self):
        self.allFonts = AllFonts()
        if self.allFonts == []:
            self.selectedFont = None

    def _updateRoundingsLabels(self, labels):
        for indexLabel, eachLabel in enumerate(labels):
            self.roundingsData[indexLabel]['labelName'] = '{}'.format(
                eachLabel['labelName'])

    def _updateRoundingsNumbers(self, data, keyStart):
        for indexRow, eachRow in enumerate(data):

            try:
                self.roundingsData[indexRow]['{}Rad'.format(keyStart)] = int(
                    eachRow['rad'])
            except ValueError:
                self.roundingsData[indexRow]['{}Rad'.format(keyStart)] = ''

            try:
                self.roundingsData[indexRow]['{}Bcp'.format(keyStart)] = int(
                    eachRow['bcp'])
            except ValueError:
                self.roundingsData[indexRow]['{}Bcp'.format(keyStart)] = ''

    def _fromRoundingsData2LabelCtrls(self):
        for eachI in range(LABELS_AMOUNT):
            try:
                labelName = self.roundingsData[eachI]['labelName']
            except IndexError as e:
                labelName = ''
            getattr(self.w, 'label{:d}'.format(eachI)).setLabelName(labelName)

    def _updateLayersCtrls(self):
        self.layerNames = ['foreground'] + self.selectedFont.layerOrder

        currentName = self.w.sourceLayerPopUp.getItems()[
            self.w.sourceLayerPopUp.get()]
        self.w.sourceLayerPopUp.setItems(self.layerNames)
        if currentName in self.layerNames:
            self.w.sourceLayerPopUp.set(self.layerNames.index(currentName))

        currentName = self.w.targetLayerCombo.get()
        self.w.targetLayerCombo.setItems(self.layerNames)
        if currentName in self.layerNames:
            self.w.targetLayerCombo.set(currentName)

    def _extractDataFromRoundings(self, keyTitle):
        listData = [{
            'rad': aDict['{}Rad'.format(keyTitle)],
            'bcp': aDict['{}Bcp'.format(keyTitle)]
        } for aDict in self.roundingsData]
        return listData

    def _fromRoundingsData2Lists(self):
        labelNameListData = [{
            'labelName': aDict['labelName']
        } for aDict in self.roundingsData]
        self.w.labelNameList.set(labelNameListData)
        fortyFiveListData = self._extractDataFromRoundings('fortyFive')
        self.w.fortyFiveList.set(fortyFiveListData)
        ninetyListData = self._extractDataFromRoundings('ninety')
        self.w.ninetyList.set(ninetyListData)
        hundredThirtyFiveListData = self._extractDataFromRoundings(
            'hundredThirtyFive')
        self.w.hundredThirtyFiveList.set(hundredThirtyFiveListData)

    def _roundCurrentGlyph(self):
        if self.sourceLayerName == self.targetLayerName:
            self.showMessage(
                'ERROR',
                u'source layer name and target layer name should be different')
            return None

        currentGlyph = CurrentGlyph()
        if currentGlyph is not None:
            self.rounderLogger.info(
                'start: _roundCurrentGlyph(), glyph {} from {} {}'.format(
                    currentGlyph.name, self.selectedFont.info.familyName,
                    self.selectedFont.info.styleName))
            selectedFont = currentGlyph.getParent()
            roundingsData = pullRoundingsDataFromFont(selectedFont)

            if roundingsData is not None:
                makeGlyphRound(currentGlyph,
                               roundingsData,
                               sourceLayerName=self.sourceLayerName,
                               targetLayerName=self.targetLayerName)
                UpdateCurrentGlyphView()
                self.rounderLogger.info(
                    'end: _roundCurrentGlyph(), glyph {} from {} {}'.format(
                        currentGlyph.name, selectedFont.info.familyName,
                        selectedFont.info.styleName))
        elif currentGlyph is not None:
            self.showMessage('ERROR', NO_DATA_INTO_FONT)
            self.rounderLogger.error(NO_DATA_INTO_FONT)

        else:
            self.showMessage('ERROR', NO_GLYPH_TO_ROUND)
            self.rounderLogger.error(NO_GLYPH_TO_ROUND)

    # observers callbacks
    def _keyDown(self, notification):
        glyph = notification['glyph']
        pressedKeys = notification['event'].charactersIgnoringModifiers()
        modifierFlags = notification['event'].modifierFlags()
        if modifierFlags in MODIFIERS and MODIFIERS[
                modifierFlags] == 'CMD_LEFT' and pressedKeys == 'r':
            self._roundCurrentGlyph()

    def fontDidOpenCallback(self, notification):
        if self.allFonts != []:
            currentName = os.path.basename(
                self.allFonts[self.w.fontPopUp.get()].path)
        else:
            currentName = None
        self._updateFontsAttributes()
        newNames = [os.path.basename(item.path) for item in self.allFonts]
        self.w.fontPopUp.setItems(newNames)

        if currentName is not None:
            self.w.fontPopUp.set(newNames.index(currentName))

    def fontDidCloseCallback(self, notification):
        self._updateFontsAttributes()
        newNames = [os.path.basename(item.path) for item in self.allFonts]
        self.w.fontPopUp.setItems(newNames)

        if self.allFonts != []:
            self.selectedFont = self.allFonts[0]
            self.roundingsData = pullRoundingsDataFromFont(self.selectedFont)
            if self.roundingsData is None:
                self._initRoundingsData()
            self._fromRoundingsData2Lists()
            self._fromRoundingsData2LabelCtrls()
        else:
            self.selectedFont = None
            self.roundingsData = None

    def windowCloseCallback(self, sender):
        removeObserver(self, 'fontDidOpen')
        removeObserver(self, 'fontDidClose')
        removeObserver(self, 'keyDown')
        self.rounderLogger.info('that\'s all folks!')

    # standard callbacks
    def fontPopUpCallback(self, sender):
        self.selectedFont = self.allFonts[sender.get()]
        self.roundingsData = pullRoundingsDataFromFont(self.selectedFont)
        if self.roundingsData is None:
            self._initRoundingsData()
        self._fromRoundingsData2Lists()
        self._fromRoundingsData2LabelCtrls()
        self._updateLayersCtrls()
        self._checkPushButton()

    def attachCallback(self, sender):
        labelName = sender.get()
        attachLabelToSelectedPoints(labelName)

    def _checkPushButton(self):
        if hasattr(self.w, 'pushButton') is True:
            if PLUGIN_LIB_NAME not in self.selectedFont.lib or self.roundingsData != self.selectedFont.lib[
                    PLUGIN_LIB_NAME]:
                self.w.pushButton.enable(True)
            else:
                self.w.pushButton.enable(False)

    def labelNameListCallback(self, sender):
        self._updateRoundingsLabels(sender.get())
        self._checkPushButton()
        self._checkRoundButtons()

    def _checkRoundButtons(self):
        if hasattr(self.w, 'roundGlyphButton') is True and hasattr(
                self.w, 'roundFontButton'):
            if (PLUGIN_LIB_NAME in self.selectedFont.lib and self.roundingsData
                    != self.selectedFont.lib[PLUGIN_LIB_NAME]
                ) or self.roundingsData == DUMMY_ROUNDINGS:
                self.w.roundGlyphButton.enable(False)
                self.w.roundFontButton.enable(False)
            else:
                self.w.roundGlyphButton.enable(True)
                self.w.roundFontButton.enable(True)

    def fortyFiveListCallback(self, sender):
        self._updateRoundingsNumbers(sender.get(), 'fortyFive')
        self._checkPushButton()
        self._checkRoundButtons()

    def ninetyListCallback(self, sender):
        self._updateRoundingsNumbers(sender.get(), 'ninety')
        self._checkPushButton()
        self._checkRoundButtons()

    def hundredThirtyFiveListCallback(self, sender):
        self._updateRoundingsNumbers(sender.get(), 'hundredThirtyFive')
        self._checkPushButton()
        self._checkRoundButtons()

    def pushButtonCallback(self, sender):
        thisFont = self.selectedFont
        if thisFont is not None:
            pushRoundingsDataIntoFont(thisFont, self.roundingsData)
            self.showMessage(
                'INFO',
                DATA_PUSHED.format(familyName=thisFont.info.familyName,
                                   styleName=thisFont.info.styleName))
            self.rounderLogger.info(
                DATA_PUSHED.format(familyName=thisFont.info.familyName,
                                   styleName=thisFont.info.styleName))
        else:
            self.showMessage('ERROR', NO_FONT_TO_PUSH)
            self.rounderLogger.error(NO_FONT_TO_PUSH)
        self._checkPushButton()
        self._checkRoundButtons()

    def clearLibButtonCallback(self, sender):
        if PLUGIN_LIB_NAME in self.selectedFont.lib:
            del self.selectedFont.lib[PLUGIN_LIB_NAME]
        self._initRoundingsData()
        self._fromRoundingsData2Lists()
        self._fromRoundingsData2LabelCtrls()
        self._checkPushButton()
        self._checkRoundButtons()

    def sourceLayerPopUpCallback(self, sender):
        self.sourceLayerName = self.layerNames[sender.get()]

    def targetLayerComboCallback(self, sender):
        self.targetLayerName = sender.get()

    def roundGlyphButtonCallback(self, sender):
        if self.selectedFont == CurrentFont():
            self._roundCurrentGlyph()
        else:
            self.showMessage('ERROR', FONT_MISMATCH)
            self.rounderLogger.error(FONT_MISMATCH)

    def roundFontButtonCallback(self, sender):
        if self.sourceLayerName == self.targetLayerName:
            self.showMessage('ERROR', LAYERS_MATCH)
            self.rounderLogger.error(LAYERS_MATCH)
            return None

        if self.selectedFont == CurrentFont():
            self.rounderLogger.info(
                'start: roundFontButtonCallback(), {} {}'.format(
                    selectedFont.info.familyName, selectedFont.info.styleName))
            for eachGlyph in self.selectedFont:
                makeGlyphRound(eachGlyph,
                               self.roundingsData,
                               sourceLayerName=self.sourceLayerName,
                               targetLayerName=self.targetLayerName)
            self.rounderLogger.info(
                'end: roundFontButtonCallback(), {} {}'.format(
                    selectedFont.info.familyName, selectedFont.info.styleName))

        else:
            self.showMessage('ERROR', FONT_MISMATCH)
            self.rounderLogger.error(FONT_MISMATCH)
Пример #41
0
class RotateView(GeneralPlugin):
    @objc.python_method
    def settings(self):
        self.name = "Rotate View"

    @objc.python_method
    def start(self):
        newMenuItem = NSMenuItem(self.name, self.showWindow_)
        Glyphs.menu[WINDOW_MENU].append(newMenuItem)

    ## creates Vanilla Window
    #------------------------

    def showWindow_(self, sender):
        try:
            from vanilla import Group, Slider, TextBox, Window
            self.windowWidth = 300
            self.windowHeight = 240

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

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

            self.w.open()
            self.changeGlyph_(None)
            Glyphs.addCallback(
                self.changeGlyph_, UPDATEINTERFACE
            )  #will be called on ever change to the interface
        except:
            print(traceback.format_exc())

    @objc.python_method
    def __del__(self):
        Glyphs.removeCallback(self.changeGlyph_, UPDATEINTERFACE)

    ## slider callback
    #------------------------------

    @objc.python_method
    def sliderCallback(self, sender):
        currentValue = '{:.0f}'.format(sender.get())
        self.w.controlBox.textBox.set(str(currentValue) + "°")
        self.w.Preview._rotationFactor = float(currentValue)
        self.w.Preview.redraw()

    ## on Glyph Change, update the viewer
    #------------------------------

    def changeGlyph_(self, sender):
        self.w.controlBox.slider.getNSSlider().setEnabled_(
            Glyphs.font and Glyphs.font.selectedLayers)
        self.w.Preview.redraw()

    @objc.python_method
    def __file__(self):
        """Please leave this method unchanged"""
        return __file__
 class Test:
     
     def __init__(self):
         self.w = Window((400, 400))
         self.w.e = CodeEditor((0, 0, -0, -0), t, lexer=GlyphConstructionLexer())
         self.w.open()
Пример #43
0
    def show(self):
        self.w.show()

    def documentWindowToFront(self, sender=None):
        self.w.makeKey()

def do(sender):
    controller = getController()
    controller.runCode() # runt je script opnieuw.
    
def getController():
    document = AppKit.NSDocumentController.sharedDocumentController().currentDocument()
    print document
    
    if not document:
        raise DrawBotError("There is no document open")
    controller = document.vanillaWindowController
    try:
        controller._variableController.buildUI(variables)
        controller._variableController.show()
    except:
        controller._variableController = VariableController(variables, controller.runCode, document)

    return controller

w = Window((978, 388, 400, 400), 'Test Vanilla in DrawBot')
w.button = Button((10, 10, 150, 30), 'Do', callback=do)
w.checkbox = CheckBox((10, 150, 150, 30), 'Check', callback=do)
w.open()
class PenBallWizardController(object):

    def __init__(self):
        self.filters = PenBallFiltersManager()
        self.filters.loadFiltersFromJSON('/'.join([LOCALPATH, JSONFILE]))
        self.glyphNames = []
        self.observedGlyphs = []
        self.cachedFont = RFont(showUI=False)
        self.currentFont = CurrentFont()
        filtersList = self.filters.keys()
        if len(filtersList) > 0:
            self.currentFilterName = filtersList[0]
        else:
            self.currentFilterName = None
        self.fill = True

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

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

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

        self.updateControls()

        self.w.bind('close', self.end)
        self.launchWindow()
        self.w.open()

    def generateGlyphsToFont(self, sender):
        newFont = RFont(showUI=False)
        font = self.currentFont
        filterName = self.currentFilterName
        currentFilter = self.filters[filterName]
        if font is not None:
            glyphs = [font[glyphName] for glyphName in font.selection if glyphName in font]
            for glyph in glyphs:
                if len(glyph.components) > 0:
                    for comp in glyph.components:
                        baseGlyphName = comp.baseGlyph
                        baseGlyph = font[baseGlyphName]
                        baseFilteredGlyph = currentFilter(baseGlyph)
                        newFont.insertGlyph(baseFilteredGlyph, baseGlyphName)
                        newFont[baseGlyphName].unicode = baseFilteredGlyph.unicode
                filteredGlyph = currentFilter(glyph)
                if filteredGlyph is not None:
                    newFont.insertGlyph(filteredGlyph, glyph.name)
            newFont.showUI()

    def generateGlyphsToLayer(self, layerName):
        font = self.currentFont
        filterName = self.currentFilterName
        currentFilter = self.filters[filterName]
        if font is not None:
            glyphs = [font[glyphName] for glyphName in font.selection if glyphName in font]
            for glyph in glyphs:
                if len(glyph.components) == 0:
                    layerGlyph = glyph.getLayer(layerName)
                    filteredGlyph = currentFilter(glyph)
                    if filteredGlyph is not None:
                        layerGlyph.appendGlyph(filteredGlyph)

    def updateFiltersList(self, selectedIndex=0):
        filtersList = self.filters.keys()
        self.w.filtersPanel.filtersList.set(filtersList)
        self.w.filtersPanel.filtersList.setSelection([selectedIndex])

    def setArgumentValue(self, sender):
        value = sender.get()
        valueType = sender.type
        if valueType == 'bool':
            value = bool(value)
        key = sender.name
        if self.currentFilterName is not None:
            self.filters.setArgumentValue(self.currentFilterName, key, value)
            self.resetRepresentations()
        self.updatePreview()

    def resetRepresentations(self):
        font = self.currentFont
        self.cachedFont = RFont(showUI=False)
        if font is not None:
            for glyphName in self.glyphNames:
                if glyphName in font:
                    font[glyphName].naked().destroyAllRepresentations()

    def processGlyphs(self):
        font = self.currentFont
        if font is not None:
            sourceGlyphs = []
            for glyphName in self.glyphNames:
                if glyphName in font:
                    glyph = font[glyphName]
                    if glyph not in self.observedGlyphs:
                        glyph.addObserver(self, 'glyphChanged', 'Glyph.Changed')
                        self.observedGlyphs.append(glyph)
                    sourceGlyphs.append(glyph)
            filterName = self.currentFilterName
            filteredGlyphs = self.filterGlyphs(filterName, sourceGlyphs, self.cachedFont)
            return filteredGlyphs
        return []

    def filterGlyphs(self, filterName, glyphs, font):
        currentFilter = self.filters[filterName]
        filteredGlyphs = []
        for glyph in glyphs:
            if len(glyph.components) > 0:
                for comp in glyph.components:
                    baseGlyphName = comp.baseGlyph
                    baseGlyph = glyph.getParent()[baseGlyphName]
                    baseFilteredGlyph = currentFilter(baseGlyph)
                    if baseFilteredGlyph is not None:
                        font.insertGlyph(baseFilteredGlyph, baseGlyphName)
            filteredGlyph = currentFilter(glyph)
            if filteredGlyph is not None:
                font.insertGlyph(filteredGlyph, glyph.name)
                filteredGlyphs.append(font[glyph.name])
        return filteredGlyphs

    def updatePreview(self, notification=None):
        glyphs = self.processGlyphs()
        self.w.preview.setFont(self.cachedFont)
        self.w.preview.set(glyphs)

    def updateControls(self):
        if self.currentFilterName is not None:
            if hasattr(self.w.filtersPanel, 'controls'):
                delattr(self.w.filtersPanel, 'controls')
            currentFilter = self.filters[self.currentFilterName]
            self.w.filtersPanel.controls = Group((0, 0, 0, 0))
            hasSubfilters = self.filters.hasSubfilters(self.currentFilterName)

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

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

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

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

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

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

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

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

                        boxHeight += lineheight

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

            height += 40

            self.w.filtersPanel.filtersList.setPosSize((0, 0, -0, -height))
            self.w.filtersPanel.controls.setPosSize((0, -height, -0, -45))

    def stringInput(self, sender):
        text = sender.get()
        if self.currentFont is not None:
            cmap = self.currentFont.getCharacterMapping()
            self.glyphNames = splitText(text, cmap)
        else:
            self.glyphNames = []
        self.updatePreview()

    def filterEdit(self, sender):
        filterName = self.currentFilterName
        if self.filters.hasSubfilters(filterName):
            self.buildFilterGroupSheet(filterName)
        else:
            self.buildFilterSheet(filterName)
        self.filterSheet.open()

    # def buildGenerationSheet(self, sender):
    #     self.generationSheet = Sheet((0, 0, 400, 350), self.w)
    #     self.generationSheet.title = TextBox((15, 15, -15, 22), u'Generate selected glyphs to:')

    def buildFilterSheet(self, filterName='', makeNew=False):
        sheetFields = {
            'file': '',
            'module': '',
            'filterObjectName': '',
            'limits': {},
            'arguments': {},
        }
        if filterName != '':
            filterDict = self.filters[filterName].getFilterDict()
            for key in filterDict:
                if key == "arguments":
                    entry = OrderedDict(filterDict[key])
                else:
                    entry = filterDict[key]
                sheetFields[key] = entry

        self.filterSheet = Sheet((0, 0, 400, 350), self.w)
        self.filterSheet.new = makeNew
        self.filterSheet.index = self.filters[filterName].index if not makeNew else -1
        applyTitle = 'Add Filter' if filterName == '' else 'Update Filter'
        self.filterSheet.apply = SquareButton((-115, -37, 100, 22), applyTitle, callback=self.processFilter, sizeStyle='small')
        self.filterSheet.cancel = SquareButton((-205, -37, 80, 22), 'Cancel', callback=self.closeFilterSheet, sizeStyle='small')

        y = 20
        self.filterSheet.nameTitle = TextBox((15, y, 100, 22), 'Filter Name')
        self.filterSheet.name = EditText((125, y, -15, 22), filterName)
        y += 22

        tabs = ['module','file']
        selectedTab = 0 if len(sheetFields['module']) >= len(sheetFields['file']) else 1
        filterObjectName = sheetFields['filterObjectName']

        y += 20
        self.filterSheet.importPath = Tabs((15, y, -15, 75), tabs)
        self.filterSheet.importPath.set(selectedTab)
        modulePathTab = self.filterSheet.importPath[0]
        filePathTab = self.filterSheet.importPath[1]

        modulePathTab.pathInput = EditText((10, 10, -10, -10), sheetFields['module'])
        filePathTab.pathInput = EditText((10, 10, -110, -10), sheetFields['file'])
        filePathTab.fileInput = SquareButton((-100, 10, 90, -10), u'Add File…', sizeStyle='small', callback=self.getFile)
        y += 75

        y += 10
        self.filterSheet.filterObjectTitle = TextBox((15, y, 100, 22), 'Filter Object (pen, function)')
        self.filterSheet.filterObject = EditText((125, y, -15, 22), filterObjectName)
        y += 22

        y += 20
        columns = [
            {'title': 'argument', 'width': 160, 'editable':True},
            {'title': 'value', 'width': 71, 'editable':True},
            {'title': 'min', 'width': 49, 'editable':True},
            {'title': 'max', 'width': 49, 'editable':True}
        ]

        arguments = sheetFields['arguments']
        limits = sheetFields['limits']

        argumentItems = []

        for key, value in arguments.items():
            if isinstance(value, bool):
                value = str(value)
            elif isinstance(value, float):
                value = round(value, 2)
            argItem = {
                'argument': key,
                'value': value
                }
            if key in limits:
                minimum, maximum = sheetFields['limits'][key]
                argItem['min'] = minimum
                argItem['max'] = maximum

            argumentItems.append(argItem)

        buttonSize = 20
        gutter = 7
        self.filterSheet.arguments = List((15 + buttonSize + gutter, y, -15, -52), argumentItems, columnDescriptions=columns, allowsMultipleSelection=False, allowsEmptySelection=False)
        self.filterSheet.addArgument = SquareButton((15, -52-(buttonSize*2)-gutter, buttonSize, buttonSize), '+', sizeStyle='small', callback=self.addArgument)
        self.filterSheet.removeArgument = SquareButton((15, -52-buttonSize, buttonSize, buttonSize), '-', sizeStyle='small', callback=self.removeArgument)
        if len(argumentItems) == 0:
            self.filterSheet.removeArgument.enable(False)

        if filterName == '':
            self.currentFilterName = ''

    def buildFilterGroupSheet(self, filterName='', makeNew=False):

        subfilters = self.filters[filterName].subfilters if filterName in self.filters else []
        subfilterItems = [{'filterName': subfilterName, 'mode': subfilterMode if subfilterMode is not None else '', 'source': source if source is not None else ''} for subfilterName, subfilterMode, source in subfilters]

        self.filterSheet = Sheet((0, 0, 400, 350), self.w)
        self.filterSheet.new = makeNew
        self.filterSheet.index = self.filters[filterName].index if not makeNew else -1
        applyTitle = 'Add Operation' if filterName == '' else 'Update Operation'
        self.filterSheet.apply = SquareButton((-145, -37, 130, 22), applyTitle, callback=self.processFilterGroup, sizeStyle='small')
        self.filterSheet.cancel = SquareButton((-210, -37, 60, 22), 'Cancel', callback=self.closeFilterSheet, sizeStyle='small')

        y = 20
        self.filterSheet.nameTitle = TextBox((15, y, 100, 22), 'Filter Name')
        self.filterSheet.name = EditText((125, y, -15, 22), filterName)
        y += 22

        columns = [
            {'title': 'filterName', 'editable': True, 'width': 140},
            {'title': 'mode', 'editable': True, 'width': 89},
            {'title': 'source', 'editable': True, 'width': 100}
        ]

        buttonSize = 20
        gutter = 7

        y += 20
        self.filterSheet.subfilters = List((15 + buttonSize + gutter, y, -15, -52), subfilterItems, columnDescriptions=columns, allowsMultipleSelection=False, allowsEmptySelection=False)
        self.filterSheet.addSubfilter = SquareButton((15, -52-(buttonSize*2)-gutter, buttonSize, buttonSize), '+', sizeStyle='small', callback=self.addSubfilter)
        self.filterSheet.removeSubfilter = SquareButton((15, -52-buttonSize, buttonSize, buttonSize), '-', sizeStyle='small', callback=self.removeSubfilter)
        if len(subfilters) == 0:
            self.filterSheet.removeSubfilter.enable(False)
        y += 75
        self.filterSheet.moveSubfilterUp = SquareButton((15, y, buttonSize, buttonSize), u'⇡', sizeStyle='small', callback=self.moveSubfilterUp)
        self.filterSheet.moveSubfilterDown = SquareButton((15, y + buttonSize + gutter, buttonSize, buttonSize), u'⇣', sizeStyle='small', callback=self.moveSubfilterDown)

        if filterName == '':
            self.currentFilterName = ''

    def addArgument(self, sender):
        argumentsList = self.filterSheet.arguments.get()
        argumentsList.append({'argument': 'rename me', 'value': 50, 'min': 0, 'max': 100})
        if len(argumentsList) > 0:
            self.filterSheet.removeArgument.enable(True)
        self.filterSheet.arguments.set(argumentsList)

    def removeArgument(self, sender):
        argumentsList = self.filterSheet.arguments.get()
        if len(argumentsList) == 0:
            self.filterSheet.removeArgument.enable(False)
        selection = self.filterSheet.arguments.getSelection()[0]
        argumentsList.pop(selection)
        self.filterSheet.arguments.set(argumentsList)

    def addSubfilter(self, sender):
        subfiltersList = self.filterSheet.subfilters.get()
        subfilterDict = {'filterName': '{enter filter name}', 'mode': '', 'source': ''}
        subfiltersList.append(subfilterDict)
        if len(subfiltersList) > 0:
            self.filterSheet.removeSubfilter.enable(True)
        self.filterSheet.subfilters.set(subfiltersList)

    def removeSubfilter(self, sender):
        subfiltersList = self.filterSheet.subfilters.get()
        if len(subfiltersList) == 0:
            self.filterSheet.removeSubfilter.enable(False)
        selection = self.filterSheet.subfilters.getSelection()[0]
        subfiltersList.pop(selection)
        self.filterSheet.subfilters.set(subfiltersList)

    def moveSubfilterUp(self, sender):
        subfiltersList = self.filterSheet.subfilters.get()
        nItems = len(subfiltersList)
        if nItems > 1:
            selection = self.filterSheet.subfilters.getSelection()[0]
            if selection > 0:
                itemToMove = subfiltersList.pop(selection)
                subfiltersList.insert(selection-1, itemToMove)
                self.filterSheet.subfilters.set(subfiltersList)

    def moveSubfilterDown(self, sender):
        subfiltersList = self.filterSheet.subfilters.get()
        nItems = len(subfiltersList)
        if nItems > 1:
            selection = self.filterSheet.subfilters.getSelection()[0]
            if selection < nItems-1:
                itemToMove = subfiltersList.pop(selection)
                subfiltersList.insert(selection+1, itemToMove)
                self.filterSheet.subfilters.set(subfiltersList)

    def getFile(self, sender):
        path = getFile(fileTypes=['py'], allowsMultipleSelection=False, resultCallback=self.loadFilePath, parentWindow=self.filterSheet)

    def loadFilePath(self, paths):
        path = paths[0]
        self.filterSheet.importPath[1].pathInput.set(path)

    def closeFilterSheet(self, sender):
        self.filterSheet.close()
        delattr(self, 'filterSheet')

    def processFilter(self, sender):
        argumentsList = self.filterSheet.arguments.get()
        filterName = self.filterSheet.name.get()
        index = self.filterSheet.index
        filterDict = {}

        if len(filterName) > 0:
            sourceIndex = self.filterSheet.importPath.get()
            mode = ['module','file'][sourceIndex]
            importString = self.filterSheet.importPath[sourceIndex].pathInput.get()

            if len(importString) > 0:
                filterDict[mode] = importString

                filterObjectName = self.filterSheet.filterObject.get()
                filterDict['filterObjectName'] = filterObjectName

                if len(filterObjectName) > 0:

                    for argItem in argumentsList:
                        if 'argument' in argItem:
                            key = argItem['argument']
                            if 'value' in argItem:
                                value = self.parseValue(argItem['value'])
                                if 'arguments' not in filterDict:
                                    filterDict['arguments'] = OrderedDict()
                                filterDict['arguments'][key] = value
                                if 'min' in argItem and 'max' in argItem and isinstance(value, (float, int)):
                                    try:
                                        mini, maxi = float(argItem['min']), float(argItem['max'])
                                        if 'limits' not in filterDict:
                                            filterDict['limits'] = {}
                                        filterDict['limits'][key] = (mini, maxi)
                                    except:
                                        pass

                    if filterName in self.filters:
                        self.filters.setFilter(filterName, filterDict)

                    elif self.filterSheet.new == False:
                        index = self.filterSheet.index
                        self.filters.changeFilterNameByIndex(index, filterName)
                        self.filters.setFilter(filterName, filterDict)

                    elif self.filterSheet.new == True:
                        self.filters.setFilter(filterName, filterDict)

                    self.closeFilterSheet(sender)
                    self.updateFiltersList(index)
                    self.updateControls()
                    self.resetRepresentations()
                    self.updatePreview()

    def processFilterGroup(self, sender):
        filterName = self.filterSheet.name.get()
        subfiltersList = self.filterSheet.subfilters.get()
        isNew = self.filterSheet.new
        index = self.filterSheet.index
        subfilters = []

        for item in subfiltersList:
            subfilterName = item['filterName'] if 'filterName' in item else ''
            mode = item['mode'] if 'mode' in item else None
            source = item['source'] if 'source' in item else None
            try:
                source = int(source)
            except:
                pass
            subfilters.append((subfilterName, mode, source))

        if filterName in self.filters:
            self.filters.updateFilterChain(filterName, subfilters)
        elif not isNew:
            self.filters.changeFilterNameByIndex(index, filterName)
            self.filters.updateFilterChain(filterName, subfilters)
        elif isNew:
            self.filters.setFilterChain(filterName, subfilters)

        self.closeFilterSheet(sender)
        self.updateFiltersList(index)
        self.updateControls()
        self.resetRepresentations()
        self.updatePreview()

    def addFilter(self, sender):
        self.buildFilterSheet(makeNew=True)
        self.filterSheet.open()

    def addFilterChain(self, sender):
        self.buildFilterGroupSheet(makeNew=True)
        self.filterSheet.open()

    def addExternalFilter(self, filterName, filterDict):
        self.filters.addFilter(filterName, filterDict)
        self.updateFiltersList()

    def removeFilter(self, sender):
        filterName = self.currentFilterName
        self.filters.removeFilter(filterName)
        self.updateFiltersList()

    def filterSelectionChanged(self, sender):
        selectedFilterName = self.getSelectedFilterName()
        self.cachedFont = RFont(showUI=False)
        self.currentFilterName = selectedFilterName
        self.updateControls()
        self.updatePreview()

    def getSelectedFilterName(self):
        filtersList = self.w.filtersPanel.filtersList
        filterNamesList = filtersList.get()
        if len(filterNamesList):
            selectedIndices = filtersList.getSelection()
            if len(selectedIndices):
                selection = filtersList.getSelection()[0]
                return filterNamesList[selection]
        return None

    def switchFillStroke(self, sender):
        self.fill = not self.fill
        displayStates = self.w.preview.getDisplayStates()
        if self.fill == True:
            sender.setTitle('Stroke')
            displayStates['Fill'] = True
            displayStates['Stroke'] = False
        elif self.fill == False:
            sender.setTitle('Fill')
            displayStates['Fill'] = False
            displayStates['Stroke'] = True
        self.w.preview.setDisplayStates(displayStates)

    def parseValue(self, value):
        if isinstance(value, bool):
            value = bool(value)
        elif isinstance(value, (str, unicode)) and value.lower() == 'true':
            value = True
        elif isinstance(value, (str, unicode)) and value.lower() == 'false':
            value = False
        elif value is not '' or value is not None:
            try:
                value = float(value)
            except:
                pass
        return value

    def fontChanged(self, notification):
        if 'font' in notification:
            self.releaseObservedGlyphs()
            self.stringInput(self.w.textInput)
            self.currentFont = notification['font']
            self.cachedFont = RFont(showUI=False)
            self.updatePreview()

    def releaseObservedGlyphs(self):
        for glyph in self.observedGlyphs:
            glyph.removeObserver(self, 'Glyph.Changed')
        self.observedGlyphs = []

    def glyphChanged(self, notification):
        glyph = notification.object
        glyph.destroyAllRepresentations()
        self.updatePreview()

    def launchWindow(self):
        postEvent("PenBallWizardSubscribeFilter", subscribeFilter=self.addExternalFilter)

    def end(self, notification):
        self.filters.saveFiltersToJSON('/'.join([LOCALPATH, JSONFILE]))
        self.releaseObservedGlyphs()
        for callback, event in self.observers:
            removeObserver(self, event)
Пример #45
0
from vanilla import Window, Slider, Button  # or from vanilla import *

w = Window((400, 300), "My new window")

w.mySlider = Slider((10, 10, 200, 20))
w.myButton = Button((10, 40, 100, 20), "Click me!")

w.open()