observer for adding new glyph to the font



  • Hi,
    I started to create a script that marks every added glyph with a specific colour.

    To do that I used defcon observer font.addObserver(self, 'glyphOrderChangedCallback', 'Font.GlyphOrderChanged'), but somehow it doesn't work.

    here is the method for that observer:

    def glyphOrderChangedCallback(self, info):
            
            oldValue = info['oldValue']
            newValue = info['newValue']
            newGlyphNames = list(set(oldValue)-set(newValue))
            for name in newGlyphNames:
                self.font[name].colorMark = (1,0,0,1)
    

    Maybe there is a better way to track the names of added glyph objects to the font?

    Thanks in advance for any advice on how to make it work.


  • admin

    hi @RafaŁ-Buchner,

    I gave it a try — this seems to work:

    from vanilla import FloatingWindow
    from mojo.events import addObserver, removeObserver
    
    class NewGlyphMarker:
        
        def __init__(self):
            ### for debugging only
            self.w = FloatingWindow((200, 50), "mark new glyphs")
            self.w.bind("close", self.windowCloseCallback)
            self.w.open()
            ### end debugging
            self.font = None
            addObserver(self, "currentFontChanged", "fontBecameCurrent")        
            self.subscribeFont(CurrentFont())
        
        def __del__(self):
            self.unsubscribeFont()
    
        def windowCloseCallback(self, sender):
            removeObserver(self, "fontBecameCurrent")
            self.unsubscribeFont()
        
        def subscribeFont(self, font):
            self.unsubscribeFont()
            if font is not None:
                self.font = font
                self.font.addObserver(self, "glyphOrderChanged", "Font.GlyphOrderChanged")
            
        def unsubscribeFont(self):
            if self.font is not None:
                self.font.removeObserver(self, "Font.GlyphOrderChanged")
                self.font = None
                
        def currentFontChanged(self, notification):
            print('current font changed')
            # a robofont event notification
            self.subscribeFont(notification["font"])
            print(notification['font'])
            
        def glyphOrderChanged(self,  notification):
            print('glyph order changed')
            # a defcon notification
            font = notification.object
            font = RFont(font)
    
            oldGlyphOrder = notification.data['oldValue']
            newGlyphOrder = notification.data['newValue']
            newGlyphNames = list(set(newGlyphOrder) - set(oldGlyphOrder))
            for glyphName in newGlyphNames:
                self.font[glyphName].markColor = 1, 0, 0, 1
    
    NewGlyphMarker()
    

    (based on an older example script by @frederik)

    I hope this does what you need… cheers!



  • @gferreira said in observer for adding new glyph to the font:

    from vanilla import FloatingWindow
    from mojo.events import addObserver, removeObserver
    
    class NewGlyphMarker:
        
        def __init__(self):
            ### for debugging only
            self.w = FloatingWindow((200, 50), "mark new glyphs")
            self.w.bind("close", self.windowCloseCallback)
            self.w.open()
            ### end debugging
            self.font = None
            addObserver(self, "currentFontChanged", "fontBecameCurrent")        
            self.subscribeFont(CurrentFont())
        
        def __del__(self):
            self.unsubscribeFont()
    
        def windowCloseCallback(self, sender):
            removeObserver(self, "fontBecameCurrent")
            self.unsubscribeFont()
        
        def subscribeFont(self, font):
            self.unsubscribeFont()
            if font is not None:
                self.font = font
                self.font.addObserver(self, "glyphOrderChanged", "Font.GlyphOrderChanged")
            
        def unsubscribeFont(self):
            if self.font is not None:
                self.font.removeObserver(self, "Font.GlyphOrderChanged")
                self.font = None
                
        def currentFontChanged(self, notification):
            print('current font changed')
            # a robofont event notification
            self.subscribeFont(notification["font"])
            print(notification['font'])
            
        def glyphOrderChanged(self,  notification):
            print('glyph order changed')
            # a defcon notification
            font = notification.object
            font = RFont(font)
    
            oldGlyphOrder = notification.data['oldValue']
            newGlyphOrder = notification.data['newValue']
            newGlyphNames = list(set(newGlyphOrder) - set(oldGlyphOrder))
            for glyphName in newGlyphNames:
                self.font[glyphName].markColor = 1, 0, 0, 1
    
    NewGlyphMarker()
    

    Gustavo, You're the best !!! Big Thanks!!!

    I messed up with getting data in the callback. Somehow nothing appeared in the output window (it is set to show every possible error).


  • admin

    @RafaŁ-Buchner thanks for asking good questions here, it helps to improve the docs :)

    this example is super valuable because it shows how to use RoboFont and defcon notifications together. thanks @frederik!


  • admin

    There are defcon notifications for different actions see the source.

    You can even set a global font wise observer (only with defcon objects)

    font = CurrentFont()
    defconFont = font.naked()
    defconFont.dispatcher.addObsever(observer=self, methodName="glyphAdded", notification="Layer.GlyphAdded", observable=None)
    

    when observable is None the notification center sends out a notification for each call, not only for the object its observing

    good luck



  • @frederik said in observer for adding new glyph to the font:

    font = CurrentFont()
    defconFont = font.naked()
    defconFont.dispatcher.addObsever(observer=self, methodName="glyphAdded", notification="Layer.GlyphAdded", observable=None)

    class Test(object):
        def __init__(self, *args):
            font = CurrentFont()
            defconFont = font.naked()
            defconFont.dispatcher.addObsever(observer=self, methodName="glyphAdded", notification="Layer.GlyphAdded", observable=None)
        
        def glyphAdded(self, notification):
            print(notification)
    Test()
    
    Traceback (most recent call last):
      File "<untitled>", line 9, in <module>
      File "<untitled>", line 5, in __init__
    AttributeError: 'NotificationCenter' object has no attribute 'addObsever'
    

    Am I doing something wrong? I will check also Defcon source code, but I think it should work


  • admin

    @RafaŁ-Buchner haven’t tried to run the code, but there’s a typo: addObseveraddObserver


  • admin

    Keep a reference of the font in your class otherwise the observer will be gone after the script is finished.

    Thats why the examples have an open window, so its the font and observers stays alive!

    good luck