displaying/hiding a graph on a tab in a panel

I would like to have a panel with multiple tabs. On one tab, a graph should display. The panel and TabControl code below, however, does not work as intended...

Function my_panel()
    my_globals()  //makes some globals
    PauseUpdate; Silent 1       // building window...
    NewPanel/N=my_panel/K=1 /W=(104,71,804,621) as "My Panel"
    ModifyPanel fixedSize=1
    SetDrawLayer UserBack
    SetDrawEnv fsize= 28,fstyle= 1,textrgb= (1,1,1)
    DrawText 10,33,"My Panel Aide"
    TabControl size_cal_tab,pos={5,70},size={690,475},proc=my_tabcontrol
    TabControl size_cal_tab,tabLabel(0)="Tab1",tabLabel(1)="Tab2", tabLabel(2)="Tab3", tabLabel(3)="Tab4"

        //a bunch of extraneous code that successfully creates controls, e.g. buttons, setvars, etc.

       display/N=not_graph/HOST=my_panel0 root:testwv      //not sure why NewPanel appends 0 to the end of the panel name but it does...
End

Function my_tabcontrol(ctrlName, tabNum) : TabControl
    String ctrlName
    Variable tabNum
   
    variable cont_disp,idex,nCont
    string cont_list, cont_item

    cont_list=controlnamelist("")
    nCont=itemsinlist(cont_list)
   
    for (idex=0;idex<nCont;idex+=1)
        cont_item=stringfromlist(idex,cont_list)
        strswitch (cont_item[0,3])
               //......
               //extraneous code that successfully hides/shows controls like buttons when various tabs are clicked
      endfor

         string myWInList, winStr
    variable  num
   
    myWInList = ChildWindowList("my_panel0")
    num= ItemsInList(myWinList)
    for(idex=0;idex<num;idex+=1)
       
        winStr = stringFromList(idex, myWInList)
        if(tabNum!=1)
            if (stringmatch("not", winStr[0,2])  )
                KillWindow $"my_Panel0#"+winStr
            endif      
        endif
       
    endfor
End


When clicking a tab that is not tab 1 (0th indexed), the graph display of testwv is successfully killed. The problem is that 1) the graph is displayed on tab 0 at startup of the panel and 2) the graph does not reappear if it is killed and then the user clicks on tab 1...

Is there a better method to write the display command? Do I need to use something akin to what is in the DisplayHelpTopic "TabControl" where it discusses using a predefined structure WMTabControlAction? Will I need to rewrite my above tabcontrol to fit in that or can i add it for only 1 specific tab?
We always recommend using the newer structure-based action procedures. They get all the good, new stuff, they are faster, and give you more control over what's happening.

Instead of killing your graph, how about hiding it? SetWindow $"my_Panel0#"+winStr, hide = 1 or 0

You should be able to create the graph hidden with Display/HIDE=1. That has some problems sometimes, but you could give it a try. Things that don't work that way are likely bugs, which you will report to us :)

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Thanks for the help in this thread and the other John, much appreciated.

I rewrote my tab control in the form:

Structure my_tabinfo
    Int32 eventcode
    Int32 tab
EndStructure


Function my_tabcontrol_new(tca) : TabControl

    STRUCT WMTabControlAction &tca
   
    switch(tca.eventCode)
       
        case 2:
            String controlsin_tab0 = ControlNameList("",";","tab0_*")
                        String controlsin_xxtab = ControlNameList("",";","xxtab_*")
                        //etc.
                 
                      if(tca.tab==0)
                        ModifyControlList controlsin_tab0 disable = 0
            ModifyControlList controlsin_xxtab disable = 1

            SetWindow $"my_Panel0#not_graph", hide = 1
                      endif

                     //analogous code for tca.tab==1, etc.
         endswitch
         return 0
end


I know it's not the most elegant solution, but it works for my purposes of learning igor structures and tabs...

The above code works for me as long as I put a setwindow hide=1 right after the display command in the panel creation function.

However....the popupsetvars from my other question are not hiding correctly. The title of them disappears but the outline and arrow to bring up the popup box remain. Not sure if that is a bug or my own poor programming.


