Filter-Plugin export problem and more

I’ve made a Filter Plugin to handle components and some other things on export but have a major problem (and noticed some other things).

Details about the idea behind the plugin and it’s functionality you can find in this post: Instances: Combine, manipulate and replace glyphs on export

  1. When the plugin is called as custom filter, all components are already decomposed when Layer is passed to processLayerWithValues.
    In Edit View the plugin works just fine and components can be manipulated without any problem.
    Because of this “misbehaving” the main functionality of my plugin is not working at the moment.
    Called by the UI the "A" has: 5 components and 0 paths.
    Called as custom filter the "A" has: 0 components and 4 path - which is exactly what I get when I apply decomposeComponents() and removeOverlap().
    I wonder if this behavior could be disabled and/or applied after all existing custom filters - just before the export.
    It seems filterNeedsRemoveOverlap() is not called, but anyway I would expect that False would be the default return value and that removeOverlap() would be applied after each time the filter is called…
    However, I’m running out of ideas and really hope you guys can help me with my problem.

  2. When manipulating components with the plugin in Edit View there is some kind of glitch with the preview (via ShadowLayers I think).
    When changing the UI input, the preview does not reset properly and the changes are not indicated like they are when you use removePathAtIndex_(0) and then e.g. change it to removePathAtIndex_(1) — compared to removeComponentAtIndex_() where no grey outlines appear and the component is fully from the Edit View removed till the UI is closed.
    The same problem I have with my own component manipulating functions.
    Is there something I could do to improve the current behavior?

Additional questions and stuff about (Filter-)Plugins:

  • About the Filter Plugin code sample: I wonder if Layer.clearSelection() from within process_() is at the right spot at the moment.
    Currently Layer.clearSelection() is only applied to the last Layer because it’s not in the loop (missing indentation?), therefore it throws an error when there is no Layer at all.

  • Is it wise to use beginUndo/endUndo, beginChanges/endChanges and even disableUpdateInterface/enableUpdateInterface in general or only in one of the two possible ways a Filter Plugin can be used?
    Or are (some of) those functions called in the background already?
    I’ve noticed an improvement with beginUndo/endUndo when the plugin is used in Edit View but don’t know the impact it might have when called as custom filter etc.
    A few more details in the documentation could help to understand when they should (not) be used.

  • Is there a difference between and ?
    /new was crawled by Google but isn’t actually linked on your website. If you’re currently working on that you might want to disable access via htpasswd or something :wink:

Tested with Glyphsapp 2.1.1 and a test font with 1 master, 1 instance, 1 real glyph (the “A”) and 5 components for the “A”.

Thank you in advance for your help
best regards

Unless you call it with a PreFilter parameter.

I would need to take a look at your plugin for that.

Those functions make no sense for the custom parameter method. So only use it in the method for being called from the Filter menu.

disableUpdateInterface can speed up processing when many glyphs are selected.

Only use We used /new to prepare the website update.


AWESOME, that’s exactly what I was looking for! Thank you very much.
With PreFilter instead of Filter the plugin works as expected so I will now cleanup and finish the plugin as soon as possible.

Now I just wonder: Is there an easy way to show a proper preview in each instance as well?

Actually you can test this behavior with your LayerGeek plugin as well. My plugin is kind of extending your idea with additional functions for the layer.
Just try removePathAtIndex_(0) and change it to removePathAtIndex_(1) then try to do the same with removeComponentAtIndex_(0) and you should see the difference.
But I can also send you the unfinished plugin if you like.

Again: Thank you very much for your help and the details about beginUndo/endUndo/etc. It’s very much appreciated.

if you like to see a preview, apply the changed to the Layer. And for each run of the plugin, use a copy of the content of the shadowLayer, process it and put it into the Layer.

Export in the Adobe Fonts folder:

I found the issue with the preview in Edit View.
After adding the following line where the paths are already handled (see in sample code), also the components will be reset properly when changing the UI input.

Layer.setComponents_( NSMutableArray.alloc().initWithArray_copyItems_( ShadowLayer.pyobjc_instanceMethods.components(), True ) )

I’m not sure I follow… but I suppose I need to add some shadowLayer handling to processFont_withArguments_ . I just can’t find a way to get the shadowLayers associated to the layers accessed via thisGlyph.layers[FontMasterId].
Is there a chance to get some more insight into built-in plugins so I could figure it out myself?

