
User interface for naming and storing a wave

tony
Mon, 09/04/2023 - 03:23 am
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)
SaveWave#SaveWaveUI(foo)
#pragma rtGlobals=3
#pragma ModuleName=SaveWave
static function/WAVE SaveWaveUI(wave w, [string basename, int overwrite])
basename = SelectString(ParamIsDefault(basename), basename, "wave")
overwrite = ParamIsDefault(overwrite) ? 1 : overwrite // default is to allow user to overwrite a wave
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"
SetWindow SaveWaveDialog Userdata(source) = GetWavesDataFolder(w, 2)
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#SetVarProc
PopupMenu popFolder,pos={25,50},size={157,14},title="Data Folder", fsize=12
PopupMenu popFolder,value=#"GetDataFolder(0)", userdata(folder)=GetDataFolder(1), Proc=SaveWave#PopupProc
// note: value=GetDataFolder(0) sets the value correctly, but on mousedown the selection
// is fleetingly shown as "none" without runtime evaluation.
Button btnCancel,pos={40,100},size={55,20},title="Cancel", Proc=SaveWave#ButtonProc
Button btnDoIt,pos={130,100},size={50,20},title="Do It", Proc=SaveWave#ButtonProc, userdata=num2str(overwrite)
PauseForUser SaveWaveDialog
wave/WAVE w_savewave
wave/Z saved = w_savewave[0]
KillWaves w_savewave
return saved
end
static function PopupProc(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
// trigger setvar to check whether output wave exists in selected folder
STRUCT WMSetVariableAction sv
sv.ctrlName = "svName"
sv.eventCode = 8
ControlInfo/W=$s.win svName
sv.sval = s_value
SetVarProc(sv)
return 0
end
static function ButtonProc(STRUCT WMButtonAction &s) : ButtonControl
if (s.eventcode!=2)
return 0
endif
Make/O/WAVE w_savewave = {$""}
strswitch (s.ctrlName)
case "btnDoIt":
wave source = $GetUserData(s.win, "", "source")
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
Duplicate/O source $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 SetVarProc(STRUCT WMSetVariableAction &s)
if (s.eventCode < 0) // excludes Igor8 eventcodes -2 and -3
return 0
endif
if (cmpstr(s.ctrlName, "svName") == 0)
if (strlen(s.sval) == 0)
s.sval = UniqueName(GetUserData(s.win, s.ctrlName, "base"), 1, 0)
SetVariable $s.ctrlName win=$s.win, value=_STR:s.sval
endif
if (exists(GetSelectedFolder(1) + s.sval))
SetVariable $s.ctrlName win=$s.win, valueBackColor=(0xFFFF,0,0)
else
SetVariable $s.ctrlName win=$s.win, valueBackColor=0
endif
endif
return 0
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
#pragma ModuleName=SaveWave
static function/WAVE SaveWaveUI(wave w, [string basename, int overwrite])
basename = SelectString(ParamIsDefault(basename), basename, "wave")
overwrite = ParamIsDefault(overwrite) ? 1 : overwrite // default is to allow user to overwrite a wave
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"
SetWindow SaveWaveDialog Userdata(source) = GetWavesDataFolder(w, 2)
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#SetVarProc
PopupMenu popFolder,pos={25,50},size={157,14},title="Data Folder", fsize=12
PopupMenu popFolder,value=#"GetDataFolder(0)", userdata(folder)=GetDataFolder(1), Proc=SaveWave#PopupProc
// note: value=GetDataFolder(0) sets the value correctly, but on mousedown the selection
// is fleetingly shown as "none" without runtime evaluation.
Button btnCancel,pos={40,100},size={55,20},title="Cancel", Proc=SaveWave#ButtonProc
Button btnDoIt,pos={130,100},size={50,20},title="Do It", Proc=SaveWave#ButtonProc, userdata=num2str(overwrite)
PauseForUser SaveWaveDialog
wave/WAVE w_savewave
wave/Z saved = w_savewave[0]
KillWaves w_savewave
return saved
end
static function PopupProc(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
// trigger setvar to check whether output wave exists in selected folder
STRUCT WMSetVariableAction sv
sv.ctrlName = "svName"
sv.eventCode = 8
ControlInfo/W=$s.win svName
sv.sval = s_value
SetVarProc(sv)
return 0
end
static function ButtonProc(STRUCT WMButtonAction &s) : ButtonControl
if (s.eventcode!=2)
return 0
endif
Make/O/WAVE w_savewave = {$""}
strswitch (s.ctrlName)
case "btnDoIt":
wave source = $GetUserData(s.win, "", "source")
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
Duplicate/O source $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 SetVarProc(STRUCT WMSetVariableAction &s)
if (s.eventCode < 0) // excludes Igor8 eventcodes -2 and -3
return 0
endif
if (cmpstr(s.ctrlName, "svName") == 0)
if (strlen(s.sval) == 0)
s.sval = UniqueName(GetUserData(s.win, s.ctrlName, "base"), 1, 0)
SetVariable $s.ctrlName win=$s.win, value=_STR:s.sval
endif
if (exists(GetSelectedFolder(1) + s.sval))
SetVariable $s.ctrlName win=$s.win, valueBackColor=(0xFFFF,0,0)
else
SetVariable $s.ctrlName win=$s.win, valueBackColor=0
endif
endif
return 0
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

Forum

Support

Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More
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
September 5, 2023 at 01:52 pm - Permalink
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.
September 6, 2023 at 02:49 am - Permalink
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 :)
September 6, 2023 at 10:51 am - Permalink
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?
September 7, 2023 at 12:11 pm - Permalink