EDIT: using the old style of tabcontrol, the popupsetvars do disappear completely on the non-relevant tabs
You might have found a bug. What version of Igor are you using? Could you post complete code or an Igor experiment file with your procedures adopted, so that we can try it? I would also recommend updating to the latest Igor if you haven't done that already: Help->Updates for Igor Pro xxx.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Hmmmmm....I reopened igor to copy/paste the code and it seems that the bug has manifested itself in a slightly different way. Now, instead of not hiding the popup boxes at all on tab2,3,4 now the arrow to indicate that the box is a popup is missing when I use the new style of tabcontrol. Sometimes the arrow does not show up on panel creation for the old style either, but the arrows show up if you click off tab 1 and back on.

Using version 6.3.7.2. Unable to upgrade to 7 yet because some of the custom ipf's I use have not been fully error checked in 7...


Both the old style and new style tab controls are there, just comment/decomment the appropriate 2 lines in size_cal_panel()

Also, I know that a better way to write the new style tabcontrol for hiding the tab buttons would be to rename the tabs to something procedural (e.g. tab0_*, tab1_*, etc) but I already started this way and don't want to rework it right now. If you have a suggestion of a way to do the modifycontrollist calls in 1 call instead of 4, without renaming anything, I'd love to hear it though!

#pragma rtGlobals=1     // Use modern global access method

#include <WaveSelectorWidget>
#include <PopupWaveSelector>


Menu "SizeCal"
    "Size Cal Aide/4",  /q,SC_getSCwin()
End


Function SC_getSCwin()
   
    string windows=winlist("size_cal_panel",";","WIN:64")
    if(strlen(windows)>0)
        dowindow/f size_cal_panel
    else
        size_cal_globals()
        size_cal_panel()
    endif

End


Function size_cal_panel()
    size_cal_globals()
    PauseUpdate; Silent 1       // building window...
    NewPanel/N=size_cal_panel/K=1 /W=(104,71,804,621) as "Size Calibration Panel"
    ModifyPanel fixedSize=1
    SetDrawLayer UserBack
    SetDrawEnv fsize= 28,fstyle= 1,textrgb= (1,1,1)
    DrawText 10,33,"AMS Size Calibration Aide"
   
