/* Toolset Creator
 * http://rsb.info.nih.gov/ij/macros/toolsets/Toolset%20Creator.txt
 *
 * Makes tool sets of 'Menu Tools' listing commands of plugins subfolders
 * 
 * The Menus will list all [".ijm",".js"] files (v1.41 and later) and [".class",".jar",
 * ".txt",".ijm",".js"], files that have at least one underscore in the filename);
 *
 * v. 07 - Fixed: File.separator not working for Windows;
 * v .06 - Added: Dropped support for macros subfolders listings (Wayne Rasband's suggestion);
 *                With IJ 1.41n any macro moved to the plugins folder with the ".ijm" extension
 *                no longer requires an "_" in the name to be installed in the plugins menu.
 * v .05 - Added: .ijm and .js support (Wayne Rasband);
 *       - Added: Append Menus from different sources;
 * v .04 - Fixed: macros subfolders not working properly (at all, actually);
 *       - Added: (only for macros): 
 *                'List All', Open/Install with 'shift' and 'alt';
 * v .03 - Added: AutoRun;
 *       - Added: more icons choice;
 *       - Fixed: cleaned code;
 * v .02 - Fixed: subfolders containing hyphens;
 *       - Added: possibility for macros subfolders listing;
 *       - Added: acknowledge when no executable is found on subfolder;
 *
 * Icons based on other tools listed at http://rsb.info.nih.gov/ij/macros/tools/
 * or created with Jerome Mutterer's 'Image To Tool Icon' macro:
 * http://rsb.info.nih.gov/ij/macros/tools/Image_To_Tool_Icon.txt
 * 
 * Tiago Fereira, 2008.10 
 * ferreira<at>embl<dot>it
 */
