Last active
April 16, 2020 15:16
-
-
Save frankrolf/26d5e1883342e1090c1576b5382e8325 to your computer and use it in GitHub Desktop.
RoboFont observer for keeping anchors consistent.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
## 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