SOLVED Getting a GadgetID during BFM_INTERACTSTART

Hello,
I'd like to detect when an EditSlider gadget in my GeDialog is first being dragged. I am overriding the Message function and listening for c4d.BFM_INTERACTSTART so I can see which Gadget sent the Message. A strange thing occurs though: when I try to print the msg and result BaseContainers, neither return any values.

I can check if the EditSlider is active using GeDialog.IsActive(), but it fires with every c4d.BFM_INTERACTSTART Message, which is undesired.

Is there a way to detect the GadgetID from the c4d.BFM_INTERACTSTART Message?

Here is code demonstrating my issue:

import c4d
from c4d import gui

PLUGIN_ID=1972142
GROUP_ID1=1000
SLIDER=1001

class MyDlg(gui.GeDialog):
    def CreateLayout(self):
        self.SetTitle("Interact Start Demo")
        if self.GroupBegin(GROUP_ID1, c4d.BFH_SCALEFIT, 1, 1):
            self.GroupBorderSpace(20,20,20,20)
            self.AddEditSlider(SLIDER, c4d.BFH_SCALEFIT | c4d.BFV_CENTER, initw=0, inith=0)
        self.GroupEnd()
        return True

    def InitValues(self):
        self.SetFloat(SLIDER, value=50, min=0, max=100, step=1)
        return True

    def Message(self, msg, result):
        if msg.GetId() == c4d.BFM_INTERACTSTART:
            print "*"*100
            #Can I get the Gadget ID from this Message?
            for cid,value in msg:
                print "MSG id: %s, value: %s"%(cid,value)
                #doesn't print
            for cid,value in result:
                print "RESULT id: %s, value: %s"%(cid,value)
                #doesn't print
            print "slider active: %s"%self.IsActive(SLIDER) #Can't use as is because it fires True with every interaction where the slider is active (not just dragging the slider).
        return c4d.gui.GeDialog.Message(self, msg, result)

c4d.CallCommand(12305) # Console
global dlg
dlg = MyDlg()
dlg.Open(c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=300, defaulth=100, xpos=-2, ypos=-2)

Thank you!

Hi,

I do not think that you can get the id. The reason that your code does not print anything, is because you treat the message id and data containers like iterables for a loop. Which in turn will not do anything when said containers are empty.

Is there a specific reason why you do not (want to) use GeDialog.Command? It has a specific message for drag events of sliders (BFM_ACTION_INDRAG).

Cheers,
zipit

Hi,

I do not think that you can get the id. The reason that your code does not print anything, is because you treat the message id and data containers like iterables for a loop. Which in turn will not do anything when said containers are empty.

Is there a specific reason why you do not (want to) use GeDialog.Command? It has a specific message for drag events of sliders (BFM_ACTION_INDRAG).

Cheers,
zipit

Hi @zipit , thank you for your reply. I am treating the message & data containers as iterables because they are both BaseContainers and I don't know which IDs they contain. If the containers are empty, where is msg.GetId() getting its data? Is the ID separate from the msg BaseContainer's data?

I have something working with BFM_ACTION_INDRAG but it is not very elegant as the drag ID is executed many times during a drag. As mentioned in the original post, I am interested in executing code only once on the initial touch of the slider.

This is what I'm doing:

import c4d
from c4d import gui

PLUGIN_ID=1972142
GROUP_ID1=1000
SLIDER=1001

class MyDlg(gui.GeDialog):
    def __init__(self):
        self.firstInteraction = False
    
    def CreateLayout(self):
        self.SetTitle("Interact Start Demo")
        if self.GroupBegin(GROUP_ID1, c4d.BFH_SCALEFIT, 1, 1):
            self.GroupBorderSpace(20,20,20,20)
            self.AddEditSlider(SLIDER, c4d.BFH_SCALEFIT | c4d.BFV_CENTER, initw=0, inith=0)
        self.GroupEnd()
        return True

    def InitValues(self):
        self.SetFloat(SLIDER, value=50, min=0, max=100, step=1)
        return True

    def Command(self,id,msg):
        if id == SLIDER:
            if self.firstInteraction == False:
                if msg[c4d.BFM_ACTION_INDRAG] == 1:
                    if self.firstInteraction == False:
                        print "first interaction"
                        # first interaction code goes here
                        self.firstInteraction = True
            if msg[c4d.BFM_ACTION_INDRAG] == None:
                self.firstInteraction = False
        return True

c4d.CallCommand(12305) # Console
global dlg
dlg = MyDlg()
dlg.Open(c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=300, defaulth=100, xpos=-2, ypos=-2)

Do you or anyone else have any thoughts on this implementation? Thank you!

Hi,

@blastframe said in Getting a GadgetID during BFM_INTERACTSTART:

If the containers are empty, where is msg.GetId() getting its data? Is the ID separate from the msg BaseContainer's data?

yes, the id of a container is separate from its data. It is just an easy to access integer attached to the container which is used to tell the recipient something about the purpose of the container. What you are effectively doing is something like this:

data = []
#Will not do anything since the iterator of data will never yield anything.
for item in data:
    print item

I have something working with BFM_ACTION_INDRAG but it is not very elegant as the drag ID is executed many times during a drag [...]

Aside from the crazy amount of branching I do not see anything inherently inelegant about your code. Do you have any specific concerns? Without that any suggestions for "improvement" would be highly subjective.

Cheers,
zipit

hi,

I don't see what's wrong neither. Using a boolean to know if your function have been already execute once is pretty common.
As long as you got what you need.

Cheers,
Manuel

Thank you both! @zipit & @m_magalhaes 😄