User interface for naming and storing a wave

A little modal dialog to ask the user where to store a wave. Copy the code into a new procedure window and execute the following:

make foo
SaveWave#SaveWaveUI(foo)
#pragma rtGlobals=3
#pragma ModuleName=SaveWave
#pragma version = 1.21

static function/WAVE SaveWaveUI(wave w, [string basename, int overwrite])
	
	overwrite = ParamIsDefault(overwrite) ? 1 : overwrite // default is to allow user to overwrite a wave
	if (ParamIsDefault(basename))
		basename = NameOfWave(w)
		if (cmpstr(basename, "_free_") == 0)
			basename = "wave"
		endif
	endif
	
	DoWindow/K SaveWaveDialog
	GetMouse
	variable left, top, right, bottom
	left = pixel2cpu(V_left) - 50
	top = pixel2cpu(V_top) - 50
	right = left + 220
	bottom = top + 150
	NewPanel/K=1/W=(left,top,right,bottom)/N=SaveWaveDialog as "Save Wave"
	SetVariable svName,pos={25,20},size={157,14},title="Wave Name", userdata(base) = basename
	SetVariable svName,value=_STR:UniqueName(basename, 1, 0), fsize=12, Proc=SaveWave#SaveWaveSetVars
	PopupMenu popFolder,pos={25,50},size={157,14},title="Data Folder", fsize=12
	PopupMenu popFolder,value=#"GetDataFolder(0)", userdata(folder)=GetDataFolder(1), Proc=SaveWave#SaveWavePopups
	Button btnCancel,pos={40,100},size={55,20},title="Cancel", Proc=SaveWave#SaveWaveButtons
	Button btnDoIt,pos={130,100},size={50,20},title="Do It", Proc=SaveWave#SaveWaveButtons, userdata=num2str(overwrite)
	PauseForUser SaveWaveDialog
	wave/Z/WAVE w_savewave
	if (WaveExists(w_savewave))
		wave/Z saved = w_savewave[0]
		string strPathToNewWave = GetWavesDataFolder(saved, 2)
		KillWaves/Z saved
		Duplicate/O w $strPathToNewWave /wave=saved
		KillWaves w_savewave
		return saved
	endif
	return $""
end

static function SaveWavePopups(STRUCT WMPopupAction &s) : PopupMenuControl
	
	if (s.eventCode != 3)
		return 0
	endif

	string strFolder = StringFromList(0, SelectFolder(s.popStr))
	if (strlen(strFolder))
		PopupMenu popFolder, win=$s.win, userdata(folder)=strFolder
		PopupMenu popFolder, win=$s.win, value=#"SaveWave#GetSelectedFolder(0)"
	endif
	
	CheckNameSetvar()

	return 0
end

static function SaveWaveButtons(STRUCT WMButtonAction &s) : ButtonControl

	if (s.eventcode != 2)
		return 0
	endif
	
	strswitch (s.ctrlName)
		case "btnDoIt":
			int overwrite = str2num(s.userdata)
			ControlInfo/W=$s.win svName
			if (!overwrite && exists(GetSelectedFolder(1)+PossiblyQuoteName(s_value)))
				DoAlert 0, s_value + " exists."
				return 0
			endif
			KillWaves/Z $GetSelectedFolder(1)+PossiblyQuoteName(s_value)
			wave/Z w = $GetSelectedFolder(1)+PossiblyQuoteName(s_value)
			if (WaveExists(w))
				DoAlert 0, s_value + " exists and is in use, cannot overwrite."
				return 0
			endif
			Make/O/N=0 $GetSelectedFolder(1)+PossiblyQuoteName(s_value) /wave=w
			Make/O/WAVE w_savewave = {w}
		case "btnCancel" : // Cancel or Do It
			DoWindow/K $s.win
			break
	endswitch
	return 0
end

static function SaveWaveSetVars(STRUCT WMSetVariableAction &s)
	
	if (s.eventCode < 0) // excludes Igor8 eventcodes -2 and -3
		return 0
	endif
	
	if (cmpstr(s.ctrlName, "svName") == 0)
		CheckNameSetvar()
	endif
	return 0
end

static function CheckNameSetvar()
	ControlInfo/W=SaveWaveDialog svName
	if (strlen(S_Value) == 0)
		S_Value = UniqueName(GetUserData("SaveWaveDialog", "svName", "base"), 1, 0)
		SetVariable svName win=SaveWaveDialog, value=_STR:S_Value
	endif
	if (exists(GetSelectedFolder(1) + S_Value))
		SetVariable svName win=SaveWaveDialog, valueBackColor=(0xFFFF,0,0)
	else
		SetVariable svName win=SaveWaveDialog, valueBackColor=0
	endif
end

static function/T GetSelectedFolder(int fullpath)
	string strFolder = GetUserData("SaveWaveDialog", "popFolder", "folder")
	return SelectString(fullpath, ParseFilePath(0, strFolder, ":", 1, 0), strFolder)
end

static function/T SelectFolder(string selection)
	CreateBrowser/M Prompt="Select Data Folder"
	ModifyBrowser/M showWaves=0, showVars=0, showStrs=0
	ModifyBrowser/M ShowInfo=0, showPlot=0
	ModifyBrowser/M select=selection
	ModifyBrowser/M showModalBrowser
	if (V_Flag == 0)
		return "" // User cancelled
	endif
	return S_BrowserList
end

static function pixel2cpu(variable pixel, [string win])
	variable expansion = ParamIsDefault(win) ? 1 : PanelResolution(win)/PanelResolution("")
	return (ScreenResolution > 96 ? pixel * 72 / ScreenResolution : pixel) / expansion
end

 

Tony,

I gave this a quick test and found that if the "Data Folder" popup menu is clicked, the Data Browser opens.  After selecting a folder and clicking "Ok", the browsers closes and immediately opens a second time.  Clicking "Ok" a second time the wave is saved in the selected directory.

This is with a couple of directories existing in the root directory.  IP9.03B01 on Win10.

Jeff

Ah, I see.

The intention was to allow either mouse or keyboard input. In testing on mac it worked OK, except that I cannot use tab to cycle through the controls in the panel, so keyboard input doesn't work. In Windows, on the other hand, a mouse click produces both 'hovering' and 'control received keyboard focus' events, resulting in the double-modal-browser behaviour. I've fixed it by ignoring the 'control received keyboard focus' event.

I used a popup control because it provides a visual indication that it should be clicked to select. A button could also be used for the same purpose, it would look a bit like the built-in make waves dialog.

The WaveSelectorWidget and HierarchicalListWidget use a button with a downward-pointing trace marker as the menu indicator, like this: \\JR(no selection) \\W623. The \\W623 is the marker, and \\JR is for right-justification so the marker is at the right edge of the button.

To get the full tab navigation on a Mac, in the Keyboard settings, Shortcuts tab, turn on the All Control radio button under the Full keyboard access title near the bottom. At least on OS 10.14 :)

No more Doppel-browser - it opens only once now.

I was looking into creating the modal browser with the "New Data Folder" button intact (Because I would forget to create a new folder before invoking your function.), but that doesn't seem possible.  Or am I missing something?

I have updated the snippet with a new version that works with free waves. This means that you can provide the user with a free wave and the user saves a copy of the wave with a name/location of their choice in the current experiment. I couldn't find a simple way to allow the user to create a new data folder as part of the dialog.

Forum

Support

Gallery

Igor Pro 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More