Create List Filter via Script

Is this possible? Couldn’t find it in the docu.

unfortunately not. At least not in a sane way. Can you add a feature request to: http://bugreport.glyphsapp.com

Still the same answer here?

not sure if there’s a better way, but I do it like this:

filterContent = {"Count" : 1,
				 "ShallHaveCount" : 1,
				 "icon" : "CustomFilterListTemplate",
				 "isLeaf" : 1,
				 "list" : ["A"],
				 "name" : "myNewFilter"
				 }

filterController = Font.fontView.glyphsGroupViewController()
filters = filterController.glyphGroups()[2]["subGroup"]
filters.append(filterContent)
filterController.update()
2 Likes

That looks very good.

Any updates on this? It doesn’t seem to work anymore with Glyphs 3.

from Foundation import NSMutableDictionary
font = Glyphs.font
filterController = font.fontView.glyphsGroupViewController()
glyphGroups = filterController.glyphGroups()
filters = glyphGroups[3]
print(filters)
flt = NSMutableDictionary.dictionaryWithObjectsAndKeys_(
	True, "isLeaf",
	"MyListFilter", "name",
	["A", "B"], "list",
	"CustomFilterListTemplate", "icon",
	None
)
# Neither of those two options work:
# filters.insertObject_inSubItemsAtIndex_(flt, 0)
# filters.insertSubItems_atIndex_([flt], 0)
filterController.update()

Alternatively, is there a way to filter the font view from within a script temporarily without adding a filter to the sidebar?

Alternatively, is there a way to filter the font view from within a script temporarily without adding a filter to the sidebar?

I have thought the same thing a few years ago:

class SearchState(object):
	ALL     = 0
	NAME    = 1
	UNICODE = 2
	NOTE    = 3
	@staticmethod
	def make_key(key, searchField):
		if Glyphs.versionNumber < 3.0:
			return 'GlyphList{0}'.format(key)
		return searchField.key_(key)
	@classmethod
	def set_state_in_font(cls, font, state, search=False):
		controller = font.fontView
		searchField = controller.glyphSearchField()
		searchField.setStringValue_(state.pattern)
		Glyphs.defaults[cls.make_key('SearchState', searchField)] = state.mode
		Glyphs.defaults[cls.make_key('SearchStateMatchCase', searchField)] = state.match_case
		Glyphs.defaults[cls.make_key('SearchStateRegex', searchField)] = state.regex
		if search:
			controller.filterGlyphs_(searchField)
	@classmethod
	def from_font(cls, font):
		controller = font.fontView
		searchField = controller.glyphSearchField()
		return cls(
			searchField.stringValue(),
			Glyphs.defaults[cls.make_key('SearchState', searchField)],
			bool(Glyphs.defaults[cls.make_key('SearchStateMatchCase', searchField)]),
			bool(Glyphs.defaults[cls.make_key('SearchStateRegex', searchField)])
		)
	def __init__(self, pattern, mode=0, match_case=False, regex=False):
		self.pattern    = pattern
		self.mode       = mode if not regex else self.NAME
		self.match_case = match_case
		self.regex      = regex
	def perform_temporal_search(self, font):
		prev = self.from_font(font)
		try:
			self.set_state_in_font(font, self, search=True)
		finally:
			self.set_state_in_font(font, prev, search=False)
	@classmethod
	def reset(cls, font):
		cls.set_state_in_font(font, cls.from_font(font), search=True)

if __name__ == '__main__':
	SearchState('A|B|C', mode=SearchState.NAME, match_case=True, regex=True).perform_temporal_search(Glyphs.font)

I came up with the code above. My idea at that time was to perform a regex search, and then restore only the UI state as if nothing happened.

To add a new filter:

GSSidebarItem = objc.lookUpClass("GSSidebarItem")
font = Glyphs.font
filterController = font.fontView.glyphsGroupViewController()
glyphGroups = filterController.glyphGroups()
filters = glyphGroups[3]
print(filters)
newItem = GSSidebarItem.new()
newItem.setName_("MyListFilter1")
newItem.setCoverage_(["A", "B"])
newItem.setIconName_("CustomFilterListTemplate")
newItem.setItemType_(3)
filters.insertObject_inSubItemsAtIndex_(newItem, len(filters.subItems()))
filterController.didChangeSidebarItem_(filters)

And to temporarily change the sorting in Font view:

from AppKit import NSSortDescriptor
font = Glyphs.font
glyphsArrayController = font.fontView.glyphsArrayController()
glyphsArrayController.setSortDescriptors_([NSSortDescriptor.alloc().initWithKey_ascending_("layer0.LSB", True)])

And when you like to use a predefined list of names:

GSSortDescriptorNameList = objc.lookUpClass("GSSortDescriptorNameList")
font = Glyphs.font
glyphsArrayController = font.fontView.glyphsArrayController()
sortDescriptor = GSSortDescriptorNameList.alloc().initWithKey_ascending_("name", True)
sortDescriptor.setReferenceList_(["z", "y", "x"])
glyphsArrayController.setSortDescriptors_([sortDescriptor])
5 Likes

Whoa. I can even set up a filter smarter than a smart filter:

newItem = GSSidebarItem.new()
newItem.setName_("MySmartFilter1")
newItem.setPredicate_(NSPredicate.predicateWithFormat_("""\
	NOT (name MATCHES '[A-Z].+')
	AND ((name CONTAINS 'acute') OR (name CONTAINS 'grave'))
	AND (export == 1)
	AND ((layer0.countOfPaths > 0) OR (layer0.countOfComponents > 0))
"""))
newItem.setIconName_('CustomFilterPredicateTemplate')
newItem.setItemType_(3)

This will be definitely a time saver for me. Thanks for the snippets!

2 Likes

I am trying to use this code to implement a temporarily change to the sorting in the Font view using a pre-defined list of names. I’m able to see the Font View change successfully, but after a second or two, it updates again and restores back to the standard view. This didn’t happen when I was running the plugin on Glyphs2, so that leads me to think this is something new in Glyphs3. Is there some way to prevent the fontview from updating again or to preserve the predefined sort for longer?

Following up on this @GeorgSeifert. Any idea why this is happening?

I used the script and the sorting is still there even after I worked on the font for some time.

But any selection in the sidebar and adding/removing glyphs will most likely reset it.

Ah, thanks! It seems one of the instances of Glyphs.font.fontView.glyphsGroupViewController().update() in my script was being re-run for some reason, clearing the view.