SOLVED Can “default” checkboxes in font info actually store that value in the UFO?



  • Currently the "default value" checkboxes in font info only flag to internal RF processes to auto-generate a default value in that field upon generate.

    Problem: if running processes external to RF (FDK generation in Terminal for instance), those values aren't written into the UFO and can therefore raise a flag.

    Could the "default value" checkbox just store the actual value in the UFO when checked?

    0fa844ee-0245-4d32-92d2-02129083ddcf-image.png

    Currently writing a script to write it to the UFO on save, but seems messy.

    TIA,
    Ryan


  • admin

    the default values are calculated by ufo2fdk getAttrWithFallback

    from ufo2fdk.fontInfoData import getAttrWithFallback
    from defcon import Info
    
    info = Info()
    info.descender = -250
    print(getAttrWithFallback(info, "openTypeOS2WinDescent"))
    info.openTypeOS2WinDescent = 350
    print(getAttrWithFallback(info, "openTypeOS2WinDescent"))
    

    also see the defconAppKit fontInfoView



  • What keeps you from just saving the value (such as the PS font name) into the UFO? Check the box once and you’re done.
    Does the font name change that often? ;-)

    FWIW, I’d rather confirm some of Robofont’s suggestions by unchecking the ✅ Use Default Value box, than hunting for “helpfully” set default values in my UFO file.

    So – please reconsider your suggestion! :-)



  • @frankrolf I'm often working with variable fonts in a quick-and-dirty fashion, versioning, potentially delivering variable logotypes to clients to test. Can get messy very fast, and a mismatched set of ps names can be a confusing speed bump. The only thing I'm trying to avoid is postscript names being empty when needed externally of RF. Is there a disadvantage to—when changing family name and style name in Font Info, with default checkboxes checked—ps names being stored in the ufo?

    I've experienced this for a while, and am only now surfacing it because the confusion recently came up amongst friends.

    In the meantime, prior to any replies here, I wrote a pretty clunky script (should potentially rewrite once I understand above reply) to keep this updated. Would love to not need something like this.

    from mojo.events import addObserver
    
    class postScriptFontNameGen:
        
        def __init__(self):
            
            addObserver(self, "psNameChange", "fontDidSave")
            
        def psNameChange(self, notification):
            f = notification["font"]
            
            # set postscript names
            if f.info.familyName != None and f.info.styleName != None:
    
                attributes = {
                    'postscriptFontName': str(f.info.familyName + "-" + f.info.styleName).replace(" ", ""),
                    'postscriptFullName': str(f.info.familyName + f.info.styleName).replace(" ", "")
                    }
                for attr, value in attributes.items():
                    setattr(f.info, attr, value) 
            
            # set postscript weight name
            if f.info.openTypeOS2WeightClass != None:
                ranges = {
                        100: "Thin",
                        200: "Extra-light",
                        300: "Light",
                        400: "Normal",
                        500: "Medium",
                        600: "Semi-bold",
                        700: "Bold",
                        800: "Extra-bold",
                        900: "Black",
                        }
                os2_w = f.info.openTypeOS2WeightClass  
                f.info.postscriptWeightName = "Thin"      
                for attr, value in ranges.items():
                    if os2_w >= attr:
                        f.info.postscriptWeightName = value
            else:
                f.info.postscriptWeightName = "Normal"
                    
            f.save()
                    
                    
    postScriptFontNameGen()
    

  • admin

    hello @ryan,

    Is there a disadvantage to—when changing family name and style name in Font Info, with default checkboxes checked—ps names being stored in the ufo?

    I think so: it goes against the DRY principle and would actually increase the chance of mismatched data down the line (for example if familyName or styleName are changed with a script or without the checkbox).

    if you generate the fonts with font.generate or with ufo2fdk.OTFCompiler, all default values are calculated automatically for you. this is very convenient. special cases can be handled with a script, as you’re doing.

    below is a modified version of your script, which stores the default values in the font when it is saved. it uses getAttrWithFallback to calculate the defaults. (I’ve added a window to toggle it ON/OFF while testing)

    from ufo2fdk.fontInfoData import getAttrWithFallback
    from vanilla import FloatingWindow, CheckBox
    from mojo.events import addObserver, removeObserver
    from defconAppKit.windows.baseWindow import BaseWindowController
    
    class psNameGenerator(BaseWindowController):
        
        def __init__(self):
            self.w = FloatingWindow((123, 44))
            self.w.button = CheckBox((10, 10, -10, 24), 'activate', value=False, callback=self.toggleObserverCallback)
            self.setUpBaseWindowBehavior()
            self.w.open()
    
        def psNameChange(self, notification):
            f = notification["font"]
            psNames = ['postscriptFontName', 'postscriptFullName', 'postscriptWeightName']
            print(f'saving {f.info.familyName} {f.info.styleName}...\n')
            for psName in psNames:
                value = getAttrWithFallback(f.info, psName)
                setattr(f.info, psName, value)
                print(f'\t{psName}: {getattr(f.info, psName)}')
            f.save()
            print('\n...done.\n')
    
        def toggleObserverCallback(self, sender):
            if sender.get():
                print('observer is ON\n')
                addObserver(self, "psNameChange", "fontDidSave")
            else:
                print('observer is OFF\n')
                removeObserver(self, 'fontDidSave')
    
        def windowCloseCallback(self, sender):
            removeObserver(self, 'fontDidSave')
            super(psNameGenerator, self).windowCloseCallback(sender)
                    
    psNameGenerator()
    

    hope this makes sense… cheers!



  • @gferreira Makes sense, thanks very much!