Change Icon based on State in CommandData

On 26/09/2013 at 07:52, xxxxxxxx wrote:

Hello,

I am wondering if it's possible to change the icon of CommandData plugin based on a its state.

I searched on the forums here and cgtalk but it looks like it can't be done (but not sure), so I wan't to ask to be clear on this.

Thanks for any info.

On 26/09/2013 at 08:29, xxxxxxxx wrote:

Technically yes, practically no / you shouldn't. Invoking BaseList2D.GetIcon() will return a reference 
to the BaseBitmap used by c4d to draw the interface. Any modifications made here will also show 
up in the gui, but we are actually meant to treat that bitmap as readonly, so handle with care ;)

import c4d, random
from c4d import bitmaps
  
def main() :
    if isinstance(op, c4d.BaseList2D) :
        data = op.GetIcon()
        bmp = data['bmp']
        sx, sy = data['x'], data['y']
        w, h = data['w'], data['h']
        for px in xrange(sx, sx + w) :
            for py in xrange(sy, sy + h) :
                r = random.randint(0,255)
                g = random.randint(0,255)
                b = random.randint(0,255)
                bmp.SetPixel(px,py,r,g,b)
        bitmaps.ShowBitmap(bmp)
    c4d.EventAdd()
    
if __name__=='__main__':
    main()

That code chunk will change the color information of the selected objects icon to some random 
color noise. For anything useful you would have to write some alpha informations too.

FYI: For a command plugin you would have to grab the BasePlugin instance of your plugin.

happy rendering,
ferdinand

On 26/09/2013 at 23:56, xxxxxxxx wrote:

thanks alot for that, but how do I get an instance of my plugin, searching the forums I found

myPlugin = c4d.BaseList2D(c4d.plugins.BasePlugin(PLUGIN_ID))

but this gives "this cannot be instantiated" error

which is also mentioned in python documentation, so is this a dead end?

On 27/09/2013 at 00:32, xxxxxxxx wrote:

The BasePlugin can be found via c4d.plugins.FindPlugin(PLUGIN_ID)

You can use c4d.gui.GetIcon() instead, too.

-Niklas

On 27/09/2013 at 01:39, xxxxxxxx wrote:

Originally posted by xxxxxxxx

myPlugin = c4d.BaseList2D(c4d.plugins.BasePlugin(PLUGIN_ID))

I can not really believe that you have found that code fragment somewhere in the c4d python
documentation, as it does not make any sense on a very basic level. There is only one constructor
for BaseList2D and that does require you to pass an integer as an argument. You are trying to 
pass a BasePlugin instance, which does not work because the BasePlugin class cannot be 
instantiated, as the interpreter already did tell you and also is not the correct argument type for 
the BaseList2D constructor.

Also trying to instantiate your plugin does not really make sense in that case, as it is one of the
plugin types (CommandData, MessageData etc.)  which cannot be instantiated, or more precisely 
are only instantiated once after the start up by c4d. It is also quite important to understand the 
difference of your plugin class derived from BaseData, a BasePlugin and an actual node  repre-
senting a plugin object.

On 27/09/2013 at 01:41, xxxxxxxx wrote:

awesome, thanks for all the help!

On 27/09/2013 at 01:55, xxxxxxxx wrote:

Yeah thats not a direct copy, most of the code I simply copy from here and there.

I don't have any deep understanding of the sdk, but I get along with trial and error, examples and forums =)

Thanks for that explanation.

On 27/09/2013 at 08:27, xxxxxxxx wrote:

Originally posted by xxxxxxxx

I am wondering if it's possible to change the icon of CommandData plugin based on a its state.

It's not possible to dynamically change the icon images for CommandData plugins in the menu.
That image is set during the registration process when C4D starts up. And cannot be changed dynamically.

The CommandData plugin does have a checkbox option for it which might look like an icon image. But it's not. It's done with a flag. And doesn't use the bitmap image where the icons are stored.
It's an internal thing hard coded by Maxon.

