Description
The left, right, top, bottom margins rely on glyph bounds, which is fine for most work. There are times when it would be nice to be able to specify the y (in the case of left, right) where we want the measurement to be taken instead of the bounding box. I started writing this for a tool, but then realized that it might be useful in fontParts. Here's the idea (for left, right for now, but top, bottom are similar):
- the y value is defined with a guideline
- the guideline can be located at the font or glyph level.
- glyph guidelines override font guidelines.
- guidelines may be defined for use on both sides, the left or the right by setting the guideline name:
margins
,margin-left
, margin-right` - side specific guidelines override both side guidelines.
- if a side specific guideline is not defined, the base
leftMargin
orrightMargin
value is used.
These would be accessible through properties, just like leftMargin
and rightMargin
. The names that popped into my head were smartLeftMargin
and smartRightMargin
but I don't really like the vagueness of smart
. It implies magic but there is no magic in this. Maybe something like local*Margin
? I don't know...
Here is a quick implementation:
from fontPens.marginPen import MarginPen
def getSmartMargins(glyph):
font = glyph.font
both = None
left = None
right = None
# look for glyph level guidelines
while any((both is None, left is None, right is None)):
for guideline in glyph.guidelines:
if guideline.name == "margins":
both = guideline
elif guideline.name == "margin-left":
left = guideline
elif guideline.name == "margin-right":
right = guideline
break
# use font guidelines if there
# glyph level guidelines are
# not defined
buffer = 10
if all((font is not None, both is None, left is None, right is None)):
buffer = font.info.unitsPerEm * 0.01
while any((both is None, left is None, right is None)):
for guideline in glyph.guidelines:
if all((both is None, guideline.name == "margins")):
both = guideline
elif all((left is None, guideline.name == "margin-left")):
left = guideline
elif all((right is None, guideline.name == "margin-right")):
left = guideline
break
# calculate the left
leftMargin = 0
if all((left is None, both is None)):
leftMargin = glyph.leftMargin
elif any((glyph.contours, glyph.components)):
if left is not None:
y = left.y
elif both is not None:
y = both.y
pen = MarginPen(glyphSet=glyph.layer, value=y)
glyph.draw(pen)
leftMargin = pen.getMargins()[0]
# calculate the right
rightMargin = 0
if all((right is None, both is None)):
rightMargin = glyph.rightMargin
elif any((glyph.contours, glyph.components)):
if right is not None:
y = right.y
elif both is not None:
y = both.y
pen = MarginPen(glyphSet=glyph.layer, value=y)
glyph.draw(pen)
rightMargin = glyph.width - pen.getMargins()[1]
# done
return (leftMargin, rightMargin)
def setSmartLeftMargin(glyph, value):
oldValue = getSmartMargins(glyph)[0]
diff = value - oldValue
glyph.leftMargin += diff
def setSmartRightMargin(glyph, value):
oldValue = getSmartMargins(glyph)[1]
diff = value - oldValue
glyph.rightMargin += diff
Would this be a good addition to fontParts or is this something better left to an extension or something like that?