Scripting Smart Sets ↩
The scripts below demonstrate the mojo.smartSet API.
Inspecting Smart Sets
If you only need to inspect smart sets without altering the data, you can use getSmartSets()
from mojo.smartSet import getSmartSets
# get default sets
defaultSets = getSmartSets()
print(defaultSets)
# get font sets
f = CurrentFont()
fontSets = getSmartSets(f)
print(fontSets)
Modifying Smart Sets
Instead, if you need to alter the smart sets, we strongly advice to use the with smartSetsEditor()
context, to force an update of the RoboFont UI at the end of the process. The with
context exposes a list
that can be modified with standard methods like .append()
, .extend()
or .remove()
Append one smart set
from mojo.smartSet import SmartSetsEditor, SmartSet
with SmartSetsEditor() as smartSets:
smartSets.append(
SmartSet(smartSetName="foo", glyphNames=["a", "b"]),
)
Append several smart sets
from mojo.smartSet import SmartSet, SmartSetsEditor
# a bunch of fresh new smart sets
items = [
SmartSet(smartSetName="foo", glyphNames=["a", "b"]),
SmartSet(smartSetName="bar", query="Width < 200")
]
with SmartSetsEditor() as smartSets:
smartSets.extend(items)
Append smart set per mark color name
from mojo.UI import getDefault
from mojo.smartSet import SmartSet, SmartSetsEditor
from lib.tools.misc import rgbaToString
# get all colors
colors = getDefault("markColors")
with SmartSetsEditor() as smartSets:
group = None
# look if there is already a Mark Color smart set group
for smartset in smartSets:
if smartset.name == "Mark Colors":
group = smartset
# remove all the group items
group.removeGroups()
break
# if nothing is found, create a new group smart set
if group is None:
group = SmartSet()
group.name = "Mark Colors"
smartSets.append(group)
# loop over all colors and name and add a smart set query
for rgba, name in colors:
group.addGroupSmartSet(SmartSet(smartSetName=name, query=f"MarkColor == '{rgbaToString(rgba)}'"))
Clear all smart sets
The following example will delete all existing smart sets, be aware!
from mojo.smartSet import SmartSetsEditor
with SmartSetsEditor() as smartSets:
smartSets.clear()
Font-specific smart sets
If you want to create a font-specific smart set, remember to pass the font object to the with smartSetsEditor()
context. The SmartSet
object itself does not know if it belongs to a font or not. Check the example:
from mojo.smartSet import SmartSetsEditor, SmartSet
from mojo.roboFont import CurrentFont
fontSmartSet = SmartSet(smartSetName="alternates",
glyphNames=["a.001", "b.001"])
myFont = CurrentFont()
with SmartSetsEditor(myFont) as smartSets:
smartSets.append(fontSmartSet)
Remove Smart Sets
If you want to remove a SmartSet
by using its name, you can do it either globally:
from mojo.smartSet import SmartSetsEditor
removeName = 'mySmartset'
# global sets!
with SmartSetsEditor() as smartSets:
for smartset in smartSets:
if smartset.name == removeName:
smartSets.remove(smartset)
or locally:
from mojo.smartSet import SmartSetsEditor
from mojo.roboFont import CurrentFont
removeName = 'mySmartset'
# font sets!
font = CurrentFont()
with SmartSetsEditor(font) as smartSets:
for smartset in smartSets:
if smartset.name == removeName:
smartSets.remove(smartset)
Query-based Smart Sets
Queries are expressed using Apple’s Predicate Format String Syntax.
Language tokens
These are the main building blocks of the predicate language:
construct | examples |
---|---|
literals | False True 'a' 42 {'a', 'b'} |
compound expressions | and or not |
aggregate operations | any some all none in |
basic comparisons | = >= <= > < != between |
string comparisons | contains beginswith endswith like matches |
The
matches
comparison requires a regular expression. (see the example below)
Glyph attributes and supported comparisons
These are the glyph attribute names, their data types and supported comparisons.
type | attributes | comparisons |
---|---|---|
str |
Name ComponentsNames AnchorNames
|
in
contains
beginswith
endswith
like
matches
|
int or float |
Width LeftMargin RightMargin Unicode Contours Components Anchors
|
<
=
>
!=
between
in
|
str |
MarkColor
|
=
!=
contains
matches
|
bool |
Empty GlyphChanged Template SkipExport
|
True False
|
str |
Note
|
contains
|
Example queries
"Name == 'a'"
"Name in {'a', 'b'}"
"Empty == 'True'"
"Name contains 'a' AND Width < 300"
"Name matches '[A-z]'"
"Width in {120, 240, 360}")