It would be very nice to be able swap our own icon images for the on/off state of these plugins. Instead of being stuck with that checkmark option. Lots of people want to do that.
But it's not possible until Maxon adds that ability to the API.

-ScottA

On 27/09/2013 at 10:17, xxxxxxxx wrote:

It is possible. You can easily change the icon of the Cube plugin with this script.
>
>
>
>
> import c4d
>
> def set_icon(pluginid, bmp, overwrite_alpha=True) :
> icon = c4d.gui.GetIcon(pluginid)
> if not icon:
> return c4d.gui.RegisterIcon(pluginid, bmp)
>
> ref = icon['bmp']
> w, h = icon['w'], icon['h']
>
> temp = c4d.bitmaps.BaseBitmap()
> if temp.Init(w, h, bmp.GetBt()) != c4d.IMAGERESULT_OK:
> return False
>
> bmp.ScaleIt(temp, 256, True, True)
>
> a1 = a2 = None
> if overwrite_alpha:
> a1 = ref.GetInternalChannel()
> a2 = temp.GetInternalChannel()
> for x in xrange(w) :
> rx = x + icon['x']
> for y in xrange(h) :
> ry = y + icon['y']
> ref[rx, ry] = temp[x, y]
> if a1:
> if a2:
> alpha = temp.GetAlphaPixel(a2, x, y)
> else:
> alpha = 255
> ref.SetAlphaPixel(a1, rx, ry, alpha)
>
> return True
>
> def main() :
> fn = c4d.storage.LoadDialog()
> if not fn: return
>
> bmp = c4d.bitmaps.BaseBitmap()
> res = bmp.InitWith(fn)[0]
> if res != c4d.IMAGERESULT_OK:
> print "Invalid image:", res
> return
>
> set_icon(c4d.Ocube, bmp)
> c4d.gui.GeUpdateUI()
> c4d.EventAdd()
>
> main()

It is not possible to change the icon of an individual node, but that is also not a necessity when
working with a CommandData plugin.

Best,
-Niklas

On 27/09/2013 at 10:21, xxxxxxxx wrote:

Well actually it is Scott, my example above shows how to ;). But it is kind of black magic, as we
are meant to treat the BaseBitmap as readonly.

On 27/09/2013 at 10:46, xxxxxxxx wrote:

I think we're talking about different things.
Your code shows how to edit the read only bitmap file found in: resource\icons\interface_icons.tif
But a CommandData plugin does not use this file.

The CommandData plugin uses a flag in the GetState() method to toggle a check mark on/off

    if(menustate) return CMD_ENABLED|CMD_VALUE;  //Enable the menu checkmark  
  else return CMD_ENABLED;                     //Turn off the menu checkmark

AFAIK. It's not possible toggle between two images instead of this checkmark.
There's nothing in the SDK that allows us to do this.
Many people have tried. No one has succeeded.

-ScottA

On 27/09/2013 at 11:48, xxxxxxxx wrote:

Not sure what you mean, for me it is just working fine. It actually does not matter if the
bitmap is located in the main icon file or somewhere else. Took a command data plugin
of mine and did a quick test.

import c4d, random
from c4d import bitmaps, gui
  
CMD_DATA_ID = 1030901
  
def main() :
    data = gui.GetIcon(CMD_DATA_ID)
    bmp = data['bmp']
    sx, sy = data['x'], data['y']
    w, h = data['w'], data['h']
    for px in xrange(sx, sx + w) :
        for py in xrange(sy, sy + h) :
            bmp.SetPixel(px,py,255,0,0)
    gui.GeUpdateUI()
    c4d.EventAdd()
    
if __name__=='__main__':
    main()

On 27/09/2013 at 12:11, xxxxxxxx wrote:

Scott, the GetState() method has nothing to do with the icon of the command. As littledevil
already pointed out, it doesn't matter whether you modify an icon which originates from
Cinema's own icon-table bitmap. You are only modifying the copy in the RAM, not the one
on the HD.

Download the full plugin
 