var alphaindex=   newArray("a","b","c","d","e","f","g","h");
var items=        newArray(" -- None -- ","Bricks","Depth","Dump","Gear","Histogram","Hourglass","Image","List (I)","List (II)","Measure","Movie","Reduce","Sigma","Shuffle","Stacks","Tag","Tiles (filled)","Tiles (frame)","Tool","Write");
var colors=       newArray("Default","Black","Gray","Red","Green","Blue");
var icons=        newArray("",
                  "D00D03D06D09D0cD0fD10D13D16D19D1cD1fD20D21D22D23D26D27D28D29D2cD2dD2eD2fD30D33D36D39D3cD3fD40D43D46D49D4cD4fD50D53D54D55D56D59D5aD5bD5cD5fD60D63D66D69D6cD6fD70D73D76D79D7cD7fD80D83D86D89D8cD8fD90D91D92D93D96D97D98D99D9cD9dD9eD9fDa0Da3Da6Da9Db0Db3Db6Db9Dc0Dc3Dc4Dc5Dc6Dc9DcaDcbDd0Dd3Dd6Dd9De0De3De6De9Df0Df3Df6Df9", // Bricks
                  "D20D21D2bD2cD2dD30D3aD3dD40D49D4dD50D58D5dD60D67D6dD70D76D7dD80D85D8dD90D94D9dDa0Da3DadDb0Db1Db2DbcDbd", // Depth
                  "D2aD2bD2cD2dD2eD3eD4eD58D5eD68D69D6eD71D72D73D74D75D76D77D78D79D7aD7eD81D82D83D84D85D86D87D88D89D8aD8bD8eD91D92D93D94D95D96D97D98D99D9aD9bD9eDa1Da2Da3Da4Da5Da6Da7Da8Da9DaaDaeDb8Db9DbeDc8DceDdeDeeDfaDfbDfcDfdDfe", // Dump
                  "D49D33D34D35D36D37D38D39D3aD43D44D45D46D47D48D4aD53D54D55D58D59D5aD63D64D69D6aD73D74D79D7aD83D84D85D89D8aD93D94D95D96D97D98D99D9aDa3Da5Da6Da7Da8Da9DaaD88Da4D26D62D6bDb6D27D72D7bDb7D16D61D6cDc6D23D2aD32D3bDa2DabDb3DbaD17D71D7cDc7CaaaD57D75D78D87CaaaD56D65D68D86CaaaCbbbCcccD24D29D42D4bD92D9bDb4Db9CcccD22D2bDb2CcccDbbCcccCdddCeeeD5bCeeeD25D28D52D82D8bDb5Db8CeeeCfffD0bD4cD77Db0Dc2DccDd7", // Gear 
                  "D1eD2dD1fD2eD3cD3dD4bD4cD5aD5bD6aD14D15D16D17D18D19D1aD1bD1cD1dD20D21D22D23D24D25D26D27D28D29D2aD2bD2cD2fD33D34D35D36D37D38D39D3aD3bD3eD3fD47D48D49D4aD4dD4eD4fD5cD5dD5eD5fD6bD6cD6dD6eD6fD7dD7eD7fD8dD8eD8fD9dD9eD9fDaeDafDbeDbfDcfDdf", // Histogram
                  "D10D1fD20D21D22D2dD2eD2fD30D33D3cD3fD40D44D4bD4fD50D55D5aD5fD60D66D67D68D69D6fD70D75D7aD7fD80D84D8bD8fD90D93D9cD9fDa0Da1Da2DadDaeDafDb0Dbf", // Hourglass
                  "R01fbR2397", // Image
                  "L00f0L03f3L06f6L09f9L0cfcL0fbf", // Continuous list
                  "L00a0L03f3L06a6L09c9L0cfcL0fbf", // Indented list
                  "L15f5L1519Lf5f9L8885L5855Lb8b5", // Measure
                  "D00D01D02D03D04D05D06D07D08D09D0aD0bD0cD0dD0eD0fD12D17D1cD22D27D2cD30D31D32D33D34D35D36D37D38D39D3aD3bD3cD3dD3eD3fD40D4bD50D5bD60D6bD70D7bD80D8bD90D9bDa0DabDb0Db1Db2Db3Db4Db5Db6Db7Db8Db9DbaDbbDbcDbdDbeDbfDc2Dc7DccDd2Dd7DdcDe0De1De2De3De4De5De6De7De8De9DeaDebDecDedDeeDef", // Movie
                  "D17D23D27D2bD33D34D37D3aD3bD40D41D42D43D44D45D47D49D4aD4bD4cD4dD4eD53D54D57D5aD5bD63D67D6bD77D83D87D8bD93D94D97D9aD9bDa0Da1Da2Da3Da4Da5Da7Da9DaaDabDacDadDaeDb3Db4Db7DbaDbbDc3Dc7DcbDd7", // Reduce
                  "D00D01D02D03D0dD0eD0fD10D11D12D13D14D1cD1dD1eD1fD20D21D24D25D2bD2cD2eD2fD30D31D35D36D3aD3bD3eD3fD40D41D46D47D49D4aD4eD4fD50D51D57D58D59D5eD5fD60D61D68D6eD6fD70D71D7eD7fD80D81D82D83D8cD8dD8eD8fD90D91D92D93D9cD9dD9eD9f", //Sigma
                  "D05D06D07D16D17D25D27D2aD34D3bD43D4cD52D5dD5fD6eD6fD7dD7eD7fD80D81D82D90D91Da0Da2DadDb3DbcDc4DcbDd5Dd8DdaDe8De9Df8Df9Dfa", // Shuffle
                  "L00f0L01f1L04f4L05f5L08f8L09f9L0cbcL0dbd", // Stacks
                  "D22D23D24D25D26D27D32D33D34D35D36D37D38D42D43D46D47D48D49D52D53D56D57D58D59D5aD62D63D64D65D66D67D68D69D6aD6bD72D73D74D75D76D77D78D79D7aD7bD7cD83D84D85D86D87D88D89D8aD8bD8cD8dD94D95D96D97D98D99D9aD9bD9cD9dD9eDa5Da6Da7Da8Da9DaaDabDacDadDaeDb6Db7Db8Db9DbaDbbDbcDbdDc7Dc8Dc9DcaDcbDccDd8Dd9DdaDdbDe9Dea", // Tag
                  "F0077F9977F9077F0977", // Tiles (filled)
                  "R0077R9077R9977R0977", // Tiles (frame)
                  "D3eD4eD5eD6bD6cD6dD7aD89D98Da7Db6Dc6Dd6De4De5D2aD5dDa2Dd5D59D68D69D77D78D86D87D96D1aD1bD1cD29D2bD39D49D4bD4cD4dD58D67D76D85D92D93D94Da1Db1Db2Db4Dc1Dc4Dd4De3D5aD6aD79D88D95D97Da5Da6D19D91D4aD5bDa4Db5D3aD5cDa3Dc5", // Tool
                  "D1dD2aD2bD2cD37D38D39D3aD3bD3eD43D44D45D46D47D48D49D4aD4dD4eD53D54D55D56D57D58D59D5cD5dD63D64D65D66D67D68D6bD6cD6dD73D74D75D76D77D7aD7bD7cD7dD84D85D86D87D89D8aD8bD8cD92D93D95D96D97D98D99D9aD9bD9cDa1Da2Da3Da4Da6Da7Da8Da9DaaDabDacDb2Db3Db4Db5Db7Db8Db9DbaDbbDbcDc3Dc4Dc5Dc6Dc8Dc9DcaDcbDccDd4Dd5Dd6De5De6" // Write
                  );
         
