Highlighted Command Text/Icon when it is executed?



  • Hi,

    I'm trying to replicate a UI behavior in one of Cineversity's plug-ins where the command text/icon is highlighted when it is toggled for on and off.

    You can check the behavior here:
    https://www.dropbox.com/s/3ozfoplfyg3yaj9/c4d133_command_highlighting.mp4?dl=0

    How do I achieve that?

    Thank you for looking at the problem

    PS. I can't check the code. It's in pypv.



  • @bentraje Yes as you pass not c4d.CMD_ENABLE as its stand it's not enabled.

    Besides that, I also reworked a bit your example to make it pythonic by settings state as a property so when you retrieve state its actually the state from the current document.

    import c4d
    from c4d import gui, plugins, bitmaps, utils, documents
    
    PLUGIN_ID   = 1010203
    
    class MyMenuPlugin(plugins.CommandData):
    
        def Execute(self, doc):
            self.state = not self.state
    
            return True
    
        def GetState(self, doc):
            # Previously you were almost safe but in case of self.state is something different than True or False you returned nothing
            if not self.state:
                return c4d.CMD_ENABLED
            else:
                return c4d.CMD_VALUE | c4d.CMD_ENABLED
    
        @property
        def state(self):
            doc = c4d.documents.GetActiveDocument()
            bd = doc.GetActiveBaseDraw()
            displayFilter = bd.GetDisplayFilter()
    
            if displayFilter & c4d.DISPLAYFILTER_HYPERNURBS:
                return bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS]
    
            return False
        
        @state.setter
        def state(self, value):
            # Checks if the value is a boolean
            if not isinstance(value, bool):
                raise TypeError("value is not a bool.")
    
            doc = c4d.documents.GetActiveDocument()
            bd = doc.GetActiveBaseDraw()
            displayFilter = bd.GetDisplayFilter()
    
            if displayFilter & c4d.DISPLAYFILTER_HYPERNURBS:
                bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS] = False
                print "Switched Off Subdivision Surface Display Filter"
            else:
                bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS] = True
                print "Switched On Subdivision Surface Display Filter"
    
            bd.Message(c4d.MSG_CHANGE)
            c4d.EventAdd()
            c4d.StatusClear()
    
    if __name__ == "__main__":
        status = plugins.RegisterCommandPlugin(PLUGIN_ID, "bt_Visibility",0, None, "bt_Visibility", MyMenuPlugin())
        if (status):
            print "Visibility plug-in successfully initialized"
    

    Cheers,
    Maxime.



  • Hi, just to be sure you talk about the blueish things on the menu?
    If that's the case you simply have to return c4d.CMD_VALUE | CMD_ENABLED c4d. in your GetState method of your CommandData.

    Cheers,
    Maxime.



  • @m_adam

    Thanks for the solution. Sorry also for the late response.
    I tried implementing the following logic of the visibility plug-in: If not visible: Don't enable. If visible: Enable. (i.e. the highlighting.

    However, it gives me two errors:

    1. 'MyMenuPlugin' object has no attribute 'status' on the self.state = self.status line. Which is a bit confusing since I already declared status variable above.
    2. Also, I'm not sure if I'm returning properly with the not c4d.CMD_VALUE | c4d.CMD_ENABLED statement. LOL

    Just to recap, I'm after this behavior
    https://www.dropbox.com/s/3ozfoplfyg3yaj9/c4d133_command_highlighting.mp4?dl=0

    Here is the code so far:
    import c4d
    from c4d import gui, plugins, bitmaps, utils, documents
    
    PLUGIN_ID   = 1010203
    
    class MyMenuPlugin(plugins.CommandData):
    
        def toggle_vis_subd(self):
            self.doc = c4d.documents.GetActiveDocument()
            bd = self.doc.GetActiveBaseDraw()
            displayFilter = bd.GetDisplayFilter()
    
            if displayFilter & c4d.DISPLAYFILTER_HYPERNURBS:
                bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS] = False
                print "Switched Off Subdivision Surface Display Filter"
            else:
                bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS] = True
                print "Switched On Subdivision Surface Display Filter"
    
            self.status = bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS]
            bd.Message(c4d.MSG_CHANGE)
            c4d.EventAdd()
            c4d.StatusClear()
    
        def Execute(self, doc):
            self.toggle_vis_subd()
    
            return True
    
        def GetState(self, doc):
    
            self.state = self.status
    
            if self.state == False:
                return not c4d.CMD_VALUE | c4d.CMD_ENABLED
            if self.state == True:
                return c4d.CMD_VALUE | c4d.CMD_ENABLED
    
    if __name__ == "__main__":
        status = plugins.RegisterCommandPlugin(PLUGIN_ID, "bt_Visibility",0, None, "bt_Visibility", MyMenuPlugin())
        if (status):
            print "Visibility plug-in successfully initialized"
    

    Thank you for looking at problem. The visibility code block I think is from a github c4d sample script.



  • Hi @bentraje the issue is that GetState is called way before Execute (it's called at the moment you display the command into the UI, so at the plugin registration).

    So either you create a __init__ method en define the default status value either you can do something like that in your get state method

    def GetState(self, doc):
        # Retrieves the status member of self, and if it's not present it will return True
        status = getattr(self, "status", True)
        self.state = status
    
        # Previously you were almost safe but in case of self.state is something different than True or False you returned nothing
        if not self.state:
            return not c4d.CMD_VALUE | c4d.CMD_ENABLED
        else:
            return c4d.CMD_VALUE | c4d.CMD_ENABLED
    

    Cheers,
    Maxime.



  • @m_adam

    Thanks again for the response, especially the code.

    I no longer have the error but there is a glitch.
    Whenever I execute the command, it works okay at first click but not on the second click. It is permanently disabled. (i.e. I can't toggle with the command).

    I tried using either not c4d.CMD_VALUE only or not c4d.CMD_ENABLED but I still have the same result?

    Is there a way around this?



  • @bentraje Yes as you pass not c4d.CMD_ENABLE as its stand it's not enabled.

    Besides that, I also reworked a bit your example to make it pythonic by settings state as a property so when you retrieve state its actually the state from the current document.

    import c4d
    from c4d import gui, plugins, bitmaps, utils, documents
    
    PLUGIN_ID   = 1010203
    
    class MyMenuPlugin(plugins.CommandData):
    
        def Execute(self, doc):
            self.state = not self.state
    
            return True
    
        def GetState(self, doc):
            # Previously you were almost safe but in case of self.state is something different than True or False you returned nothing
            if not self.state:
                return c4d.CMD_ENABLED
            else:
                return c4d.CMD_VALUE | c4d.CMD_ENABLED
    
        @property
        def state(self):
            doc = c4d.documents.GetActiveDocument()
            bd = doc.GetActiveBaseDraw()
            displayFilter = bd.GetDisplayFilter()
    
            if displayFilter & c4d.DISPLAYFILTER_HYPERNURBS:
                return bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS]
    
            return False
        
        @state.setter
        def state(self, value):
            # Checks if the value is a boolean
            if not isinstance(value, bool):
                raise TypeError("value is not a bool.")
    
            doc = c4d.documents.GetActiveDocument()
            bd = doc.GetActiveBaseDraw()
            displayFilter = bd.GetDisplayFilter()
    
            if displayFilter & c4d.DISPLAYFILTER_HYPERNURBS:
                bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS] = False
                print "Switched Off Subdivision Surface Display Filter"
            else:
                bd[c4d.BASEDRAW_DISPLAYFILTER_HYPERNURBS] = True
                print "Switched On Subdivision Surface Display Filter"
    
            bd.Message(c4d.MSG_CHANGE)
            c4d.EventAdd()
            c4d.StatusClear()
    
    if __name__ == "__main__":
        status = plugins.RegisterCommandPlugin(PLUGIN_ID, "bt_Visibility",0, None, "bt_Visibility", MyMenuPlugin())
        if (status):
            print "Visibility plug-in successfully initialized"
    

    Cheers,
    Maxime.



  • Thank you @m_adam. Work as expected!
    (I actually just ended up learning about the decorator property since its new to me. haha. Thanks for that).

    Just want to confirm, am I right to think this is the code flow:

    1. Register Plug-In
    2. @property state
    3. GetState
    4. Execute(Button Click)
    5. @state.setter state
    6. @property state
    7. GetState

    Then back again to #4 for the click.


Log in to reply