How to import SF Symbols as a NSImage in vanilla?

I’m making the plugin now that I need to use some image buttons for UI.

Here’s the sample code from vanilla:

import AppKit
from vanilla import Window, ImageButton

class ImageButtonDemo:

     def __init__(self):
         self.w = Window((50, 50))
         self.w.button = ImageButton((10, 10, 30, 30),
             imageNamed=AppKit.NSImageNameRefreshTemplate)
         self.w.open()

ImageButtonDemo()

I can change other system icon name by customize imageNamed, but how can I use the icon from SF Symbols such as the icons below?

Any hints will be helpful for me. Thank you.

Instead of imageNamed, use imageObject. You get the image object like so:

NSImage.imageWithSystemSymbolName_accessibilityDescription_("symbol.name", None)

For example:

import AppKit
from vanilla import Window, ImageButton

class ImageButtonDemo:

     def __init__(self):
         self.w = Window((50, 50))
         self.w.button = ImageButton((10, 10, 30, 30),
             imageObject=AppKit.NSImage.imageWithSystemSymbolName_accessibilityDescription_("textformat.size", None))
         self.w.open()

ImageButtonDemo()

Thanks a lot! It work for me.

By the way, is this possible to let a text or list items appends NSImage?

For example, in PopUpButton component, I’m now using emoji as the icon for each items, but I’m wondering to know whether it can contain NSImage or not.

Also, sometimes I just want to display an image/icon, rather than using ImageButton without callback function to embed the image on window, can I use TextBox component to made it?

image

Yes, but you need to create the menu item manually using NSMenuItem.

For example:

from AppKit import NSMenuItem, NSImage
from vanilla import Window, PopUpButton

class PopUpButtonDemo:

    def __init__(self):
        self.w = Window((120, 40))
        itemA = NSMenuItem.new()
        itemA.setTitle_("Item A")
        itemA.setImage_(NSImage.imageWithSystemSymbolName_accessibilityDescription_("sun.max", None))
        itemB = NSMenuItem.new()
        itemB.setTitle_("Item B")
        itemB.setImage_(NSImage.imageWithSystemSymbolName_accessibilityDescription_("moon.fill", None))
        self.w.popUpButton = PopUpButton((10, 10, 100, 20),
                              [itemA, itemB],
                              callback=self.popUpButtonCallback)
        self.w.open()

    def popUpButtonCallback(self, sender):
        print("pop up button selection!", sender.get())

PopUpButtonDemo()

would result in:

In that case use an ImageView:

https://vanilla.robotools.dev/en/latest/objects/ImageView.html

Sorry for on more question!

What’s the None attribute here means? Is it about color or icon size?

Because I want to make a PopButtonList for selecting glyph color and so on, with color circles are more easily to recognize than using text only.

I know that SF Symbol can customize color in Swift, but how to customize the color of SF Symbol in vanilla?

Thank you.

I got it.

It works fine for me, but different method is welcome!

NSImage.imageWithSystemSymbolName_accessibilityDescription_("circle.fill", None)._flatImageWithColor_(NSColor.colorWithString_("#88ff88"))

You are not working inside vanilla, but in python. With pyobjc you can use objectiveC/AppKit directly: all those NS classes and long method names with underscores.

This might help to work with SFSymbols: Configuring and displaying symbol images in your UI | Apple Developer Documentation

When you like to just display a colored circle, you don’t need SFSymbols for this. You can make an empty NSImage and draw into it in code.

import os
from AppKit import NSImage, NSBezierPath, NSColor, NSMakeSize, NSMakeRect
def circleImage(color):
	circleImage = NSImage.alloc().initWithSize_(NSMakeSize(16, 16))
	circleImage.lockFocus()
	rect = NSMakeRect(1, 1, 14, 14)
	path = NSBezierPath.bezierPathWithOvalInRect_(rect)
	color.set()
	path.fill()
	circleImage.unlockFocus()
	return circleImage
	
blueCircleImage = circleImage(NSColor.blueColor())
redCircleImage = circleImage(NSColor.redColor())

blueCircleImage.TIFFRepresentation().writeToFile_atomically_(os.path.expanduser("~/Desktop/blueCircleImage.tif"), False)
redCircleImage.TIFFRepresentation().writeToFile_atomically_(os.path.expanduser("~/Desktop/redCircleImage.tif"), False)
1 Like