Icons in macros

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
ulrich1a
Veteran
Posts: 1957
Joined: Sun Jul 07, 2013 12:08 pm

Icons in macros

Post by ulrich1a »

In order to distribute and maintain macros it is often best to have them in a single file. Now the question, is it possible also to define an SVG-definition of an icon inside the code? The samples only contain an XPM definitions inside of the code like this:

Code: Select all

    def getIcon(self):
        '''Return the icon in XPM format which will appear in the tree view. This method is\
                optional and if not defined a default icon is shown.'''
        return """
            /* XPM */
            static const char * ViewProviderBox_xpm[] = {
            "16 16 6 1",
            "   c None",
            ".  c #141010",
            "+  c #615BD2",
            "@  c #C39D55",
            "#  c #000000",
            "$  c #57C355",
            "        ........",
            "   ......++..+..",
            "   .@@@@.++..++.",
            "   .@@@@.++..++.",
            "   .@@  .++++++.",
            "  ..@@  .++..++.",
            "###@@@@ .++..++.",
            "##$.@@$#.++++++.",
            "#$#$.$$$........",
            "#$$#######      ",
            "#$$#$$$$$#      ",
            "#$$#$$$$$#      ",
            "#$$#$$$$$#      ",
            " #$#$$$$$#      ",
            "  ##$$$$$#      ",
            "   #######      "};
            """
Ulrich
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Icons in macros

Post by triplus »

I investigated this area for TabBar purposes. I haven't yet decided if i will embed some SVG icons or provide them as separate files. Anyway this is one of the prototypes i made:

Code: Select all

from PySide import QtGui

icon = """<svg xmlns="http://www.w3.org/2000/svg" height="64" width="64">
  <rect height="64" width="64" fill="#204a87" />
</svg>"""

mw = FreeCADGui.getMainWindow()
button = QtGui.QToolButton(mw)
action = QtGui.QAction(button)

pixmap = QtGui.QPixmap()
pixmap.loadFromData(icon)

action.setIcon(QtGui.QIcon(pixmap))
button.setDefaultAction(action)
button.show()
wmayer
Founder
Posts: 20245
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Icons in macros

Post by wmayer »

This way you should be able to create a pixmap from the SVG

Code: Select all

from PySide.QtGui import QImage, QPainter
from PySide.QtCore import QByteArray
from PySide.QtSvg import QSvgRenderer

image=QImage(32,32,QImage.Format_ARGB32_Premultiplied)
image.fill(0)
p=QPainter(image)

data=QByteArray(contents) # contents are the SVG data
svg=QSvgRenderer(data)
svg.render(p)
p.end()
However, compared to XPM the SVG files are much larger.
ulrich1a
Veteran
Posts: 1957
Joined: Sun Jul 07, 2013 12:08 pm

Re: Icons in macros

Post by ulrich1a »

I may have ask wrong or I am missing one step. The Viewprovider for an document object has to define the function def getIcon(self):
I tried now the following

Code: Select all

from PySide.QtGui import QImage, QPainter
from PySide.QtCore import QByteArray
from PySide.QtSvg import QSvgRenderer

...

    def getIcon(self):
        icon = """<svg xmlns="http://www.w3.org/2000/svg" height="64" width="64">
              <rect height="64" width="64" fill="#204a87" />
              </svg>"""
        
        image=QImage(32,32,QImage.Format_ARGB32_Premultiplied)
        image.fill(0)
        p=QPainter(image)
        
        data=QByteArray(icon) # contents are the SVG data
        svg=QSvgRenderer(data)
        svg.render(p)
        p.end()
              
        return p
But then I am getting the following error-message

Code: Select all

<unknown exception traceback><type 'exceptions.TypeError'>: PyCXX: Error creating object of type N2Py7SeqBaseINS_4CharEEE from <PySide.QtGui.QIcon object at 0x7f259366fc68>
I can not figure out how to use the examples for the method getIcon().

