Skip to content

Instantly share code, notes, and snippets.

@frankrolf
Last active April 16, 2020 15:16
Show Gist options
  • Save frankrolf/26d5e1883342e1090c1576b5382e8325 to your computer and use it in GitHub Desktop.
Save frankrolf/26d5e1883342e1090c1576b5382e8325 to your computer and use it in GitHub Desktop.
RoboFont observer for keeping anchors consistent.
'''
## anchorBaby.py
RoboFont script for keeping anchors consistent.
Inspired by an idea from James T. Edmondson, this script will take note of
anchor movement in a given glyph, and replicate that movement in all
dependent glyphs.
For instance, if a font has the glyphs `a` `a.init` and `a.fina`; and all three
have an anchors named “top”; any dragging of that anchor will be replicated
in all the dependent glyphs.
It does not matter which glyph the anchor is dragged in. Anchor names also
do not matter, as long as they are consistent among dependent glyphs.
Ideally, this script is run as a RoboFont startup script.
Writing this was a good trip into the world of observers.
Thanks for the opportunity, James! :-)
'''
from mojo.events import addObserver, removeObserver
class AnchorWatcher(object):
def __init__(self, anchor):
self.anchor = anchor
self.glyph = self.anchor.getParent()
self.font = self.glyph.getParent()
self.friends = self.findFriends(self.glyph.name)
self.anchor.addObserver(
self, "anchorChangedCallback", "Anchor.Changed")
# print('added observer for anchor %s in %s' % (
# self.anchor.name, self.glyph.name))
def unsubscribe(self):
# print(self, self.anchor)
self.anchor.removeObserver(self, "Anchor.Changed")
# print('removed observer for anchor %s in %s' % (
# self.anchor.name, self.anchor.getParent().name))
def findFriends(self, glyphName):
'''
Find all glyphs that share the same name before the dot,
except the main glyph.
e.g. ['a', 'a.alt', 'a.norm', 'a.fina', 'a.whatever'].
'''
baseGlyphName = glyphName.split('.')[0]
friends = [g.name for g in self.font if(
g.name.split('.')[0] == baseGlyphName and not g.name == glyphName)]
return friends
def anchorChangedCallback(self, sender):
for glyphName in self.friends:
for anchor in self.font[glyphName].anchors:
if anchor.name == self.anchor.name:
anchor.position = self.anchor.position
class GlyphWatcher(object):
def __init__(self):
self.observedGlyphs = {}
addObserver(self, "glyphObserver", "currentGlyphChanged")
def glyphObserver(self, info):
activeGlyph = info['glyph']
if activeGlyph is not None:
self.observedGlyphs.setdefault(activeGlyph.name, [])
if activeGlyph is not None:
for gName in list(self.observedGlyphs.keys()):
if gName == activeGlyph.name:
# Collect Anchor observer objects for the active glyph.
for anchor in activeGlyph.anchors:
aw = AnchorWatcher(anchor)
self.observedGlyphs[gName].append(aw)
else:
# Unsubscribe from Anchor observer objects
# in inactive glyphs.
for observer in self.observedGlyphs[gName]:
if observer.anchor in activeGlyph.getParent()[gName].anchors:
observer.unsubscribe()
del self.observedGlyphs[gName]
print('AnchorBaby active')
GlyphWatcher()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment