PR #2481: Improve FreeCADGui.addIcon()

Merged, abandoned or rejected pull requests are moved here to clear the main Pull Requests forum.
Post Reply
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

PR #2481: Improve FreeCADGui.addIcon()

Post by realthunder »

PR link

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[0],size[1],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
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
User avatar
yorik
Founder
Posts: 13640
Joined: Tue Feb 17, 2009 9:16 pm
Location: Brussels
Contact:

Re: PR #2481: Improve FreeCADGui.addIcon()

Post by yorik »

cool! the overlay ability is nice
Post Reply