//--version--1.6
// 1.6 adds the '?' button that points to the wiki page
//     panel labels are now drawn on an overlay
//     added overlay commands and copy to system clipboard to the rightclick menu
// Montage tools for easy montage manipulation
// jerome.mutterer at ibmp.fr

var str="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var lcas=false;
var antialiasedLabels = true;
var n=0;
var xoffset=0.05;
var yoffset=0.05;
var pos="Clicked quadrant";

var commands = newArray("Copy", "Paste","-", "Scale Bar...", 
    "Brightness/Contrast...", "-", "Extract Selected Panels","Crop Montage [F3]","-",
    "Add Panel to Manager [F1]","Selected panels to stack [F2]", "Montage to Stack", "-",
    "Fit Clipboard content into panel [F4]","Fill Panel with Clipboard content [F5]","-",
    "Set Montage Layout","Change Montage Layout","-",
    "Hide Overlay","Show Overlay", "Remove Overlay", "Flatten", "-",
    "Copy to System"));

var toolCmds = newMenu("Magic Montage Menu Tool",commands);
var pmCmds = newMenu("Popup Menu",commands);
 
macro "Popup Menu" {
   runCommand();
}

macro "Auto Montage Action Tool - C66fF0077C6f6F9977Cf66F9077C888F0977" {
    setBatchMode(true);
    b=bitDepth;
    if ((b!=24)&&(nSlices==1)) 	{ exit("Stack, Composite, or RGB image required.");}
    if ((b==24)&&(nSlices==1)) 	{ run("Make Composite"); b=8;}
    Stack.getDimensions(width, height, channels, slices, frames);
    getVoxelSize(xp,yp,zp,unit);
    if (channels==1) { channels = channels* frames*slices; Stack.setDimensions(channels,1,1); }
    id=getImageID;
    t=getTitle;
    if (b!=24) {
        newImage("tempmont", "RGB", width, height,channels);
        id2=getImageID;
        for (i=1;i<=channels;i++) {
            setPasteMode("copy");
            selectImage(id);
            Stack.setChannel(i);
            getLut(r,g,b);
            run("Duplicate...", "title=temp"+i);
            setLut(r,g,b);
            run("RGB Color");
            run("Copy");
            selectImage(id2);
            setSlice(i);
            run("Paste");
        }
    }
    run("Make Montage...", "scale=1 border=0");
    rename(getTitle+" of "+t);
    setVoxelSize(xp,yp,zp,unit);
    setBatchMode(false);
}

macro "Select Panels Tool - Cf44R0077R9077C888R9977R0977"{
    run("Select None");
    setPasteMode("copy");
    w = getWidth;
    h = getHeight;
    getCursorLoc(x, y, z, flags);
    id=getImageID;
    t=getTitle;
    selectImage(id);
    xn = info("xMontage");
    yn = info("yMontage");
    if ((xn==0)||(yn==0))
       exit;
    xc = floor(x/(w/xn));
    yc = floor(y/(h/yn));
    makeRectangle(xc*(w/xn),yc*(h/yn),(w/xn),(h/yn));
    xstart = x; ystart = y;
    x2=x; y2=y;
    x2c=xc;y2c=yc;
    while (flags&16 !=0) {
        getCursorLoc(x, y, z, flags);
        if (x!=x2 || y!=y2) {
            x2c = floor(x/(w/xn));
            y2c = floor(y/(h/yn));
            makeRectangle(xc*(w/xn),yc*(h/yn),(w/xn)*(x2c-xc+1),(h/yn)*(y2c-yc+1));
            x2=x; y2=y;
            wait(10);
        }
    }
    setPasteMode("add");
}

macro "Extract Selected Panels"{
    t=getTitle;
    xn = info("xMontage");
    yn = info("yMontage");
    pw = getWidth/xn;
    ph = getHeight/yn;
    run("Duplicate...", "title=[Extract of "+t+"]");
    setMetadata("Info","xMontage="+getWidth/pw+"\nyMontage="+getHeight/ph+"\n");
}

