
HDF5 Browser

coltblaze
this is what I have stumbled upon when I was exploring into my automation problems regarding the HDF5 files
#pragma rtGlobals=1 // Use modern global access method. // The routines in this file implement the HDF5 Browser control panel. // Version 1.00, May 9, 2005: Initial release. // Version 1.01, May 10, 2005: Revamped preferences code. // Version 1.02, May 14, 2005: Revamped preferences code again using // the LoadPackagePrefs and SavePackagePrefs operations. This requires // Igor Pro 5.04B07 or later. // Version 1.03, January 15, 2010: Now uses HDF5ListGroup/R=2 to deal with // files that use hard or soft links to include the same group more than one time. // This version of this procedure file requires HDF5XOP 1.09 or later. // Version 1.04, May 21, 2015: Defines HDF5 library constants such as // H5T_ORDER_LE and H5T_ORDER_BE. This version of this procedure file requires // HDF5XOP 1.14 or earlier. #pragma version = 1.04 #include <WaveSelectorWidget> #pragma moduleName=HDF5Browser Menu "Load Waves" "New HDF5 Browser", /Q, CreateNewHDF5Browser() End Constant H5S_MAX_RANK = 32 // Constants for HDF5DataInfo datatype_order field and HDF5DatatypeInfo order field Constant H5T_ORDER_ERROR = -1 // Error Constant H5T_ORDER_LE = 0 // Little endian Constant H5T_ORDER_BE = 1 // Big endian Constant H5T_ORDER_VAX = 2 // VAX mixed endian // The following is valid only with HDF5 library 1.8.5 or before because this value was changed in 1.8.6. #if (Exists("HDF5LibraryInfo") == 3) // This is just to create a compile error if you are running with a newer HDF5 XOP // and therefore should be using a new "HDF5 Browser.ipf" file. #define *** You are using a newer HDF5 XOP which uses a newer HDF5 library. You need a newer "HDF5 Browser.ipf" file - version 1.20 or later. *** #endif Constant H5T_ORDER_NONE = 3 // No particular order (strings, bits,..) // Constants for HDF5DataInfo datatype_sign field and HDF5DatatypeInfo sign field Constant H5T_SGN_ERROR = -1 // Error Constant H5T_SGN_NONE = 0 // Unsigned Constant H5T_SGN_2 = 1 // Two's complement // Constants for HDF5DataInfo datatype_class field and HDF5DatatypeInfo type_class field Constant H5T_NO_CLASS = -1 // Error Constant H5T_INTEGER = 0 // Integer types Constant H5T_FLOAT = 1 // Floating-point types Constant H5T_TIME = 2 // Date and time types Constant H5T_STRING = 3 // Character string types Constant H5T_BITFIELD = 4 // Bit field types Constant H5T_OPAQUE = 5 // Opaque types Constant H5T_COMPOUND = 6 // Compound types Constant H5T_REFERENCE = 7 // Reference types Constant H5T_ENUM = 8 // Enumeration types Constant H5T_VLEN = 9 // Variable-Length types Constant H5T_ARRAY = 10 // Array types // Constants for HDF5DataInfo dataspace_type field Constant H5S_NO_CLASS = -1 // Error Constant H5S_SCALAR = 0 // Scalar variable Constant H5S_SIMPLE = 1 // Constant simple data space Constant H5S_NULL = 2 // Constant null data space // Constants for HDF5DatatypeInfo strpad field Constant H5T_STR_ERROR = -1 // Error Constant H5T_STR_NULLTERM = 0 // Null terminate like in C Constant H5T_STR_NULLPAD = 1 // Ppad with nulls Constant H5T_STR_SPACEPAD = 2 // Pad with spaces like in Fortran // Constants for HDF5DatatypeInfo cset field Constant H5T_CSET_ERROR = -1 // Error Constant H5T_CSET_ASCII = 0 // US ASCII Constant H5T_CSET_UTF8 = 1 // UTF-8 Unicode encoding Structure HDF5BrowserData SVAR browserName Wave/T groupsList Wave/T groupAttributesList Wave/T datasetsList Wave/T datasetAttributesList Wave/T groupFullPaths SVAR groupPath SVAR hyperSelectionWavePath NVAR fileID SVAR fileName SVAR path SVAR fullPath NVAR readOnly SVAR datasetInfo // Panel readout info for currently-selected dataset EndStructure static Function CreateHDF5BrowserGlobals(newBrowserName) String newBrowserName // Create globals that apply to this browser window. String savedDataFolder = SetBrowserDataFolder(newBrowserName) String/G browserName = newBrowserName Make/O/T/N=0 groupsList Make/O/T/N=0 groupAttributesList Make/O/T/N=0 datasetsList Make/O/T/N=0 datasetAttributesList Make/O/T/N=0 groupFullPaths // For each group, contains the corresponding full path to that group. String/G groupPath = "/" // Path to currently selected group String/G hyperSelectionWavePath // Path to hyperselection wave, if any. Variable/G fileID = 0 // 0 means no file is open for this browser. String/G fileName = "" String/G path = "" String/G fullPath = "" Variable/G readOnly = 1 String/G datasetInfo SetDataFolder savedDataFolder End Function/S SetBrowserDataFolder(browserName) // Pass "" for browserName to set to master browser folder. String browserName String savedDataFolder = GetDataFolder(1) NewDataFolder/O/S root:Packages NewDataFolder/O/S HDF5Browser if (strlen(browserName) > 0) NewDataFolder/O/S $browserName endif return savedDataFolder End static Function SetHDF5BrowserData(browserName, bd) String browserName STRUCT HDF5BrowserData &bd String savedDataFolder = SetBrowserDataFolder(browserName) // These statements set the structure fields to reference the corresponding waves and variables in the data folder. SVAR bd.browserName Wave/T bd.groupsList Wave/T bd.groupAttributesList Wave/T bd.datasetsList Wave/T bd.datasetAttributesList Wave/T bd.groupFullPaths SVAR bd.groupPath SVAR bd.hyperSelectionWavePath NVAR bd.fileID SVAR bd.fileName SVAR bd.path SVAR bd.fullPath NVAR bd.readOnly SVAR bd.datasetInfo SetDataFolder savedDataFolder End static Function CountSlashes(item) String item Variable slashes = 0 Variable pos = 0 do pos = strsearch(item, "/", pos) if (pos < 0) break endif slashes += 1 pos += 1 while (1) return slashes End Function/S GetGroupHierarchy(fileID, startPath, level, mode) Variable fileID String startPath Variable level Variable mode // 0 to just get group names; 1 to get full path to each group. String result = "" String indent = "" // Used only for mode 0. Variable i, j // This gives full hierarchy with full paths // The /R=2 flag requires HDF5 1.09 or later. If you get an error here, you need to activate a more recent version of HDF5XOP. HDF5ListGroup /F /R=2 /TYPE=1 fileID, startPath // REQUIRES HDF5XOP 1.09 or later result = S_HDF5ListGroup if (mode == 0) // Want just names, not full paths result = "" Variable numItems = ItemsInList(S_HDF5ListGroup) for(i=0; i<numItems; i+=1) String item = StringFromList(i, S_HDF5ListGroup) level = CountSlashes(item) indent = "" for(j=0; j<level; j+=1) indent += " " endfor item = ParseFilePath(0, item, "/", 1, 0) // Get last element item = indent + item // Prepend indentation result += item + ";" endfor endif return result End static Function/S GetFileHierarchy(bd, mode) STRUCT HDF5BrowserData &bd Variable mode // 0 to just get group names; 1 to get full path to each group. if (bd.fileID == 0) // No file is open? return "" endif String hierarchy, rootName if (mode == 1) rootName = "/" // For purposes of storing full path, use true root name else rootName = "root" // For display purposes, use "root" as root name endif hierarchy = rootName + ";" + GetGroupHierarchy(bd.fileID, "/", 1, mode) return hierarchy End static Function ResetListSelections(bd, resetGroupsList, resetGroupAttributesList, resetDatasetsList, resetDatasetAttributesList) STRUCT HDF5BrowserData &bd Variable resetGroupsList, resetGroupAttributesList, resetDatasetsList, resetDatasetAttributesList if (resetGroupsList) ListBox GroupsList, win=$bd.browserName, selRow=0 endif if (resetGroupAttributesList) ListBox GroupAttributesList, win=$bd.browserName, selRow=0 endif if (resetDatasetsList) ListBox DatasetsList, win=$bd.browserName, selRow=0 endif if (resetDatasetAttributesList) ListBox DatasetAttributesList, win=$bd.browserName, selRow=0 endif End Function/S HDF5GetObjectFullPath(groupPath, objectName) String groupPath // Path to parent group String objectName // Name of dataset or group in parent group String fullPath if (CmpStr(groupPath, "/") == 0) fullPath = "/" + objectName else fullPath = groupPath + "/" + objectName endif return fullPath End Function/S GetTextPreviewString(tw) Wave/T tw // tw has already been flattened to 1D. String preview, temp Variable len Variable row, numRows, totalLength totalLength = 0 numRows = numpnts(tw) if (numRows == 0) return "" endif preview = "" row = 0 do temp = tw[row] temp = ReplaceString("\r", temp, "<CR>", 1) // Convert CR to "\r" temp = ReplaceString("\n", temp, "<LF>", 1) // Convert LF to "\n" len = strlen(temp) if (len > 128) if (numRows == 1) sprintf preview, "\"%s\" . . . (%d characters total)", temp[0,127], len else preview += " . . . <Strings too long to display here>" endif row = numRows // To prevent extra . . . break endif preview += "\"" + temp + "\"" row += 1 totalLength += len if (row >= numRows) break endif if (totalLength >= 256) // Enough is enough break endif preview += ", " while(1) if (row < numRows) preview += " . . ." endif return preview End Function/S GetNumericPreviewString(w) Wave w // w has already been flattened to 1D. String preview, temp Variable row, numRows, totalLength totalLength = 0 numRows = numpnts(w) if (numRows == 0) return "" endif preview = "" row = 0 do sprintf temp, "%g", w[row] preview += temp row += 1 totalLength += strlen(temp) if (row >= numRows) break endif if (totalLength >= 256) // Enough is enough break endif preview += ", " while(1) if (row < numRows) preview += " . . ." endif return preview End Function/S GetPreviewString(locationID, objectType, di, fullPath, attributeName) Variable locationID Variable objectType // 1 = group, 2 = dataset STRUCT HDF5DataInfo &di String fullPath // Full path to group or dataset String attributeName // "" if this is a dataset, not an attribute String value = "<Can't display here>" String temp Variable rank = di.ndims Variable dim, numElements if (rank == 0) numElements = 1 else numElements = di.dims[0] for(dim=1; dim<rank; dim+=1) numElements *= di.dims[dim] endfor endif strswitch(di.datatype_class_str) case "H5T_INTEGER": case "H5T_FLOAT": case "H5T_ENUM": case "H5T_OPAQUE": case "H5T_BITFIELD": if (numElements > 100) value = "<Too big to display here>"// It would take too long to load. break endif HDF5LoadData /A=attributeName /N=tempNumericAttributeWave /O /Q /TYPE=(objectType) /VAR=0 /Z locationID, fullPath if (V_flag != 0) value = "ERROR!" else Wave tempNumericAttributeWave if (rank > 1) // So we can treat multi-dimensional wave as one big row. Redimension/N=(numElements)/E=1 tempNumericAttributeWave endif value = GetNumericPreviewString(tempNumericAttributeWave) endif KillWaves/Z tempNumericAttributeWave break case "H5T_REFERENCE": if (numElements > 10) value = "<Too big to display here>" // It would take too long to load. break endif HDF5LoadData /A=attributeName /N=tempTextAttributeWave /O /Q /TYPE=(objectType) /VAR=0 /Z locationID, fullPath if (V_flag != 0) value = "ERROR!" else if (rank > 1) // So we can treat multi-dimensional wave as one big row. Redimension/N=(numElements)/E=1 tempTextAttributeWave endif // Remove the prefix (e.g., "D:" for a dataset, which is there for // programmatic use but would confuse in a preview. Wave/T references = tempTextAttributeWave // Created by HDF5LoadData String tmp Variable npnts=numpnts(references), len Variable i for(i=0; i<npnts; i+=1) tmp = references[i] len = strlen(tmp) references[i] = tmp[2,len] endfor value = GetTextPreviewString(references) endif KillWaves/Z tempTextAttributeWave break case "H5T_STRING": if (numElements > 100) value = "<Too big to display here>" // It would take too long to load. break endif HDF5LoadData /A=attributeName /N=tempTextAttributeWave /O /Q /TYPE=(objectType) /VAR=0 /Z locationID, fullPath if (V_flag != 0) value = "ERROR!" else if (rank > 1) // So we can treat multi-dimensional wave as one big row. Redimension/N=(numElements)/E=1 tempTextAttributeWave endif value = GetTextPreviewString(tempTextAttributeWave) endif KillWaves/Z tempTextAttributeWave break case "H5T_TIME": case "H5T_COMPOUND": case "H5T_VLEN": case "H5T_ARRAY": value = "<Can't display this type here>" break endswitch return value End static Function FillDatasetsList(bd) STRUCT HDF5BrowserData &bd HDF5ListGroup /TYPE=2 bd.fileID, bd.groupPath Variable numItemsInList = ItemsInList(S_HDF5ListGroup) if (numItemsInList == 0) Redimension/N=0 bd.datasetsList else Redimension/N=(numItemsInList, 5) bd.datasetsList SetDimLabel 1, 0, Dataset, bd.datasetsList SetDimLabel 1, 1, Rank, bd.datasetsList SetDimLabel 1, 2, 'Dim Sizes', bd.datasetsList SetDimLabel 1, 3, Type, bd.datasetsList SetDimLabel 1, 4, Value, bd.datasetsList bd.datasetsList[][0] = StringFromList(p, S_HDF5ListGroup) String dataset Variable i, numDatasets numDatasets = ItemsInList(S_HDF5ListGroup) for(i=0; i<numDatasets; i+=1) dataset = StringFromList(i, S_HDF5ListGroup) String fullPath = HDF5GetObjectFullPath(bd.groupPath, dataset) STRUCT HDF5DataInfo di InitHDF5DataInfo(di) // Set input fields. HDF5DatasetInfo(bd.fileID, fullPath, 0, di) Variable rank = di.ndims bd.datasetsList[i][1] = num2istr(rank) String dimsStr="" Variable dim for(dim=0; dim<rank; dim+=1) dimsStr += num2istr(di.dims[dim]) + ";" endfor bd.datasetsList[i][2] = dimsStr bd.datasetsList[i][3] = di.datatype_str String preview = GetPreviewString(bd.fileID, 2, di, fullPath, "") bd.datasetsList[i][4] = preview endfor endif End static Function FillGroupAttributesList(bd) STRUCT HDF5BrowserData &bd Variable numAttributes = 0 String groupPath = bd.groupPath if (strlen(groupPath) > 0) HDF5ListAttributes/TYPE=1 bd.fileID, groupPath numAttributes = ItemsInList(S_HDF5ListAttributes) endif if (numAttributes == 0) Redimension/N=0 bd.groupAttributesList else Redimension/N=(numAttributes, 5) bd.groupAttributesList SetDimLabel 1, 0, Attribute,bd.groupAttributesList SetDimLabel 1, 1, Rank,bd.groupAttributesList SetDimLabel 1, 2, 'Dim Sizes',bd.groupAttributesList SetDimLabel 1, 3, Type,bd.groupAttributesList SetDimLabel 1, 4, Value,bd.groupAttributesList bd.groupAttributesList[][0] = StringFromList(p, S_HDF5ListAttributes) String attribute Variable i for(i=0; i<numAttributes; i+=1) String attributeName attributeName = StringFromList(i, S_HDF5ListAttributes) attribute = attributeName STRUCT HDF5DataInfo di InitHDF5DataInfo(di) // Set input fields. HDF5AttributeInfo(bd.fileID, groupPath, 1, attribute, 0, di) Variable rank = di.ndims bd.groupAttributesList[i][1] = num2istr(rank) String dimsStr="" Variable dim for(dim=0; dim<rank; dim+=1) dimsStr += num2istr(di.dims[dim]) + ";" endfor bd.groupAttributesList[i][2] = dimsStr bd.groupAttributesList[i][3] = di.datatype_str String preview = GetPreviewString(bd.fileID, 1, di, groupPath, attributeName) bd.groupAttributesList[i][4] = preview endfor endif End static Function FillDatasetAttributesList(bd) STRUCT HDF5BrowserData &bd Variable numAttributes = 0 String datasetPath = SelectedDatasetPath(bd) if (strlen(datasetPath) > 0) HDF5ListAttributes/TYPE=2 bd.fileID, datasetPath numAttributes = ItemsInList(S_HDF5ListAttributes) endif if (numAttributes == 0) Redimension/N=0 bd.datasetAttributesList else Redimension/N=(numAttributes, 5) bd.datasetAttributesList SetDimLabel 1, 0, Attribute,bd.datasetAttributesList SetDimLabel 1, 1, Rank,bd.datasetAttributesList SetDimLabel 1, 2, 'Dim Sizes',bd.datasetAttributesList SetDimLabel 1, 3, Type,bd.datasetAttributesList SetDimLabel 1, 4, Value,bd.datasetAttributesList bd.datasetAttributesList[][0] = StringFromList(p, S_HDF5ListAttributes) String attribute Variable i for(i=0; i<numAttributes; i+=1) String attributeName attributeName = StringFromList(i, S_HDF5ListAttributes) attribute = attributeName STRUCT HDF5DataInfo di InitHDF5DataInfo(di) // Set input fields. HDF5AttributeInfo(bd.fileID, datasetPath, 2, attribute, 0, di) Variable rank = di.ndims bd.datasetAttributesList[i][1] = num2istr(rank) String dimsStr="" Variable dim for(dim=0; dim<rank; dim+=1) dimsStr += num2istr(di.dims[dim]) + ";" endfor bd.datasetAttributesList[i][2] = dimsStr bd.datasetAttributesList[i][3] = di.datatype_str String preview = GetPreviewString(bd.fileID, 2, di, datasetPath, attributeName) bd.datasetAttributesList[i][4] = preview endfor endif End static Function FillLists(bd) STRUCT HDF5BrowserData &bd if (bd.fileID == 0) // No file is open? Redimension/N=(0) bd.groupsList Redimension/N=(0) bd.groupAttributesList Redimension/N=(0) bd.datasetsList Redimension/N=(0) bd.datasetAttributesList return -1 endif Variable numItemsInList String hierarchy // Show entire hierarchy in Groups list. hierarchy = GetFileHierarchy(bd, 0) numItemsInList = ItemsInList(hierarchy) Redimension/N=(numItemsInList) bd.groupsList bd.groupsList = StringFromList(p, hierarchy) // The groupFullPaths wave stores the full path to each group hierarchy = GetFileHierarchy(bd, 1) numItemsInList = ItemsInList(hierarchy) Redimension/N=(numItemsInList) bd.groupFullPaths bd.groupFullPaths = StringFromList(p, hierarchy) // Show datasets in current group in Datasets list. FillDatasetsList(bd) // Show attributes of currently-selected group. FillGroupAttributesList(bd) // Show attributes of currently-selected dataset. FillDatasetAttributesList(bd) End Function/S SelectedGroupName(bd) STRUCT HDF5BrowserData &bd if (numpnts(bd.groupsList) == 0) return "" endif ControlInfo/W=$bd.browserName GroupsList Variable selRow = V_value String groupName = bd.groupsList[selRow] // Group names may have leading spaces at this point. The spaces are used to create // indentation in the list to show the hierarchy. We must remove the leading spaces. sscanf groupName, " %s", groupName if (strlen(groupName) > 0) return groupName endif return "" End Function/S SelectedGroupPath(bd) STRUCT HDF5BrowserData &bd String groupPath = bd.groupPath return groupPath End Function/S SelectedDatasetName(bd) STRUCT HDF5BrowserData &bd if (numpnts(bd.datasetsList) == 0) return "" endif ControlInfo/W=$bd.browserName DatasetsList Variable selRow = V_value String datasetName = bd.datasetsList[selRow][0] if (strlen(datasetName) > 0) return datasetName endif return "" End Function/S SelectedDatasetPath(bd) STRUCT HDF5BrowserData &bd String datasetName = SelectedDatasetName(bd) if (strlen(datasetName) == 0) return "" // Nothing is selected endif String datasetPath = bd.groupPath if (CmpStr(datasetPath[strlen(datasetPath)-1],"/") != 0) datasetPath += "/" endif datasetPath += datasetName return datasetPath End Function/S SelectedAttributeName(bd, isGroupAttribute) STRUCT HDF5BrowserData &bd Variable isGroupAttribute String controlName if (isGroupAttribute) controlName = "GroupAttributesList" Wave/T list = bd.groupAttributesList else controlName = "DatasetAttributesList" Wave/T list = bd.datasetAttributesList endif if (numpnts(list) == 0) return "" endif ControlInfo/W=$bd.browserName $controlName Variable selRow = V_value String attributeName = list[selRow][0] if (strlen(attributeName) > 0) return attributeName endif return "" End Function/S SelectedAttributePath(bd, isGroupAttribute) STRUCT HDF5BrowserData &bd Variable isGroupAttribute String attributeName = SelectedAttributeName(bd, isGroupAttribute) if (strlen(attributeName) == 0) return "" // Nothing is selected endif String path if (isGroupAttribute) path = SelectedGroupPath(bd) else path = SelectedDatasetPath(bd) endif path += "/" + attributeName return path End StrConstant kLoadAllMembersString = "_Load_All_Members_" static Function SetMembersPopupMenu(bd) STRUCT HDF5BrowserData &bd Variable hideMembers String memberList hideMembers = 1 memberList = kLoadAllMembersString + ";" if (bd.fileID != 0) // File is open for this browser? String fullPath fullPath = SelectedDatasetPath(bd) if (strlen(fullPath) > 0) STRUCT HDF5DataInfo di InitHDF5DataInfo(di) HDF5DatasetInfo(bd.fileID, fullPath, 0, di) if (CmpStr(di.datatype_class_str, "H5T_COMPOUND") == 0) hideMembers = 0 ControlInfo /W=$bd.browserName Members Variable selectedItemNumber = V_Value STRUCT HDF5DatatypeInfo dti InitHDF5DatatypeInfo(dti) if (HDF5TypeInfo(bd.fileID, fullPath, "", "", 1, dti)) memberList += "HDF5TypeInfo Error!" else memberList += dti.names if (selectedItemNumber > dti.nmembers+1) // +1 because of "_Load_All_Members_" item. selectedItemNumber = 1 // Force menu selection to be in bounds. endif endif PopupMenu Members, win=$bd.browserName, mode=selectedItemNumber endif endif endif PopupMenu Members, win=$bd.browserName, disable=hideMembers String cmd // What a pain. Can't use local variable with PopupMenu value= sprintf cmd, "PopupMenu Members, win=%s, value=\"%s\"", bd.browserName, memberList Execute cmd End Function HDF5GetReadOnlySetting(browserName) String browserName Variable result ControlInfo /W=$browserName ReadOnly result = V_value return result End Function HDF5GetCompLoadInfo(bd, isCompound, compMode, memberName) STRUCT HDF5BrowserData &bd Variable &isCompound // Output: If non-zero, a compound dataset is selected. Variable &compMode // Output: Value suitable for passing to HDF5LoadData /COMP flag. String &memberName // Output: If "" load all members. isCompound = 0 memberName = "" ControlInfo /W=$bd.browserName Members if (V_disable == 0) isCompound = 1 memberName = S_value if (CmpStr(memberName, kLoadAllMembersString) == 0) memberName = "" endif endif compMode = isCompound && strlen(memberName)>0 End Function HDF5GetTranspose2DSetting(browserName) String browserName Variable result ControlInfo /W=$browserName Transpose2DDatasets result = V_value return result End static Function HDF5GetLoadDatasetOptions(browserName, tableDisplayMode, graphDisplayMode) String browserName Variable &tableDisplayMode, &graphDisplayMode ControlInfo /W=$browserName DisplayInTable tableDisplayMode = V_value - 1 // 0=no; 1=display; 2=append ControlInfo /W=$browserName DisplayInGraph graphDisplayMode = V_value - 1 // 0=no; 1=display; 2=append return tableDisplayMode || graphDisplayMode End static Function MembersPopupProc(ctrlName,popNum,popStr) : PopupMenuControl String ctrlName Variable popNum String popStr String browserName = HDF5GetTopBrowserName() STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) HDF5DisplaySelectedDataset(bd) End static Function SetButtonStates(bd) STRUCT HDF5BrowserData &bd if (bd.fileID == 0) // No file is open for this browser? Button CreateFile, win=$bd.browserName, disable=0 // Enable Create Button OpenFile, win=$bd.browserName, disable=0 // Enable Open Button CloseFile, win=$bd.browserName, disable=2 // Disable Close Button LoadGroup, win=$bd.browserName, disable=2 // Disable Load Group Button SaveDataFolder, win=$bd.browserName, disable=2 // Disable Save Data Folder Button LoadDataset, win=$bd.browserName, disable=2 // Disable Load Dataset Button SaveWaves, win=$bd.browserName, disable=2 // Disable Save Waves else Button CreateFile, win=$bd.browserName, disable=2 // Disable Create Button OpenFile, win=$bd.browserName, disable=2 // Disable Open Button CloseFile, win=$bd.browserName, disable=0 // Enable Close String groupName = SelectedGroupName(bd) Variable code = strlen(groupName) > 0 ? 0:2 Button LoadGroup, win=$bd.browserName, disable=code // Enable Load Group code = bd.readOnly == 0 ? 0:2 Button SaveDataFolder, win=$bd.browserName, disable=code // Enable Save Data Folder String datasetName = SelectedDatasetName(bd) code = strlen(datasetName) > 0 ? 0:2 Button LoadDataset, win=$bd.browserName, disable=code // Enable Load Dataset code = bd.readOnly == 0 ? 0:2 Button SaveWaves, win=$bd.browserName, disable=code // Enable Save Waves endif SetMembersPopupMenu(bd) SetGraphButtonTitle(bd.browserName) SetTableButtonTitle(bd.browserName) SetDumpButtonTitle(bd.browserName) SetVariable HyperSelectionWave, win=$bd.browserName, value= bd.hyperSelectionWavePath End static Function DrawFilePath(bd) STRUCT HDF5BrowserData &bd // TitleBox FilePath, win=$bd.browserName, title=bd.fullPath // This is limited to 63 characters. TitleBox FilePath, win=$bd.browserName, variable=bd.fullPath End static Function DrawGroupPath(bd) STRUCT HDF5BrowserData &bd TitleBox GroupPath, win=$bd.browserName, variable=bd.groupPath End static Function DrawDatasetInfo(bd) STRUCT HDF5BrowserData &bd TitleBox Dataset, win=$bd.browserName, variable=bd.datasetInfo End static Function UpdateAfterFileCreateOrOpen(isCreate, browserName, fileID, path, fileName) Variable isCreate String browserName Variable fileID String path, fileName STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) ResetListSelections(bd, 1, 1, 1, 1) bd.fileID = fileID bd.fileName = fileName bd.path = path bd.fullPath = path + fileName DrawFilePath(bd) bd.readOnly = isCreate ? 0 : HDF5GetReadOnlySetting(browserName) bd.groupPath = "/" DrawGroupPath(bd) SetButtonStates(bd) FillLists(bd) UpdateAfterGroupSelected(bd, "/") String datasetName = SelectedDatasetName(bd) if (strlen(datasetName) > 0) SelectDataset(bd, datasetName) endif End static Function CreateFileButtonProc(ctrlName) : ButtonControl String ctrlName String browserName = HDF5GetTopBrowserName() STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) Variable fileID HDF5CreateFile /I /O fileID as "" if (V_flag == 0) // Create OK? UpdateAfterFileCreateOrOpen(1, browserName, fileID, S_path, S_fileName) endif End static Function OpenFileButtonProc(ctrlName) : ButtonControl String ctrlName String browserName = HDF5GetTopBrowserName() Variable readOnly = HDF5GetReadOnlySetting(browserName) Variable locFileID if (readOnly) HDF5OpenFile/R locFileID as "" else HDF5OpenFile locFileID as "" endif if (V_flag == 0) // Open OK? UpdateAfterFileCreateOrOpen(0, browserName, locFileID, S_path, S_fileName) endif End // This detects if the file is no longer open, such as if you save the experiment, quit Igor and then reopen the experiment. Function FileWasUnexpectedlyClosed(bd) STRUCT HDF5BrowserData &bd if (bd.fileID == 0) return 0 // File is closed but not unexpectedly. endif HDF5ListAttributes/Q /TYPE=1 /Z bd.fileID , "/" // Try to list the attributes of the root of the file. if (V_flag != 0) return 1 // Error: Assume file was closed. endif return 0 End static Function FileWasClosed(bd) // Does cleanup after a file is closed. STRUCT HDF5BrowserData &bd bd.fileID = 0 Redimension/N=(0) bd.groupFullPaths bd.groupPath = "" bd.fileName = "" bd.path = "" bd.fullPath = "" bd.datasetInfo = "" DrawFilePath(bd) SetButtonStates(bd) FillLists(bd) End static Function CloseFileButtonProc(ctrlName) : ButtonControl String ctrlName String browserName = HDF5GetTopBrowserName() STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) HDF5CloseFile bd.fileID CloseSavePanels() FileWasClosed(bd) End static Function LoadDatasetButtonProc(ctrlName) : ButtonControl String ctrlName String browserName = HDF5GetTopBrowserName() STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) String datasetPath = SelectedDatasetPath(bd) String slabWaveStr = "" ControlInfo /W=$bd.browserName UseHyperSelection if (V_value) // Use Hyperselection is checked? slabWaveStr = bd.hyperSelectionWavePath endif WAVE/Z slabWave = $slabWaveStr // It is OK if wave does not exist and slabWave is NULL. HDF5LoadData will simply ignore /SLAB. Variable isCompound String memberName Variable compMode HDF5GetCompLoadInfo(bd, isCompound, compMode, memberName) // If isFormalImage is true, we are loading an image written // according to the HDF5 Image and Palette Specification. Variable isFormalImage = 0 if (!isCompound) String savedDataFolder = SetBrowserDataFolder("") // tempClassAttribute goes in master HDF5Browser data folder HDF5LoadData /Z /O /N=tempClassAttribute /A="CLASS" /Q /VAR=1 bd.fileID, datasetPath if (V_flag == 0) WAVE/T tempClassAttribute // HDF5LoadData will have created this string if (CmpStr(tempClassAttribute[0],"IMAGE") == 0) isFormalImage = 1 endif KillWaves/Z tempClassAttribute endif SetDataFolder savedDataFolder endif Variable tableDisplayMode, graphDisplayMode // 0=no; 1=display; 2=append HDF5GetLoadDatasetOptions(bd.browserName, tableDisplayMode, graphDisplayMode) if (isFormalImage) HDF5LoadImage /O /GRPH=(graphDisplayMode) /T=(tableDisplayMode) bd.fileID, datasetPath else Variable transpose2D = HDF5GetTranspose2DSetting(bd.browserName) HDF5LoadData /O /SLAB=slabWave /TRAN=(transpose2D) /COMP={compMode,memberName} /GRPH=(graphDisplayMode) /T=(tableDisplayMode) bd.fileID, datasetPath endif End static Function LoadGroupButtonProc(ctrlName) : ButtonControl String ctrlName String browserName = HDF5GetTopBrowserName() STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) String groupPath = SelectedGroupPath(bd) ControlInfo /W=$bd.browserName LoadGroupsRecursively if (V_value) // Use LoadGroupsRecursively is checked? HDF5LoadGroup /O /R /T /IMAG=1 :, bd.fileID, groupPath else HDF5LoadGroup /O /T /IMAG=1 :, bd.fileID, groupPath endif // For debugging Variable numItems Variable debug = 1 if (debug) Wave/Z/T groupPaths = root:groupPaths if (WaveExists(groupPaths)) numItems = ItemsInList(S_groupPaths) Redimension/N=(numItems) groupPaths groupPaths = StringFromList(p, S_groupPaths) endif Wave/Z/T dataFolderPaths = root:dataFolderPaths if (WaveExists(dataFolderPaths)) numItems = ItemsInList(S_dataFolderPaths) Redimension/N=(numItems) dataFolderPaths dataFolderPaths = StringFromList(p, S_dataFolderPaths) endif Wave/Z/T wavePaths = root:wavePaths if (WaveExists(wavePaths)) numItems = ItemsInList(S_objectPaths) Redimension/N=(numItems) wavePaths wavePaths = StringFromList(p, S_objectPaths) endif endif End Function AttachListWaves(bd) STRUCT HDF5BrowserData &bd ListBox GroupsList win=$bd.browserName, listWave=bd.groupsList ListBox GroupAttributesList win=$bd.browserName, listWave=bd.groupAttributesList ListBox DatasetsList win=$bd.browserName, listWave=bd.datasetsList ListBox DatasetAttributesList win=$bd.browserName, listWave=bd.datasetAttributesList End Function HDF5BrowserPanelHook(infoStr) String infoStr String browserName= StringByKey("WINDOW",infoStr) String event= StringByKey("EVENT",infoStr) STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) strswitch(event) case "activate": // We do not get this on Windows when the panel is first created. // This detects if the file is no longer open, such as if you save the experiment, quit Igor and then reopen the experiment. if (FileWasUnexpectedlyClosed(bd)) Printf "The file \"%s\" is no longer open.\r", bd.fileName FileWasClosed(bd) endif SetGraphButtonTitle(browserName) SetTableButtonTitle(browserName) SetDumpButtonTitle(browserName) break case "resize": HDF5ResizeBrowser(browserName) break case "moved": // This message was added in Igor Pro 5.04B07. // If this is the last HDF5 browser, save the browser window size and position. if (strlen(HDF5GetIndexedBrowserName(1)) == 0) SetPrefWindowCoords(browserName) endif break case "kill": if (bd.fileID != 0) HDF5CloseFile bd.fileID bd.fileID = 0 CloseSavePanels() endif KillDataFolder root:Packages:HDF5Browser:$browserName break endswitch return 0 End Function SelectDataset(bd, datasetName) STRUCT HDF5BrowserData &bd String datasetName String info if (strlen(datasetName) == 0) info = "" else String fullPath fullPath = HDF5GetObjectFullPath(bd.groupPath, datasetName) STRUCT HDF5DataInfo di InitHDF5DataInfo(di) // Set input fields. HDF5DatasetInfo(bd.fileID, fullPath, 0, di) // Print s sprintf info, "%s, class=%s", datasetName, di.datatype_class_str endif bd.datasetInfo = info DrawDatasetInfo(bd) SetButtonStates(bd) FillDatasetAttributesList(bd) End Function UpdateAfterGroupSelected(bd, fullGroupPath) STRUCT HDF5BrowserData &bd String fullGroupPath Variable selectedGroupChanged = CmpStr(bd.groupPath, fullGroupPath) != 0 bd.groupPath = fullGroupPath DrawGroupPath(bd) FillGroupAttributesList(bd) FillDatasetsList(bd) if (selectedGroupChanged) ResetListSelections(bd, 0, 1, 1, 1) String datasetName = "" if (numpnts(bd.datasetsList) > 0) datasetName = bd.datasetsList[0][0] endif SelectDataset(bd, datasetName) endif SetButtonStates(bd) End static Function GroupsListActionProc(s, bd) : ListboxControl STRUCT WMListboxAction &s STRUCT HDF5BrowserData &bd String browserName = s.win Variable result = 0 // As of now, the return value must always be zero. switch(s.eventCode) case 4: // Cell selection String fullGroupPath = bd.groupFullPaths[s.row] UpdateAfterGroupSelected(bd, fullGroupPath) // Printf "Row=%d, column=%d, path=%s\r", s.row, s.col, fullGroupPath if (HDF5BrowserDumpIsVisible()) HDF5DisplayDumpOfSelectedGroup(bd) endif break endswitch return result End static Function GroupAttributesListActionProc(s, bd) : ListboxControl STRUCT WMListboxAction &s STRUCT HDF5BrowserData &bd String browserName = s.win Variable result = 0 // As of now, the return value must always be zero. switch(s.eventCode) case 3: // Double-click break; case 4: // Cell selection // Printf "Row=%d, column=%d\r", s.row, s.col HDF5DisplaySelectedAttribute(bd, 1) // Update various windows if they are displayed break endswitch return result End Function HandleDatasetDoubleClick(s, bd) STRUCT WMListboxAction &s STRUCT HDF5BrowserData &bd String datasetPath = SelectedDatasetPath(bd) if (strlen(datasetPath) == 0) return -1 endif STRUCT HDF5DataInfo di InitHDF5DataInfo(di) HDF5DatasetInfo(bd.fileID, datasetPath, 0, di) switch(di.datatype_class) default: // Load dataset here. break endswitch End static Function DatasetsListActionProc(s, bd) : ListboxControl STRUCT WMListboxAction &s STRUCT HDF5BrowserData &bd String browserName = s.win Variable result = 0 // As of now, the return value must always be zero. switch(s.eventCode) case 3: // Double-click HandleDatasetDoubleClick(s, bd) break; case 4: // Cell selection String name = bd.datasetsList[s.row][0] SelectDataset(bd, name) // Printf "Row=%d, column=%d, name=%s\r", s.row, s.col, name HDF5DisplaySelectedDataset(bd) // Update various windows if they are displayed break endswitch return result End static Function DatasetAttributesListActionProc(s, bd) : ListboxControl STRUCT WMListboxAction &s STRUCT HDF5BrowserData &bd String browserName = s.win Variable result = 0 // As of now, the return value must always be zero. switch(s.eventCode) case 3: // Double-click break; case 4: // Cell selection // Printf "Row=%d, column=%d\r", s.row, s.col HDF5DisplaySelectedAttribute(bd, 0) // Update various windows if they are displayed break endswitch return result End static Function ListBoxActionProc(s) : ListboxControl STRUCT WMListboxAction &s String browserName = s.win STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) Variable result = 0 // As of now, the return value must always be zero. strswitch(s.ctrlName) case "GroupsList": result = GroupsListActionProc(s, bd) break case "GroupAttributesList": result = GroupAttributesListActionProc(s, bd) break case "DatasetsList": result = DatasetsListActionProc(s, bd) break case "DatasetAttributesList": result = DatasetAttributesListActionProc(s, bd) break endswitch return result End static Function SetGraphButtonTitle(browserName) String browserName if (HDF5BrowserGraphIsVisible()) Button Graph, win=$browserName, title="Hide Graph" else Button Graph, win=$browserName, title="Show Graph" endif End static Function GraphButtonProc(ctrlName) : ButtonControl String ctrlName String browserName = HDF5GetTopBrowserName() if (HDF5BrowserGraphIsVisible()) DoWindow/K HDF5BrowserGraph else HDF5CreateBrowserGraph() // Create if it does not exist. endif SetGraphButtonTitle(browserName) End static Function SetTableButtonTitle(browserName) String browserName if (HDF5BrowserTableIsVisible()) Button Table, win=$browserName, title="Hide Table" else Button Table, win=$browserName, title="Show Table" endif End static Function TableButtonProc(ctrlName) : ButtonControl String ctrlName String browserName = HDF5GetTopBrowserName() if (HDF5BrowserTableIsVisible()) DoWindow/K HDF5BrowserTable else HDF5CreateBrowserTable() // Create if it does not exist. endif SetTableButtonTitle(browserName) End static Function SetDumpButtonTitle(browserName) String browserName if (HDF5BrowserDumpIsVisible()) Button Dump, win=$browserName, title="Hide Dump" else Button Dump, win=$browserName, title="Show Dump" endif End static Function DumpButtonProc(ctrlName) : ButtonControl String ctrlName String browserName = HDF5GetTopBrowserName() if (HDF5BrowserDumpIsVisible()) Notebook HDF5DumpNotebook, visible=0 else HDF5CreateDumpWindow() // Create if it does not exist. DoWindow/F HDF5DumpNotebook // Show it. endif SetDumpButtonTitle(browserName) End static Function HelpButtonProc(ctrlName) : ButtonControl String ctrlName DisplayHelpTopic "The HDF5 Browser" End static Function CreateHDF5BrowserPanel(browserName) String browserName Variable isMacintosh = 0 if (CmpStr(IgorInfo(2),"Macintosh") == 0) isMacintosh = 1 endif // Determine panel size and position Variable left, top, right, bottom GetPrefWindowCoords("HDF5Browser", left, top, right, bottom) // See if prefs set. if (right-left<200 || bottom-top<200) // These values are calculated to fill a typical 17 inch screen (832x624) on Macintosh. left = 5 top = 50 right = 820 bottom = 625 endif Variable readOnly, loadGroupsRecursively, transpose2DDatasets GetPrefBrowserSettings(readOnly, loadGroupsRecursively, transpose2DDatasets) NewPanel /W=(left, top, right, bottom)/K=1 as "HDF5 Browser" DoWindow/C $browserName DoWindow/T $browserName, browserName // This marks this control panel as an HDF5 browser. SetWindow kwTopWin, userdata(HDF5BrowserName)=browserName SetDrawLayer ProgBack SetDrawEnv fstyle= 1 DrawText 18,75,"File:" SetDrawEnv fstyle= 1 DrawText 18,103,"Selected Group:" SetDrawEnv fstyle= 1 DrawText 18,130,"Selected Dataset:" TitleBox FilePath,pos={55,57},size={706,21} left = isMacintosh ? 150 : 125 TitleBox GroupPath,pos={left,86},size={658,20} TitleBox Dataset,pos={left,113},size={13,21} CheckBox UseHyperSelection,pos={15,155},size={110,14},title="Use Hyperselection",value= 0 CheckBox UseHyperSelection,help={"For experts only. Allows loading a subset of a dataset."} SetVariable HyperSelectionWave,pos={140,155},size={390,16},title="Hyper Selection Wave:" SetVariable HyperSelectionWave,help={"Enter full path to wave containing hyperselection information. See HDF5LoadData /SLAB keyword help."} CheckBox LoadGroupsRecursively,pos={15,181},size={137,14},title="Load Groups Recursively",value=loadGroupsRecursively CheckBox LoadGroupsRecursively,proc=HDF5BrowserPrefCheckboxProc,help={"When checked, the Load Group button loads subgroups."} Button CreateFile,pos={15,8},size={125,20},proc=HDF5Browser#CreateFileButtonProc,title="Create HDF5 File" Button OpenFile,pos={159,8},size={125,20},proc=HDF5Browser#OpenFileButtonProc,title="Open HDF5 File" Button CloseFile,pos={296,8},size={125,20},proc=HDF5Browser#CloseFileButtonProc,title="Close HDF5 File" Button Help,pos={435,8},size={50,20},proc=HDF5Browser#HelpButtonProc,title="Help" CheckBox ReadOnly,pos={186,32},size={68,14},title="Read Only",proc=HDF5BrowserPrefCheckboxProc,value=readOnly // Start Preview Button Graph,pos={556,27},size={90,20},proc=HDF5Browser#GraphButtonProc,title="Show Graph" Button Graph help={"Shows or hides a graph which displays the last dataset or attribute that you selected."} Button Table,pos={672,27},size={90,20},proc=HDF5Browser#TableButtonProc,title="Show Table" Button Table help={"Shows or hides a table which displays the last dataset or attribute that you selected."} Button Dump,pos={556,59},size={90,20},proc=HDF5Browser#DumpButtonProc,title="Show Dump" Button Dump help={"Shows or hides a window which displays a dump of the last dataset or attribute that you selected."} CheckBox ShowAttributesInDump,pos={653,71},size={100,14},title="Show Attributes In Dump" CheckBox ShowAttributesInDump help={"Check to display the dataset's attributes in the dump window."} CheckBox ShowDataInDump,pos={653,56},size={114,14},title="Show Data In Dump" CheckBox ShowDataInDump,help={"Check to display data in the dump window. For large datasets this can take a long time."} GroupBox PreviewOptions,pos={543,5},size={258,87},title="Preview Options" // End Preview TitleBox GroupsTitle,pos={15,230},size={50,16},disable=2,title="Groups",fSize=14 TitleBox GroupsTitle,frame=0,fStyle=1 ListBox GroupsList,pos={15,250},size={306,170}, mode=2, proc=HDF5Browser#ListBoxActionProc ListBox GroupsList,fSize=14 Button LoadGroup,pos={80,224},size={100,20},proc=HDF5Browser#LoadGroupButtonProc,title="Load Group" Button LoadGroup,help={"Loads the currently selected group into the current data folder."} Button SaveDataFolder,pos={194,224},size={120,20},proc=HDF5Browser#SaveDataFolderButtonProc,title="Save Data Folder" Button SaveDataFolder,help={"Saves a data folder in the currently selected group. Available if the current HDF5 file is open for read/write."} TitleBox GroupAttributesTitle,pos={15,435},size={111,16},disable=2,title="Group Attributes" TitleBox GroupAttributesTitle,fSize=14,frame=0,fStyle=1 ListBox GroupAttributesList,pos={15,455},size={306,109}, mode=2, proc=HDF5Browser#ListBoxActionProc ListBox GroupAttributesList, widths={175,40,80,120,1000}, userColumnResize= 1 // userColumnResize requires Igor Pro 5.02. ListBox GroupAttributesList,fSize=14 TitleBox DatasetsTitle,pos={341,230},size={62,16},disable=2,title="Datasets" TitleBox DatasetsTitle,fSize=14,frame=0,fStyle=1 ListBox DatasetsList,pos={341,250},size={459,170}, mode=2, proc=HDF5Browser#ListBoxActionProc ListBox DatasetsList, widths={175,40,80,120,1000}, userColumnResize= 1 // userColumnResize requires Igor Pro 5.02. ListBox DatasetsList,fSize=14 TitleBox DatasetAttributesTitle,pos={341,435},size={123,16},disable=2,title="Dataset Attributes" TitleBox DatasetAttributesTitle,fSize=14,frame=0,fStyle=1 ListBox DatasetAttributesList,pos={341,455},size={459,109}, mode=2, proc=HDF5Browser#ListBoxActionProc ListBox DatasetAttributesList, widths={175,40,80,120,1000}, userColumnResize= 1 // userColumnResize requires Igor Pro 5.02. ListBox DatasetAttributesList,fSize=14 Button LoadDataset,pos={415,224},size={100,20},proc=HDF5Browser#LoadDatasetButtonProc,title="Load Dataset" Button LoadDataset,help={"Loads the currently selected dataset into the current data folder."} Button SaveWaves,pos={529,224},size={100,20},proc=HDF5Browser#SaveWavesButtonProc,title="Save Waves" Button SaveWaves,help={"Saves waves in the currently selected group. Available if the current HDF5 file is open for read/write."} CheckBox Transpose2DDatasets,pos={189,181},size={130,14},title="Transpose 2D Datasets",value=transpose2DDatasets CheckBox Transpose2DDatasets,proc=HDF5BrowserPrefCheckboxProc,help={"When checked, 2D datasets are transposed so that Igor image plots will match HDFView."} PopupMenu Members,pos={342,194},size={216,24},title="Members" PopupMenu Members,mode=1,value= #"\"Load All Members\"" PopupMenu Members proc=HDF5Browser#MembersPopupProc PopupMenu Members,help={"Choose the compound member to preview or load."} // Load Dataset Options PopupMenu DisplayInTable,pos={565,123},size={200,24},title="Table:" PopupMenu DisplayInTable,mode=2,value= #"\"No Table;Display in New Table;Append to Top Table\"" PopupMenu DisplayInGraph,pos={563,154},size={203,24},title="Graph:" PopupMenu DisplayInGraph,mode=2,value= #"\"No Graph;Display in New Graph;Append to Top Graph\"" GroupBox LoadDatasetOptions,pos={542,100},size={258,87},title="Load Dataset Options" HDF5ResizeBrowser(browserName) // Needed because we used preferred browser size. SetWindow kwTopWin,hook=HDF5BrowserPanelHook EndMacro Function HDF5BrowserPrefCheckboxProc(ctrlName,checked) : CheckBoxControl String ctrlName Variable checked STRUCT HDF5BrowserPrefs prefs HDF5BrowserLoadPackagePrefs(prefs) strswitch(ctrlName) case "ReadOnly": prefs.readOnly = checked break case "LoadGroupsRecursively": prefs.loadGroupsRecursively = checked break case "Transpose2DDatasets": prefs.transpose2DDatasets = checked break case "SaveGroupsRecursively": prefs.saveGroupsRecursively = checked break case "IncludeIgorAttributes": prefs.includeIgorAttributes = checked break endswitch HDF5BrowserSavePackagePrefs(prefs) End Function CreateNewHDF5Browser() if (Exists("HDF5LoadData") != 4) String message message = "The HDF5XOP is not activated. Please see the HDF5XOP Help file for instructions." DoAlert 0, message DisplayHelpTopic "HDF5XOP" return -1 endif String browserName = UniqueName("HDF5Browser", 9, 0) CreateHDF5BrowserGlobals(browserName) CreateHDF5BrowserPanel(browserName) STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) AttachListWaves(bd) SetButtonStates(bd) End Static Function IsHDF5Browser(name) String name // Name of a window if (WinType(name) != 7) return 0 // Not a control panel window endif String data = GetUserData(name, "", "HDF5BrowserName") // HDF5BrowserName property is set by CreateHDF5BrowserPanel if (CmpStr(data,name) == 0) // Is this an HDF5Browser? return 1 endif return 0 End Function/S HDF5GetIndexedBrowserName(index) Variable index if (index < 0) return "" // Bad index endif String panelName Variable i = 0 do panelName = WinName(i, 64) if (strlen(panelName) == 0) break endif if (IsHDF5Browser(panelName)) // Is this an HDF5Browser? if (index == 0) return panelName endif index -= 1 endif i += 1 while(1) return "" // No HDF5 browser with that index End Function/S HDF5GetTopBrowserName() String browserName = HDF5GetIndexedBrowserName(0) return browserName End Function HDF5AreAnyBrowsersOpen() String browserName = HDF5GetIndexedBrowserName(0) if (strlen(browserName) > 0) return 1 endif return 0 End // FixCloseHDF5FileButtons() // If experiment was saved with an HDF5 file open, it is no longer open but the panel's Open // and Close buttons will be out-of-sync. This fixes that. static Function FixCloseHDF5FileButtons() STRUCT HDF5BrowserData bd String browserName Variable index = 0 do browserName = HDF5GetIndexedBrowserName(index) if (strlen(browserName) == 0) break endif SetHDF5BrowserData(browserName, bd) if (FileWasUnexpectedlyClosed(bd)) FileWasClosed(bd) endif index += 1 while(1) End static Function AfterFileOpenHook(refNum,file,pathName,type,creator,kind) Variable refNum,kind String file,pathName,type,creator // DoAlert 0, "AfterFileOpenHook" // For debugging switch (kind) case 1: // Packed experiment case 2: // Unpacked experiment FixCloseHDF5FileButtons() // If experiment was saved with an HDF5 file open, it is no longer open break endswitch return 0 End // ************* Start of HDF5 Browser Display Routines *************** static Function WaveRank(w) Wave w Variable dimension for(dimension=3; dimension>=0; dimension-=1) if (DimSize(w, dimension) > 0) return dimension+1 endif endfor return 0 End // *** DISPLAY IN DUMP WINDOW *** Function HDF5BrowserDumpIsVisible() // Returns true if dump window exists and is visible. // Returns false if it does not exist or is invisible. DoWindow HDF5DumpNotebook if (V_flag == 0) return 0 // Does not exist endif String name Variable index = 0 do name = WinName(index, 16, 1) if (strlen(name) == 0) return 0 // Did not find HDF5DumpNotebook among visible notebooks. endif if (CmpStr(name, "HDF5DumpNotebook") == 0) return 1 // Found HDF5DumpNotebook among visible notebooks endif index += 1 while(1) return 0 // This will never execute. End Function HDF5BrowserDumpHook(infoStr) String infoStr String event= StringByKey("EVENT",infoStr) strswitch(event) case "activate": // We do not get this on Windows when the panel is first created. break case "resize": case "moved": // This message was added in Igor Pro 5.04B07. SetPrefWindowCoords("HDF5DumpNotebook") break endswitch return 0 End Function HDF5CreateDumpWindow() DoWindow HDF5DumpNotebook if (V_flag == 0) Variable left, top, right, bottom GetPrefWindowCoords("HDF5DumpNotebook", left, top, right, bottom) if (right > left) // Were prefs ever set? NewNotebook /F=0 /N=HDF5DumpNotebook/K=1 /W=(left, top, right, bottom) else NewNotebook/F=0/N=HDF5DumpNotebook/K=1 endif SetWindow HDF5DumpNotebook,hook=HDF5BrowserDumpHook if (NumType(FontSizeHeight("Courier New", 12, 0)) == 0) // Courier New exists? Notebook HDF5DumpNotebook font="Courier New", fSize=12 endif Notebook HDF5DumpNotebook text="A dump will appear here when you click a dataset.\r" endif End // CleanupDump(dump) // Removes nulls, converts \n to CR, etc. Dump of NASA strings can contain lots of such "garbage". // For an example, see the attribute /StructMetadata.O_GLOSDS in the NASA sample file MISRAERO.h5. static Function/S CleanupDump(dump) String dump // Convert literal string "\000" to "". Null characters are represented in dump by "\000" dump = ReplaceString("\\000", dump, "", 1) // Convert literal string "\r\n" to CR dump = ReplaceString("\\r\\n", dump, "\r", 1) // Convert literal string "\r" to CR dump = ReplaceString("\\r", dump, "\r", 1) // Convert literal string "\n" to CR dump = ReplaceString("\\n", dump, "\r", 1) // Convert literal string "\t" to tab dump = ReplaceString("\\t", dump, "\t", 1) // Convert CRLF to CR dump = ReplaceString("\r\n", dump, "\r", 1) // Convert LF to CR dump = ReplaceString("\n", dump, "\r", 1) return dump End Function HDF5DisplayDumpOfSelectedGroup(bd) STRUCT HDF5BrowserData &bd String path = SelectedGroupPath(bd) if (strlen(path) == 0) return -1 endif ControlInfo /W=$bd.browserName ShowAttributesInDump Variable showAttributes = V_value HDF5Dump /Q /H=1 /ATTR=(showAttributes) /G=path bd.fullPath // This sets S_HDF5Dump. S_HDF5Dump = CleanupDump(S_HDF5Dump) HDF5CreateDumpWindow() Notebook HDF5DumpNotebook selection={startOfFile, endOfFile} Notebook HDF5DumpNotebook text=S_HDF5Dump Notebook HDF5DumpNotebook selection={startOfFile, startOfFile}, findText={"",1} End static Function DisplayDumpOfSelectedDataset(bd) STRUCT HDF5BrowserData &bd String datasetPath = SelectedDatasetPath(bd) if (strlen(datasetPath) == 0) return -1 endif ControlInfo /W=$bd.browserName ShowAttributesInDump Variable showAttributes = V_value ControlInfo /W=$bd.browserName ShowDataInDump Variable showData = V_value HDF5Dump /Q /ATTR=(showAttributes) /H=(!showData) /D=datasetPath bd.fullPath // This sets S_HDF5Dump. S_HDF5Dump = CleanupDump(S_HDF5Dump) HDF5CreateDumpWindow() Notebook HDF5DumpNotebook selection={startOfFile, endOfFile} Notebook HDF5DumpNotebook text=S_HDF5Dump Notebook HDF5DumpNotebook selection={startOfFile, startOfFile}, findText={"",1} End static Function DisplayDumpOfSelectedAttribute(bd, isGroupAttribute) STRUCT HDF5BrowserData &bd Variable isGroupAttribute String path = SelectedAttributePath(bd, isGroupAttribute) if (strlen(path) == 0) return -1 endif HDF5Dump /Q /A=path bd.fullPath // This sets S_HDF5Dump. S_HDF5Dump = CleanupDump(S_HDF5Dump) HDF5CreateDumpWindow() Notebook HDF5DumpNotebook selection={startOfFile, endOfFile} Notebook HDF5DumpNotebook text=S_HDF5Dump Notebook HDF5DumpNotebook selection={startOfFile, startOfFile}, findText={"",1} End // *** DISPLAY IN GRAPH *** Function HDF5BrowserGraphIsVisible() // Returns true if dump window exists and is visible. // Returns false if it does not exist or is invisible. DoWindow HDF5BrowserGraph if (V_flag == 0) return 0 // Does not exist endif // Graphs are always visible so we don't need to check that. return 1 // This will never execute. End Function HDF5BrowserGraphHook(infoStr) String infoStr String event= StringByKey("EVENT",infoStr) strswitch(event) case "activate": // We do not get this on Windows when the panel is first created. break case "resize": case "moved": // This message was added in Igor Pro 5.04B07. SetPrefWindowCoords("HDF5BrowserGraph") break endswitch return 0 End Function HDF5CreateBrowserGraph() DoWindow HDF5BrowserGraph if (V_flag == 0) Variable left, top, right, bottom GetPrefWindowCoords("HDF5BrowserGraph", left, top, right, bottom) if (right > left) // Were prefs ever set? Display /K=1 /W=(left, top, right, bottom) else Display /K=1 endif DoWindow/C HDF5BrowserGraph SetWindow HDF5BrowserGraph,hook=HDF5BrowserGraphHook endif End static Function SetImageLayer(ctrlName,varNum,varStr,varName) : SetVariableControl String ctrlName Variable varNum String varStr String varName NVAR imageLayer = root:Packages:HDF5Browser:imageLayer ModifyImage /W=HDF5BrowserGraph BrowserWave, plane=varNum End static Function DisplayGraphOfSelectedData(bd, isAttribute, objectType, listOfWavesLoaded) // The data is already loaded into waves specified by listOfWavesLoaded STRUCT HDF5BrowserData &bd Variable isAttribute Variable objectType // Host object type of attribute. 1=group, 2=dataset String listOfWavesLoaded HDF5CreateBrowserGraph() String firstWaveLoaded = StringFromList(0, listOfWavesLoaded) Wave browserWave = root:Packages:HDF5Browser:$firstWaveLoaded Variable newDataIsText = WaveType(browserWave) == 0 Variable oldRank = 0, newRank = 0 if (strlen(TraceNameList("HDF5BrowserGraph", ";", 1)) > 0) oldRank = 1 endif if (strlen(ImageNameList("HDF5BrowserGraph", ";")) > 0) oldRank = 2 endif newRank = WaveRank(browserWave) // Will be zero for zero-point wave String savedDataFolder = SetBrowserDataFolder("") // browserWave goes in master HDF5Browser data folder Variable displayedDimensionalityChanged = (oldRank <= 1) != (newRank <= 1) // Switching between 1D and >1D ? Variable index, browserWaveIsDisplayed String waveLoaded, nameOfGraphWave // Remove any waves in graph not in listOfWavesLoaded or all waves if dimensionality changed index = 0 do if (oldRank == 1) Wave/Z graphWave = WaveRefIndexed("HDF5BrowserGraph", index, 1) if (!WaveExists(graphWave)) break endif nameOfGraphWave = NameOfWave(graphWave) else nameOfGraphWave = StringFromList(index, ImageNameList("HDF5BrowserGraph", ";" )) if (strlen(nameOfGraphWave) == 0) break endif endif Variable waveIsInListOfLoadedWaves = WhichListItem(nameOfGraphWave, listOfWavesLoaded) >= 0 if (displayedDimensionalityChanged || !waveIsInListOfLoadedWaves) if (oldRank == 1) RemoveFromGraph /W=HDF5BrowserGraph $nameOfGraphWave endif if (oldRank > 1) RemoveImage /W=HDF5BrowserGraph $nameOfGraphWave endif index -= 1 endif if (!waveIsInListOfLoadedWaves) KillWaves/Z $nameOfGraphWave endif index += 1 while(1) // Append any waves to graph in listOfWavesLoaded index = 0 do waveLoaded = StringFromList(index, listOfWavesLoaded) if (strlen(waveLoaded) == 0) break endif Wave browserWave = root:Packages:HDF5Browser:$waveLoaded Variable browserWaveType = WaveType(browserWave) nameOfGraphWave = waveLoaded CheckDisplayed /W=HDF5BrowserGraph browserWave browserWaveIsDisplayed = V_flag if (!newDataIsText) if (browserWaveType != 0) // When loading compound data we can get a mix of numeric and non-numeric. if (browserWaveIsDisplayed == 0) if (newRank <= 1) AppendToGraph /W=HDF5BrowserGraph browserWave if (displayedDimensionalityChanged) SetAxis/A left endif else AppendImage /W=HDF5BrowserGraph browserWave if (displayedDimensionalityChanged) SetAxis/A/R left // Reverse left axis like NewImage does. endif endif endif if (newRank >= 2) NVAR formalImageType = root:Packages:HDF5Browser:formalImageType switch (formalImageType) // browserPalette would be created by HDF5LoadImage case 0: // Not a formal image. case 1: // No palette wave loaded. ModifyImage /W=HDF5BrowserGraph $nameOfGraphWave ctab= {*,*,Grays,0} break case 2: // Palette wave was loaded. Wave browserPalette = root:Packages:HDF5Browser:browserPalette ModifyImage /W=HDF5BrowserGraph $nameOfGraphWave, cindex=browserPalette break endswitch endif endif endif if (newDataIsText) // Display a snippet of the text wave. if (browserWaveType == 0) // When loading compound data we can get a mix of numeric and non-numeric. String text Wave/T w = root:Packages:HDF5Browser:$nameOfGraphWave if (numpnts(w) > 0) text = CleanupDump(w[0]) else text = "" endif if ( (strlen(text) > 256) || (numpnts(w)>1) ) text = "A snippet of the text:\r\r" + text[0,255] endif TextBox/C/N=browserTextbox/W=HDF5BrowserGraph/A=LT text endif else TextBox/K/N=browserTextbox/W=HDF5BrowserGraph endif index += 1 while(1) // Show Image Layer control if displaying a stack of images Variable numDims = WaveDims(browserWave) Variable isStack = 0 if (!newDataIsText && newRank>2) if (DimSize(browserWave,2) == 3) // Igor assumes that this is an RGB wave using direct color. if (numDims > 3) isStack = 1 // This is a stack of RGB images. endif else isStack = 1 // This is a stack of indexed color images. endif endif if (isStack) Variable/G root:Packages:HDF5Browser:imageLayer = 0 Variable dim, numLayers numLayers = 1 for(dim=2; dim<numDims; dim+=1) numLayers *= DimSize(browserWave, dim) endfor ControlBar/W=HDF5BrowserGraph 25 SetVariable ImageLayer win=HDF5BrowserGraph, title="Layer",size={100,20},format="%d" SetVariable ImageLayer win=HDF5BrowserGraph, proc=HDF5Browser#SetImageLayer SetVariable ImageLayer win=HDF5BrowserGraph, value=imageLayer, limits={0,numLayers-1,1} else KillControl/W=HDF5BrowserGraph ImageLayer ControlBar/W=HDF5BrowserGraph 0 endif String title = "HDF5 Preview - " if (isAttribute) title += SelectedAttributeName(bd, objectType==1) else title += SelectedDatasetName(bd) endif title = title[0,39] // Unfortunately titles are limited to 40 characters. DoWindow /T HDF5BrowserGraph, title SetDataFolder savedDataFolder End // *** DISPLAY IN TABLE *** Function HDF5BrowserTableIsVisible() // Returns true if dump window exists and is visible. // Returns false if it does not exist or is invisible. DoWindow HDF5BrowserTable if (V_flag == 0) return 0 // Does not exist endif // Tables are always visible so we don't need to check that. return 1 // This will never execute. End Function HDF5BrowserTableHook(infoStr) String infoStr String event= StringByKey("EVENT",infoStr) strswitch(event) case "activate": // We do not get this on Windows when the panel is first created. break case "resize": case "moved": // This message was added in Igor Pro 5.04B07. SetPrefWindowCoords("HDF5BrowserTable") break endswitch return 0 End Function HDF5CreateBrowserTable() DoWindow HDF5BrowserTable if (V_flag == 0) Variable left, top, right, bottom GetPrefWindowCoords("HDF5BrowserTable", left, top, right, bottom) if (right > left) // Were prefs ever set? Edit /K=1 /W=(left, top, right, bottom) else Edit /K=1 endif DoWindow/C HDF5BrowserTable SetWindow HDF5BrowserTable,hook=HDF5BrowserTableHook endif End static Function DisplayTableOfSelectedData(bd, isAttribute, objectType, listOfWavesLoaded) // The data is already loaded into waves listed by listOfWavesLoaded STRUCT HDF5BrowserData &bd Variable isAttribute Variable objectType // Host object type of attribute. 1=group, 2=dataset String listOfWavesLoaded HDF5CreateBrowserTable() String waveLoaded Variable index // Remove any waves in table not in listOfWavesLoaded index = 0 do Wave/Z tableWave = WaveRefIndexed("HDF5BrowserTable", index, 3) if (!WaveExists(tableWave)) break endif String nameOfTableWave = NameOfWave(tableWave) if (WhichListItem(nameOfTableWave, listOfWavesLoaded) < 0) RemoveFromTable /W=HDF5BrowserTable tableWave KillWaves/Z tableWave index -= 1 endif index += 1 while(1) // Append any waves to table in listOfWavesLoaded index = 0 do waveLoaded = StringFromList(index, listOfWavesLoaded) if (strlen(waveLoaded) == 0) break endif Wave browserWave = root:Packages:HDF5Browser:$waveLoaded CheckDisplayed /W=HDF5BrowserTable browserWave if (V_flag == 0) AppendToTable /W=HDF5BrowserTable browserWave endif index += 1 while(1) String title = "HDF5 Preview - " if (isAttribute) title += SelectedAttributeName(bd, objectType==1) else title += SelectedDatasetName(bd) endif title = title[0,39] // Unfortunately titles are limited to 40 characters. DoWindow /T HDF5BrowserTable, title End static Function RemoveFromGraphAndTable(w) Wave w String name = NameOfWave(w) if (HDF5BrowserGraphIsVisible()) CheckDisplayed /W=HDF5BrowserGraph w if (V_flag != 0) Variable isImage = strlen(ImageNameList("HDF5BrowserGraph", ";")) > 0 if (isImage) RemoveImage /W=HDF5BrowserGraph $name else RemoveFromGraph /W=HDF5BrowserGraph $name endif endif endif if (HDF5BrowserTableIsVisible()) CheckDisplayed /W=HDF5BrowserTable w if (V_flag != 0) RemoveFromTable /W=HDF5BrowserTable w endif endif End // KillConflictingBrowserWaves(new_class_str, enumMode) // "Conflicting" means that a wave is text and we are going // to use the same name to load a numeric wave or vice versa. // This function removes conflicting waves from the browser graph // and table and then kills them. static Function KillConflictingBrowserWaves(new_class_str, enumMode) String new_class_str // Class of data we are about to load. Variable enumMode String browserDF = "root:Packages:HDF5Browser" Variable numWaves = CountObjects(browserDF, 1) Variable i for(i=0; i<numWaves; i+=1) String name = GetIndexedObjName(browserDF, 1, i) if (strlen(name)>=11 && CmpStr(name[0,11],"browserWave")==0) // Is this a browser display wave? Wave w = $(browserDF + ":" + name) Variable oldDataIsText oldDataIsText = WaveType(w) == 0 Variable newDataIsText newDataIsText = 0 strswitch(new_class_str) case "H5T_STRING": case "H5T_REFERENCE": newDataIsText = 1 break case "H5T_ENUM": if (enumMode == 1) newDataIsText = 1 endif break case "H5T_COMPOUND": // If we are loading all members of a compound dataset // at this point we need to know the class of the compound // member corresponding to the current wave. However, this // is very complicated to do and I decided not to attempt it. // The result is that, if we have an existing brower_<member> // wave whose type is string and we try to load a numeric wave // with the same name, HDF5LoadWave will get a "Can't overwrite // text with numeric and vice versa" error. break endswitch if (newDataIsText != oldDataIsText) RemoveFromGraphAndTable(w) KillWaves w // Printf "Killed %s\r", name endif endif endfor End static Function LoadSelectedDataForDisplay(bd, isAttribute, objectType, listOfWavesLoaded, errorMessage) STRUCT HDF5BrowserData &bd Variable isAttribute Variable objectType // Host object type of attribute. 1=group, 2=dataset String &listOfWavesLoaded // Output: List of waves loaded. String &errorMessage // Output: Error message or "" Variable err = 0 errorMessage = "" Wave/Z browserWave = root:Packages:HDF5Browser:browserWave String path if (isAttribute) if (objectType == 1) path = SelectedGroupPath(bd) else path = SelectedDatasetPath(bd) endif else path = SelectedDatasetPath(bd) endif if (strlen(path) == 0) return -1 endif String attributeName = "" if (isAttribute) attributeName = SelectedAttributeName(bd, objectType==1) if (strlen(attributeName) == 0) return -1 endif endif STRUCT HDF5DataInfo di InitHDF5DataInfo(di) if (isAttribute) HDF5AttributeInfo(bd.fileID, path, objectType, attributeName, 0, di) else HDF5DatasetInfo(bd.fileID, path, 0, di) endif String datatype_class_str = di.datatype_class_str STRUCT HDF5DatatypeInfo dti InitHDF5DatatypeInfo(dti) // Sets input fields. Variable isCompound = 0 Variable compMode = 0 String memberName = "" if (!isAttribute) // We support viewing members only for datasets, not for attributes. HDF5GetCompLoadInfo(bd, isCompound, compMode, memberName) endif if (compMode != 0) // Are we loading a member of a compound datatype? err = HDF5TypeInfo(bd.fileID, path, "", memberName, 1, dti) if (err != 0) return err endif datatype_class_str = dti.type_class_str else // If array, we need to know about the base datatype of the array if (CmpStr(datatype_class_str, "H5T_ARRAY") == 0) if (isAttribute) HDF5AttributeInfo(bd.fileID, path, objectType, attributeName, 2, di) // 2 means get info on base datatype of array else HDF5DatasetInfo(bd.fileID, path, 2, di) // 2 means get info on base datatype of array endif endif datatype_class_str = di.datatype_class_str endif err = HDF5CheckDataClass(datatype_class_str, errorMessage) if (err != 0) if (WaveExists(browserWave)) Redimension/N=(0) browserWave // Don't leave browserWave around which a user might endif // think goes with the selected item in the control panel return err endif String savedDataFolder = SetBrowserDataFolder("") // tempClassAttribute goes in master HDF5Browser data folder // If isFormalImage is true, we are loading an image written // according to the HDF5 Image and Palette Specification. Variable isFormalImage = 0 if (!isAttribute && !isCompound) HDF5LoadData /Z /O /N=tempClassAttribute /A="CLASS" /Q /VAR=1 bd.fileID, path if (V_flag == 0) WAVE/T tempClassAttribute // HDF5LoadData will have created this string if (CmpStr(tempClassAttribute[0],"IMAGE") == 0) isFormalImage = 1 endif KillWaves/Z tempClassAttribute endif endif SetDataFolder savedDataFolder Variable enumMode = 1 // 0: Load enum into numeric wave; 1: load enum into text wave. // If browserWave exists and we are switching from a text wave to a numeric wave // or vice-versa then we must remove browserWave from the graph and table and // kill it. Otherwise we will get an error when HDF5LoadData tries to overwrite // a text wave with numeric or vice versa. KillConflictingBrowserWaves(datatype_class_str, enumMode) // Also removes them from graph and table. savedDataFolder = SetBrowserDataFolder("") // browser waves go in master HDF5Browser data folder String slabWaveStr = "" ControlInfo /W=$bd.browserName UseHyperSelection if (V_value) // Use Hyperselection is checked? slabWaveStr = bd.hyperSelectionWavePath endif WAVE/Z slabWave = $slabWaveStr // It is OK if wave does not exist and slabWave is NULL. HDF5LoadData will simply ignore /SLAB. if (isFormalImage) String browserPaletteName = "browserPalette" HDF5LoadImage /O /N=browserWave /PALN=browserPaletteName /Q bd.fileID, path Variable/G formalImageType = 1 // Means formal image with no palette listOfWavesLoaded = StringFromList(0, S_waveNames) // We count only the image as loaded, not the palette. if (WhichListItem(browserPaletteName, S_waveNames) >= 0) formalImageType = 2 // Means formal image with palette endif else KillWaves/Z browserPalette Variable transpose2D = HDF5GetTranspose2DSetting(bd.browserName) // Note that when loading all members of a compound dataset this // will create a family of waves named browserWave_<member>. // Also when loading a VLEN dataset it will create a family of // waves named browserWave<digit>. Otherwise it just creates // one wave named browserWave. HDF5LoadData /O /IGOR=-1 /N=browserWave /COMP={compMode,memberName} /TRAN=(transpose2D) /A=attributeName /TYPE=(objectType) /ENUM=(enumMode) /SLAB=slabWave /Q /VAR=0 bd.fileID, path Variable/G formalImageType = 0 // Not a formal image listOfWavesLoaded = S_waveNames endif errorMessage = GetRTErrMessage() err = GetRTError(1) SetDataFolder savedDataFolder return err End Function HDF5DisplaySelectedDataset(bd) STRUCT HDF5BrowserData &bd if (HDF5BrowserDumpIsVisible()) DisplayDumpOfSelectedDataset(bd) endif String listOfWavesLoaded = "" Variable needToLoadData = HDF5BrowserGraphIsVisible() || HDF5BrowserTableIsVisible() if (needToLoadData) String errorMessage if (LoadSelectedDataForDisplay(bd, 0, 2, listOfWavesLoaded, errorMessage) != 0) DoAlert 0, errorMessage return -1 endif endif if (HDF5BrowserGraphIsVisible()) DisplayGraphOfSelectedData(bd, 0, 1, listOfWavesLoaded) endif if (HDF5BrowserTableIsVisible()) DisplayTableOfSelectedData(bd, 0, 1, listOfWavesLoaded) endif End Function HDF5DisplaySelectedAttribute(bd, isGroupAttribute) STRUCT HDF5BrowserData &bd Variable isGroupAttribute if (HDF5BrowserDumpIsVisible()) DisplayDumpOfSelectedAttribute(bd, isGroupAttribute) endif Variable objectType = isGroupAttribute ? 1:2 String listOfWavesLoaded = "" Variable needToLoadData = HDF5BrowserGraphIsVisible() || HDF5BrowserTableIsVisible() if (needToLoadData) String errorMessage if (LoadSelectedDataForDisplay(bd, 1, objectType, listOfWavesLoaded, errorMessage)) DoAlert 0, errorMessage return -1 endif endif if (HDF5BrowserGraphIsVisible()) DisplayGraphOfSelectedData(bd, 1, objectType, listOfWavesLoaded) endif if (HDF5BrowserTableIsVisible()) DisplayTableOfSelectedData(bd, 1, objectType, listOfWavesLoaded) endif End // ************* End of HDF5 Browser Display Routines *************** // ************* Start of HDF5 Browser Resize Routines *************** static Function MinWindowSize(winName,minwidth,minheight) String winName Variable minwidth,minheight GetWindow $winName wsize Variable width= max(V_right-V_left,minwidth) Variable height= max(V_bottom-V_top,minheight) MoveWindow/W=$winName V_left, V_top, V_left+width, V_top+height End Function PositionControlRelative(panelName, control, masterControl, xMode, yMode, dx, dy) String panelName String control, masterControl // Positions control relative to masterControl. Variable xMode // 0 = relative to master left, 1 = relative to master right, 2 = do not set x position. Variable yMode // 0 = relative to master top, 1 = relative to master bottom, 2 = do not set y position. Variable dx, dy ControlInfo/W=$panelName $masterControl Variable masterLeft = V_left, masterTop = V_top Variable masterRight = masterLeft+V_width, masterBottom=masterTop+V_height ControlInfo/W=$panelName $control Variable controlLeft = V_left, controlTop = V_top Variable left, top switch(xMode) case 0: left = masterLeft + dx break case 1: left = masterRight + dx break case 2: left = controlLeft break endswitch switch(yMode) case 0: top = masterTop + dy break case 1: top = masterBottom + dy break case 2: top = controlTop break endswitch ModifyControl $control, win=$panelName, pos={left, top} End Function OffsetControls(panelName, controlList, dx, dy) String panelName String controlList // Semicolon-separated list of control names Variable dx, dy String name Variable index = 0 do name = StringFromList(index, controlList) if (strlen(name) == 0) break endif ControlInfo/W=$panelName $name ModifyControl $name, win=$panelName, pos={V_left+dx,V_top+dy} index += 1 while(1) End Function HDF5ResizeBrowser(browserName) String browserName Variable statusCode= 0 String win = browserName GetWindow $browserName wsizeDC Variable winLeft=V_left, winTop=V_top, winRight=V_right, winBottom=V_bottom Variable winWidth = winRight - winLeft, winHeight = winBottom - winTop if (winWidth<600 || winHeight<500) return 0 // Too small. endif // Set preferred browser window size. We would like to also do this // when the browser is moved without resizing but we get no message // from Igor when a window is moved. SetPrefWindowCoords(browserName) Variable leftBorder=15, hSpaceBetweenLists=20, rightBorder=15 Variable listsTop, vSpaceBetweenLists = 30, bottomBorder = 10 ControlInfo/W=$browserName GroupsList listsTop = V_top Variable hSpaceForLists = winRight - winLeft - leftBorder - hSpaceBetweenLists - rightBorder Variable vSpaceForLists = winBottom - listsTop - vSpaceBetweenLists - bottomBorder Variable groupListsWidth = .4 * hSpaceForLists Variable datasetListsWidth = .6 * hSpaceForLists Variable groupListsHeight = .65 * vSpaceForLists Variable attributeListsHeight = .35 * vSpaceForLists Variable left, top // Set Groups list coordinates left = leftBorder top = listsTop ListBox GroupsList, win=$browserName, pos={left, top}, size={groupListsWidth, groupListsHeight} // Set Group Attributes list coordinates left = leftBorder top = listsTop + groupListsHeight + vSpaceBetweenLists ListBox GroupAttributesList, win=$browserName, pos={left, top}, size={groupListsWidth, attributeListsHeight} top -= 20 TitleBox GroupAttributesTitle, win=$browserName, pos={left, top} // Remember where DatasetsList is. it is used to position other control. ControlInfo/W=$browserName DatasetsList Variable oldDatasetsListRight = V_Left + V_Width // Set Datasets list coordinates left = leftBorder + groupListsWidth + hSpaceBetweenLists top = listsTop ListBox DatasetsList, win=$browserName, pos={left, top}, size={datasetListsWidth, groupListsHeight} // Determine how DatasetsList right edge changed. This is used to position other control. ControlInfo/W=$browserName DatasetsList Variable changeInDatsetsListRight = (V_Left + V_Width) - oldDatasetsListRight // Set Datasets Title top -= 20 TitleBox DatasetsTitle, win=$browserName, pos={left, top} // Set Load Dataset Button PositionControlRelative(browserName, "LoadDataset", "DatasetsTitle", 1, 2, 20, 0) // Set Save Waves Button PositionControlRelative(browserName, "SaveWaves", "LoadDataset", 1, 2, 20, 0) // Set Members popup menu PositionControlRelative(browserName, "Members", "DatasetsTitle", 0, 2, 0, 0) // Set Dataset Attributes list coordinates left = leftBorder + groupListsWidth + hSpaceBetweenLists top = listsTop + groupListsHeight + vSpaceBetweenLists ListBox DatasetAttributesList, win=$browserName, pos={left, top}, size={datasetListsWidth, attributeListsHeight} top -= 20 TitleBox DatasetAttributesTitle, win=$browserName, pos={left, top} // Set Preview Options String list = "PreviewOptions;Graph;Table;Dump;ShowAttributesInDump;ShowDataInDump;" OffsetControls(browserName, list, changeInDatsetsListRight, 0) // Set Load Dataset Options list = "LoadDatasetOptions;DisplayInTable;DisplayInGraph;" OffsetControls(browserName, list, changeInDatsetsListRight, 0) statusCode=1 return statusCode // 0 if nothing done, else 1 or 2 End // ************* End of HDF5 Browser Resize Routines *************** // ************* Start of HDF5 Browser Prefs Routines *************** // HDF5 Browser preferences are stored on disk in the Packages directory // in Igor's preferences directory. They are temporarily loaded into an // HDF5BrowserPrefs data structure but are not stored permanently in memory. // When a preference value has to be changed, the prefs data structure // is loaded into memory, the value is changed and the data structure is // immediately written back out to disk. // To see where prefs data is changed, search for HDF5BrowserSavePackagePrefs. static StrConstant kPackageName = "HDF5Browser" // NOTE: Package name must be distinctive! static Constant kCurrentPrefsVersion = 100 // Changes to hundreds digit means incompatible prefs static StrConstant kPrefFileName = "Preferences.bin" static Constant kPrefRecordID = 0 Structure HDF5BrowserPrefs uint32 prefsVersion // Preferences structure version number. 100 means 1.00. // Preview graph location in points. 0 means default. float graphLeft float graphTop float graphRight float graphBottom // Preview table location in points. 0 means default. float tableLeft float tableTop float tableRight float tableBottom // Dump notebook location in points. 0 means default. float dumpLeft float dumpTop float dumpRight float dumpBottom // Save Waves and Save Data Folder panel location in pixels. 0 means default. float savePanelLeft float savePanelTop float savePanelRight float savePanelBottom // HDF5 browser location in points. 0 means default. float browserLeft float browserTop float browserRight float browserBottom // Overall prefs uchar readOnly // Open file read only uchar reservedOverall[15] // Load prefs uchar loadGroupsRecursively // Controls Load Group button uchar transpose2DDatasets // Controls Load Dataset and Load Group buttons uchar reservedLoad[14] // Save prefs uchar saveGroupsRecursively // Affects Save Data Folder uchar includeIgorAttributes // Affects Save Waves and Save Data Folder uchar reservedSave[14] uint32 reserved[100] // Reserved for future use EndStructure Function HDF5BrowserLoadPackagePrefs(prefs) STRUCT HDF5BrowserPrefs &prefs Variable i // This loads preferences from disk if they exist on disk. LoadPackagePreferences kPackageName, kPrefFileName, kPrefRecordID, prefs // If prefs not loaded or not valid, initialize them. if (V_flag!=0 || prefs.prefsVersion!=kCurrentPrefsVersion) prefs.prefsVersion = kCurrentPrefsVersion prefs.graphLeft = 0 prefs.graphTop = 0 prefs.graphRight = 0 prefs.graphBottom = 0 // Preview table location in points. 0 means default. prefs.tableLeft = 0 prefs.tableTop = 0 prefs.tableRight = 0 prefs.tableBottom = 0 // Dump notebook location in points. 0 means default. prefs.dumpLeft = 0 prefs.dumpTop = 0 prefs.dumpRight = 0 prefs.dumpBottom = 0 // Save Waves and Save Data Folder panel location in pixels. 0 means default. prefs.savePanelLeft = 0 prefs.savePanelTop = 0 prefs.savePanelRight = 0 prefs.savePanelBottom = 0 // HDF5 browser location in points. 0 means default. prefs.browserLeft = 0 prefs.browserTop = 0 prefs.browserRight = 0 prefs.browserBottom = 0 // Overall prefs prefs.readOnly = 1 for(i=0; i<15; i+=1) prefs.reservedOverall[i] = 0 endfor // Load prefs prefs.loadGroupsRecursively = 1 prefs.transpose2DDatasets = 0 for(i=0; i<14; i+=1) prefs.reservedLoad[i] = 0 endfor // Save prefs prefs.saveGroupsRecursively = 1 prefs.includeIgorAttributes = 1 for(i=0; i<14; i+=1) prefs.reservedSave[i] = 0 endfor for(i=0; i<100; i+=1) prefs.reserved[i] = 0 endfor HDF5BrowserSavePackagePrefs(prefs) // Create default prefs file. endif End Function HDF5BrowserSavePackagePrefs(prefs) STRUCT HDF5BrowserPrefs &prefs SavePackagePreferences kPackageName, kPrefFileName, kPrefRecordID, prefs End static Function GetPrefWindowCoords(windowName, left, top, right, bottom) String windowName Variable &left, &top, &right, &bottom STRUCT HDF5BrowserPrefs prefs HDF5BrowserLoadPackagePrefs(prefs) strswitch(windowName) case "HDF5BrowserGraph": left = prefs.graphLeft top = prefs.graphTop right = prefs.graphRight bottom = prefs.graphBottom break case "HDF5BrowserTable": left = prefs.tableLeft top = prefs.tableTop right = prefs.tableRight bottom = prefs.tableBottom break case "HDF5DumpNotebook": left = prefs.dumpLeft top = prefs.dumpTop right = prefs.dumpRight bottom = prefs.dumpBottom break case "HDF5SaveWavesPanel": case "HDF5SaveDataFolderPanel": left = prefs.savePanelLeft top = prefs.savePanelTop right = prefs.savePanelRight bottom = prefs.savePanelBottom break default: // We want to get preferred coords for a new HDF5 browser. left = prefs.browserLeft top = prefs.browserTop right = prefs.browserRight bottom = prefs.browserBottom break endswitch End #if (Exists("PanelResolution") != 3) // Igor7 has a PanelResolution function that Igor6 lacks Static Function PanelResolution(wName) // For compatibility with Igor 7 String wName return 72 End #endif static Function SetPrefWindowCoords(windowName) String windowName STRUCT HDF5BrowserPrefs prefs HDF5BrowserLoadPackagePrefs(prefs) GetWindow $windowName wSize // NewPanel uses device coordinates. We therefore need to scale from // points (returned by GetWindow) to device units for windows created // by NewPanel. Variable scale = PanelResolution(windowName) / 72 strswitch(windowName) case "HDF5BrowserGraph": prefs.graphLeft = V_Left prefs.graphTop = V_Top prefs.graphRight = V_Right prefs.graphBottom = V_Bottom break case "HDF5BrowserTable": prefs.tableLeft = V_left prefs.tableTop = V_top prefs.tableRight = V_Right prefs.tableBottom = V_Bottom break case "HDF5DumpNotebook": prefs.dumpLeft = V_left prefs.dumpTop = V_top prefs.dumpRight = V_Right prefs.dumpBottom = V_Bottom break case "HDF5SaveWavesPanel": case "HDF5SaveDataFolderPanel": prefs.savePanelLeft = V_left * scale prefs.savePanelTop = V_top * scale prefs.savePanelRight = V_Right * scale prefs.savePanelBottom = V_Bottom * scale break default: // We want to set preferred coords for a new HDF5 browser. prefs.browserLeft = V_left * scale prefs.browserTop = V_top * scale prefs.browserRight = V_Right * scale prefs.browserBottom = V_Bottom * scale break endswitch HDF5BrowserSavePackagePrefs(prefs) End static Function GetPrefBrowserSettings(readOnly, loadGroupsRecursively, transpose2DDatasets) Variable &readOnly Variable &loadGroupsRecursively Variable &transpose2DDatasets STRUCT HDF5BrowserPrefs prefs HDF5BrowserLoadPackagePrefs(prefs) readOnly = prefs.readOnly loadGroupsRecursively = prefs.loadGroupsRecursively transpose2DDatasets = prefs.transpose2DDatasets End // ************* End of HDF5 Browser Prefs Routines *************** // ************* Start of HDF5 Utility Routines *************** Function HDF5CheckDataClass(dataClassStr, errorMessage) String dataClassStr String &errorMessage Variable err = 0 errorMessage = "" strswitch(dataClassStr) case "H5T_TIME": errorMessage = "HDF5XOP does not support data of class H5T_TIME." err = -1 break endswitch return err End Function HDF5MakeHyperslabWave(path, numRows) String path // Path to wave. e.g., "root:slab" Variable numRows Make /O /N=(numRows,4) $path Wave slab = $path slab = 1 // Set all elements to 1. Variable row String dimLabel for(row=0; row<numRows; row+=1) sprintf dimLabel, "Dimension %d", row // HR, 060206: Fixed setting of row dimension labels. SetDimLabel 0, row, $dimLabel, slab endfor SetDimLabel 1, 0, Start, slab SetDimLabel 1, 1, Stride, slab SetDimLabel 1, 2, Count, slab SetDimLabel 1, 3, Block, slab End Constant kHDF5DataInfoVersion = 1000 // 1000 means 1.000. Structure HDF5DataInfo // Use with HDF5DatasetInfo and HDF5AttributeInfo functions // Input fields (inputs to HDF5 XOP) uint32 version // Must be set to kHDF5DataInfoVersion char structName[16] // Must be "HDF5DataInfo". // Output fields (outputs from HDF5 XOP) double datatype_class; // e.g., H5T_INTEGER, H5T_FLOAT. char datatype_class_str[32]; // String with class spelled out. e.g., "H5T_INTEGER", "H5T_FLOAT". double datatype_size; // Size in bytes of one element. double datatype_sign; // H5T_SGN_NONE (unsigned), H5T_SGN_2 (signed), H5T_SGN_ERROR (this type does not have a sign, i.e., it is not an integer type). double datatype_order; // H5T_ORDER_LE, H5T_ORDER_BE, H5T_ORDER_VAX char datatype_str[64]; // Human-readable string, e.g., "16-bit unsigned integer" double dataspace_type; // H5S_NO_CLASS, H5S_SCALAR, H5S_SIMPLE double ndims; // Zero for H5S_SCALAR. Number of dimensions in the dataset for H5S_SIMPLE. double dims[H5S_MAX_RANK]; // Size of each dimension. double maxdims[H5S_MAX_RANK]; // Maximum size of each dimension. EndStructure Function InitHDF5DataInfo(di) // Sets input fields. STRUCT HDF5DataInfo &di // HDF5XOP uses these fields to make sure the structure passed in to it is compatible. di.version = kHDF5DataInfoVersion di.structName = "HDF5DataInfo" End // HDF5DatasetRank(locationID, name) // Returns rank or zero in event of error. Function HDF5DatasetRank(locationID, name) Variable locationID String name STRUCT HDF5DataInfo di InitHDF5DataInfo(di) // Set input fields. Variable err = HDF5DatasetInfo(locationID, name, 1, di) if (err != 0) return 0 endif Variable rank = di.ndims return rank End // HDF5AttributeRank(locationID, name) // Returns rank or zero in event of error. Function HDF5AttributeRank(locationID, objectName, objectType, attributeName) Variable locationID String objectName Variable objectType String attributeName STRUCT HDF5DataInfo di InitHDF5DataInfo(di) // Set input fields. Variable err = HDF5AttributeInfo(locationID, objectName, objectType, attributeName, 1, di) if (err != 0) return 0 endif Variable rank = di.ndims return rank End Constant kHDF5DatatypeInfoVersion = 1000 // 1000 means 1.000. Structure HDF5DatatypeInfo // Use with HDF5TypeInfo functions // Input fields (inputs to HDF5 XOP) uint32 version // Structure version. Used for backward compatibility. char structName[32] // Must be "HDF5DatatypeInfo". Used to prevent passing wrong structure to XFUNC. // Output fields (outputs from HDF5 XOP) double type_class // e.g., H5T_INTEGER, H5T_FLOAT. char type_class_str[32] // String with class spelled out. e.g., "H5T_INTEGER", "H5T_FLOAT". double size // Size in bytes of one element. double sign // H5T_SGN_NONE (unsigned), H5T_SGN_2 (signed), H5T_SGN_ERROR (this type does not have a sign, i.e., it is not an integer type). double order // H5T_ORDER_LE, H5T_ORDER_BE, H5T_ORDER_VAX, H5T_ORDER_ERROR (this type does not have an order). double cset // H5T_CSET_ASCII, H5T_CSET_UTF8, H5T_CSET_ERROR double strpad // H5T_str_t: H5T_STR_ERROR, H5T_STR_NULLTERM, H5T_STR_NULLPAD, H5T_STR_SPACEPAD double nmembers // For enum or compound datatypes only, number of members. String names // For enum or compound datatypes only, semicolon-separated list of enum names. int32 values[100] // For enum datatype only, list of enum values. For compound datatype, list of classes. String opaque_tag // For opaque datatypes only, tag name. EndStructure Function InitHDF5DatatypeInfo(dti) // Sets input fields. STRUCT HDF5DatatypeInfo &dti // HDF5XOP uses these fields to make sure the structure passed in to it is compatible. dti.version = kHDF5DatatypeInfoVersion dti.structName = "HDF5DatatypeInfo" End // ************* End of HDF5 Utility Routines *************** // ************* Start of HDF5 Save Routines *************** static Function StringsAreEqual(str1, str2) // Case sensitive String str1, str2 Variable len1=strlen(str1), len2=strlen(str2) if (len1 != len2) return 0 endif Variable i for(i=0; i<len1; i+=1) if (char2num(str1[i]) != char2num(str2[i])) return 0 endif endfor return 1 End static Function/S GetUnquotedLeafName(path) String path // Path to data folder or wave String name name = ParseFilePath(0, path, ":", 1, 0) // Just the name without path. // Remove single quotes if present if (CmpStr(name[0],"'") == 0) Variable len = strlen(name) name = name[1,len-2] endif return name End static Function HaveObjectNameConflict(listOfObjectsInGroup, listOfObjectsToBeSaved, conflictingObjectName) String listOfObjectsInGroup // Semicolon-separated list of all types of objects in selected group or list of datasets in selected group. String listOfObjectsToBeSaved // Semicolon-separated list of names of objects about to be saved in the HDF5 file. String &conflictingObjectName conflictingObjectName = "" Variable i, j Variable numObjectsInList, numObjectsToBeSaved numObjectsInList = ItemsInList(listOfObjectsInGroup) numObjectsToBeSaved = ItemsInList(listOfObjectsToBeSaved) for(i=0; i<numObjectsToBeSaved; i+=1) String objectToBeSavedName = StringFromList(i, listOfObjectsToBeSaved) objectToBeSavedName = GetUnquotedLeafName(objectToBeSavedName) // Just the name without path. if (CmpStr(objectToBeSavedName, "root") == 0) objectToBeSavedName = IgorInfo(1) // Use name of current experiment instead of "root". endif for(j=0; j<numObjectsInList; j+=1) String groupObjectName = StringFromList(j, listOfObjectsInGroup) if (StringsAreEqual(groupObjectName,objectToBeSavedName)) conflictingObjectName = groupObjectName return 1 endif endfor endfor return 0 End static Function SaveButtonProc(ctrlName) : ButtonControl String ctrlName String panelName = WinName(0, 64) String message String list = WS_SelectedObjectsList(panelName, "SelectorList") if (strlen(list) == 0) strswitch(panelName) case "HDF5SaveWavesPanel": DoAlert 0, "You must select one or more waves to save first." break case "HDF5SaveDataFolderPanel": DoAlert 0, "You must select a data folder to save first." break endswitch return -1 endif String browserName = HDF5GetTopBrowserName() if (strlen(browserName) == 0) return -1 // HDF5 Browser was killed. endif STRUCT HDF5BrowserData bd SetHDF5BrowserData(browserName, bd) // Get list of all types of objects in the selected group (including named datasets and links) HDF5ListGroup /TYPE=15 bd.fileID, bd.groupPath String listOfObjectsInSelectedGroup = S_HDF5ListGroup Variable haveConflict String conflictingObjectName haveConflict = HaveObjectNameConflict(listOfObjectsInSelectedGroup,list,conflictingObjectName) if (haveConflict) sprintf message, "The name '%s' is in use.\r\rOverwrite objects with conflicting names?", conflictingObjectName DoAlert 1, message if (V_flag != 1) return -1 endif endif ControlInfo /W=$panelName IncludeIgorAttributes Variable igorAttributesMask = V_value ? -1 : 0 Variable varMode = V_value ? 1 : 0 String groupPath = SelectedGroupPath(bd) // Currently selected group String newGroupPath = "" // Name of group we created, if any. Variable index = 0 do String item = StringFromList(index, list) if (strlen(item) == 0) break // No more waves endif strswitch(panelName) case "HDF5SaveWavesPanel": Wave w = $item String datasetPath = HDF5GetObjectFullPath(groupPath, NameOfWave(w)) HDF5SaveData /IGOR=(igorAttributesMask) /O w, bd.fileID, datasetPath break case "HDF5SaveDataFolderPanel": String dfName = ParseFilePath(0, item, ":", 1, 0) // Just the data folder name without path. if (CmpStr(item, "root") == 0) dfName = IgorInfo(1) // Use name of current experiment instead of "root". endif newGroupPath = HDF5GetObjectFullPath(groupPath, dfName) ControlInfo/W=$panelName SaveGroupsRecursively if (V_value) HDF5SaveGroup /IGOR=(igorAttributesMask) /VAR=(varMode) /O /R /T=dfName $item, bd.fileID, groupPath else HDF5SaveGroup /IGOR=(igorAttributesMask) /VAR=(varMode) /O /T=dfName $item, bd.fileID, groupPath endif break endswitch if (V_flag != 0) break // Save error. endif index += 1 while(1) strswitch(panelName) case "HDF5SaveWavesPanel": FillDatasetsList(bd) FillDatasetAttributesList(bd) SetButtonStates(bd) // Needed to set Load Dataset button if we go from 0 datasets to >0 datasets. break case "HDF5SaveDataFolderPanel": if (strlen(newGroupPath) > 0) FillLists(bd) endif break endswitch End static Function DoneButtonProc(ctrlName) : ButtonControl String ctrlName String panelName = WinName(0, 64) DoWindow/K $panelName End static Function GetPrefSavePanelSettings(saveGroupsRecursively, includeIgorAttributes) Variable &saveGroupsRecursively Variable &includeIgorAttributes STRUCT HDF5BrowserPrefs prefs HDF5BrowserLoadPackagePrefs(prefs) saveGroupsRecursively = prefs.saveGroupsRecursively includeIgorAttributes = prefs.includeIgorAttributes End static Function SetPrefSavePanelSettings(panelName) String panelName STRUCT HDF5BrowserPrefs prefs HDF5BrowserLoadPackagePrefs(prefs) strswitch(panelName) case "HDF5SaveWavesPanel": ControlInfo/W=$panelName IncludeIgorAttributes prefs.includeIgorAttributes = V_value break case "HDF5SaveDataFolderPanel": ControlInfo/W=$panelName SaveGroupsRecursively prefs.saveGroupsRecursively = V_value ControlInfo/W=$panelName IncludeIgorAttributes prefs.includeIgorAttributes = V_value break endswitch HDF5BrowserSavePackagePrefs(prefs) End static Function SetSaveButtonState(panelName) String panelName String selection = WS_SelectedObjectsList(panelName, "SelectorList") Variable code = strlen(selection) > 0 ? 0:2 Button Save, win=$panelName, disable=code End Function HDF5SaveWavesPanelHook(infoStr) String infoStr String panelName = "HDF5SaveWavesPanel" String event= StringByKey("EVENT",infoStr) strswitch(event) case "activate": // We do not get this on Windows when the panel is first created. SetSaveButtonState(panelName) break case "resize": case "moved": // This message was added in Igor Pro 5.04B07. SetPrefWindowCoords(panelName) break endswitch return 0 End Function HDF5SaveDataFolderPanelHook(infoStr) String infoStr String panelName = "HDF5SaveDataFolderPanel" String event= StringByKey("EVENT",infoStr) strswitch(event) case "activate": // We do not get this on Windows when the panel is first created. SetSaveButtonState(panelName) break case "resize": case "moved": // This message was added in Igor Pro 5.04B07. SetPrefWindowCoords(panelName) break endswitch return 0 End static Function DisplaySaveWavesPanel() String panelName = "HDF5SaveWavesPanel" DoWindow/F $panelName if (V_flag == 0) Variable left, top, right, bottom GetPrefWindowCoords(panelName, left, top, right, bottom) // See if prefs set. if (right-left<200 || bottom-top<200) left = 200 top = 100 right = 584 bottom = 632 endif Variable recursive, includeIgorAttributes GetPrefSavePanelSettings(recursive, includeIgorAttributes) Variable showWhat = WMWS_Waves NewPanel /W=(left,top,right,bottom) /N=$panelName /K=1 as "Save Waves as HDF5 Datasets" TitleBox ListTitle,pos={20,16},size={163,16},title="Select Wave(s) to Save as Datasets" TitleBox ListTitle,fSize=14,frame=0,fStyle=1 ListBox SelectorList,pos={16,48},size={350,390},mode=4 // Multiple disjoint selection allowed. MakeListIntoWaveSelector(panelName, "SelectorList", content=showWhat) WS_SetNotificationProc(panelName, "SelectorList", "SelectorNotification", isExtendedProc=1) Button Save,pos={46,457},size={100,20},proc=HDF5Browser#SaveButtonProc,title="Save" Button Done,pos={226,457},size={100,20},proc=HDF5Browser#DoneButtonProc,title="Done" CheckBox IncludeIgorAttributes,pos={36,488},size={121,14},title="Include Igor Attributes" CheckBox IncludeIgorAttributes,proc=HDF5BrowserPrefCheckboxProc,help={"When checked, attributes are written so that wave properties can be recreated when loading back into Igor."} CheckBox IncludeIgorAttributes,value=includeIgorAttributes SetSaveButtonState(panelName) SetWindow kwTopWin,hook=HDF5SaveWavesPanelHook endif End static Function DisplaySaveDataFolderPanel() String panelName = "HDF5SaveDataFolderPanel" DoWindow/F $panelName if (V_flag == 0) Variable left, top, right, bottom GetPrefWindowCoords(panelName, left, top, right, bottom) // See if prefs set. if (right-left<200 || bottom-top<200) left = 200 top = 100 right = 584 bottom = 632 endif Variable recursive, includeIgorAttributes GetPrefSavePanelSettings(recursive, includeIgorAttributes) Variable showWhat = WMWS_DataFolders NewPanel /W=(left,top,right,bottom) /N=$panelName /K=1 as "Save Data Folder as HDF5 Group" TitleBox ListTitle,pos={20,16},size={163,16},title="Select Data Folder to Save as Group" TitleBox ListTitle,fSize=14,frame=0,fStyle=1 ListBox SelectorList,pos={16,48},size={350,390},mode=1 // Single selection only. MakeListIntoWaveSelector(panelName, "SelectorList", content=showWhat) WS_SetNotificationProc(panelName, "SelectorList", "SelectorNotification", isExtendedProc=1) Button Save,pos={46,457},size={100,20},proc=HDF5Browser#SaveButtonProc,title="Save" Button Done,pos={226,457},size={100,20},proc=HDF5Browser#DoneButtonProc,title="Done" CheckBox SaveGroupsRecursively,pos={44,485},size={66,14},title="Save Groups Recursive",value=recursive CheckBox SaveGroupsRecursively,proc=HDF5BrowserPrefCheckboxProc,help={"When checked, sub-data folders are recursively saved."} CheckBox IncludeIgorAttributes,pos={44,507},size={121,14},title="Include Igor Attributes" CheckBox IncludeIgorAttributes,proc=HDF5BrowserPrefCheckboxProc,help={"When checked, attributes are written so that wave properties can be recreated when loading back into Igor."} CheckBox IncludeIgorAttributes,value=includeIgorAttributes SetSaveButtonState(panelName) SetWindow kwTopWin,hook=HDF5SaveDataFolderPanelHook endif End Function SelectorNotification(SelectedItem, EventCode, panelName, controlName) String SelectedItem Variable EventCode String panelName String controlName // Printf "Panel=%s, Control=%s, Event code=%d, selection=\"%s\"\r", panelName, controlName, eventCode, selectedItem switch(eventCode) case WMWS_DoubleClick: break case WMWS_FolderOpened: // Selection is emptied when folder is opened. case WMWS_FolderClosed: // Selection is emptied when folder is opened. case WMWS_SelectionChanged: case WMWS_SelectionChangedShift: SetSaveButtonState(panelName) break endswitch End static Function SaveWavesButtonProc(ctrlName) : ButtonControl String ctrlName DoWindow/K HDF5SaveDataFolderPanel // One save panel open at a time. DisplaySaveWavesPanel() return 0 End static Function SaveDataFolderButtonProc(ctrlName) : ButtonControl String ctrlName DoWindow/K HDF5SaveWavesPanel // One save panel open at a time. DisplaySaveDataFolderPanel() return 0 End static Function CloseSavePanels() DoWindow/K HDF5SaveWavesPanel DoWindow/K HDF5SaveDataFolderPanel End static Function HDF5SaveWavesPanelIsVisible() DoWindow HDF5SaveWavesPanel return V_flag End static Function HDF5SaveDFPanelIsVisible() DoWindow HDF5SaveDataFolderPanel return V_flag End // ************* End of HDF5 Save Routines ***************
I want to implement it into my own code what are the things that I need to change.
August 7, 2018 at 06:25 am - Permalink
That huge code-dump is WaveMetrics code that ships with Igor.
You have not explained to us what your aim is. Why do you need to change it at all? It's good code, I know the author well and he writes good code.
To improve your chances of getting an answer, here are some tips:
http://stackoverflow.com/help/how-to-ask
August 7, 2018 at 09:27 am - Permalink
dear johnweeks,
I had posted my problems regarding not able to call the HDF5 Load/ Open Group/Load Data due to some simple errors which i had posted previously but due to lack of community support I had to start looking around for my self then I had hit a technical snag and IGOR threw me the Errors iin the HDF5 Browser code so now i think that i shall change some features of the browser code for my own.
Here is the Link for my previous question:https://www.wavemetrics.com/forum/general/hdf5-issues-when-trying-open-and-load-it-through-program
ps No offense.
August 7, 2018 at 07:51 pm - Permalink
Please take no offense in this, but your above post comes over as somewhat aggressive. I would recommend you have a good look at the link John posted. In short:
- You are not explaining what you want to do exactly.
- You are not explaining what 'is not working' for you.
- Instead you just post dumps of code and many posts in a row without the patience to wait for answers.
How do you expect that anybody can help you this way? If you want help, please make everybody's life easier in providing the necessary (and not unnecessary) information to help in the first place. And please note that many users do not get paid and are not ready to answer any question 24/7. I have some experience in programming with HDF5 files and have read your last post. But I saw no way of helping you, short of recreating the type of data you are using and writing a test environment for testing every case what might be wrong without reading your mind. I hope there will be a way to solve your problems, which we are all interested in (and that's what the forum is for).
August 7, 2018 at 09:55 pm - Permalink
In reply to Please take no offense in… by chozo
well I had clearly stated that "I just want to load HDF5 files in IGOR through a computer program written in IGOR" . I never asked for an analysis code so why do I need to post a set of information pertaining to data and recreating testing environment. open and loading a specific type of file consists of every possible case if browser can do it, then HDF5LoadData call,HDF5OpenGroup,HDF5OpenFile shall satisfy the same purpose, isn't it?
ps: no offense.
August 8, 2018 at 05:53 am - Permalink