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 (5.33 KB)