macro "Montage Shuffler Tool - C888R0077R9977C44fR0977R9077"{
    id=getImageID;
    run("Select None");
    setPasteMode("copy");
    w = getWidth;
    h = getHeight;
    getCursorLoc(x, y, z, flags);
    xn = info("xMontage");
    yn = info("yMontage");
    if ((xn==0)||(yn==0))
       exit;
    xstart = x; ystart = y;
    x2=x; y2=y;
    while (flags&16 !=0) {
        getCursorLoc(x, y, z, flags);
        if (x!=x2 || y!=y2) spring(xstart, ystart, x, y);
        x2=x; y2=y;
        wait(10);
    }
    if (x!=xstart || y!=ystart) {
        xext=0;
        yext=0;
        if (x>w) xext=1;
        if (y>h) yext=1;
        if ((xext>0)||(yext>0)) {
            run("Canvas Size...", "width="+w+xext*(w/xn)+" height="+h+yext*(h/yn)+" position=Top-Left zero");
            setMetadata("Info","xMontage="+(parseInt(xn)+parseInt(xext))+"\nyMontage="+(parseInt(yn)+parseInt(yext))+"\n");
            exit;
        }
        sc = floor(xstart/(w/xn));
        tc = floor(x/(w/xn));
        sr = floor(ystart/(h/yn));
        tr = floor(y/(h/yn));
        swap(sc,sr,tc,tr);

    }
}

macro "Annotation Tool - C700 T2709A T8709B T1f09C T8f09D" {
    xn = info("xMontage");
    yn = info("yMontage");
    
    getCursorLoc(x, y, z, flags);
    iw = getWidth/xn;
    ih = getHeight/yn;
    
    co = floor(x/iw);
    li = floor(y/ih);

    fontsize = ih/10;
    if (fontsize<12) fontsize=12;
    marque = substring(str,n,n+1);
    if (lcas==1) marque= toLowerCase(marque);
    opt="";

    if (pos == "Clicked quadrant") {
    xoffset=0.05; yoffset=0.05; 
    if (x>((co+0.5)*iw)) xoffset=0.90; 
    if (y<((li+0.5)*ih)) yoffset=0.85; 
    }

    if (antialiasedLabels==true) opt=opt+"antialiased";
    setFont("SanSerif",fontsize, opt);
    fg = getValue("rgb.foreground");
    makeText(marque ,co*iw+xoffset*iw,(li+1)*ih-yoffset*ih-getValue("font.height"));
    Roi.setStrokeColor(fg&0xff0000>>16,fg&0x00ff00>>8,fg&0x0000ff);
    Overlay.addSelection("",0);
    run("Select None");
    n++; if (n>lengthOf(str)) n=0;
}

macro "Annotation Tool Options" {
    if (nImages>0) setupUndo;
    Dialog.create("Annotation - Options");
    Dialog.addString("Labels",str);
    Dialog.addCheckbox("Lowercase labels",lcas);
    Dialog.addCheckbox("Reset label counter",true);
    Dialog.addCheckbox("Antialiased",true);
    Dialog.addChoice("Position",newArray("Clicked quadrant","Lower left","Lower right","Upper right","Upper left"),pos);
    Dialog.show;
    str  = Dialog.getString;
    lcas = Dialog.getCheckbox;
    resetCounter = Dialog.getCheckbox;
    if (resetCounter==true)	n=0;
    antialiasedLabels = Dialog.getCheckbox;
    pos=Dialog.getChoice();
    if (pos=="Lower left") {xoffset=0.05; yoffset=0.05;}
    else if (pos=="Lower right") {xoffset=0.90; yoffset=0.05;}
    else if (pos=="Upper left") {xoffset=0.05; yoffset=0.85;}
    else if (pos=="Upper right") {xoffset=0.90; yoffset=0.85;}

}

