Simple font library browser ↩
Imagine that your UFO sources are stored in subfolders of a main folder, with one folder for each family:
myLibrary ├── myFamily1 │ ├── Bold.ufo │ ├── Condensed.ufo │ ├── Italic.ufo │ └── Regular.ufo ├── myFamily2 │ └── … └── myFamily3 └── …
This example shows how to create a simple tool to browse through the family folders and open the selected fonts:

The code could be extended to do more than just opening the selected fonts – for example setting font infos, generating fonts etc.
Some things to notice in this example:
- layout variables
- The buttons and lists are placed and sized using layout variables (padding, button height, column widths, etc). This makes it easier to change dimensions during development.
- Get Folder dialog
-
- When the user clicks on the get root folder… button, a
getFolder
dialog is opened. - After the folder has been selected, a list of all its subfolders is displayed in the left column.
- When the user clicks on the get root folder… button, a
- list selection
-
Items selection works differently in each list:
- The list of families allows only one item to be selected at once.
- The list of fonts allows selection of multiple items (default
List
behavior).
- show fonts in folder
- As the selection in the left column changes, the right column is updated to show a list of UFOs in the selected family folder.
Here’s the code:
import os
from vanilla import FloatingWindow, Button, List
from vanilla.dialogs import getFolder
class FontLibraryBrowser(object):
# root folder for families
rootFolder = None
# current family
family = None
def __init__(self):
# UI layout attributes
padding = 10
buttonHeight = 20
columnFamilies = 120
columnFonts = 200
listHeight = 240
width = columnFamilies + columnFonts + padding*3
height = listHeight + buttonHeight*2 + padding*4
self.w = FloatingWindow((width, height), "myFontLibrary")
# a button to get the root folder
x = y = padding
self.w.getFolderButton = Button(
(x, y, -padding, buttonHeight),
"get root folder...",
callback=self.getFolderCallback)
# list of folders in root folder
y += buttonHeight + padding
self.w.families = List(
(x, y, columnFamilies, listHeight),
[],
selectionCallback=self.getFontsCallback,
allowsMultipleSelection=False)
# list of fonts in folder
x += columnFamilies + padding
self.w.fonts = List(
(x, y, columnFonts, listHeight),
[])
# open selected fonts
x = padding
y += listHeight + padding
self.w.openFontsButton = Button(
(x, y, -padding, buttonHeight),
"open selected fonts",
callback=self.openFontsCallback)
# open the dialog
self.w.open()
# ---------
# callbacks
# ---------
def getFolderCallback(self, sender):
'''Get the main folder where all family folders live.'''
# open a dialog to select the root folder
folder = getFolder()
# no folder selected
if folder is None:
return
# get folder
else:
self.rootFolder = folder[0]
# update families list
self.updateFamiliesList()
def getFontsCallback(self, sender):
'''Get UFOs in current family folder.'''
# get families
families = sender.get()
if not len(families):
return
# get selected family
selection = sender.getSelection()
if not len(selection):
return
self.family = families[selection[0]]
# list all ufos in family folder
self.updateFontsList()
def openFontsCallback(self, sender):
'''Open selected fonts in current family.'''
# get fonts
allFonts = self.w.fonts.get()
if not len(allFonts):
return
# get selection
fontsSelection = self.w.fonts.getSelection()
if not len(fontsSelection):
return
# get selected fonts
selectedFonts = [f for i, f in enumerate(allFonts) if i in fontsSelection]
# open selected fonts
familyFolder = os.path.join(self.rootFolder, self.family)
for font in selectedFonts:
# get ufo path for font
ufoPath = os.path.join(familyFolder, '%s.ufo' % font)
# open ufo
print('opening %s/%s.ufo...' % (self.family, font))
OpenFont(ufoPath)
# ---------
# functions
# ---------
def updateFamiliesList(self):
'''Update the list of families in the UI.'''
# get subfolders
subFolders = []
for f in os.listdir(self.rootFolder):
fileOrFolder = os.path.join(self.rootFolder, f)
if os.path.isdir(fileOrFolder):
subFolders.append(f)
# update families list
self.w.families.set(subFolders)
def updateFontsList(self):
'''Update the list of fonts in the UI.'''
# get folder for family
familyFolder = os.path.join(self.rootFolder, self.family)
# get ufos in folder
ufos = [os.path.splitext(f)[0] for f in os.listdir(familyFolder) if os.path.splitext(f)[-1] == '.ufo']
# update fonts list
self.w.fonts.set(ufos)
# ---------------
# open the dialog
# ---------------
FontLibraryBrowser()