The motivation of this PR is to make it easy for Python workbench cache its own icons (possibly generated at runtime), saving the trouble of pre-compiling the icons as binary resources.
* Gui.addIcon(name,content,format='XPM') now support a third argument as format. Default format is 'XPM' as before. The intention is to allow user to cache other format of icon image (which most likely dynamically generated), like 'PNG'. addIcon() still supports file path input (in 'content') just as before.
* A new function Gui.isIconCached(key) is added to check if an icon is cached with the given key.
* ViewProviderPythonFeature::getIcon() (i.e. the python method getIcon() in ViewObject class) now checks if the given string argument is a key to a cached icon. The key will be the 'name' argument you passed to Gui.addIcon().
BTW, I previously added support of passing direct QIcon Python object as 'content' in Gui.addIcon(). But this requires the FreeCAD to be compiled with Pyside/Shiboken support. The recent trouble of finding Pyside2/Shiboken2 proves that this method is unreliable. The following sample code shows how to use the new icon capability and also maintain backward compatibility, i.e. it works on FreeCAD before and after this PR.
Code: Select all
import FreeCADGui from PySide.QtGui import QIcon, QPainter, QPixmap from PySide.QtCore import Qt, QIODevice, QBuffer, QByteArray def getIcon(icon_path, overlay_path=None, size=(16,16), mode=QIcon.Normal, cache=True): ''' Make an icon that are useable by FreeCAD, with optional overlay icon_path: file path to the normal icon image overlay_path: optional file path to an overlay image size: icon image size mode: icon mode to use from input icon image cache: whether to force cache icon on older FreeCAD. Note that if the icon is intended for view object tree icon, you should not cache the icon, as it is not supported. Workbench icon does support cache. Return a key for the cached overlay icon. For older version FreeCAD, return the file path if no overlay, or else return a string containing the XPM format of the icon. Example usage: to obtain an overlayed disabled icon, getIcon(icon_path, overlay_path, mode=QIcon.Disabled) ''' # The key for the generated icon. You can change to whatever you like, but # make it unique among the entire application with other workbenches. key = icon_path if overlay_path: key += overlay_path fmt = None try: if FreeCADGui.isIconCached(key): return key fmt = 'PNG' except Exception: # Exception here means it's an older version FreeCAD without isIconCached() # function. So if there is no overlay, just return the file path. Or # else, we shall later use XPM format, which will result in a slightly # uglier icon, but works nevertheless. if not overlay_path and mode==QIcon.Normal: return icon_path # Obtain the normal icon image of the given size pixmap = QIcon(icon_path).pixmap(*size,mode=mode) if overlay_path: # Load the overlay image on disk overlay = QIcon(overlay_path) # Paint the overlay to the disabled icon at the center overlay.paint(QPainter(pixmap),0,0,size,size,Qt.AlignCenter) # Construct the buffer for saving icon image data = QByteArray() buf = QBuffer(data) buf.open(QIODevice.WriteOnly) if fmt: pixmap.save(buf, fmt) FreeCADGui.addIcon(key,data.data(),fmt) else: pixmap.save(buf, 'XPM') data = data.data().decode('latin1') if not cache: return data try: FreeCADGui.addIcon(key,data) except AssertionError: # For older FreeCAD, this is the only way to check if the icon is # cached or not. You may want to cache the returned key in your # object to avoid repeatedly loading icon from disk. pass return key