This is the first of a series of Python tutorials. No prior knowledge required. In this first installment, we’ll make our first steps in the Macro window.
This multi-part tutorial will get you started with Python. You can read through it all in one morning, have lunch, and write your first scripts in the afternoon of the same day. Have fun!
The Macro Panel
Go to the Window menu and choose Macro Panel (Opt-Cmd-M). You’ll get a window like this:
The upper half is for you to write Python code in. In the lower half, Glyphs can react and answer to your code. You can drag the horizontal separator line to a position you’re comfortable with. Alright, let’s give Glyphs something to react to. Start by typing this line into the upper half:
print "Hello World!"
Uppercase/lowercase is important, so write
'...' or double
Click on the Run button (Cmd-Return, fn-Return, or Enter on extended keyboards) and you should see something like this:
Strings, Integers, Floats and Objects
Speaking of numbers, you can have Python print the result of any calculation. Python differentiates between whole numbers (‘integers’) and decimal numbers (‘floats’), and will keep the result in integers or decimals depending of what you entered. 5 divided by 2 will result in 2, but 5.0 divided by 2.0 will give you 2.5:
If you click on Run (Cmd-Return) a couple of times, you’ll see the result area cluttering up quickly. Click Clear (Cmd-K) to wipe the slate clean.
Now, let’s have Python print a few other things. Try this:
The result is not very surprising. But
Glyphs is neither a string nor a number calculation, but what we call an object. Now,
Glyphs is an object that contains other objects. To refer to those sub-objects, we add a period to
Glyphs and the name of that sub-object. Try this:
print Glyphs.fonts print Glyphs.font
And Python will print the list of currently opened fonts between brackets (the result of
print Glyphs.fonts), plus the frontmost font (the result of
print Glyphs.font). If you have no fonts open, you’ll receive an empty list (brackets with nothing in between) and
None as answer:
Open a few fonts, go back to the Macro Panel and click Clear (Cmd-K) and Run (Cmd-Return) again. Bring different fonts to the front and see what happens if you run your code again.
So, Glyphs.fonts returns a list of fonts. You can access the individual fonts in the list by adding digits in brackets, starting at 0, like this:
print Glyphs.fonts # 1st open font, same as Glyphs.font print Glyphs.fonts # 2nd open font
Oh, yes: the number sign
# marks a comment. Everything following it will be ignored. It’s a good idea to insert descriptive comments into your code. If you try to fix or adapt your script years later, you will thank yourself for your commentary. Really.
And you probably guessed it already: You can use
Glyphs.font as a short cut for
And as you can imagine, even a font has sub-objects. Again, we can address those by adding a period and the object name. Try this:
You can access individual glyphs by adding either their index number or their name in brackets. Try these:
print Glyphs.font.glyphs print Glyphs.font.glyphs["a"]
Again, we can add a period and access whatever information a glyph contains. Try these:
print Glyphs.font.glyphs["a"].name print Glyphs.font.glyphs["a"].category print Glyphs.font.glyphs["a"].subCategory print Glyphs.font.glyphs["a"].unicode
Remember, you can use Copy and Paste. You don’t have to retype every line.
Sure enough, this is a pretty inefficient way of accessing glyph info. If we want the same info about b, we’d have to change a to b in four lines. So let’s introduce a variable:
glyphname = "b" print Glyphs.font.glyphs[glyphname].name print Glyphs.font.glyphs[glyphname].category print Glyphs.font.glyphs[glyphname].subCategory print Glyphs.font.glyphs[glyphname].unicode
Add a comma to the end of a print line if you want to avoid a linebreak and keep all the info on one line:
glyphname = "b" print Glyphs.font.glyphs[glyphname].name, print Glyphs.font.glyphs[glyphname].category, print Glyphs.font.glyphs[glyphname].subCategory, print Glyphs.font.glyphs[glyphname].unicode
Now, programming is about not having to retype everything. We should let Python do the repetitive stuff. You see the stuff that stays the same in all lines? Let’s add another variable for that and perhaps a blank line for clarity:
glyphname = "b" myGlyph = Glyphs.font.glyphs[glyphname] print myGlyph.name, print myGlyph.category, print myGlyph.subCategory, print myGlyph.unicode
All we need to change now is the glyph name in the first line.
But let’s say, we want those infos for every glyph in the font, what do we do? Sure, we could copy and paste the whole block a hundred times and change the glyph name everywhere. But that’s boring for non-robots, so let’s have Python do that for us:
for myGlyph in Glyphs.font.glyphs: print myGlyph.name, print myGlyph.category, print myGlyph.subCategory, print myGlyph.unicode
Note that all the
Python steps through all the glyphs, and prints an info line each time. Hey! This is, like, the first result in this tutorial we can actually use for something. We can, for instance, copy it and paste it into an e-mail for a status report. Let’s make it a little more versatile, get rid of all but one
for myGlyph in Glyphs.font.glyphs: print myGlyph.name, myGlyph.category, myGlyph.subCategory, myGlyph.unicode
Now, we want our glyph info report for all open fonts. Luckily, we can nest indentations. How about this:
for myFont in Glyphs.fonts: print print "Report for:", myFont.familyName for myGlyph in myFont.glyphs: print myGlyph.name, myGlyph.category, myGlyph.subCategory, myGlyph.unicode
Want your report to contain other info? Head on over to the Glyphs Python Documentation and see what else the Glyph object (‘GSGlyph’) and the Font object (‘GSFont’) can do for you.
In the next part, we’ll dig a little deeper into GSGlyph and drill all the way down to the nodes.
Update 2014-10-04: Added shortcut Glyphs.font, and link to part 2.
Update 2015-07-30: Updated Screenshots for Glyphs 2.
Update 2016-12-08: Updated screenshots, fixed formatting, use Glyphs.font instead of Glyphs.currentDocument.
Update 2016-12-09: Added first paragraph.