showMessage("Toolset Creator...", "This macro must be installed before running.\n \n"+
                                  "For convenience, copy this file into the /macros/toolsets/ folder\n"+
                                  "and it will be accessible through the '>>' drop down menu.");

macro "Toolset Creator" {
        folders= listDirs(getDirectory("plugins")); 
    Dialog.create("Toolset Creator...");
    Dialog.addString("Toolset name (without extension)","",20);
    Dialog.addNumber("Containing how many tools? (1-7)",2);
    Dialog.show;
        n=      Dialog.getNumber;
        name=   Dialog.getString;
        parent= Dialog.getChoice;
    if(n<1||n>7) exit("The number of tools must be between 1 and 7");
    if(name==""||name==" ") showMessageWithCancel("Toolset Creator...","Proceed with an empty name?\nThis file may not be recognized by your OS."); 
        path= getDirectory("macros");
    if(path=="") exit("macros directory not found!\n \nToolset cannot be saved");
        path= getDirectory("macros")+"toolsets"+File.separator;
    if(!File.exists(path)) {File.makeDirectory(path); showStatus("Toolset folder created");}
        path= getDirectory("macros")+"toolsets"+File.separator+name+".txt";
    if(File.exists(path)) showMessageWithCancel("Toolset Creator","A file named "+name+".txt already exists.\nOverwrite?");
        f= File.open(path);
    printHeader();
    for (i=1; i<n+1; i++) promptForSettings();
    printFoot();
    print("Toolset '"+name+"' created");
    print("You can now install it by using the '>>' drop down menu");
    print("To edit list filters hold down 'shift' while clicking the menu");
    if(getVersion>='1.41l') run("Update Menus");
}

macro "AutoRun"{
    wait(15);
    run("Toolset Creator");
}
   
// Functions:
function listDirs(plgn) {
        msg= "This macro creates toolsets from plugins\n"+
             "subfolders populated with executable files.\n"+
             "Please create the files and restart again...";
    if (!File.exists(plgn)) exit("plugins directory not found!\n \n"+msg);
        rawlist= getFileList(plgn);
        count= 0;
    for (i=0; i< rawlist.length; i++) if (endsWith(rawlist[i], '/')) count++;
    if (count==0) exit("No subfolders found in the plugins directory.\n \n"+msg);
        list= newArray(count); index =0;
    for (i=0; i< rawlist.length; i++) {
    if (endsWith(rawlist[i], '/'))
        list[index++] = substring(rawlist[i], 0, lengthOf(rawlist[i])-1);
    }
    return list;
 }     
function printHeader() {
    getDateAndTime(year, month, week, day, hour, min, sec, msec);
    print(f,"/* File generated with the 'Toolset Creator' macro");
    print(f," * ");
    print(f," * Filename:  '"+name+".txt'");
    print(f," * Created:    "+year+"."+pad(month)+"."+day+" "+hour+":"+min+":"+sec);
    print(f," * ");
    print(f," * Edit the two lines below '// Settings:' to change which files");
    print(f," * should be listed (e.g. you can exclude .jar files implementing");
    print(f," * multiple commands via a plugins.config file)");
    print(f," * ");
    print(f," * For '.ijm' and '.js' files use key modifiers while selecting an");
    print(f," * item from the list: 'shift': opens the macro file;");
    print(f," *                     'alt':   installs the macro;");
    print(f," */");
    print(f,"");
    print(f,"// Settings:");
    print(f,"var AllowedFileExtensions= newArray('class','txt','ijm','jar','js');");
    print(f,"var IgnoreFilenamesContaining= newArray('$','//','//','//');");
    print(f,"");
    print(f,"");
    print(f,"// Macros:");
    print(f," macro 'Unused Tool -' {}");
    print(f,"");
 }