macro "Montage Sync Tool - C800L07f7L707fG" {
    w=getWidth;
    h= getHeight;
    getCursorLoc(x,y,z,flags);
    xn = info("xMontage");
    yn = info("yMontage");
    if ((xn==0)||(yn==0)) {
       run("Set Montage Layout");
       exit;
    }
    xc = floor(x/(w/xn));
    yc = floor(y/(h/yn));
    x0 = x-xc*w/xn;
    y0 = y-yc*h/yn;
    np = 1*xn*yn;
    xp =newArray(np);
    yp =newArray(np);
    for (i=0;i<xn;i++) {
        for (j=0;j<yn;j++) {
            xp[j*xn+i] = x0+i*(w/xn);
            yp[j*xn+i] = y0+j*(h/yn);
        }
    }
    makeSelection("point yellow large hybred",xp,yp);
}

macro "Magic Montage Menu Tool - C800G027ff200" {
   runCommand();
}

function runCommand() {
   cmd = getArgument();
    if (cmd=="Scale Bar...")
       doCommand(cmd);
    else
       run(getArgument());
}

macro "Magic Montage Help Action Tool - C911T4e18?"{
     run("URL...", "url=http://wsr.imagej.net/macros/toolsets/MagicMontage.pdf");
      //run("URL...", "url=http://imagejdocu.tudor.lu/doku.php?id=howto:working:work_with_magic_montage");     
}

// Returns numeric value associated with 'key' or 0 if not found. 
function info(key) {
   value = getInfo(key);
   if (value=="")
      return 0;
   else
      return parseInt(value);
}

function swap(a,b,c,d) {
    setupUndo;
    setBatchMode(true);
    makeRectangle(a*(w/xn),b*(h/yn),(w/xn),(h/yn));
    run("Duplicate...", "title=tmp");
    selectImage(id);
    makeRectangle(c*(w/xn),d*(h/yn),(w/xn),(h/yn));
    run("Copy");
    makeRectangle(a*(w/xn),b*(h/yn),(w/xn),(h/yn));
    run("Paste");
    selectWindow("tmp");
    run("Select All");
    run("Copy");
    selectImage(id);
    makeRectangle(c*(w/xn),d*(h/yn),(w/xn),(h/yn));
    run("Paste");
    run("Select None");
    setBatchMode(false);
}

function spring(x0,y0,x1,y1) {
    d = sqrt((y1-y0)*(y1-y0)+(x1-x0)*(x1-x0));
    step=3;
    r=15;
    xa = newArray(floor(d/step));
    ya = newArray(xa.length);
    for (i=0;i<xa.length;i++) {
        j=i*step;
        xa[i]=x0+j*(x1-x0)/d+sin(j/7)*r;
        ya[i]=y0+j*(y1-y0)/d+cos(j/7)*r;
    }
    if (xa.length>1) {
        xa[0]=x0;
        ya[0]=y0;
        xa[xa.length-1]=x1;
        ya[ya.length-1]=y1;
    }
    makeSelection("freeline",xa,ya);
}

macro "Add Panel to Manager [F1]" {
    roiManager("Add");
    setOption("Show All",true);
}

macro "Montage to Stack" {
   columns = info("xMontage");
   rows = info("yMontage");
   if (rows==0 || columns==0) {
       run("Set Montage Layout");
       columns = info("xMontage");
       rows = info("yMontage");
    }
   run("Montage to Stack...", "columns=&columns rows=&rows");
}

macro "Selected panels to stack [F2]" {
    id=getImageID;
    t=getTitle;
    selectImage(id);
    roiManager("select",0);
    getSelectionBounds(x,y,sw,sh);
    setBatchMode(true);
    newImage("Extracted Panels of "+t, "RGB", sw,sh,roiManager("count"));
    id2=getImageID;
    setPasteMode("copy");
    for (i=0;i<roiManager("count");i++) {
        selectImage(id);
        roiManager("select",i);
        run("Copy");
        selectImage(id2);
        setSlice(i+1);
        run("Paste");
    }
    setBatchMode(false);
}