//  TabControl size_cal_tab,pos={5,70},size={690,475},proc=size_cal_tabcontrol
//  TabControl size_cal_tab,tabLabel(0)="Identify Waves",tabLabel(1)="Determine Rising Edge", tabLabel(2)="Perform Calculations", tabLabel(3)="Fit Function"


    TabControl size_cal_tab,pos={5,70},size={690,475},proc=size_cal_tabcontrol_new
    TabControl size_cal_tab,tabLabel(0)="Identify Waves",tabLabel(1)="Determine Rising Edge", tabLabel(2)="Perform Calculations", tabLabel(3)="Fit Function"



    GroupBox idWv_SqReqs,pos={10,100},size={675,250}, title="Using this Panel"
    GroupBox idWv_SqReqs,fStyle=1,fColor=(43520,43520,0)
    //unimportant strings to display in the groupbox go here

   
    SetVariable idWv_PopupWvSelectorSV_smallest,pos={30,360},size={300,15},bodyWidth= 150,title="Smallest Size"
    MakeSetVarIntoWSPopupButton("size_Cal_panel0", "idWv_PopupWvSelectorSV_smallest", "DemoPopupWaveSelectorNotify", "root:SizeCalPanel:output_smallest",  options=PopupWS_OptionFloat+PopupWS_OptionSVFramed)

    SetVariable idWv_PopupWvSelectorSV_small,pos={30,390},size={300,15},bodyWidth= 150,title="Small Size "
    MakeSetVarIntoWSPopupButton("size_Cal_panel0", "idWv_PopupWvSelectorSV_small", "DemoPopupWaveSelectorNotify", "root:SizeCalPanel:output_small",  options=PopupWS_OptionFloat+PopupWS_OptionSVFramed)

    SetVariable idWv_PopupWvSelectorSV_large,pos={30,420},size={300,15},bodyWidth= 150,title="Large Size"
    MakeSetVarIntoWSPopupButton("size_Cal_panel0", "idWv_PopupWvSelectorSV_large", "DemoPopupWaveSelectorNotify", "root:SizeCalPanel:output_large",  options=PopupWS_OptionFloat+PopupWS_OptionSVFramed)

    SetVariable idWv_PopupWvSelectorSV_largest,pos={30,450},size={300,15},bodyWidth= 150,title="Largest Size"
    MakeSetVarIntoWSPopupButton("size_Cal_panel0", "idWv_PopupWvSelectorSV_largest", "DemoPopupWaveSelectorNotify", "root:SizeCalPanel:output_largest",  options=PopupWS_OptionFloat+PopupWS_OptionSVFramed)
   
   
    SetVariable idWv_sizeinnm_smallest, pos={405,360}, size={75,15},title="Size in nm", bodyWidth=75, value=root:SizeCalPanel:output_smallest_nm
    SetVariable idWv_sizeinnm_small, pos={405,390}, size={75,15},title="Size in nm", bodyWidth=75, value=root:SizeCalPanel:output_small_nm
    SetVariable idWv_sizeinnm_large, pos={405,420}, size={75,15},title="Size in nm", bodyWidth=75, value=root:SizeCalPanel:output_large_nm
    SetVariable idWv_sizeinnm_largest, pos={405,450}, size={75,15},title="Size in nm", bodyWidth=75, value=root:SizeCalPanel:output_largest_nm
   
    Button idWv_prelimcalcs title="Do Preliminary \rCalculations",size={120,75},fSize=14, fstyle=1, pos={530,380}, proc=idWv_prelimcalcs_proc
   
   
    //2nd panel things ; temporary placeholder below
    SetVariable DRE_testvar, pos={450,450}, size={75,15},title="test", bodyWidth=75,value=root:SizeCalPanel:testvar
   
   
    //make sure upon initialization that only 1st tab things show up
    string contlist = ControlNameList("",";","!idWv*")
    contlist = removefromlist("size_cal_tab", contlist) //otherwise the tabs are hidden too.
    ModifyControlList contlist, disable=1

    display/N=DRE_graph/HOST=size_cal_panel0
    SetWindow $"size_cal_Panel0#DRE_graph", hide = 1

End


Function create_DRE_graph()         ///function to append the traces to the DRE graph that were selected by user via popup bars
                                    ///to be called by button
    if(Waveexists(root:testwave))
    //  if(Waveexists(
    endif

End


Function DemoPopupWaveSelectorNotify(event, wavepath, windowName, ctrlName)
    Variable event
    String wavepath
    String windowName
    String ctrlName
   
    print "Selected wave:",wavepath, " using control", ctrlName
   
    if(!DataFolderExists("root:SizeCalPanel:outputwaves"))
        NewDataFolder root:SizeCalPanel:outputwaves
    endif
   
    string dfSav = GetDataFolder(1)
   
    strswitch (ctrlName)
        case "idWv_PopupWvSelectorSV_smallest":
            SetDataFolder root:SizeCalPanel:outputwaves
            SVAR output_smallest
            if(!SVAR_exists(output_smallest))                       //is this if necessary? why not just kill and reinitialize every time?
                initglobal_SVAR("output_smallest", wavepath)
            else
                KillStrings output_smallest
                initglobal_SVAR("output_smallest", wavepath)
            endif
            SetDataFolder $dfSav
           
        case "idWv_PopupWvSelectorSV_small":
            SetDataFolder root:SizeCalPanel:outputwaves
            SVAR output_small
            if(!SVAR_exists(output_small))
                initglobal_SVAR("output_small", wavepath)
            else
                KillStrings output_small
                initglobal_SVAR("output_small", wavepath)
            endif
            SetDataFolder $dfSav
           
        case "idWv_PopupWvSelectorSV_large":
            SetDataFolder root:SizeCalPanel:outputwaves
            SVAR output_large
            if(!SVAR_exists(output_large))
                initglobal_SVAR("output_large", wavepath)
            else
                KillStrings output_large
                initglobal_SVAR("output_large", wavepath)
            endif
            SetDataFolder $dfSav
       
        case "idWv_PopupWvSelectorSV_largest":
            SetDataFolder root:SizeCalPanel:outputwaves
            SVAR output_largest
            if(!SVAR_exists(output_largest))
                initglobal_SVAR("output_largest", wavepath)
            else
                KillStrings output_largest
                initglobal_SVAR("output_largest", wavepath)
            endif
            SetDataFolder $dfSav   
    endswitch
   
    traceongraph("size_cal_Panel0#DRE_graph", wavepath)
   
    //Appendtograph/W=$"size_cal_Panel0#DRE_graph" $wavepath
   
   
    //string/G tempstr = wavepath
   
    //rename tempstr, $ctrlname
    //SetFullDirectory_userinputs()
   
    //print PopupWS_GetSelectionFullPath(windowName, ctrlName)
