Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    CommandData with Options Dialog - Docked command button

    Bugs
    windows python r21 s24
    2
    5
    1.4k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • a_blockA
      a_block
      last edited by ferdinand

      Hi,

      I have a CommandData plugin which opens an asynchronous dialog and also supports an options dialog (PLUGINFLAG_COMMAND_OPTION_DIALOG).

      Everything is nice and dandy, until I dock the command into a palette in C4D's layout. In this case I get a shiny button with a cogwheel on the right side. Nice.
      The problem is, if the command has been called to open the dialog (and thus is enabled, i.e. shows highlighted in menu), then the cogwheel part of the command button does no longer work. Instead of calling ExecuteOptionID() it then calls the normal Execute(), which is obviously not what I would expect. From menu, this works as expected, regardless of the command's state, clicking the cogwheel in menu calls ExecuteOptionID(), but not so from a button palette.

      Is this intended operation or maybe a bug?

      I have tested the behavior in R21 and S24.

      Cheers,
      Andreas

      Edit: I forgot to mention, all my test were done on Win 10.

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @a_block
        last edited by ferdinand

        Hello Andreas,

        thank you for reaching out to us. And special thank you for making the effort of describing and testing bugs in such a detailed manner as you do and have done in the past, much appreciated.

        With that being said, I struggle a bit with reproducing your problem. I might be misunderstanding something here.

        1. You talk about a CommandData being highlighted in the menu when the dialog is opened. But that is not the case for CommandData in my experience. Other than for tool plugins, e.g., ToolData in Python, their icon is not being highlighted "when they are running". I double checked in S24 and R21 and could not reproduce this. The icon of a CommandData is only being highlighted when hovered. It can be enabled or disabled via overwriting CommandData.GetState, but that has nothing to do with an execution state or however wants to call this.
        2. Regarding the reported mixup of Execute() and ExecuteOptionID(), I can unfortunately also not reproduce this. I opened the option dialog of the example plugin shown at the end of the posting both in R21 and S24. Then I added the plugin as an icon to a palette and invoked the major and minor/option gadget of that icon while dialog was still opened. In all versions Cinema did execute the correct method.

        So, I would have to ask you to clarify where I have misunderstood you or share some code, so, that we can to the bottom of why this is happening for you.

        Cheers,
        Ferdinand

        What I did (in S24):
        demo.gif

        The code:

        """Example for executing an options dialog.
        
        As discussed in:
            https://developers.maxon.net/forum/topic/13407/
        """
        import c4d
        
        class PluginDialog (c4d.gui.GeDialog):
            """A dialog for a CommandData plugin.
            """
            ID_INT_VALUE = 1000
        
            def CreateLayout(self):
                """Adds gadgets to the dialog.
                """
                self.SetTitle("Some Dialog")
                self.AddEditSlider(
                    id=PluginDialog.ID_INT_VALUE,
                    flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT)
                return True
        
            def InitValues(self):
                """Initialize the dialog values.
                """
                self.SetInt32(PluginDialog.ID_INT_VALUE, 42)
                return True
        
        
        class PC13407(c4d.plugins.CommandData):
            """A CommandData plugin with a dialog.
            """
            ID_PLUGIN = 1057432
            _pluginDialog = None
        
            @classmethod
            def GetPluginDialog(cls):
                """Returns the class bound instance of the plugin dialog.
                """
                if cls._pluginDialog is None:
                    cls._pluginDialog = PluginDialog()
                return cls._pluginDialog
        
            def Execute(self, doc):
                """
                """
                print("Running {}.Execute()".format(self))
                return True
        
            def ExecuteOptionID(self, doc, plugid, subid):
                """Opens the option dialog.
                """
                print("Running {}.ExecuteOptionID()".format(self))
                dialog = PC13407.GetPluginDialog()
                result = True
                if not dialog.IsOpen():
                    result = dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC,
                                         pluginid=PC13407.ID_PLUGIN)
        
                return result
        
            def RestoreLayout(self, secret):
                """Restores the dialog on layout changes.
                """
                dialog = PC13407.GetPluginDialog()
                return dialog.Restore(PC13407.ID_PLUGIN, secret)
        
        
        if __name__ == '__main__':
            c4d.plugins.RegisterCommandPlugin(
                id=PC13407.ID_PLUGIN,
                str="Options Test",
                info=c4d.PLUGINFLAG_COMMAND_OPTION_DIALOG,
                icon=None,
                help="",
                dat=PC13407())
        
        

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • a_blockA
          a_block
          last edited by a_block

          Hi Ferdinand,

          thanks for your quick reply.
          Please find a small plugin to reproduce below.
          Looks like you thanked me too early for giving detailed bug reports, because obviously I did not mention an important detail (GetState())...

          As far as I know, every manager dialog in C4D gets opened via CommandData, don't they? And all of these represent their open state by highlighting/checking their command using GetState(). And this is what I'd like to reproduce, except that my manager not only has a main dialog, but also makes use of an additional "options command".

          So in order to reproduce, use below plugin.
          Then:

          1. Customize a palette and drag the "Test Command Button" into it.
          2. You should get a button with a cogwheel.
          3. Click the cogwheel to see "ExecuteOptionID" being printed to the console.
          4. Click the left/main section of the button to have it open its dialog (now, thinking about it, the dialog is redundant here, any state change would do... anyway too lazy to change the example code again...)
          5. Now, the palette button is highlighted.
          6. Press the cogwheel again.
          7. See "Execute" being printed to the console, instead of the expected "ExecuteOptionID".

          Thanks for looking into it.

          Cheers,
          Andreas

          import c4d
          
          PLUGIN_ID = 1234567 # MAKE SURE TO USE A UNIQUE ID FROM Plugin Café
          PLUGIN_NAME = 'Test Command Button'
          PLUGIN_TOOLTIP = 'Dock command to layout palette'
          
          class DialogMain(c4d.gui.GeDialog):
          
              def CreateLayout(self):
                  self.SetTitle('{0}'.format(PLUGIN_NAME))
          
                  self.AddDlgGroup(c4d.DLG_OK)
          
                  return True
          
          
              def Command(self, id, msg):
                  if id == c4d.DLG_OK:
                      self.Close()
          
                  return True
          
          
          class CommandDataTest(c4d.plugins.CommandData):
              _dlgMain = None
          
          
              def Execute(self, doc):
                  print('Execute')
          
                  if self._dlgMain is None:
                      self._dlgMain = DialogMain()
          
                  if self._dlgMain.IsOpen():
                      self._dlgMain.Close()
                      return True
          
                  self._dlgMain.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, xpos=-1, ypos=-1, defaultw=300, defaulth=0)
          
                  return True
          
          
              def ExecuteOptionID(self, doc, plugid, subid):
                  print('ExecuteOptionID')
          
                  return True
          
          
              def GetState(self, doc):
                  state = c4d.CMD_ENABLED
          
                  if self._dlgMain is not None and self._dlgMain.IsOpen():
                      state |= c4d.CMD_VALUE
          
                  return state
          
          
          if __name__ == '__main__':
              c4d.plugins.RegisterCommandPlugin(PLUGIN_ID, PLUGIN_NAME,
                                                c4d.PLUGINFLAG_COMMAND_OPTION_DIALOG, None, PLUGIN_TOOLTIP, CommandDataTest())
          
          1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by

            Hello Andreas,

            thank you for the clarification, CMD_VALUE was indeed the part that was not obvious to me. I can confirm the behavior and would also consider it to be a bug, especially since there has been a bug in 18.04 which has been fixed and was similar in nature.

            There is unfortunately not much what you can do currently regarding workarounds. At least I do not see one. This is because the root of the problem lies within the handling of palettes (and might be related to/ a side effect of the fix of the 18.04 issue) and therefore far outside of the wiggle room of the public API/SDK. I have reached out to the dev who fixed the older bug, and we will see if we want to consider this to be a bug or an accepted limitation.

            I will give you here a status update on what we will do once I know it.

            Cheers,
            Ferdinand

            The pruned plugin example to reproduce this:

            """Example for buggy ExecuteOptionID behavior when a CommandData state is 
            c4d.CMD_ENABLED | c4d.CMD_VALUE.
            
            As discussed in:
                https://developers.maxon.net/forum/topic/13407/
            """
            
            class PC13407(c4d.plugins.CommandData):
                """A CommandData plugin implementing GetState and being registered with
                PLUGINFLAG_COMMAND_OPTION_DIALOG.
            
                The CommandData has an internal toggle to either set it as checked, i.e., 
                c4d.CMD_VALUE, or not. Which is here being toggled in Execute() and then 
                reflected in GetState().
            
                The problem which then arises is that when the plugin icon is docked into
                a palette, and brought into the c4d.CMD_VALUE state, that Cinema will not
                distinguish properly anymore between clicks onto the major gadget, the 
                icon, and the cogwheel next to it. The user looses then in this state the
                ability to invoke ExecuteOptionID() via clicking onto the cogwheel. 
                Clicking onto the cogwheel will then invoke Execute() instead.
            
                When invoking the plugin from a menu, e.g., the Extensions menu, this does
                not happen.
                """
                ID_PLUGIN = 1057432
                _isActive = False
            
                def Execute(self, doc):
                    PC13407._isActive = not PC13407._isActive
                    print(f'Execute(),  _isActive: {PC13407._isActive}')
                    return True
            
                def ExecuteOptionID(self, doc, plugid, subid):
                    print('ExecuteOptionID()')
                    return True
            
                def GetState(self, doc):
                    return (c4d.CMD_ENABLED 
                            if not PC13407._isActive else
                            c4d.CMD_ENABLED | c4d.CMD_VALUE)
            
            
            if __name__ == '__main__':
                c4d.plugins.RegisterCommandPlugin(
                    id=PC13407.ID_PLUGIN,
                    str="Options Test",
                    info=c4d.PLUGINFLAG_COMMAND_OPTION_DIALOG,
                    icon=None,
                    help="",
                    dat=PC13407())
            

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 0
            • a_blockA
              a_block
              last edited by

              Hi Ferdinand,

              thanks for the confirmation and looking into it.

              While it's a bit unfortunate, I do not consider this a major road block. From my side this thread can be considered close.

              Cheers

              1 Reply Last reply Reply Quote 0
              • maxonM maxon moved this topic from Cinema 4D SDK on
              • First post
                Last post