mekkablue: Well, when I write a Filter Plugin and you guys provide a preview for each instance I sure want my plugin to support this as well :smiley:

You mean the preview at the bottom? It only shows a few select filter effects. You can override it and draw your own preview though. This has recently been documented in the source code. Make sure you have the latest source files. Keep in mind, however, that Python code can slow down app performance.

Exactly! I would like to give it a shot with the instance preview to find out how time and resource consuming it is in my case. I might even add a plugin setting to enable it manually for easier testing.
And maybe the code can be applied only to the characters actually visible in the preview or something to make things faster

But I don’t really get what you mean with documented in the source code? The source code of the Can you point me in the right direction here?
I couldn’t find much about shadowLayer there, just some objc definitions/interfaces (also in the newest version).
I’m kind of struggling with hidden functionality I know it’s there (at least in this case) but I can’t figure out where it is and how it needs to be used. It seems to me the part I’m looking for is either “compiled” and/or not available in the online documentation.
But according to the fact that you’re building a newer/better documentation I just hope you will extend the plugin section a little and/or let us see what’s happening in built-in plugins (soon).

I’ve stumbled over help(GSLayer) yesterday and will now try to find out if there are more things of interest - compared to what I get with dir().

No. In the templates of the GlyphsSDK. They used to be a mistake in there, but it is now corrected. Perhaps you want to make sure that you have the latest version.

To be clear, you would need to write your own reporter plugin for drawing a preview. In the source code, you will find documentation strings for each method. Take a look at drawBackgroundForInactiveLayer_() and needsExtraMainOutlineDrawingForInactiveLayer_().

I’m sorry but I could need some further assistance here…

For my understanding:
As I want a preview for each instance (Font Info -> Instances), I don’t think I actually have to write a Reporter Plugin also/instead, but I should be abel to add some functionality of if or similar to it to my FilterPluginWithDialog, right?

As the GlyphsReporter protocol does not work for a filter plugin, I tried to use the GlyphsFilter protocol instead and implemented all the required methods, but then the UI/dialog won’t show anymore.
With or without the protocol, none of the drawXY functions nor the needsExtraMainOutlineDrawingForInactiveLayer_ are ever called. But I’m still not sure I even have to use those in order to apply the user input to the glyphs visible in the instance preview (via shadowLayers I guess).

However, I still couldn’t figure out how to hook me into the process of preparing the preview for an instance and how to access the corresponding input for that.
How do other FilterPlugins like GlyphsFilterOffsetCurve do that?

Your advice and maybe an example would be appreciated.
Thank you in advance.

A few things I’ve noticed during debugging:

  • init() is called about 4 times (each time you switch to another instance - multiplied by the number of times used in the same instance).
  • only when using the GlyphsFilter protocol:
  • self.setup() and self.process_() don’t get called anymore (deprecated or just the wrong protocol?).
  • the UI won’t show automatically - no idea how to do it manually.
  • there is no user input from the UI available in runFilterWithLayer_error_(), afaik.

If you want to draw a preview, you will need the Reporter Protocol. What I would do is write the Reporter and the Filter.

They are only called as part of the Reporter protocol.

There is a step-by-step explanation at the beginning of the .py file. It describes the steps you need to take in Xcode for building the UI in IB, compiling it, and hooking it up with your code.

Well, the Plugin works with the UI and on export when based on the Filter with Dialog sample code but I couldn’t find a way to show a preview for each instance.
Sorry for asking again, but the main question remains: how/where could I do that?

Let me recapitulate:

  • The GlyphsReporter is not what I need for my custom filter plugin (no dialog will be shown).
  • The GlyphsFilter protocol is not working when using a dialog. Not sure if another protocol exists for Filter with Dialog.
  • My code in the “old” version (without any protocol) would show the dialog and all works fine - except the instance preview.

Can you send me the code of the filter plugin?

The Reporter is not for dialogs. It is for drawing on the canvas. In other words, for a preview.

Hey Georg,
do you have any kind of hint for my request?
I’ve sent you the plugin in an email with the subject “Support request: Preview for instances”.
thank you in advance