end

Function traceongraph(graphname, tracename)     ///needs rework

    string graphname, tracename
    string existingtraces = tracenamelist(graphname,";",0)
   
    if(!stringmatch(existingtraces,tracename))
        AppendtoGraph/W=$graphname $tracename
    else
    RemoveFromGraph/W=$graphname $tracename
    AppendtoGraph/W=$graphname $tracename
    endif
End

Function size_cal_globals()
    if ( datafolderexists( "root:SizeCalPanel" ) != 1 )
        newdatafolder root:SizeCalPanel
    endif
   
   
    //string variables for setvars
    initglobal_SVAR("root:SizeCalpanel:output_smallest","")
    initglobal_SVAR("root:SizeCalpanel:output_small","")
    initglobal_SVAR("root:SizeCalpanel:output_large","")
    initglobal_SVAR("root:SizeCalpanel:output_largest","")
   
    //numeric variables
   
    initglobal_NVAR("root:SizeCalPanel:testvar",nan)
   
End

Function initglobal_SVAR(SVarName, SVarVal)
    string SVarName
    string SVarVal

    svar/z myVar = $SVarName
    if (!SVar_Exists(myVar))
        string/g $SVarName
        SVar/z myVar = $SVarName
        myVar = SVarVal
    endif

End

Function initglobal_NVAR(NVarName, NVarVal)
    string NVarName
    variable NVarVal

    Nvar/z myVar = $NVarName
    if (!NVar_Exists(myVar))
        string/g $NVarName
        NVar/z myVar = $NVarName
        myVar = NVarVal
    endif

End



Function size_cal_tabcontrol(ctrlName, tabNum) : TabControl
//ripped almost directly from something else
    String ctrlName
    Variable tabNum
   
    variable cont_disp,idex,nCont
    string cont_list, cont_item

    cont_list=controlnamelist("")
    nCont=itemsinlist(cont_list)
   
    for (idex=0;idex<nCont;idex+=1)
        cont_item=stringfromlist(idex,cont_list)
        strswitch (cont_item[0,3])
            case "Gen":     // outside of tabs 
                cont_disp=0
                break
            case "idWv":   
                cont_disp=tabNum!=0
                break
            case "DRE_":   
                cont_disp=tabNum!=1
                break
            case "PCal":   
                cont_disp=tabNum!=2
                break
            case "FtFn":   
                cont_disp=tabNum!=3
                break
        endswitch
        controlinfo /w=Size_cal_Panel0 $cont_item
        switch (abs(v_flag))
            case 1:
                button $cont_item disable=cont_disp
                break
            case 2:
                checkbox  $cont_item disable=cont_disp
                break
            case 3:
                popupmenu $cont_item disable=cont_disp
                break
            case 4:
                valdisplay $cont_item disable=cont_disp
                break
            case 5:
                setvariable $cont_item disable=cont_disp
                break
            case 6:
                chart $cont_item disable=cont_disp
                break
            case 7:
                slider $cont_item disable=cont_disp
                break
            case 8:
                tabcontrol $cont_item disable=cont_disp
                break
            case 9:
                groupbox $cont_item disable=cont_disp
                break
            case 10:
                titlebox $cont_item disable=cont_disp
                break
            case 11:
                listbox $cont_item disable=cont_disp
                break
        endswitch
    endfor
   
    string myWInList, winStr
    variable  num
   
    myWInList = ChildWindowList("size_Cal_panel0")
    num= ItemsInList(myWinList)
    for(idex=0;idex<num;idex+=1)
       
        winStr = stringFromList(idex, myWInList)
        if(tabNum!=1)
            if (stringmatch("DRE", winStr[0,2])  )
                SetWindow $"size_Cal_Panel0#"+winStr,hide=1
            endif
        endif
        if(tabNum==1)
            if(stringmatch("DRE", winStr[0,2]) )
                SetWindow $"size_Cal_Panel0#"+winStr,hide=0
            endif
        endif
       
    endfor
   
   