>
> _<_t_>_
>
>
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> 8
> 9
> 10
> 11
> 12
> 13
> 14
> 15
> 16
> 17
> 18
> 19
> 20
> 21
> 22
> 23
> 24
> 25
> 26
> 27
> 28
> 29
> 30
> 31
> 32
> 33
> 34
> 35
> 36
> 37
> 38
> 39
> 40
> 41
> 42
> 43
> 44
> 45
> 46
> 47
> 48
> 49
> 50
> 51
> 52
> 53
> 54
> 55
> 56
> 57
> 58
> 59
> 60
> 61
> 62
> 63
> 64
> 65
> 66
> 67
> 68
> 69
> 70
> 71
> 72
> 73
>
> |
>
>
> import os
> import c4d
>
> def get_res_bitmap(filename) :
> bmp = c4d.bitmaps.BaseBitmap()
> result = bmp.InitWith(os.path.join(os.path.dirname(__file__), 'res', filename))
> if not result or result[0] != c4d.IMAGERESULT_OK:
> return None
>
> return bmp
>
> def set_icon(pluginid, bmp, overwrite_alpha=True) :
> icon = c4d.gui.GetIcon(pluginid)
> if not icon and bmp:
> return c4d.gui.RegisterIcon(pluginid, bmp)
> elif icon and not bmp:
> return c4d.gui.UnregisterIcon(pluginid, bmp)
> elif not icon:
> return
>
> ref = icon['bmp']
> w, h = icon['w'], icon['h']
>
> temp = c4d.bitmaps.BaseBitmap()
> if temp.Init(w, h, bmp.GetBt()) != c4d.IMAGERESULT_OK:
> return False
>
> bmp.ScaleIt(temp, 256, True, True)
>
> a1 = a2 = None
> if overwrite_alpha:
> a1 = ref.GetInternalChannel()
> a2 = temp.GetInternalChannel()
> for x in xrange(w) :
> rx = x + icon['x']
> for y in xrange(h) :
> ry = y + icon['y']
> ref[rx, ry] = temp[x, y]
> if a1:
> if a2:
> alpha = temp.GetAlphaPixel(a2, x, y)
> else:
> alpha = 255
> ref.SetAlphaPixel(a1, rx, ry, alpha)
>
> return True
>
> class MyCommand(c4d.plugins.CommandData) :
>
> pluginid = 1000010 # TEST ID ONLY
> state = False
> bmp_a = get_res_bitmap('state-a.png')
> bmp_b = get_res_bitmap('state-b.png')
>
> def Register(self) :
> c4d.plugins.RegisterCommandPlugin(self.pluginid, "Icon Toggler", 0,
> None, "Execute to switch the icon of the command.", self)
> self.UpdateIcon()
>
> def UpdateIcon(self) :
> if not self.state:
> bmp = self.bmp_a
> else:
> bmp = self.bmp_b
> set_icon(self.pluginid, bmp)
>
> def Execute(self, doc) :
> self.state = not self.state
> self.UpdateIcon()
> return True
>
> if __name__ == "__main__":
> MyCommand().Register()
>
> <_<_t_>_

Best,
-Niklas

On 27/09/2013 at 13:01, xxxxxxxx wrote:

Thanks for the code Nik.

It doesn't solve the problem I was talking about.
But storing the icon in RAM is an interesting way to get around the problem.

-ScottA

On 27/09/2013 at 13:08, xxxxxxxx wrote:

Originally posted by xxxxxxxx

Thanks for the code Nik.

It doesn't solve the problem I was talking about.
But storing the icon in RAM is an interesting way to get around the problem.

-ScottA

I am not sure what problem you are talking about, could you pinpoint it for me please?

Best,
-Niklas

On 27/09/2013 at 14:44, xxxxxxxx wrote:

Well. It was a long time ago. And now I'm wondering if I'm remembering something else we were trying to do and having problems.
I can't remember if we couldn't update the CommandData icons in the menu. Or if it was the icons for a plugin that were docked in the UI. Or something like that.
The original poster commented about reading this problem on CGTalk. I'm guessing he was probably reading our old posts.

We were trying to swap images that were stored on the HD using COFFEE. But could not figure it out.
It was a long time ago.

-ScottA