Skip to content

Instantly share code, notes, and snippets.

@okay-type
Last active May 10, 2022 15:05
Show Gist options
  • Save okay-type/73637a66de2772a0d18c68efa404a1e7 to your computer and use it in GitHub Desktop.
Save okay-type/73637a66de2772a0d18c68efa404a1e7 to your computer and use it in GitHub Desktop.
start of a rf4 anchor tool using merz and subscriber
from AppKit import NSScreen
from vanilla import *
import merz
import mojo.subscriber as subs
from mojo.subscriber import Subscriber, WindowController, registerCurrentGlyphSubscriber, registerGlyphEditorSubscriber, registerSubscriberEvent, getRegisteredSubscriberEvents, unregisterGlyphEditorSubscriber, listRegisteredSubscribers
from mojo.extensions import registerExtensionDefaults, setExtensionDefault, getExtensionDefault, removeExtensionDefault
from mojo.drawingTools import *
from math import radians, tan, pi
from AppKit import NSColor
from fontTools.pens.basePen import BasePen
from mojo.UI import getDefault, setDefault, SetCurrentGlyphByName
import fnmatch
# color settings
uiBackgroundColor = (.5, 1, .5, .25)
uiBackgroundColorOff = (.8, 1, .8, .2)
fillColor = (.1, 0, 1, .25)
selectedFillColor = (.5, 0, 1, .666) # also use for path-to-point in positionHelper
boundsColor = (0, 1, 0, .333)
positionHelperColor = (0, 1, 1, 1)
# position helper settings
fuzz = 25
glyphRelationships = {
# glyph: (referenceGlyph, name transformation)
# * wildcard
# transformations can be 'upper', 'lower', 'title'
'*.sc' : ('*', 'title'),
'ae*.sc' : ('AE*', None),
'oe*.sc' : ('OE*', None),
'oslash.sc': ('o.sc', None),
'ohorn.sc': ('o.sc', None),
'uhorn.sc': ('u.sc', None),
'Oslash': ('O', None),
'Ohorn': ('O', None),
'Uhorn': ('U', None),
'oslash': ('o', None),
'ohorn': ('o', None),
'uhorn': ('u', None),
}
'''
recent updates:
differentiates between on-but-no-anchors and off (shows options when on)
now a dropdown menu in the glyph edit window
stores checked components as a preference
expand/collapse state persists when switching glyphs
close button turns off the view (still need to figure out how to remove the tool)
draws glyph guidelines (left, middle, right)
updates when anchors are added or deleted
draw accents that have components, thanks conner!
fixed(?): error when matching 'anchor' and '_anchor' don't exist
draws suggested anchor positions for dependent glyphs (smallcaps, oslash, etc)
ui options for view modes
save ui options in preferences
improved glyphRelationships dict for position helper
has wildcards and case tranformations
when anchors are selected, the preview color darkens
triple click on component changes the edit window to that component, thanks again conner!
waiting for beta updates to do:
draw in preview mode
make it a real tool that you can turn on and off for real
to do:
on off - seperate from show/hide
don't update data if it's not visible
make anchor list scrollable for small windows
draw ui to fix selected anchors suggest postions
load colors from preferences - use component color pref as start
when nothing selected
change anchor colors to color-coded, maybe with a message or icon
show fix [add] [remove] [move all x] [move all y] [move all xy] buttons
when anchors are selected
hide components unrelated to the selected anchor
show the components' bounds as guides
show fix [move x] [move y] [move xy] buttons
'''
class anchorHelper(Subscriber):
debug = False
def build(self):
print('building anchorHelper')
# preferences
self.prefKey = 'com.okay.anchorHelper'
initialDefaults = {
self.prefKey + 'anchorOn': [],
self.prefKey + 'showUI': 1,
self.prefKey + 'toggleComponents': 1,
self.prefKey + 'toggleGuidelines': 0,
self.prefKey + 'togglePositions': 1,
self.prefKey + 'toggleTool': 1,
}
# for v, p in initialDefaults.items():
# removeExtensionDefault(v)
registerExtensionDefaults(initialDefaults)
# initial data
self.anchorOn = getExtensionDefault(self.prefKey + 'anchorOn')
self.showUI = getExtensionDefault(self.prefKey + 'showUI')
self.toggleComponents = getExtensionDefault(self.prefKey + 'toggleComponents')
self.toggleGuidelines = getExtensionDefault(self.prefKey + 'toggleGuidelines')
self.togglePositions = getExtensionDefault(self.prefKey + 'togglePositions')
self.toggleTool = getExtensionDefault(self.prefKey + 'toggleTool')
self.getAnchorData()
self.added = []
self.anchorCount = None
self.selectedAnchors = []
self.anchorsToRemove = []
self.anchorsToAdd = {} # dict of name: position
self.anchorsToMove = {} # dict of name: position
self.anchorColor = tuple(float(a) for a in getDefault('glyphViewAnchorColor'))
self.anchorSize = getDefault('glyphViewOffCurvePointsSize')
self.anchorTextSize = getDefault('textFontSize')
# for mousedown to component
self.clickableComponents = {}
# glyph view layer
self.glyphEditor = self.getGlyphEditor()
self.anchorPreview = self.glyphEditor.extensionContainer(
identifier='com.okay.anchorHelper.background',
location='background',
clear=True,
)
self.previewContainer = self.glyphEditor.extensionContainer(
identifier='com.robofont.anchorHelper.preview',
location='preview',
clear=True
)
# ui
self.x = 0
self.w = 180
self.u = 22
self.controls = Group((self.x, 0, self.w, self.u))
self.controls.showTool = CheckBox(
(8, 0, -30, -0),
'⚓ Helper',
sizeStyle='small',
value=self.toggleTool,
callback=self.toggleViews,
)
self.controls.viewExpand = CheckBox(
(-30, 0, -15, -0),
'',
sizeStyle='small',
value=self.showUI,
callback=self.toggleViews,
)
self.controls.closeTool = Button(
(-15, 0, 0, -0),
'X',
sizeStyle='mini',
callback=self.removeTool,
)
self.glyphEditor.addGlyphEditorSubview(self.controls)
self.main = Group((self.x, self.u, self.w, -0))
self.anchorController= Group((0, 0, -0, -0))
y = 0
h = 22
self.anchorController.line = HorizontalLine((8, y+h+2, -8, 1))
self.anchorController.line.setBorderWidth(1)
y += h + 5
self.anchorController.viewComponent = CheckBox(
(8, y, -8, h),
'👀 Components',
sizeStyle='small',
value=self.toggleComponents,
callback=self.toggleViews,
)
y += h
self.anchorController.viewGuidelines = CheckBox(
(8, y, -8, h),
'👀 Bounds Lines',
sizeStyle='small',
value=self.toggleGuidelines,
callback=self.toggleViews,
)
y += h
self.anchorController.viewPositions = CheckBox(
(8, y, -8, h),
'👀 Position Helper',
sizeStyle='small',
value=self.togglePositions,
callback=self.toggleViews,
)
y += h
self.main.scrollView = ScrollView((0, 0, -0, -0), self.anchorController.getNSView())
self.glyphEditor.addGlyphEditorSubview(self.main)
self.anchorController.setPosSize((0, 0, self.w, y), False)
# get blues (for position helper)
font = CurrentFont()
self.blues = []
self.blues.extend(font.info.postscriptBlueValues)
self.blues.extend(font.info.postscriptOtherBlues)
self.blues = [(self.blues[i], self.blues[i+1]) for i in range(0, len(self.blues), 2)]
def toggleViews(self, sender):
self.showUI = self.controls.viewExpand.get()
testToggleTool = self.controls.showTool.get()
if testToggleTool != self.toggleTool:
if testToggleTool == False:
self.showUI = False
self.toggleTool = testToggleTool
self.toggleComponents = self.anchorController.viewComponent.get()
self.toggleGuidelines = self.anchorController.viewGuidelines.get()
self.togglePositions = self.anchorController.viewPositions.get()
self.drawAnchorControls()
self.positionHelper()
self.drawAnchors()
def destroy(self):
print('destroying anchorHelper')
setExtensionDefault(self.prefKey + 'anchorOn', self.anchorOn)
setExtensionDefault(self.prefKey + 'showUI', self.showUI)
setExtensionDefault(self.prefKey + 'toggleComponents', self.toggleComponents)
setExtensionDefault(self.prefKey + 'toggleGuidelines', self.toggleGuidelines)
setExtensionDefault(self.prefKey + 'togglePositions', self.togglePositions)
setExtensionDefault(self.prefKey + 'toggleTool', self.toggleTool)
self.anchorPreview.clearSublayers()
self.previewContainer.clearSublayers()
self.getGlyphEditor().removeGlyphEditorSubview(self.main)
self.getGlyphEditor().removeGlyphEditorSubview(self.controls)
def removeTool(self, sender):
self.destroy()
registered_subscribers = listRegisteredSubscribers(subscriberClassName='anchorHelper')
if len(registered_subscribers) > 0:
for target_subscriber in registered_subscribers:
unregisterGlyphEditorSubscriber(target_subscriber)
#
#
# events
#
def glyphEditorDidSetGlyph(self, info):
## shouldn't have to do this in next beta
self.previewContainer = self.glyphEditor.extensionContainer(
identifier='com.robofont.anchorHelper.preview',
location='preview',
clear=True
)
#
self.glyph = info['glyph']
if self.glyph is None:
return
self.componentsToDraw = self.getGlyphComponentData(self.glyph)
self.drawAnchorControls()
self.positionHelper()
self.drawAnchors()
def glyphEditorGlyphDidChangeAnchors(self, info):
self.glyph = info['glyph']
if self.glyph is None:
return
if self.anchorCount != len(self.glyph.anchors):
self.anchorCount = len(self.glyph.anchors)
self.componentsToDraw = self.getGlyphComponentData(self.glyph)
self.drawAnchorControls()
self.positionHelper()
self.drawAnchors()
def glyphSelectionChanged(self, notification):
glyph = notification['lowLevelEvents'][0].object
if glyph is None:
return
selectedAnchors = []
for a in glyph.anchors:
if a.selected:
selectedAnchors.append(a.name)
if selectedAnchors != self.selectedAnchors:
self.selectedAnchors = selectedAnchors
self.drawAnchors()
self.drawHelperUI()
def glyphEditorDidMouseDown(self, info):
lle = info['lowLevelEvents'][0]
point = lle['point']
cc = lle['clickCount']
if cc == 3:
for componentKey in self.clickableComponents:
componentObject = self.clickableComponents[componentKey]
path = componentObject.naked().getRepresentation('defconAppKit.NSBezierPath')
if path.containsPoint_(point):
SetCurrentGlyphByName(componentKey)
break
#
#
# build data
#
def getAnchorData(self):
# family-level data
# anchor.name: (list of glyph.names)
self.anchorData = {}
f = CurrentFont()
if f is not None:
glyphOrder = f.glyphOrder
for g in glyphOrder:
glyph = f[g]
if len(glyph.anchors) > 0:
for anchor in glyph.anchors:
if anchor.name not in self.anchorData:
self.anchorData[anchor.name] = []
self.anchorData[anchor.name].append(glyph.name)
def getGlyphComponentData(self, glyph):
componentsToDraw = {}
if len(glyph.anchors) > 0:
for anchor in glyph.anchors:
mateAnchor = self.mateAnchor(anchor.name)
if mateAnchor not in componentsToDraw:
componentsToDraw[mateAnchor] = []
if mateAnchor in self.anchorData:
for component in self.anchorData[mateAnchor]:
componentsToDraw[mateAnchor].append(component)
return componentsToDraw
#
#
# helper functions
#
def mateAnchor(self, anchorName):
if '_' == anchorName[0]:
mateAnchor = anchorName.replace('_', '')
else:
mateAnchor = '_' + anchorName
return mateAnchor
def getAnchorByName(self, glyph, anchorName):
return next((
anchor for anchor in glyph.anchors if
anchor.name == anchorName), None)
def italicShiftedX(self, x, y, italicAngle):
if italicAngle != 0:
return x + (tan(-italicAngle * pi / 180) * y)
else:
return x
#
#
# build UI
#
def drawAnchorControls(self):
unit = self.u
offset = 92
length = len(self.componentsToDraw)
for i in self.componentsToDraw.values():
length += len(i)+1
height = length * unit + offset - unit/2
if self.showUI == False:
self.main.show(False)
self.anchorController.show(False)
else:
self.main.show(True)
self.anchorController.show(True)
self.anchorController.setPosSize((0, 0, self.w, height), False)
# remove old stuff
for added in self.added:
if hasattr(self.anchorController, added):
delattr(self.anchorController, added)
# build new stuff
count = 0
y = offset
self.added = []
for anchor in self.componentsToDraw:
count += 1
this = TextBox((8, y+unit*.5, -8, unit), '⚓︎ '+anchor, sizeStyle='small')
name = 'Label'+anchor
if hasattr(self.anchorController, name):
delattr(self.anchorController, name)
self.added.append(name)
setattr(self.anchorController, name, this)
this = HorizontalLine((8, y+19+unit*.5, -8, 1))
this.setBorderWidth(1)
name = 'Line'+anchor
if hasattr(self.anchorController, name):
delattr(self.anchorController, name)
self.added.append(name)
setattr(self.anchorController, name, this)
y += unit*1.5
for component in self.componentsToDraw[anchor]:
count += 1
check = False
if [component, anchor] in self.anchorOn:
check = True
this = okCheckBox(
(8, y, -8, unit),
component,
component=component,
anchor=anchor,
value=check,
sizeStyle='small',
callback=self.checkAnchorData,
)
name = 'CheckBox'+component+anchor
if hasattr(self.anchorController, name):
delattr(self.anchorController, name)
setattr(self.anchorController, name, this)
self.added.append(name)
y += unit
def checkAnchorData(self, sender):
component = sender.component
anchor = sender.anchor
if sender.get() == 1 and [component, anchor] not in self.anchorOn:
self.anchorOn.append([component, anchor])
if sender.get() == 0 and [component, anchor] in self.anchorOn:
self.anchorOn.remove([component, anchor])
self.drawAnchors()
#
#
# draw anchor preview
#
def drawAnchors(self):
self.anchorPreview.clearSublayers()
self.previewContainer.clearSublayers()
if self.toggleTool == False:
return
if self.glyph is None:
return
font = self.glyph.font
self.clickableComponents = {}
# prep drawing
self.anchorPreview.clearSublayers()
self.previewContainer.clearSublayers()
anchorLayer = self.anchorPreview.getSublayer('anchorLayer')
if anchorLayer is None:
anchorLayer = self.anchorPreview.appendPathSublayer(name='anchorLayer')
previewLayer = self.previewContainer.getSublayer('previewLayer')
if previewLayer is None:
previewLayer = self.previewContainer.appendPathSublayer(
name='previewLayer',
)
# draw
with anchorLayer.drawingTools() as bot:
bot.stroke(None)
if self.toggleComponents == True:
with previewLayer.drawingTools() as previewbot:
previewbot.fill(0, 0, 0, 1)
for anchor in self.componentsToDraw:
for component in self.componentsToDraw[anchor]:
c = font[component]
mateAnchor = self.mateAnchor(anchor)
cAnchor = self.getAnchorByName(c, anchor)
bAnchor = self.getAnchorByName(self.glyph, mateAnchor)
shift = (bAnchor.x-cAnchor.x, bAnchor.y-cAnchor.y)
name = 'CheckBox'+component+anchor
componentVisibility = False
if hasattr(self.anchorController, name):
componentVisibility = getattr(self.anchorController, name).get()
if componentVisibility == True:
bot.fill(*fillColor,)
if mateAnchor in self.selectedAnchors:
bot.fill(*selectedFillColor,)
componentCopy = RGlyph()
pen = DecompPen(font, componentCopy.getPen())
font[component].draw(pen)
componentCopy.moveBy(shift)
bot.drawGlyph(componentCopy)
if component not in self.clickableComponents:
self.clickableComponents[component] = componentCopy
previewbot.drawGlyph(componentCopy)
if self.toggleGuidelines == True:
self.drawGuide((0, 0), bot)
if self.togglePositions == True:
self.drawPositionHelper(bot)
def drawGuide(self, shift, bot):
font = self.glyph.font
italicAngle = font.info.italicAngle or 0
italicOffset = font.lib.get('com.typemytype.robofont.italicSlantOffset') or 0
shiftx, shifty = shift
bot.fill(None)
bot.strokeWidth((1))
bot.stroke(*boundsColor,)
Ytop = font.info.ascender + 500
Ybot = font.info.descender - 500
# leftz
xL = self.glyph.angledLeftMargin + italicOffset + shiftx
Xtop = self.italicShiftedX(xL, Ytop, italicAngle)
Xbot = self.italicShiftedX(xL, Ybot, italicAngle)
bot.newPath()
bot.moveTo((Xbot, Ybot))
bot.lineTo((Xtop, Ytop))
bot.closePath()
bot.drawPath()
# right
xR = self.glyph.width - self.glyph.angledRightMargin + italicOffset + shiftx
Xtop = self.italicShiftedX(xR, Ytop, italicAngle)
Xbot = self.italicShiftedX(xR, Ybot, italicAngle)
bot.newPath()
bot.moveTo((Xbot, Ybot))
bot.lineTo((Xtop, Ytop))
bot.closePath()
bot.drawPath()
# middle
xC = (xL + xR)/2
Xtop = self.italicShiftedX(xC, Ytop, italicAngle)
Xbot = self.italicShiftedX(xC, Ybot, italicAngle)
bot.newPath()
bot.moveTo((Xbot, Ybot))
bot.lineTo((Xtop, Ytop))
bot.closePath()
bot.drawPath()
#
#
# anchor position
#
def drawPositionHelper(self, bot):
# draw a red x over anchors to remove
if self.anchorsToRemove:
for remove in self.anchorsToRemove:
removeAnchor = self.getAnchorByName(self.glyph, remove)
x, y = removeAnchor.x, removeAnchor.y
bot.fill(None)
bot.strokeWidth((self.anchorSize/2))
bot.stroke(*positionHelperColor,)
size = self.anchorSize * 2
bot.newPath()
bot.moveTo((x-size, y-size))
bot.lineTo((x+size, y+size))
bot.closePath()
bot.drawPath()
bot.newPath()
bot.moveTo((x+size, y-size))
bot.lineTo((x-size, y+size))
bot.closePath()
bot.drawPath()
# draw a red circle around missing anchor
if self.anchorsToAdd:
for add in self.anchorsToAdd:
x, y = self.anchorsToAdd[add]
bot.fill(None)
bot.strokeWidth((self.anchorSize/2))
bot.stroke(*positionHelperColor,)
size = self.anchorSize * 2
bot.newPath()
bot.moveTo((x-size, y))
bot.lineTo((x+size, y))
bot.closePath()
bot.drawPath()
bot.newPath()
bot.moveTo((x, y-size))
bot.lineTo((x, y+size))
bot.closePath()
bot.drawPath()
bot.fill(*positionHelperColor,)
bot.fontSize(self.anchorTextSize)
labelwidth = 60
bot.textBox('+ '+add, (x-labelwidth/2, y+size-5, labelwidth, 20), align='center')
# alignment not working
#
# draw a red line to the recommended position
if self.anchorsToMove:
for move in self.anchorsToMove:
toMoveAnchor = self.getAnchorByName(self.glyph, move)
x1, y1 = toMoveAnchor.x, toMoveAnchor.y
x2, y2 = self.anchorsToMove[move]
size = self.anchorSize * 2
# fuzz line
bot.fill(None)
bot.stroke(*positionHelperColor,)
bot.strokeWidth((self.anchorSize*1.5))
bot.newPath()
bot.moveTo((x2-fuzz, y2))
bot.lineTo((x2+fuzz, y2))
bot.closePath()
bot.drawPath()
# target point
bot.fill(1, 1, 1, 1)
bot.stroke(*positionHelperColor,)
bot.strokeWidth((2))
bot.oval(x2-size*.7, y2-size*.7, size*1.4, size*1.4)
# path to point
bot.fill(None)
bot.stroke(*selectedFillColor,)
bot.strokeWidth((1))
bot.newPath()
bot.moveTo((x1, y1))
bot.lineTo((x2, y2))
bot.closePath()
bot.drawPath()
def positionHelper(self):
font = self.glyph.font
# get reference glyph
refGlyph = transformation = None
if self.glyph.name in glyphRelationships:
refGlyph, transformation = glyphRelationships[self.glyph.name]
else:
for key, value in glyphRelationships.items():
if fnmatch.fnmatch(self.glyph.name, key):
cleanGlyph = self.glyph.name
wildcardRef = key
refGlyph, transformation = value
x = refGlyph.split('*')
for n, string in enumerate(wildcardRef.split('*')):
cleanGlyph = cleanGlyph.replace(string, x[n])
refGlyph = cleanGlyph
if transformation != None:
refGlyph = getattr(refGlyph, transformation)()
# data to fill
self.anchorsToRemove = []
self.anchorsToAdd = {} # dict of name: position
self.anchorsToMove = {} # dict of name: position
# stop if reference glyph doesnt exist
if refGlyph not in font.glyphOrder:
return
refGlyph = font[refGlyph]
# get blue-zone-adjusted bounds and scale factors
gVerticalbounds = self.snapToBlue(self.glyph.bounds[1], self.glyph.bounds[3])
rVerticalbounds = self.snapToBlue(refGlyph.bounds[1], refGlyph.bounds[3])
rHeight = rVerticalbounds[1] - rVerticalbounds[0]
gHeight = gVerticalbounds[1] - gVerticalbounds[0]
scaleY = gHeight / rHeight
# scaleX = (self.glyph.bounds[2]-self.glyph.bounds[0]) / (refGlyph.bounds[2]-refGlyph.bounds[0])
scaleX = self.glyph.width / refGlyph.width
# test number of anchors
if len(self.glyph.anchors) != len(refGlyph.anchors):
gA = set(self.anchorListByName(self.glyph.anchors))
rA = set(self.anchorListByName(refGlyph.anchors))
self.anchorsToRemove = list(sorted(gA - rA))
for a in list(sorted(rA - gA)):
missingAnchor = self.getAnchorByName(refGlyph, a)
self.anchorsToAdd[a] = (int(missingAnchor.x * scaleX), int(missingAnchor.y * scaleY))
# test positions of anchors
for anchor in self.glyph.anchors:
x1 = anchor.x - fuzz
x2 = anchor.x + fuzz
gY = anchor.y
for refAnchor in refGlyph.anchors:
if anchor.name in refAnchor.name:
oldPos = [anchor.x, anchor.y]
newPos = [anchor.x, anchor.y]
# check X positions
scaledx = int(refAnchor.x * scaleX)
if not scaledx - fuzz < anchor.x < scaledx + fuzz:
newPos[0] = scaledx
# check Y positions
rY = refAnchor.y
# if inside the glyph bounds - use scale
if rVerticalbounds[0] < rY < rVerticalbounds[1]:
yshift = gVerticalbounds[0] - rVerticalbounds[0]
gY = int(refAnchor.y * scaleY + yshift)
# if above the glyph bounds - use offset
elif rY > rVerticalbounds[1]:
yshift = rY - rVerticalbounds[1]
gY = gVerticalbounds[1] + yshift
# if below the glyph bounds - use offset
elif rY < rVerticalbounds[0]:
yshift = rVerticalbounds[0] - rY
gY = gVerticalbounds[0] - yshift
# if y needs to change
if gY != anchor.y:
newPos[1] = gY
# if x or y changed, add to dict
if str(oldPos) != str(newPos):
self.anchorsToMove[anchor.name] = newPos
def anchorListByName(self, anchors):
anchorNames = []
for a in anchors:
anchorNames.append(a.name)
return anchorNames
def snapToBlue(self, bottom, top):
for zone in self.blues:
if zone[0] <= bottom <= zone[1]:
bottom = zone[1]
if zone[0] <= top <= zone[1]:
top = zone[0]
return (bottom, top)
def drawHelperUI(self):
for anchorName in self.selectedAnchors:
anchor = self.getAnchorByName(self.glyph, anchorName)
print('draw ui for', anchorName, 'at', anchor.x, anchor.y)
def positionFixer(self):
print('positionFixer')
class okCheckBox(CheckBox):
def __init__(self, *args, **kwargs):
self.component = kwargs['component']
del kwargs['component']
self.anchor = kwargs['anchor']
del kwargs['anchor']
super(okCheckBox, self).__init__(*args, **kwargs)
class DecompPen(BasePen):
def __init__(self, glyphSet, outPen):
super(DecompPen, self).__init__(glyphSet)
self._moveTo = outPen.moveTo
self._lineTo = outPen.lineTo
self._curveToOne = outPen.curveTo
self._closePath = outPen.closePath
self._endPath = outPen.endPath
eventName = 'okay.Glyph.SelectionChanged'
allEvents = getRegisteredSubscriberEvents()
if eventName not in allEvents:
registerSubscriberEvent(
subscriberEventName=eventName,
methodName='glyphSelectionChanged',
lowLevelEventNames=['Glyph.SelectionChanged'],
dispatcher='defcon.Glyph',
delay=0,
documentation='This will be called when a defcon.Glyph event `Glyph.SelectionChanged` event is posted. Get the glyph with "notification.object". Default delay: 0 seconds.'
)
registerGlyphEditorSubscriber(anchorHelper)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment