Plugin development with PyObjC
Yesterday I made a decent amount of progress on the plugin, while today I was mostly just stuck on trying to make the “intersectPath” method work.
Then I noticed that I haven’t exactly started with the beginning on developing a Glyphs plugin. So I thought I’d go through the steps of making one.
The whole process has been a mix of reading the docs on the Glyphs website, asking around in the forums and the docs in the SDK-repo.
https://glyphsapp.com/learn/plugins
I initially attempted to make one using Objective C, and it was a fairly straightforward process of setting up a project in Xcode, but I found that debugging and logging wasn’t that easy and Objective C not being my main programming language I found that it was far easier to experiment and do exploratory testing using Python.
When I got stuck I turned toward the forums, which in turn pointed me toward the GlyphsSDK and how to use that to create a Python project.
https://github.com/schriftgestalt/GlyphsSDK/tree/Glyphs3
After all of that was set up with GitHub and everything, I needed to find a way to work with the GUI.
The GUI is set up in an xml-file with suffix .xib, where TextFields and connectors are defined and I need to connect them to their proper accessor methods in plugin.py. The editing there is done in Xcode as well, but since it’s hidden behind a .glyphsPlugin or .glyphsFilter directory, I have to open the contents of that package in Finder and then open it in Xcode.
When I’ve made changes to the .xib it needs to compile into a .nib using:
find . -name "*.xib" -type f | awk '{sub(/.xib/,"");print}' | xargs -I % ibtool --compile %.nib %.xib
In the directory of the .xib-file
For the ThorTypeFilter I have it in a shell script, but if I want to release the plugin as I want to do with the AdvancedHatch, I should probably just set up an alias in .bashrc or .zshrc for convenience.
Another thing I’ve learned is how to work with wrapper libraries for entirely different programming languages. In this case PyObjC to use Objective C methods from Python. As an example, I noticed that there were some static methods in the GSPathOperator-class I needed to intersect paths. To access this class I can use:
GSPathOperator = objc.lookUpClass("GSPathOperator")
Then I’ll just have to use the python “dir” and “inspect” methods to see how it looks like on the Python side, while I’ll cross reference that with the header-files as I mentioned yesterday.
On another note, I learned today that adding curve points to two parallel paths and making sure the curve remains parallel is a non-trivial problem which involves a lot of math even to approximate – so if I want to add a curved path feature to the hatching effect I might have to find a way around that.
I’m already considering writing the HatchOutline-function manually by using the intersect method on a list of overlapping straight path segments, so an easier way might be to just intersect an a readymade wavy pattern with the original outline. Implementing the HatchOutline effect manually would mean that the plugin is less susceptible to break from changes to the API of the original HatchOutline-filter, even though it’s supposed to be a built in function.
Being so close to a working solution and getting stuck on a boolean operation reminds me of the “90 90” rule, because even though it feels like the plugin is 90% finished, the remaining 10% is really more like another 90%.