Storing and retrieving control settings from/to a panel via a Structure

I want to store the settings in a panel to recall if the panel is closed and reopened. The panel attaches to a graph window. I have settled on using a Structure. I had hoped to store the entire structure into a defined UserData string for the graph window. If I understand correctly, I will have to step through each component in the structure, convert it to a string, and append the string into a keyword-value pair list. I have to invert the process to recover the values.

Does anyone have suggestions on an approach that is less tedious, inflexible, and error prone?

As a follow up comment, I am basically seeking the equivalent to StructPut/Get with /S to encode/decode an entire structure into/out of a string. In the meantime, perhaps this is a feature request to have flags StructPut/S/A and StructGet/S/A, whereby /A means to encode/decode the entire structure into/out of a string.

I am not interested in Load/SavePackagePreferences because I want to store the panel settings to the graph window.

Finally, it would also be great if implemented to have the StructGet/Put operations with /A to encode/decode character and string variables too, not just numbers.

This is IP 9 BTW.

It's frustrating not to be able to do what you describe. I assume that the goal is to to have panel information associated with an arbitrary number of graph windows, without saving any package clutter elsewhere.

I think that if you redefine the control structure to use char arrays instead of strings your approach with StructGet/Put will work. That's how strings are stored in package preference files.

perhaps something like this

static structure PanelStatusStructure
    STRUCT ControlValueStructure control1, control2
endstructure
 
static structure ControlValueStructure
    int16 type
    char ctrlName[100]
    double value
    char sval[100]
    STRUCT RGBColor rgb
    STRUCT RGBAColor rgba
    int16 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

 

note that when the help says

"The structure fields to be exported must contain only numeric data in either integer, floating point, or double precision format"

that includes char members, which are 1 byte integers.

Tony -- Thanks! The generic function GetControlValue saves certain aspects of tedious effort at the expense of loosing long-term clarity. As I ponder this further, I will in the meantime write everything explicitly on the knowledge that, although my panel is choke-full of a variety of controls, I do not foresee making any exhaustive changes to its layout in the near-term future. Getting a method in place that works to store and recall the panel control settings is of higher value.

Specifically, the work is for the SpXZeigR package. I have a Layout panel that is to be associated with only one graph window at any time but should also be able to move to a different graph window if desired. Before the panel is removed from any graph window, I will store its current control settings in the graph window UserData string. If the Layout panel is re-attached back to the graph window, I can restore its previous settings. Eventually, this may even allow for multiple graphs to each have their own Layout panels, whereby activating any graph window restores the panel controls from the graph window string rather than from a set of package globals.

In deeper reflection, my idea could be considered as the equivalent of wishing that developers could more easily capture custom (YAML-formatted) meta-content about settings in panels attached to window objects and write that meta-content to the window object in order to define how their package should handle the window after any given major event in the experiment (activate/deactivate the window or close/reopen the experiment). It moves the meta-processing away from the (shunned) approach of using package globals.

I imagine that in some cases it may suffice to save a panel recreation macro as user text.

tony wrote: I imagine that in some cases it may suffice to save a panel recreation macro as user text.

Yes. I should consider this too.

As it turns out, the easier approach for my intentions is to capture the recreation macro for the panel before it closes and reapply it after it is re-attached. Otherwise, I have to store not only the value of a control but also its disabled state.

Having the equivalent of GetStruct/A and PutStruct/A as a way to capture, store, and re-set entire structures containing all manner of parameter types still seems to be a worthy addition for a future version.

Thanks Tony for the useful tip!

May I also propose to simply use a keyword-value pair list for the sole purpose of saving the panel's state? When using a ctrl_name:value approach it should be fairly easy to read and write using a single loop and ControlNameList(). I would be a bit wary of saving whole control states, like the disabled flag, which can easily lead to undefined behavior if one is not careful. Why not infer such states via update functions instead (e.g., controls should be only disabled when this and that is set etc.), which can be called to sync the status after the list has been applied from a saved state.

chozo wrote: May I also propose to simply use a keyword-value pair list for the sole purpose of saving the panel's state? ...

I have successfully coded a keyword-value pairing. I do need the disabled states for certain controls. Your additional suggestion ...

chozo wrote: which can be called to sync the status after the list has been applied from a saved state.

... may be worth exploring further. It would demand a bit more tedium than the approach to just recreate using its WinRecreation captured before the panel is closed. But, it may avoid edge cases as you comment. I am playing around with it a bit further. FWIW, the one downside using the WinRecreation is that WinRecreation does not capture the name of an external panel. I have to insert the name manually before applying the WinRecreation.