new menu object
hi
i made this object sometime ago for my own use and have found it helpful so decided to make it available.
https://github.com/testcase/pmenu
it is a popup menu but works differently than umenu
the menu is populated by sending it a dictionary. the dictionary can contain the names of the menu entries as well as arbitrary data that can be associated with each entry. examples in help file
this is useful for creating hierarchical menus. also menus in which the menu items may have an array, dict, string associated with it. this could represent lists, data, javascript code, scripting instructions, compressed patchers ...
there is only a mac version in the repo but there is no reason it could not be compiled for windows. if anyone wants to do that let me know.
it is pattr aware and preset aware. styles don't seem to work not sure what i am doing wrong.
would love to see this just built into max as regular object.
pmenu
Description
Pop-up menu for Max/MSP/Jitter with hierarchical listings.
Installation
This is setup in a package structure. Clone or unzip in your Max Package folder.
Details
Displays a pop-up menu. Selections will be output the first outlet and optional data can be attached to each entry.
The object must be initialized with a dict. Once initialized the menu items are saved with the patch. The pmenu can also be copied and retains menu entries. The dictionary needs to have at the top level a name key which is a string and a contents key which points to an array. the array can hold strings, other dictionaries with name and content keys (for submenus). Entries in the menu can also be a dictionary with a name key and data key. The values in the data key are ouput the 3rd outlet when the menu item is selected.
Only mac version of object is currently in repo but if anyone wants to compile for Window that would be great.
This is wonderful! Thank you for making this.
Hi there. This obj is wonderful, but there's not the explanation how to build the Dict for it (aka the Folder tree). Now here is a way to do it:
1. download this package: https://drive.google.com/file/d/1mZcmpiEBTtGhrryTK88bs0XvblUQubC5/view?fbclid=IwAR0AmiN0VqLarLwVjku4XUoBCNEEAlEqLd_2xam4irz07mmMZQQxll5PTMQ
2. perform a modification to the nodes js Lib file:
'use strict';
const FS = require('fs');
const PATH = require('path');
const constants = {
DIRECTORY: 'directory',
FILE: 'file'
}
function safeReadDirSync (path) {
let dirData = {};
try {
dirData = FS.readdirSync(path);
} catch(ex) {
if (ex.code == "EACCES")
//User does not have permissions, ignore directory
return null;
else throw ex;
}
return dirData;
}
/**
* Normalizes windows style paths by replacing double backslahes with single forward slahes (unix style).
* @param {string} path
* @return {string}
*/
function normalizePath(path) {
return path.replace(/\\/g, '/');
}
/**
* Tests if the supplied parameter is of type RegExp
* @param {any} regExp
* @return {Boolean}
*/
function isRegExp(regExp) {
return typeof regExp === "object" && regExp.constructor == RegExp;
}
/**
* Collects the files and folders for a directory path into an Object, subject
* to the options supplied, and invoking optional
* @param {String} path
* @param {Object} options
* @param {function} onEachFile
* @param {function} onEachDirectory
* @return {Object}
*/
function directoryTree (path, options, onEachFile, onEachDirectory) {
const name = PATH.basename(path);
const data = path;
path = options && options.normalizePath ? normalizePath(path) : path;
const item = { data, name };
let stats;
try { stats = FS.statSync(path); }
catch (e) { return null; }
// Skip if it matches the exclude regex
if (options && options.exclude) {
const excludes = isRegExp(options.exclude) ? [options.exclude] : options.exclude;
if (excludes.some((exclusion) => exclusion.test(path))) {
return null;
}
}
if (stats.isFile()) {
const ext = PATH.extname(path).toLowerCase();
// Skip if it does not match the extension regex
if (options && options.extensions && !options.extensions.test(ext))
return null;
//item.size = stats.size; // File size in bytes
//item.extension = ext;
//item.type = constants.FILE;
if (options && options.attributes) {
options.attributes.forEach((attribute) => {
item[attribute] = stats[attribute];
});
}
if (onEachFile) {
onEachFile(item, PATH, stats);
}
}
else if (stats.isDirectory()) {
let dirData = safeReadDirSync(path);
if (dirData === null) return null;
if (options && options.attributes) {
options.attributes.forEach((attribute) => {
item[attribute] = stats[attribute];
});
}
item.contents = dirData
.map(child => directoryTree(PATH.join(path, child), options, onEachFile, onEachDirectory))
.filter(e => !!e);
item.size = item.contents.reduce((prev, cur) => prev + cur.size, 0);
item.type = constants.DIRECTORY;
if (onEachDirectory) {
onEachDirectory(item, PATH, stats);
}
} else {
return null; // Or set item.size = 0 for devices, FIFO and sockets ?
}
return item;
}
module.exports = directoryTree;

3. build this patch

And here the system to view the files inside the pmenu (self explanatory):

Hi, i would like to use this hierarchical listing menu to visualize the objects exposed to pattrstorage, grouped by abstraction into which they are located.
Exemple if have three bpatchers named SPEED, REPO, SCATTER and they contain different named parameters, i would end with the menu showing off these name and their content.
I found this really hard to achieve since I cant'd find a solid way to build arrays of object by message to the dict object.
Any hint or help would be much appreciated