End


Structure size_cal_tabinfo
    Int32 eventcode
    Int32 tab
EndStructure


Function size_cal_tabcontrol_new(tca) : TabControl

    STRUCT WMTabControlAction &tca
   
    string cont_list, cont_item
    variable ncont

    cont_list=controlnamelist("")
    nCont=itemsinlist(cont_list)
   
   
    switch(tca.eventCode)
       
        case 2:
       
            String controlsin_idWv = ControlNameList("",";","idWv_*")
            String controlsin_DRE = ControlNameList("",";","DRE_*")
            String controlsin_PCal = ControlNameList("",";","PCal_*")
            String controlsin_FtFn = ControlNameList("",";","FtFn_*")
           
            String myWInList = ChildWindowList("size_cal_panel0")
           
            if(tca.tab==0)
                ModifyControlList controlsin_idWv disable = 0
                ModifyControlList controlsin_DRE disable = 1
                ModifyControlList controlsin_PCal disable = 1
                ModifyControlList controlsin_FtFn disable = 1
               
                SetWindow $"size_cal_Panel0#DRE_graph", hide = 1
            endif
           
            if(tca.tab==1)
                ModifyControlList controlsin_idWv disable = 1
                ModifyControlList controlsin_DRE disable = 0
                ModifyControlList controlsin_PCal disable = 1
                ModifyControlList controlsin_FtFn disable = 1
               
                SetWindow $"size_cal_Panel0#DRE_graph", hide = 0
            endif
           
            if(tca.tab==2)
                ModifyControlList controlsin_idWv disable = 1
                ModifyControlList controlsin_DRE disable = 1
                ModifyControlList controlsin_PCal disable = 0
                ModifyControlList controlsin_FtFn disable = 1
               
                SetWindow $"size_cal_Panel0#DRE_graph", hide = 1
            endif
           
            if(tca.tab==3)
                ModifyControlList controlsin_idWv disable = 1
                ModifyControlList controlsin_DRE disable = 1
                ModifyControlList controlsin_PCal disable = 1
                ModifyControlList controlsin_FtFn disable = 0
               
                SetWindow $"size_cal_Panel0#DRE_graph", hide = 1
            endif
    endswitch
    return 0
End

Structure idWv_prelimcalcs_butt_info
    Int32 eventcode
EndStructure


Function idWv_prelimcalcs_proc(B_Struct) : ButtonControl
    STRUCT WMButtonAction &B_Struct
   
    switch(B_struct.eventcode)
        case 2:
            //run some functions to do wave appending
    endswitch
   
End
Small semi-related followup question:

Is it possible to trick the new style tabcontrol into thinking an event code is being sent from something else? I would like to make the tab advance when the user clicks a button. For the old style tab control I have above, all I need to do is size_cal_tabcontrol("windowname",tabnumber) but it's less obvious if i can pass a tca.eventcode=2, tca.tab=1 kind of argument in the new style...
Small semi-related followup question:

Is it possible to trick the new style tabcontrol into thinking an event code is being sent from something else? I would like to make the tab advance when the user clicks a button. For the old style tab control I have above, all I need to do is size_cal_tabcontrol("windowname",tabnumber) but it's less obvious if i can pass a tca.eventcode=2, tca.tab=1 kind of argument in the new style...
mike_g wrote:
Small semi-related followup question:

Is it possible to trick the new style tabcontrol into thinking an event code is being sent from something else? I would like to make the tab advance when the user clicks a button. For the old style tab control I have above, all I need to do is size_cal_tabcontrol("windowname",tabnumber) but it's less obvious if i can pass a tca.eventcode=2, tca.tab=1 kind of argument in the new style...