I found the following example in FreeCAD itself

Code: Select all

    def getIcon(self):
        return ":/icons/PartDesign_InternalExternalGear.svg"
The function seems to either returns a path or a C-structure containing the XPM-data. Do I have to convert the QPainter(image) back to a C-structure?


Ulrich
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Icons in macros

Post by triplus »

As seen above it is possible to embed SVG image and after create QIcon/QPixmap out of it. I took more direct approach as Qt is smart enough and will try to determine image format by probing header to guess the file format when creating QPixmap.

Therefore this in my experience should work and now you try to use the resulting QPixmap in some way and it doesn't work. Therefore if possible could you attach the (part of the) macro you are working on as this way it will be easier to investigate where the problem is.
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Icons in macros

Post by triplus »

OK i investigate this myself and found this is probably the example for the code snippet:

http://www.freecadweb.org/wiki/index.ph ... ed_objects

After i tried to modify the snippet to return SVG string/QPixmap/QIcon and this didn't work out. Probably support for such use case would need to be implemented first.

Therefore i investigated further:

Code: Select all

def getIcon(self):
    import tempfile

    icon = """<svg xmlns="http://www.w3.org/2000/svg" height="64" width="64">
               <rect height="64" width="64" fill="#204a87" />
              </svg>"""

    iconFile = tempfile.NamedTemporaryFile(suffix=".svg", delete=False)
    iconFile.write(icon)
    iconFile.close()

    return iconFile.name
In the attached code one approach can be observed that will produce the result you are after.
ulrich1a
Veteran
Posts: 1957
Joined: Sun Jul 07, 2013 12:08 pm

Re: Icons in macros

Post by ulrich1a »

Yeah, I gave up after trying to return SVG string/QPixmap/QIcon and came to the same conclusion.

Thanks for supplying a working example. The svg-data seems to be written first to the harddisk. Do you know any solution with a virtual file system in memory? I think, I have seen something, where all the path where retrieved from a resource-file loaded into memory.

Ulrich
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Icons in macros

Post by triplus »

ulrich1a wrote:Thanks for supplying a working example.
You're welcome.
Yeah, I gave up after trying to return SVG string/QPixmap/QIcon and came to the same conclusion.
As using "SVG string" directly to create QPixmap is possible as seen above it would be interesting to investigate to see on why FreeCAD only supports "XPM string" or file as input for this use case.
The svg-data seems to be written first to the harddisk. Do you know any solution with a virtual file system in memory? I think, I have seen something, where all the path where retrieved from a resource-file loaded into memory.
Likely it could be achieved but from the documentation for tempfile.TemporaryFile:
This function operates exactly as TemporaryFile() does, except that the file is guaranteed to have a visible name in the file system (on Unix, the directory entry is not unlinked).
This is important as with "in memory" solutions deeper understanding would be needed and the final solution would need to be tested on all supported platforms.
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Icons in macros

Post by triplus »

Note that i don't know how exactly will your macro work and what it will do. Therefore above solution could be further optimized by first creating icon file in the tmp location and after to use that same icon file from tmp location multiple times instead of creating multiple icon files. You could therefore move icon file creation logic out of getIcon() and from getIcon() you would only return the path to the file.

You could take care of removing the icon file once it it not needed any more. For example os.unlink(getIcon()) if you don't want OS reboot to take care of that.

By doing it like that i don't see any big issues from macro point of view that you would need to worry about. Like for example storing the icon file in the memory.
wmayer
Founder
Posts: 20245
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Icons in macros

Post by wmayer »

Do you know any solution with a virtual file system in memory? I think, I have seen something, where all the path where retrieved from a resource-file loaded into memory.
You can try Qt's resource system. In FreeCAD we use this heavily to embed resources (icons, translation files, ...) into the binaries. It can be used with C++ and Python. In case of Python I think it should be possible to add the generated code into your macro.
Post Reply