macro "Crop Montage [F3]" {
    setBatchMode(true);
    setPasteMode("copy");
    w=getWidth;
    h= getHeight;
    b=bitDepth;
    getSelectionBounds(x,y,sw,sh);
    t=getTitle;
    id=getImageID;
    getVoxelSize(xp,yp,zp,unit);
    xn = info("xMontage");
    yn = info("yMontage");
    xc = floor(x/(w/xn));
    yc = floor(y/(h/yn));
    xpa = x-xc*(w/xn);
    ypa= y-yc*(h/yn);
    newImage("Crop of "+t,b+"RGB",sw,sh,(xn)*(yn));
    id2=getImageID;
    for (j=0;j<yn;j++) {
        for (i=0;i<xn;i++) {
            selectImage(id);
            makeRectangle(i*(w/xn)+xpa,j*(h/yn)+ypa,sw,sh);
            run("Copy");
            selectImage(id2);
            setSlice(j*(xn)+i+1);
            run("Paste");
        }
    }
    setVoxelSize(xp,yp,zp,unit);
    setBatchMode(false);
    setSlice(nSlices);
    setSlice(1);
}

macro "Fit Clipboard content into panel [F4]" {
    getSelectionBounds(x,y,sw,sh);
    id=getImageID;
    setBatchMode(true);
    ffp=sw/sh;
    run("Internal Clipboard");
    run("RGB Color");
    ffc=getWidth/getHeight;
    if (ffc>ffp) {
        run("Size...", "width="+sw+" height="+sw/ffc+" constrain interpolate");
        run("Canvas Size...", "width="+sw+" height="+sh+" position=Center zero");
    } else {
        run("Size...", "width="+sh*ffc+" height="+sh+" constrain interpolate");
        run("Canvas Size...", "width="+sw+" height="+sh+" position=Center zero");
    }
    run("Copy");
    close;
    selectImage(id);
    setBatchMode(false);
    setPasteMode("Copy");
    run("Paste");
}

macro "Fill Panel with Clipboard content [F5]" {
    getSelectionBounds(x,y,sw,sh);
    id=getImageID;
    setBatchMode(true);
    ffp=sw/sh;
    run("Internal Clipboard");
    run("RGB Color");
    ffc=getWidth/getHeight;
    if (ffc>ffp) {
        run("Size...", "width="+sw*ffc+" height="+sh+" constrain interpolate");
        run("Canvas Size...", "width="+sw+" height="+sh+" position=Center zero");
    } else {
        run("Size...", "width="+sw+" height="+sh/ffc+" constrain interpolate");
        run("Canvas Size...", "width="+sw+" height="+sh+" position=Center zero");
    }
    run("Copy");
    close;
    selectImage(id);
    setBatchMode(false);
    setPasteMode("Copy");
    run("Paste");
    
}

macro "Set Montage Layout" {
    columns = info("xMontage");
    rows = info("yMontage");
    if (columns>0 && rows>0)
       exit("Layout ("+columns+"x"+rows+") is already set");
    Dialog.create("Set Montage Layout");
    Dialog.addNumber("Width:", 2);
    Dialog.addNumber("Height:", 2);
    Dialog.show;
    mw = Dialog.getNumber;
    mh = Dialog.getNumber;
    setMetadata("Info","xMontage="+mw+"\nyMontage="+mh+"\n");
}

macro "Change Montage Layout" {
   columns = info("xMontage");
   rows = info("yMontage");
   if (rows==0 || columns==0) {
       run("Set Montage Layout");
       columns = info("xMontage");
       rows = info("yMontage");
    }
    id1 = getImageID;
    title = getTitle;
    getVoxelSize(xp,yp,zp,unit);
    Dialog.create("Change Montage Layout");
    Dialog.addNumber("Columns:", columns);
    Dialog.addNumber("Rows:", rows);
    Dialog.show;
    columns2 = Dialog.getNumber;
    rows2 = Dialog.getNumber;
    run("Montage to Stack...", "columns=&columns rows=&rows");
    id2 = getImageID;
    run("Make Montage...", "columns=&columns2 rows=&rows2 scale=1.0");
    rename(title);
    setVoxelSize(xp,yp,zp,unit);
    selectImage(id1); close;
    selectImage(id2); close;
}