Assuming that you want to create a function that calls your tabcontrol function, the answer is yes.

You can create an instance of the tabcontrol structure and pass it to your tabcontrol fuction. Just initialize the elements of the structure that your tabcontrol function needs.
mike_g wrote:
Small semi-related followup question:

Is it possible to trick the new style tabcontrol into thinking an event code is being sent from something else? I would like to make the tab advance when the user clicks a button. For the old style tab control I have above, all I need to do is size_cal_tabcontrol("windowname",tabnumber) but it's less obvious if i can pass a tca.eventcode=2, tca.tab=1 kind of argument in the new style...


Yes, this _can_ be done. The better approach and habit to cultivate is however to create a function that is dedicated solely to switch the tab. Call it when the user clicks the button. The temptation to use a different function to populate the structure that is passed to a panel control panel control opens the door to complications that eventually are not worth the effort. For example ... Gosh, this should work. (three days of hair pulling effort later) ... Oh! I forgot to define this specific element of the structure that I pass to the tabcontrol function and so the code is just jumping out on entry. (speaking from experience here).

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
I want to second the advice to write a function that does the common work that you're trying to get done by calling the action proc. Then the action proc can call that function, and wherever else you want that work to get done, call the worker function there, also. You will find ultimately that the action proc and the worker will diverge somewhat, or the action proc will need to do something in addition, and by separating it this way you save yourself complexity and head(or heart)ache.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
I copied your code, pasted it into the Procedure window. It compiled, it seems to run sort of...

Can you tell us how to run it so that we can see the problem? It would be helpful if the instructions include some comments like, "at this point you should see..., but instead it shows (or doesn't show) this thing...".

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com

I might bump this after nearly a year. I have found some odd behavior with ModifyControlList. Sometimes, it gives an error "Expected control name" (or equivalent). This seems to be especially true immediately after the controls are added to the panel.

I have found that this problem disappears when I add a ControlUpdate/A/W=... BEFORE I do any modifications to show/hide. So, the properly working code might have to look like this ...

DoWindow/F $k_panelName // bring panel forward (possibly not needed)

ControlUpdate/A/W=$k_panelName // update all controls (seems to be essential)

// hide prior controls
ptab = "*_tab"+ptabstr
tabList = ControlNameList(k_panelName,";",ptab)
ModifyControlList tabList disable=1

// show new controls
ptab = "*_tab"+ctabstr
tabList = ControlNameList(k_panelName,";",ptab)
ModifyControlList tabList disable=0

 

So, after further testing, I have a MWE to demonstrate the problem. When controls are located on sub-window panels, you must use the SetActiveSubWindow operation BEFORE the ModifyControlList. Otherwise, you run the danger that, when you click off the panel itself, ModifyControlList will not recognize where the controls are located.

Function MakeGraph()

    make/N=(10)/O somewave = sin(x)
    display/N=MyGraph somewave as "Test"
    NewPanel/EXT=0/HOST=#/N=MyPanel/W=(0,0,0.1,0.1)
       
    Button testit_tab0, title="Test0"      
    Button testit_tab1, title="Test1"

    return 0
end

Function TestOnOff(onoff)
    variable onoff

    string tablist
   
    // comment out the next code line
    // then activate the GRAPH
    // when you run the TestOnOff, you will get an error message
    SetActiveSubwindow MyGraph#MyPanel
   
    tablist = ControlNameList("MyPanel",";","*_tab0")
    ModifyControlList tablist disable=(onoff)
   
    tablist = ControlNameList("MyPanel",";","*_tab1")
    ModifyControlList tablist disable=(1-onoff)
   
    return 0
end

Run MakeGraph().

Run TestOnOff(...) with either 1 or 0.

Now, comment out the SetActiveSubWindow operation. Go to the graph and "touch" it to make it active (in the front of the sub-window panel).

Re-run the TestOnOff(...) function. You should get an error that 

--> While executing ModifyControlList, the following error occurred: Expected control name

It seems that perhaps ModifyControlList could benefit by a /W=winname flag.

Error in MCL.pxp