How to call a structure-based control procedure

Hello,

I am wondering if it is possible to execute a procedure that is intended to be called by a button, when this procedure is written using WMButtonAction.
I mean, the problem is that the parameter is a structure. Using the old style, it would be many parameters instead, for instance, ctrlName, eventCode... Here, I think only one parameter is allowed, and when I try to call the ButtonProc_RedefineCoords_M procedure like that :

ButtonProc_RedefineCoords_M(Button_Coords_Acetic_M_Pos)

Igor tells me that a local variable name is expected...

To sum up, I'd like to execute this procedure, normally executed when the button is clicked, but without clicking it.

Would you have any idea ?

Thank you in advance


Function Display_BtnRedefineCoords(instance_locale)

    STRUCT class_VFA &instance_locale
    SVAR Polarity = root:Polarity
       
    variable y
    string str_Button_RedefineCoords
    string strStruct4UserData
   
    SetActiveSubWindow $"MAIN_CAPTIVOCS_Panel#CAPTIVOCS_Panel_"+Polarity
       
    str_Button_RedefineCoords = "Button_Coords_" + instance_locale.str_Analyte
    y = instance_locale.numero

    StructPut /S instance_locale, strStruct4UserData //we save the structure instance in a string
   
    Button $str_Button_RedefineCoords+"_M_" + Polarity, pos={600,460+20*y},size=17,18},proc=ButtonProc_RedefineCoords_M,title="M", userdata=strStruct4UserData

End


//-  -  -  -  -  -  -  -  -  - Function to execute when the button is clicked -  -  -  -  -  -  -  -  -  -  -  

Function ButtonProc_RedefineCoords_M(ba) : ButtonControl
    STRUCT WMButtonAction &ba

    STRUCT class_VFA myVFA
       
    switch( ba.eventCode )
        case 2: // mouse up
            StructGet/S myVFA, ba.userdata  // written out to control
            RedefineCoords(myVFA,1)             // click code here
        break
    endswitch

    return 0
End
Not for sure exactly, but do you mean something like this?

Function DoButtonClick()

     STRUCT WVButtonAction ba
     ba.eventCode = 2
     ba.userData = // set the userData here as needed
     ButtonProc_RedefineCoords_M(ba)
     return 0

end

Function ButtonProc_RedefineCoords_M(ba) : ButtonControl
    STRUCT WMButtonAction &ba
 
    STRUCT class_VFA myVFA
 
    switch( ba.eventCode )
        case 2: // mouse up
            StructGet/S myVFA, ba.userdata  // written out to control
            RedefineCoords(myVFA,1)             // click code here
        break
    endswitch
 
    return 0
End


--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
It is often tempting to try to call action procedures from code, but that is a sign that you need to re-factor your code. A better design is to extract the code that actually does the work into a function designed to do that work, then call the extracted function from both the action procedure and from your other code.

If the action procedure is part of someone else's package, and you want to use their functionality in your code, you may be better off copying the "engine" code from their action procedure and re-packaging it in your own function. Naturally, you will respect any copyright :)

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Hello jjweimer and Johnweeks,

Thank you for your reply.

@Johnweeks : what you suggest makes sense, but I'm afraid that's tricky. Indeed, a button that calls the procedure of interest contains a userdata. Moreover, there are many button instancies, each containing a specific userdata (consisting of a structure passed as a string)
If I want to do so, I'd have to write a function that has STRUCT WMButtonAction &ba as a parameter.

@jjweimer : I'm going to try it in parallel to the above solution.

Thank you !

Best Regards
Hello,

:-D EDIT : After a good mug of coffee high in caffeine, I've realized that it was not necessary to retrieve the structures from their associated buttons. The confusion came from the fact a structure cannot be global, but using StructPut, it is possible to save it in a global string (that's actually what I did to store it in the button's userdata).
Thus, those global strings are used as parameters to call the procedure of interest.

Hope it will be useful for anyone.

Thanks

(It's still not working.) EDIT: Actually, it's OK..

@jjweimer : I've slightly modified your code, to that :
Function DoClick(Button_Coords_Acetic_M_Pos)
    STRUCT WMButtonAction &Button_Coords_Acetic_M_Pos

    Button_Coords_Acetic_M_Pos.eventCode = 2
    ButtonProc_RedefineCoords_M(Button_Coords_Acetic_M_Pos)
    return 0
end

But... I got this message during compilation :
"ERROR : Local variable expected"

Indeed, in the manual it's written that :
"When a Structure is passed to a user function, it can only be passed by reference, so in the declaration within the function you must use &localStructName to define the function input parameter."

That's why I've added the '&'.
Otherwise, if I wrote this, as you firstly suggested :
Function DoClick_QuantifyAll()//Button_Coords_Acetic_M_Pos)
   
STRUCT WMButtonAction Button_Coords_Acetic_M_Pos

Button_Coords_Acetic_M_Pos.eventCode = 2
//Button_Coords_Acetic_M_Pos.userdata = ... //shouldn't be necessary
   
ButtonProc_RedefineCoords_M(Button_Coords_Acetic_M_Pos)
return 0

end


it would be impossible to know to which button (=parameter of the procedure of interest) we refer.
Moreover, a button already contains the userdata, so it shouldn't be necessary to redefine it.

@johnweeks : I've split the button procedure :
//*************************(Part 1)*******************************

Function RedefineCoords_M(ba)

STRUCT WMButtonAction &ba

STRUCT class_VFA myVFA
       
    switch( ba.eventCode )
        case 2:
            StructGet/S myVFA, ba.userdata  // written out to control
            RedefineCoords(myVFA,1)     // click code here             
        break
    endswitch

    return 0
End
       
//*************************(Part 2)*******************************
Function ButtonProc_RedefineCoords_M(ba) : ButtonControl
STRUCT WMButtonAction &ba

    RedefineCoords_M(ba)
End


The problem is that the data that has to be updated is contained in the button's userdata.
Indeed, a structure cannot be global. That's why I've stored it in a button made to update it.
So, if I directly execute  RedefineCoords_M(ba) (for instance, a button can be named "Button_Coords_Acetic_M_Pos", so I execute RedefineCoords_M(Button_Coords_Acetic_M_Pos))

Then I get this error : "Local variable expected"

To sum up

Is it correct to reference the button (defined as a structure) using its name ?
If it is possible to do so, how should I proceed ?

I hope my explanations are not too confusing...


Thank you



Best Regards
Yes, buttons have names, and you can get the buttons userdata using the function GetUserData(). So you don't have to have the STRUCT WMButtonAction in order to get the button's user data. I would recommend, in fact, not using the unnamed userdata. I would do something like

    Button $str_Button_RedefineCoords+"_M_" + Polarity, pos={600,460+20*y},size=17,18},proc=ButtonProc_RedefineCoords_M,title="M", userdata(Struct4)=strStruct4UserData

Then you can get the userdata like this:

    String structString = GetUserData("MAIN_CAPTIVOCS_Panel#CAPTIVOCS_Panel_"+Polarity, str_Button_RedefineCoords+"_M_" + Polarity, "Struct4")

Naturally, these lines have references to your local string variables; you need a way to retrieve those later if you are to do anything with all this stuff.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com