function pad(n) {
    n= toString(n); if(lengthOf(n)==1) n="0"+n;return n;
}
function promptForSettings() {
    Dialog.create("Toolset Creator...  Slot "+i+" of "+n);
    Dialog.addChoice("Folder to list",folders);
    Dialog.addChoice("Icon drawing",items,"- None -");
    Dialog.addChoice("Icon color",colors,"Gray")
    Dialog.addString("Icon text","(2-chr max.)",11);
    Dialog.addChoice("Text color",colors,"Default")
    Dialog.show();
       folder=   Dialog.getChoice;
       idraw =   Dialog.getChoice;
       idrawC=   Dialog.getChoice;
       itext=    Dialog.getString;
       itextC=   Dialog.getChoice;
       j=        alphaindex[i-1];
       idrawC=   colorConverter(idrawC);
       itextC=   colorConverter(itextC);
       icon=     makeIcon(idraw, idrawC, itext,itextC);
       mcrname=  replace(folder, "-", "");
    print(f,"       var "+j+"List= getPluginList('"+folder+"');");
    print(f,"       var "+j+"Cmds= newMenu('"+mcrname+" Menu Tool',"+j+"List);");
    print(f," macro '"+mcrname+" Menu Tool - "+icon+"' {");
    print(f,"       cmd = getArgument();");
    print(f,"       if (cmd!='-') run(cmd);");
    print(f," }");
    print(f,"");	  
}
function printFoot() {
    print(f,"");
    print(f,"// Functions:");
    print(f,"function getPluginList(subfolder) {");   
    print(f,"       dir=  getDirectory('plugins')+subfolder+File.separator;");
    print(f,"       list= newArray(''+subfolder+' not found','in the plugins directory...');");
    print(f,"   if (!File.exists(dir)) return list;");
    print(f,"       rawlist= getFileList(dir);");
    print(f,"       count=   0;");
    print(f,"   for (i=0; i< rawlist.length; i++) {");
    print(f,"       isMacro= (getVersion>='1.41n') && (endsWith(rawlist[i],'.ijm')||endsWith(rawlist[i],'.js'));");
    print(f,"     if (indexOf(rawlist[i], '_')==-1&&!isMacro) rawlist[i]='-';");
    print(f,"   for (h=0; h<IgnoreFilenamesContaining.length; h++)");
    print(f,"     if (indexOf(rawlist[i], IgnoreFilenamesContaining[h])!=-1) rawlist[i]='-';");'
    print(f,"       rawlist[i]=replace(rawlist[i],'_',' ');");
    print(f,"   for (j=0; j<AllowedFileExtensions.length; j++)");
    print(f,"     if (endsWith(rawlist[i],AllowedFileExtensions[j]))count++;");
    print(f,"    }");
    print(f,"     if(count==0) list=newArray('No executable found','on '+''+subfolder);");
    print(f,"     else");
    print(f,"       list=  newArray(count);");
    print(f,"       index= 0;");
    print(f,"   for (i=0; i< rawlist.length; i++) {");
    print(f,"   for (h=0; h< AllowedFileExtensions.length; h++) {");
    print(f,"       cmdlength=lengthOf(rawlist[i])-lengthOf(AllowedFileExtensions[h])-1;");
    print(f,"     if (endsWith(rawlist[i], AllowedFileExtensions[h]))");
    print(f,"       list[index++] = substring(rawlist[i], 0, cmdlength);");
    print(f,"       }");
    print(f,"    }");
    print(f,"   return list;");
    print(f,"}");
}
function colorConverter(color) {
    if(color=="Default")    color ="C037";
    else if(color=="Black") color ="C000";
    else if(color=="Gray")  color ="C555";
    else if(color=="Red")   color ="C900";
    else if(color=="Green") color ="C090";
    else if(color=="Blue")  color ="C009";
    return color;
 }
function makeIcon(idraw, idrawC, itext,itextC) {
    for (i=0; i< items.length; i++) if(idraw ==items[i]) idraw =icons[i];
    if(startsWith(itext, "(2")) itext="  ";
    if(lengthOf(itext)==1) itext=itext+" ";
       itext1= substring(itext, 0, 1);
       itext2= substring(itext, 1, 2);
       idrawC= colorConverter(idrawC);
       itextC= colorConverter(itextC);
       finalicon=""+itextC+"T1d13"+""+itext1+"T9d13"+""+itext2+""+idrawC+""+idraw;
    return finalicon;
 }
