Passing more infos into PopupMenu list functions

I have a GUI with a SetVariable and a PopupMenu. The function providing the popup menu entries would need to read another GUI control for doing its job. As that is not possible, I now always have to reset the function defining the string for the popup menu.

Example:

Function/S GetList(string searchString)
   
    return GrepList("abcd;efgh", searchString)
End

FUnction Test()

    NewPanel/K=1
    SetVariable searchstring, value = _STR:".*",proc=SetVarProc
    PopupMenu pop, value=#"GetList(\".*\")"
End

Function SetVarProc(sva) : SetVariableControl
    STRUCT WMSetVariableAction &sva

    switch (sva.eventCode)
        case 1: // mouse up
        case 2: // Enter key
        case 3: // Live update
            PopupMenu pop, value=#("GetList(\"" + sva.sval + "\")")
            break
    endswitch

    return 0
End

Now I would prefer if the GetList function would be passed a struct similiar to WMSetVariableAction so that it could dynamically generate the list itself. This new struct should have at least a window name and control name member.


My current approach makes the code quite complicated, and also took a non-trivial amount of time to get the quoting in the popupmenu value string right ;)

If you want a function that specifically resets popupmenu lists based on setvariable actions, why not write a function that takes WMSetVariableAction as a parameter? Or are you looking for something more general?

I find getting and setting control values to be laborious in Igor. I often wish Igor had JavaScript-like window objects so that I could write something like PanelName.PopUpName.value = PanelName.SetvarName.value. Sometimes I create a structure for a panel with a substructure for each control that can be populated using a wrapper for ControlInfo like this:

static structure ControlValueStructure
    int16 type
    string ctrlName
    variable value
    string sval
    STRUCT RGBColor rgb
    STRUCT RGBAColor rgba
    variable selcol
endstructure

static function getControlValue(string win, string controlName, STRUCT ControlValueStructure &s)
    ControlInfo /W=$win $controlName
    s.ctrlName = controlName
    s.type = v_flag
    switch (abs(V_Flag))
        case 3: // popup menu
            s.rgb.red = V_Red; s.rgb.green = V_Green; s.rgb.blue = V_Blue
            s.rgba.red = V_Red; s.rgba.green = V_Green; s.rgba.blue = V_Blue
            s.rgba.alpha = V_Alpha
        case 2: // checkbox
        case 4: // valdisplay
        case 5: // SetVariable
        case 7: // slider
        case 8: // tab
            s.value = v_value
            s.sval = s_value
            break
        case 11: // listbox
            s.value = v_value
            s.sval = s_value
            s.selcol = v_selcol
            break
    endswitch
end

An equivalent SetControlValue() function could be useful. Then I could use ModifyControl and SetControlValue as control-type agnostic functions.

> If you want a function that specifically resets popupmenu lists based on setvariable actions, why not write a function that takes WMSetVariableAction as a parameter? Or are you looking for something more general?
 

Because I still would need to manually reset the value string. And I want to avoid that as it is difficult to maintain.

Your GetList function could use ControlInfo to find the value of searchstring.

I often have two popup menus when I need the user to select a wave. One to select the datafolder to look in and one with all the waves in that datafolder. To do that the wave-selection popmenu function uses ControlInfo to find the value of the datafolder popupmenu.

I still have to update the wave-selection popup menu whenever the datafolder value is changed, just as you do with your popup call when searchstring is called, but I can get away with a simple "PopupMenu DisplayedWavePopUp mode=1, win=$PU_Struct.win" without having to change the value string every time.

> Your GetList function could use ControlInfo to find the value of searchstring.

I don't think this will work. The name of the window is not fixed. And I also can't rely on the top window being the one holding the control as the GUI control could be called programmatically.

Also (Thomas has probably already thought about this, but it's worth noting here):

If you feed a user-supplied regex to grep or greplist, you need to consider what happens in the event of a regex error.

try..catch..endtry is one way to deal with runtime errors.

In reply to by thomas_braun

thomas_braun wrote:

I don't think this will work. The name of the window is not fixed. And I also can't rely on the top window being the one holding the control as the GUI control could be called programmatically.


 

Use a global string?

... I'll get my coat.

If both controls are in the same window you use $PU_Struct.win as the window name. Otherwise you will have to pass the name through the PopupMenu value=#"GetList(\".*\")" call, as a parameter for GetList.

 

EDIT

I guess the window name of the control cannot be accessed inside of GetList so you will have to pass it along through the value=#GetList call

value=#("EccentricXPS#XPSViewPopUpWaveList(2, \""+SubWindow+"\", \"DataFolderPopUp\")")

This is a quick copy-and-paste from one of my programs. It passes the window name (the variable SubWindow) along as well as the name of the control (the string value "DataFolderPopUp") to run ControlInfo on

Just to clarify: I do have a solution which works already. I just think it is too complicated to use and would like to have a more straightforward solution.

> Use a global string?

Multiple windows with multiple controls. So nope.

> If you feed a user-supplied regex to grep or greplist, you need to consider what happens in the event of a regex error.
> try..catch..endtry is one way to deal with runtime errors.

Yes, good code does that. Mine here is a MWE.

 

In reply to by olelytken

olelytken wrote:
It passes the window name (the variable SubWindow) along as well as the name of the control (the string value "DataFolderPopUp") to run ControlInfo on

olelytken's solution works, no? you must know the host window name and the corresponding setvar when you create the popup, so just hardwire the names into the GetList function call and run ControlInfo from GetList?

> olelytken's solution works, no? you must know the host window name and the corresponding setvar when you create the popup, so just hardwire the names into the GetList function call and run ControlInfo from GetList?

Yes it works in principle. But unfortunately in my case the window name is getting renamed occasionally. (Yes this was a dump thing to do in the first place, but that is how it is.)