#pragma rtGlobals=1 // Use modern global access method. #pragma ModuleName=ColorScaleSliders Menu "Macros" "Append colorscale sliders", /Q, AppendColorRangeSliders() "RGB Merge...", /Q, RunRGBMerge() End // ********************************************* // **************** Color Scale Sliders *************** // ********************************************* Function AppendColorRangeSliders() string topGraphName = WinName(0, 1, 1) if (strlen(topGraphName) == 0) Abort "No graph window to append to" endif string imagesInGraph = ImageNameList(topGraphName, ";") if (ItemsInList(imagesInGraph) == 0) Abort "No image is shown in the top graph" endif if (ItemsInList(imagesInGraph) > 1) Abort "More than one image is present; not yet supported" endif // if the panel is already shown, do nothing DoUpdate /W=topGraphName#ColorScaleSliderPanel if (V_flag != 0) return 0 endif string imageName = StringFromList(0, imagesInGraph) wave imageWave = ImageNameToWaveRef(topGraphName, imageName) // initialize the panel NewPanel /N=ColorScaleSliderPanel/W=(0,0,360,200) /EXT=0 /HOST=$topGraphName PopupMenu PMSelectColorTable,win=$topGraphName#ColorScaleSliderPanel,pos={15,8},size={205,20},bodyWidth=150,title="Color Table:" PopupMenu PMSelectColorTable,win=$topGraphName#ColorScaleSliderPanel,mode=1,value=CtabList(),proc=PMColorTableChanged Slider SLUpperLimit,win=$topGraphName#ColorScaleSliderPanel,pos={18,81},size={316,13},proc=SlidersModified Slider SLUpperLimit,win=$topGraphName#ColorScaleSliderPanel,limits={0,2,1},value= 0,side= 0,vert= 0 CheckBox CBReverseColors,win=$topGraphName#ColorScaleSliderPanel,pos={243,10},size={98,14},title="Reverse colortable" CheckBox CBReverseColors,win=$topGraphName#ColorScaleSliderPanel,value= 0,proc=CBReverseColorTable GroupBox GBUpperLimit,win=$topGraphName#ColorScaleSliderPanel,pos={12,34},size={335,73},title="Upper limit" SetVariable SVUpperLimitSliderMin,win=$topGraphName#ColorScaleSliderPanel,pos={23,58},size={75,15},proc=SVSetVariablesModified SetVariable SVUpperLimitValue,win=$topGraphName#ColorScaleSliderPanel,pos={140,57},size={75,15},proc=SVSetVariablesModified SetVariable SVUpperLimitSliderMax,win=$topGraphName#ColorScaleSliderPanel,pos={263,57},size={75,15},proc=SVSetVariablesModified Slider SLLowerLimit,win=$topGraphName#ColorScaleSliderPanel,pos={19,160},size={316,13},proc=SlidersModified Slider SLLowerLimit,win=$topGraphName#ColorScaleSliderPanel,limits={0,2,1},value= 0,side= 0,vert= 0 GroupBox GBLowerLimit,win=$topGraphName#ColorScaleSliderPanel,pos={13,113},size={335,73},title="Lower limit" SetVariable SVLowerLimitSliderMin,win=$topGraphName#ColorScaleSliderPanel,pos={24,137},size={75,15},proc=SVSetVariablesModified SetVariable SVLowerLimitValue,win=$topGraphName#ColorScaleSliderPanel,pos={141,136},size={75,15},proc=SVSetVariablesModified SetVariable SVLowerLimitSliderMax,win=$topGraphName#ColorScaleSliderPanel,pos={264,136},size={75,15},proc=SVSetVariablesModified // update the limits of the sliders to the min and max of the image variable minLimit = WaveMin(imageWave) variable maxLimit = WaveMax(imageWave) Slider SLUpperLimit,win=$topGraphName#ColorScaleSliderPanel,limits={minLimit, maxLimit, 0} Slider SLLowerLimit,win=$topGraphName#ColorScaleSliderPanel,limits={minLimit, maxLimit, 0} SetVariable SVUpperLimitSliderMax,win=$topGraphName#ColorScaleSliderPanel,value=_NUM:maxLimit SetVariable SVUpperLimitSliderMin,win=$topGraphName#ColorScaleSliderPanel,value=_NUM:minLimit SetVariable SVLowerLimitSliderMax,win=$topGraphName#ColorScaleSliderPanel,value=_NUM:maxLimit SetVariable SVLowerLimitSliderMin,win=$topGraphName#ColorScaleSliderPanel,value=_NUM:minLimit // and update the controls to the actual settings UpdateControlsToActualSettings(topGraphName) End Function UpdateControlsToActualSettings(windowName) string windowName string baseWindowName = StringFromList(0, windowName, "#") string imagesInGraph = ImageNameList(baseWindowName, ";") if (ItemsInList(imagesInGraph) == 0) Abort "No image is shown in the top graph" endif if (ItemsInList(imagesInGraph) > 1) Abort "More than one image is present; not yet supported" endif string imageName = StringFromList(0, imagesInGraph) wave imageWave = ImageNameToWaveRef(baseWindowName, imageName) // get the color scale that is currently selected string recreation = StringByKey("RECREATION", ImageInfo(baseWindowName, imageName, 0)) string ctabStr = StringByKey("ctab", recreation, "=") string lowerLimitStr, upperLimitStr, ctabName, isReverseStr variable lowerLimit, upperLimit, isReverse SplitString /E="\\{([^,]*),([^,]*),([^,]*),([0-9]+)\\}" ctabStr, lowerLimitStr, upperLimitStr, ctabName, isReverseStr if (GrepString(lowerLimitStr, "\\*")) lowerLimit = WaveMin(imageWave) else lowerLimit = str2num(lowerLimitStr) endif if (GrepString(upperLimitStr, "\\*")) upperLimit = WaveMax(imageWave) else upperLimit = str2num(upperLimitStr) endif isReverse = str2num(isReverseStr) // and update the controls to the actual settings PopupMenu PMSelectColorTable,win=$baseWindowName#ColorScaleSliderPanel,popmatch=ctabName CheckBox CBReverseColors,win=$baseWindowName#ColorScaleSliderPanel,value=isReverse Slider SLUpperLimit,win=$baseWindowName#ColorScaleSliderPanel,value=upperLimit Slider SLLowerLimit,win=$baseWindowName#ColorScaleSliderPanel,value=lowerLimit SetVariable SVUpperLimitValue,win=$baseWindowName#ColorScaleSliderPanel,value=_NUM:upperLimit SetVariable SVLowerLimitValue,win=$baseWindowName#ColorScaleSliderPanel,value=_NUM:lowerLimit End Function SlidersModified(sa) : SliderControl STRUCT WMSliderAction &sa switch( sa.eventCode ) case -1: // control being killed break default: if( sa.eventCode & 1 ) // value set Variable curval = sa.curval string baseWindowName = StringFromList(0, sa.win, "#") // update both SetVariables ControlInfo /W=$sa.win SLUpperLimit SetVariable SVUpperLimitValue,win=$sa.win,value=_NUM:V_Value ControlInfo /W=$sa.win SLLowerLimit SetVariable SVLowerLimitValue,win=$sa.win,value=_NUM:V_Value UpdateColorScaling(sa.win) endif break endswitch return 0 End Function SVSetVariablesModified(sva) : SetVariableControl STRUCT WMSetVariableAction &sva switch( sva.eventCode ) case 1: // mouse up case 2: // Enter key case 3: // Live update Variable dval = sva.dval ControlInfo /W=$sva.win SVUpperLimitSliderMax variable upperLimitMax = V_Value ControlInfo /W=$sva.win SVUpperLimitSliderMin variable upperLimitMin = V_Value ControlInfo /W=$sva.win SVUpperLimitValue variable upperLimit = V_Value ControlInfo /W=$sva.win SVLowerLimitSliderMax variable lowerLimitMax = V_Value ControlInfo /W=$sva.win SVLowerLimitSliderMin variable lowerLimitMin = V_Value ControlInfo /W=$sva.win SVLowerLimitValue variable lowerLimit = V_Value Slider SLUpperLimit,win=$sva.win,value=upperLimit,limits={upperLimitMin, upperLimitMax, 0} Slider SLLowerLimit,win=$sva.win,value=lowerLimit,limits={lowerLimitMin, lowerLimitMax, 0} break case -1: // control being killed break endswitch return 0 End Function PMColorTableChanged(pa) : PopupMenuControl STRUCT WMPopupAction &pa switch( pa.eventCode ) case 2: // mouse up Variable popNum = pa.popNum String popStr = pa.popStr UpdateColorScaling(pa.win) break case -1: // control being killed break endswitch return 0 End Function CBReverseColorTable(cba) : CheckBoxControl STRUCT WMCheckboxAction &cba switch( cba.eventCode ) case 2: // mouse up Variable checked = cba.checked UpdateColorScaling(cba.win) break case -1: // control being killed break endswitch return 0 End Function UpdateColorScaling(windowName) string windowName string baseWindowName = StringFromList(0, windowName, "#") string imagesInGraph = ImageNameList(baseWindowName, ";") if (ItemsInList(imagesInGraph) == 0) Abort "No image is shown in the top graph" endif if (ItemsInList(imagesInGraph) > 1) Abort "More than one image is present; not yet supported" endif string imageName = StringFromList(0, imagesInGraph) wave imageWave = ImageNameToWaveRef(baseWindowName, imageName) // get the color scale to use string ctabName ControlInfo /W=$baseWindowName#ColorScaleSliderPanel PMSelectColorTable ctabName = S_Value variable minVal, maxVal ControlInfo /W=$baseWindowName#ColorScaleSliderPanel SLUpperLimit maxVal = V_Value ControlInfo /W=$baseWindowName#ColorScaleSliderPanel SLLowerLimit minVal = V_Value variable isReverse ControlInfo /W=$baseWindowName#ColorScaleSliderPanel CBReverseColors isReverse = V_Value ModifyImage /W=$baseWindowName $imageName, ctab={minVal, maxVal, $ctabName, isReverse} End // ********************************************* // ****************** RGB Merging ***************** // ********************************************* Function RunRGBMerge() NewDataFolder /O root:Packages NewDataFolder /O root:Packages:ColorScaleSliders DFREF savDF = GetDataFolderDFR() // the problem with image waves is that we need to consider both mxn and mxnx1 waves // do some hackery with that string candidateWaves = RecursiveWaveList(savDF, "*", "CMPLX:0,TEXT:0") string eligibleWaves = "" variable i for (i = 0; i < ItemsInList(candidateWaves); i+=1) wave thisWave = $StringFromList(i, candidateWaves) if ((DimSize(thisWave, 0) != 0) && (DimSize(thisWave, 1) != 0) && ((DimSize(thisWave, 2) == 0) || (DimSize(thisWave, 2) == 1))) eligibleWaves += StringFromList(i, candidateWaves) + ";" endif endfor string promptString = "none;" + eligibleWaves string redWaveName, greenWaveName, blueWaveName Prompt redWaveName, "Red channel:", popup, promptString Prompt greenWaveName, "Green channel:", popup, promptString Prompt blueWaveName, "Blue channel:", popup, promptString DoPrompt "Select the channels", redWaveName, greenWaveName, blueWaveName if (V_flag == 1) return 0 endif if (StringMatch(redWaveName, "none") && StringMatch(greenWaveName, "none") && StringMatch(redWaveName, "none")) return 0 endif variable useRed = (StringMatch(redWaveName, "none")) ? 0 : 1 variable useGreen = (StringMatch(greenWaveName, "none")) ? 0 : 1 variable useBlue = (StringMatch(blueWaveName, "none")) ? 0 : 1 // get a unique name for the graph window string displayWindowName = UniqueName("RGBMerge", 6, 0) // now that we have a unique window name, set up the data folder // associated with this window NewDataFolder /O root:Packages:ColorScaleSliders:$displayWindowName DFREF windowDataFolder = root:Packages:ColorScaleSliders:$displayWindowName // the datafolder may already exist if another window was created and closed previously // so be sure to empty it first DFREF savDF = GetDataFolderDFR() SetDataFolder windowDataFolder KillWaves /A/Z SetDataFolder savDF // remember the names of the waves // these string variables contain the name of the raw data wave // followed by a comma, and the name of the display wave string /G windowDataFolder:S_RedWaveName string /G windowDataFolder:S_GreenWaveName string /G windowDataFolder:S_BlueWaveName SVAR globalRedWaveName = windowDataFolder:S_RedWaveName SVAR globalGreenWaveName = windowDataFolder:S_GreenWaveName SVAR globalBlueWaveName = windowDataFolder:S_BlueWaveName // redWaveName and the others contain a full path, i.e. root:someWave // so make appropriate names for the displayWaveName // TODO: handle the case where the wave name is too long string redDisplayWaveName, greenDisplayWaveName, blueDisplayWaveName if (useRed) globalRedWaveName = redWaveName redDisplayWaveName = ParseFilePath(3, globalRedWaveName, ":", 0, 1) + "_RGB" globalRedWaveName += ";" + redDisplayWaveName wave redWave = $redWaveName else globalRedWaveName = "" endif if (useGreen) globalGreenWaveName = GreenWaveName greenDisplayWaveName = ParseFilePath(3, globalGreenWaveName, ":", 0, 1) + "_RGB" globalGreenWaveName += ";" + greenDisplayWaveName wave greenWave = $greenWaveName else globalGreenWaveName = "" endif if (useBlue) globalBlueWaveName = BlueWaveName blueDisplayWaveName = ParseFilePath(3, globalBlueWaveName, ":", 0, 1) + "_RGB" globalBlueWaveName += ";" + blueDisplayWaveName wave blueWave = $blueWaveName else globalBlueWaveName = "" endif // set up RGB copies of the waves if (useRed) Duplicate /O redWave, windowDataFolder:$StringFromList(1, globalRedWaveName) wave redDisplayWave = windowDataFolder:$StringFromList(1, globalRedWaveName) Redimension /N=(-1, -1, 3) /W/U redDisplayWave endif if (useGreen) Duplicate /O greenWave, windowDataFolder:$StringFromList(1, globalGreenWaveName) wave greenDisplayWave = windowDataFolder:$StringFromList(1, globalGreenWaveName) Redimension /N=(-1, -1, 3) /W/U greenDisplayWave endif if (useBlue) Duplicate /O blueWave, windowDataFolder:$StringFromList(1, globalBlueWaveName) wave blueDisplayWave = windowDataFolder:$StringFromList(1, globalBlueWaveName) Redimension /N=(-1, -1, 3) /W/U blueDisplayWave endif // Make a merged RGB wave if (useRed) Duplicate /O redDisplayWave, windowDataFolder:M_Merged_RGB elseif (useGreen) Duplicate /O greenDisplayWave, windowDataFolder:M_Merged_RGB elseif (useBlue) Duplicate /O blueDisplayWave, windowDataFolder:M_Merged_RGB endif // display the waves in a single image NewImage /N=$displayWindowName windowDataFolder:M_Merged_RGB ModifyGraph width={Aspect, DimSize(windowDataFolder:M_Merged_RGB, 0) / DimSize(windowDataFolder:M_Merged_RGB, 1)} // add the exterior subwindow with the controls string redTitle = "Red Channel: " + NameOfWave(redWave) string greenTitle = "Green Channel: " + NameOfWave(greenWave) string blueTitle = "Blue Channel: " + NameOfWave(blueWave) NewPanel /N=ColorScaleSliderPanel/W=(0,0,360,350) /EXT=0 /HOST=$displayWindowName GroupBox GBRed,pos={12,4},size={335,109},title=redTitle Slider SLUpperLimitRed,pos={18,50},size={316,13},disable=(!useRed * 2) Slider SLUpperLimitRed,limits={0,2,1},value= 0,side= 0,vert= 0,proc=SLRGBMergeProc SetVariable SVUpperLimitSliderMinRed,pos={23,26},size={75,15},disable=(!useRed * 2) SetVariable SVUpperLimitValueRed,pos={140,26},size={75,15},disable=(!useRed * 2) SetVariable SVUpperLimitSliderMaxRed,pos={263,26},size={75,15},disable=(!useRed * 2) Slider SLLowerLimitRed,pos={19,94},size={316,13},disable=(!useRed * 2) Slider SLLowerLimitRed,limits={0,2,1},value= 0,side= 0,vert= 0,proc=SLRGBMergeProc SetVariable SVLowerLimitSliderMinRed,pos={24,70},size={75,15},disable=(!useRed * 2) SetVariable SVLowerLimitValueRed,pos={141,70},size={75,15},disable=(!useRed * 2) SetVariable SVLowerLimitSliderMaxRed,pos={264,70},size={75,15},disable=(!useRed * 2) GroupBox GBGreen,pos={12,120},size={335,109},title=greenTitle Slider SLUpperLimitGreen,pos={18,166},size={316,13},disable=(!useGreen * 2) Slider SLUpperLimitGreen,limits={0,2,1},value= 0,side= 0,vert= 0,proc=SLRGBMergeProc SetVariable SVUpperLimitSliderMinGreen,pos={23,142},size={75,15},disable=(!useGreen * 2) SetVariable SVUpperLimitValueGreen,pos={140,142},size={75,15},disable=(!useGreen * 2) SetVariable SVUpperLimitSliderMaxGreen,pos={263,142},size={75,15},disable=(!useGreen * 2) Slider SLLowerLimitGreen,pos={19,210},size={316,206},disable=(!useGreen * 2) Slider SLLowerLimitGreen,limits={0,2,1},value= 0,side= 0,vert= 0,proc=SLRGBMergeProc SetVariable SVLowerLimitSliderMinGreen,pos={24,186},size={75,15},disable=(!useGreen * 2) SetVariable SVLowerLimitValueGreen,pos={141,186},size={75,15},disable=(!useGreen * 2) SetVariable SVLowerLimitSliderMaxGreen,pos={264,186},size={75,15},disable=(!useGreen * 2) GroupBox GBBlue,pos={12,236},size={335,109},title=blueTitle Slider SLUpperLimitBlue,pos={18,282},size={316,13},disable=(!useBlue * 2) Slider SLUpperLimitBlue,limits={0,2,1},value= 0,side= 0,vert= 0,proc=SLRGBMergeProc SetVariable SVUpperLimitSliderMinBlue,pos={23,258},size={75,15},disable=(!useBlue * 2) SetVariable SVUpperLimitValueBlue,pos={140,258},size={75,15},disable=(!useBlue * 2) SetVariable SVUpperLimitSliderMaxBlue,pos={263,258},size={75,15},disable=(!useBlue * 2) Slider SLLowerLimitBlue,pos={19,326},size={316,206},disable=(!useBlue * 2) Slider SLLowerLimitBlue,limits={0,2,1},value= 0,side= 0,vert= 0,proc=SLRGBMergeProc SetVariable SVLowerLimitSliderMinBlue,pos={24,302},size={75,15},disable=(!useBlue * 2) SetVariable SVLowerLimitValueBlue,pos={141,302},size={75,15},disable=(!useBlue * 2) SetVariable SVLowerLimitSliderMaxBlue,pos={264,302},size={75,15},disable=(!useBlue * 2) // provide some default values variable redMin, redMax variable greenMin, greenMax variable blueMin, blueMax if (useRed) redMin = WaveMin(redWave) redMax = WaveMax(redWave) Slider SLUpperLimitRed,limits={redMin,redMax,0},value= redMax Slider SLLowerLimitRed,limits={redMin,redMax,0},value= redMin SetVariable SVUpperLimitSliderMinRed,value=_NUM:redMin SetVariable SVUpperLimitValueRed,value=_NUM:redMax SetVariable SVUpperLimitSliderMaxRed,value=_NUM:redMax SetVariable SVLowerLimitSliderMinRed,value=_NUM:redMin SetVariable SVLowerLimitValueRed,value=_NUM:redMin SetVariable SVLowerLimitSliderMaxRed,value=_NUM:redMax endif if (useGreen) greenMin = WaveMin(greenWave) greenMax = WaveMax(greenWave) Slider SLUpperLimitGreen,limits={greenMin,greenMax,0},value= greenMax Slider SLLowerLimitGreen,limits={greenMin,greenMax,0},value= greenMin SetVariable SVUpperLimitSliderMinGreen,value=_NUM:greenMin SetVariable SVUpperLimitValueGreen,value=_NUM:greenMax SetVariable SVUpperLimitSliderMaxGreen,value=_NUM:greenMax SetVariable SVLowerLimitSliderMinGreen,value=_NUM:greenMin SetVariable SVLowerLimitValueGreen,value=_NUM:greenMin SetVariable SVLowerLimitSliderMaxGreen,value=_NUM:greenMax endif if (useBlue) blueMin = WaveMin(blueWave) blueMax = WaveMax(blueWave) Slider SLUpperLimitBlue,limits={blueMin,blueMax,0},value= blueMax Slider SLLowerLimitBlue,limits={blueMin,blueMax,0},value= blueMin SetVariable SVUpperLimitSliderMinBlue,value=_NUM:blueMin SetVariable SVUpperLimitValueBlue,value=_NUM:blueMax SetVariable SVUpperLimitSliderMaxBlue,value=_NUM:blueMax SetVariable SVLowerLimitSliderMinBlue,value=_NUM:blueMin SetVariable SVLowerLimitValueBlue,value=_NUM:blueMin SetVariable SVLowerLimitSliderMaxBlue,value=_NUM:blueMax endif RGBMergeUpdate(displayWindowName) End Function RGBMergeUpdate(windowName) string windowName DFREF windowDataFolder = root:Packages:ColorScaleSliders:$windowName // update all of the RGB waves, and calculate a new merged image // first get the actual settings wave mergedImage = windowDataFolder:M_Merged_RGB variable minValue, maxValue string colors = "Red;Green;Blue;" variable i for (i = 0; i < ItemsInList(colors); i+=1) SVAR globalWaveName = windowDataFolder:$("S_" + StringFromList(i, colors) + "WaveName") if (strlen(globalWaveName) != 0) ControlInfo /W=$windowName#ColorScaleSliderPanel $("SLUpperLimit" + StringFromList(i, colors)) maxValue = V_Value ControlInfo /W=$windowName#ColorScaleSliderPanel $("SLLowerLimit" + StringFromList(i, colors)) minValue = V_Value wave dataWave = $StringFromList(0, globalWaveName) wave displayWave = windowDataFolder:$StringFromList(1, globalWaveName) MatrixOP /O/FREE M_ThisImagePlane = (clip(dataWave, minValue, maxValue) - minValue) / (maxValue - minValue) * 65535 ImageTransform /P=(i) /D=M_ThisImagePlane setPlane, mergedImage endif endfor End Function SLRGBMergeProc(sa) : SliderControl STRUCT WMSliderAction &sa switch( sa.eventCode ) case -1: // control being killed break default: if( sa.eventCode & 1 ) // value set Variable curval = sa.curval // update the setvariable to the correct value string controlName = sa.ctrlName string baseWindowName = StringFromList(0, sa.win, "#") string setVariableName if (StringMatch(controlName, "*UpperLimit*")) setVariableName = ReplaceString("SLUpperLimit", controlName, "SVUpperLimitValue") else setVariableName = ReplaceString("SLLowerLimit", controlName, "SVLowerLimitValue") endif SetVariable $setVariableName,win=$baseWindowName#ColorScaleSliderPanel,value=_NUM:curval RGBMergeUpdate(baseWindowName) endif break endswitch return 0 End Function SVRGBMergeSetVariablesModified(sva) : SetVariableControl STRUCT WMSetVariableAction &sva switch( sva.eventCode ) case 1: // mouse up case 2: // Enter key case 3: // Live update Variable dval = sva.dval string baseWindowName = StringFromList(0, sva.win, "#") string controlName = sva.ctrlName // adjust the sliders to the values of the SetVariables ControlInfo /W=$sva.win SVUpperLimitSliderMax variable upperLimitMax = V_Value ControlInfo /W=$sva.win SVUpperLimitSliderMin variable upperLimitMin = V_Value ControlInfo /W=$sva.win SVUpperLimitValue variable upperLimit = V_Value ControlInfo /W=$sva.win SVLowerLimitSliderMax variable lowerLimitMax = V_Value ControlInfo /W=$sva.win SVLowerLimitSliderMin variable lowerLimitMin = V_Value ControlInfo /W=$sva.win SVLowerLimitValue variable lowerLimit = V_Value Slider SLUpperLimit,win=$sva.win,value=upperLimit,limits={upperLimitMin, upperLimitMax, 0} Slider SLLowerLimit,win=$sva.win,value=lowerLimit,limits={lowerLimitMin, lowerLimitMax, 0} break case -1: // control being killed break endswitch return 0 End // ********************************************* // ***************** Utility Routines **************** // ********************************************* Function /S RecursiveWaveList(startDF, nameFilter, optionsFilter) DFREF startDF string nameFilter, optionsFilter // get a list of the waves in the requested data folder DFREF savDF = GetDataFolderDFR() SetDataFolder startDF string matchingWaves = WaveList(nameFilter, ";", optionsFilter) variable nMatches = ItemsInList(matchingWaves) variable i string matchingWavesFullPath = "" for (i = 0; i < nMatches; i+=1) wave matchingWaveRef = startDF:$StringFromList(i, matchingWaves) matchingWavesFullPath += GetWavesDataFolder(matchingWaveRef, 2 ) + ";" endfor // for every data folder in this one, recurse and append the result string DFName for (i = 0; ; i+=1) DFName = GetIndexedObjNameDFR(startDF, 4, i) if (strlen(DFName) == 0) break endif DFRef subFolder = startDF:$DFName matchingWavesFullPath += RecursiveWaveList(subFolder, nameFilter, optionsFilter) endfor SetDataFolder savDF return matchingWavesFullPath End