How to create an info box in plugin

Hi!

I want to make a plugin with a custom info box (or inspector). I read the Select Tool guide, and try to use vanilla library to create GUI. I use the following code:

from GlyphsApp.plugins import *
from vanilla import *
from vanilla.vanillaGroup import Group

import objc

# Our own patched Vanilla Group class
class PatchedGroup(Group):
    nsViewClass = objc.lookUpClass("GSInspectorView") # GSInspectorView

class CJKMetrics(ReporterPlugin):

	def settings(self):
		self.menuName = 'CJK Metrics'
		self.name = 'CJK Metrics'

		# Create Vanilla window and group with controls
		viewWidth = 150
		viewHeight = 40
		self.sliderMenuView = Window((viewWidth, viewHeight))
		# Using PatchedGroup() here instead of Group()
		self.sliderMenuView.group = PatchedGroup((0, 0, viewWidth, viewHeight))
		self.sliderMenuView.group.text = TextBox((10, 0, -10, -10), self.name)
		self.sliderMenuView.group.slider = Slider((10, 18, -10, 23), callback=self.sliderCallback)

		# Define the menu
		self.generalContextMenus = [
			{"view": self.sliderMenuView.group.getNSView()}
		]

	# Prints the slider’s value
	def sliderCallback(self, sender):
		print('Slider value:', sender.get())

But I can only find the group added into the context menu, rather than the info box:

Could you please explain what happens here and how I can add the custom info box?


By the way, in the original guide, the statement nsViewClass = GSInspectorView leaves an error NameError: name 'GSInspectorView' is not defined, so I use objc.lookUpClass("GSInspectorView") instead. Is this correct? And if so, please update the document, thank you!

You are adding your view to the content menu (# Define the menu).

What does the slider change? It might be better off in the context menu after all.

You need to add a callback “GSInspectorViewControllersCallback” and implement

def inspectorViewControllersForLayer_(self, layer):
    return [self]
def view(self):
    return self.sliderMenuView.group.getNSView()

inspectorViewControllersForLayer_ is supposed to return NSViewControllers, but any object that can return a view will do.

This his the full code:

import objc
from GlyphsApp import *
from GlyphsApp.plugins import *
from vanilla import *
from vanilla.vanillaGroup import Group

# Our own patched Vanilla Group class
class PatchedGroup(Group):
	nsViewClass = objc.lookUpClass("GSInspectorView") # GSInspectorView

class CJKMetrics(ReporterPlugin):

	@objc.python_method
	def settings(self):
		self.menuName = 'CJK Metrics'
		self.name = 'CJK Metrics'

		# Create Vanilla window and group with controls
		viewWidth = 150
		viewHeight = 40
		self.sliderWindow = Window((viewWidth, viewHeight))
		self.sliderWindow.group = PatchedGroup((0, 0, viewWidth, viewHeight)) # Using PatchedGroup() here instead of Group()
		self.sliderWindow.group.text = TextBox("auto", self.name)
		self.sliderWindow.group.slider = Slider("auto", callback=self.sliderCallback_)
		rules = [
			"H:|-[text]-|",
			"H:|-[slider]-|",
			"V:|-3-[text]-2-[slider]-3-|",
		]
		metrics = {}
		self.sliderWindow.group.addAutoPosSizeRules(rules, metrics)
		GSCallbackHandler.addCallback_forOperation_(self, "GSInspectorViewControllersCallback")
		
	def inspectorViewControllersForLayer_(self, layer):
		return [self]
	def view(self):
		return self.sliderWindow.group.getNSView()

The auto layout stuff is needed as Glyphs internally uses it and the way vanilla sets up the views is not playing well together with it.

I think your solution can work now. Thank you!