package ij.gui;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.*;
import java.io.File;
import java.util.*;
import ij.*;
import ij.plugin.frame.Recorder;
import ij.plugin.frame.Editor; 
import ij.plugin.MacroInstaller;
import ij.plugin.RectToolOptions;
import ij.plugin.tool.PlugInTool;
import ij.plugin.tool.MacroToolRunner;
import ij.macro.Program;

/** The ImageJ toolbar. */
public class Toolbar extends Canvas implements MouseListener, MouseMotionListener, ItemListener, ActionListener {

	public static final int RECTANGLE = 0;
	public static final int OVAL = 1;
	public static final int POLYGON = 2;
	public static final int FREEROI = 3;
	public static final int LINE = 4;
	public static final int POLYLINE = 5;
	public static final int FREELINE = 6;
	public static final int POINT = 7, CROSSHAIR = 7;
	public static final int WAND = 8;
	public static final int TEXT = 9;
	public static final int UNUSED = 10;
	public static final int MAGNIFIER = 11;
	public static final int HAND = 12;
	public static final int DROPPER = 13;
	public static final int ANGLE = 14;
	public static final int CUSTOM1 = 15;
	public static final int CUSTOM2 = 16;
	public static final int CUSTOM3 = 17;
	public static final int CUSTOM4 = 18;
	public static final int CUSTOM5 = 19;
	public static final int CUSTOM6 = 20;
	public static final int CUSTOM7 = 21;
	
	public static final int DOUBLE_CLICK_THRESHOLD = 650;

	public static final int RECT_ROI=0, ROUNDED_RECT_ROI=1, ROTATED_RECT_ROI=2;
	public static final int OVAL_ROI=0, ELLIPSE_ROI=1, BRUSH_ROI=2;
	
	private static final String[] builtInTools = {"Arrow","Brush","Command Finder", "Developer Menu","Flood Filler",
		"LUT Menu","Overlay Brush","Pencil","Pixel Inspector","Selection Rotator", "Smooth Wand",
		"Spray Can","Stacks Menu"};
	private static final String[] builtInTools2 = {"Pixel Inspection Tool","Paintbrush Tool","Flood Fill Tool"};

	private static final int NUM_TOOLS = 23;
	private static final int MAX_EXTRA_TOOLS = 8;
	private static final int MAX_TOOLS = NUM_TOOLS+MAX_EXTRA_TOOLS;
	private static final int NUM_BUTTONS = 21;
	private static final int BUTTON_WIDTH = 28;
	private static final int BUTTON_HEIGHT = 29;
	private static final int SIZE = 28;  // no longer used
	private static final int GAP_SIZE = 9;
	private static final int OFFSET = 6;
	private static final String BRUSH_SIZE = "toolbar.brush.size";
	public static final String CORNER_DIAMETER = "toolbar.arc.size";
	public static String TOOL_KEY = "toolbar.tool";
		
	private Dimension ps = new Dimension(BUTTON_WIDTH*NUM_BUTTONS-(BUTTON_WIDTH-GAP_SIZE), BUTTON_HEIGHT);
	private boolean[] down;
	private static int current;
	private int previous;
	private int x,y;
	private int xOffset, yOffset;
	private long mouseDownTime;
	private Graphics g;
	private static Toolbar instance;
	private int mpPrevious = RECTANGLE;
	private String[] names = new String[MAX_TOOLS];
	private String[] icons = new String[MAX_TOOLS];
	private PlugInTool[] tools = new PlugInTool[MAX_TOOLS];
	private PopupMenu[] menus = new PopupMenu[MAX_TOOLS];
	private int nExtraTools;
	private MacroInstaller macroInstaller;
	private boolean addingSingleTool;
	private boolean installingStartupTool;
	private boolean doNotSavePrefs;
	private int pc;
	private String icon;
	private int startupTime;
	private PopupMenu rectPopup, ovalPopup, pointPopup, linePopup, switchPopup;
	private CheckboxMenuItem rectItem, roundRectItem, rotatedRectItem;
	private CheckboxMenuItem ovalItem, ellipseItem, brushItem;
	private CheckboxMenuItem pointItem, multiPointItem;
	private CheckboxMenuItem straightLineItem, polyLineItem, freeLineItem, arrowItem;
	private String currentSet = "Startup Macros";

	private static Color foregroundColor = Prefs.getColor(Prefs.FCOLOR,Color.white);
	private static Color backgroundColor = Prefs.getColor(Prefs.BCOLOR,Color.black);
	private static int ovalType = OVAL_ROI;
	private static int rectType = RECT_ROI;
	private static boolean multiPointMode = Prefs.multiPointMode;
	private static boolean arrowMode;
	private static int brushSize = (int)Prefs.get(BRUSH_SIZE, 15);
	private static int arcSize = (int)Prefs.get(CORNER_DIAMETER, 20);
	private int lineType = LINE;
	private static boolean legacyMode;
	//private static BasicStroke widerLine = new BasicStroke(1.5f);
	
	private Color gray = new Color(228,228,228);
	private Color brighter = gray.brighter();
	private Color darker = new Color(180, 180, 180);
	private Color evenDarker = new Color(110, 110, 110);
	private Color triangleColor = new Color(150, 0, 0);
	private Color toolColor = new Color(0, 25, 45);
	
	/** Obsolete public constants */
	public static final int SPARE1=UNUSED, SPARE2=CUSTOM1, SPARE3=CUSTOM2, SPARE4=CUSTOM3, 
		SPARE5=CUSTOM4, SPARE6=CUSTOM5, SPARE7=CUSTOM6, SPARE8=CUSTOM7, SPARE9=22;


	public Toolbar() {
		down = new boolean[MAX_TOOLS];
		resetButtons();
		down[0] = true;
		setForeground(Color.black);
		setBackground(ImageJ.backgroundColor);
		addMouseListener(this);
		addMouseMotionListener(this);
		instance = this;
		names[getNumTools()-1] = "\"More Tools\" menu (switch toolsets or add tools)";
		icons[getNumTools()-1] = "C900T1e15>T7e15>"; // ">>"
		addPopupMenus();
	}

	void addPopupMenus() {
		rectPopup = new PopupMenu();
		if (Menus.getFontSize()!=0)
			rectPopup.setFont(Menus.getFont());
		rectItem = new CheckboxMenuItem("Rectangle", rectType==RECT_ROI);
		rectItem.addItemListener(this);
		rectPopup.add(rectItem);
		roundRectItem = new CheckboxMenuItem("Rounded Rectangle", rectType==ROUNDED_RECT_ROI);
		roundRectItem.addItemListener(this);
		rectPopup.add(roundRectItem);
		rotatedRectItem = new CheckboxMenuItem("Rotated Rectangle", rectType==ROTATED_RECT_ROI);
		rotatedRectItem.addItemListener(this);
		rectPopup.add(rotatedRectItem);
		add(rectPopup);

		ovalPopup = new PopupMenu();
		if (Menus.getFontSize()!=0)
			ovalPopup.setFont(Menus.getFont());
		ovalItem = new CheckboxMenuItem("Oval selections", ovalType==OVAL_ROI);
		ovalItem.addItemListener(this);
		ovalPopup.add(ovalItem);
		ellipseItem = new CheckboxMenuItem("Elliptical selections", ovalType==ELLIPSE_ROI);
		ellipseItem.addItemListener(this);
		ovalPopup.add(ellipseItem);
		brushItem = new CheckboxMenuItem("Selection Brush Tool", ovalType==BRUSH_ROI);
		brushItem.addItemListener(this);
		ovalPopup.add(brushItem);
		add(ovalPopup);

		pointPopup = new PopupMenu();
		if (Menus.getFontSize()!=0)
			pointPopup.setFont(Menus.getFont());
		pointItem = new CheckboxMenuItem("Point Tool", !multiPointMode);
		pointItem.addItemListener(this);
		pointPopup.add(pointItem);
		multiPointItem = new CheckboxMenuItem("Multi-point Tool", multiPointMode);
		multiPointItem.addItemListener(this);
		pointPopup.add(multiPointItem);
		add(pointPopup);

		linePopup = new PopupMenu();
		if (Menus.getFontSize()!=0)
			linePopup.setFont(Menus.getFont());
		straightLineItem = new CheckboxMenuItem("Straight Line", lineType==LINE&&!arrowMode);
		straightLineItem.addItemListener(this);
		linePopup.add(straightLineItem);
		polyLineItem = new CheckboxMenuItem("Segmented Line", lineType==POLYLINE);
		polyLineItem.addItemListener(this);
		linePopup.add(polyLineItem);
		freeLineItem = new CheckboxMenuItem("Freehand Line", lineType==FREELINE);
		freeLineItem.addItemListener(this);
		linePopup.add(freeLineItem);
		arrowItem = new CheckboxMenuItem("Arrow tool", lineType==LINE&&!arrowMode);
		arrowItem.addItemListener(this);
		linePopup.add(arrowItem);
		add(linePopup);

		switchPopup = new PopupMenu();
		if (Menus.getFontSize()!=0)
			switchPopup.setFont(Menus.getFont());
		add(switchPopup);
	}
	
	/** Returns the ID of the current tool (Toolbar.RECTANGLE, Toolbar.OVAL, etc.). */
	public static int getToolId() {
		int id = current;
		if (legacyMode) {
			if (id==CUSTOM1)
				id=UNUSED;
			else if (id>=CUSTOM2)
				id--;
		}
		return id;
	}

	/** Returns the ID of the tool whose name (the description displayed in the status bar)
		starts with the specified string, or -1 if the tool is not found. */
	public int getToolId(String name) {
		int tool =  -1;
		for (int i=0; i=CUSTOM1)
				tool++;
			if ((tool==POLYLINE && lineType!=POLYLINE) || (tool==FREELINE && lineType!=FREELINE))
				return;
		}
        int index = toolIndex(tool);
        int x = index*BUTTON_WIDTH + 1;
        if (tool>=CUSTOM1)
        	x -= BUTTON_WIDTH-GAP_SIZE;
        if (tool!=UNUSED)
        	fill3DRect(g, x, 1, BUTTON_WIDTH, BUTTON_HEIGHT-1, !down[tool]);
        g.setColor(toolColor);
        x = index*BUTTON_WIDTH + OFFSET;
        if (tool>=CUSTOM1)
        	x -= BUTTON_WIDTH-GAP_SIZE;
		int y = OFFSET;
		if (down[tool]) { x++; y++;}
		this.g = g;
		if (tool>=CUSTOM1 && tool<=getNumTools() && icons[tool]!=null) {
			drawIcon(g, tool, x+1, y+1);
			return;
		}
		switch (tool) {
			case RECTANGLE:
				xOffset = x; yOffset = y;
				if (rectType==ROUNDED_RECT_ROI)
					g.drawRoundRect(x-1, y+1, 17, 13, 8, 8);
				else if (rectType==ROTATED_RECT_ROI)
					polyline(0,10,7,0,15,6,8,16,0,10); 
				else
					g.drawRect(x-1, y+1, 17, 13);
				drawTriangle(16,15);
				return;
			case OVAL:
				xOffset = x; yOffset = y;
				if (ovalType==BRUSH_ROI) {
					yOffset = y - 1;
					polyline(6,4,8,2,12,1,15,2,16,4,15,7,12,8,9,11,9,14,6,16,2,16,0,13,1,10,4,9,6,7,6,4);
				} else if (ovalType==ELLIPSE_ROI) {
					xOffset = x - 1;
					yOffset = y + 1;
					polyline(11,0,13,0,14,1,15,1,16,2,17,3,17,7,12,12,11,12,10,13,8,13,7,14,4,14,3,13,2,13,1,12,1,11,0,10,0,9,1,8,1,7,6,2,7,2,8,1,10,1,11,0);
				} else
					g.drawOval(x, y+1, 17, 13);
				drawTriangle(16,15);
				return;
			case POLYGON:
				xOffset = x+1; yOffset = y+2;
				polyline(4,0,15,0,15,1,11,5,11,6,14,11,14,12,0,12,0,4,4,0);
				return;
			case FREEROI:
				xOffset = x; yOffset = y+3;
				polyline(2,0,5,0,7,3,10,3,12,0,15,0,17,2,17,5,16,8,13,10,11,11,6,11,4,10,1,8,0,6,0,2,2,0); 
				return;
			case LINE:
				xOffset = x; yOffset = y;
				if (arrowMode) {
					m(1,14); d(14,1); m(6,5); d(14,1); m(10,9); d(14,1); m(6,5); d(10,9);
				} else {
					m(0,12); d(17,3);
					drawDot(0,11); drawDot(17,2);
				}
				drawTriangle(15,15);
				return;
			case POLYLINE:
				xOffset = x; yOffset = y;
				polyline(15,6,11,2,1,2,1,3,7,9,2,14);
				drawTriangle(13,15);
				return;
			case FREELINE:
				xOffset = x; yOffset = y;
				polyline(16,4,14,6,12,6,9,3,8,3,6,7,2,11,1,11);
				drawTriangle(13,15);
				return;
			case POINT:
				xOffset = x; yOffset = y;
				if (multiPointMode) {
					drawPoint(1,3); drawPoint(9,1); drawPoint(15,5);
					drawPoint(10,11); drawPoint(2,12);
				} else {
					m(1,8); d(6,8); d(6,6); d(10,6); d(10,10); d(6,10); d(6,9);
					m(8,1); d(8,5); m(11,8); d(15,8); m(8,11); d(8,15);
					m(8,8); d(8,8);
					g.setColor(Roi.getColor());
					g.fillRect(x+7, y+7, 3, 3);
				}
				drawTriangle(15,15);
				return;
			case WAND:
				xOffset = x+2; yOffset = y+1;
				dot(4,0);  m(2,0); d(3,1); d(4,2);  m(0,0); d(1,1);
				m(0,2); d(1,3); d(2,4);  dot(0,4); m(3,3); d(13,13);
				g.setColor(Roi.getColor());
				m(1,2); d(3,2); m(2,1); d(2,3);
				return;
			case TEXT:
				xOffset = x+2; yOffset = y+1;
				m(0,13); d(3,13);
				m(1,12); d(7,0); d(12,13);
				m(11,13); d(14,13);
				m(3,8); d(10,8);
				return;
			case MAGNIFIER:
				xOffset = x+2; yOffset = y+2;
				polyline(3,0,3,0,5,0,8,3,8,5,7,6,7,7,6,7,5,8,3,8,0,5,0,3,3,0);
				polyline(8,8,9,8,13,12,13,13,12,13,8,9,8,8);
				return;
			case HAND:
				xOffset = x+1; yOffset = y+1;
				polyline(5,14,2,11,2,10,0,8,0,7,1,6,2,6,4,8,4,6,3,5,3,4,2,3,2,2,3,1,4,1,5,2,5,3);
				polyline(6,5,6,1,7,0,8,0,9,1,9,5,9,1,11,1,12,2,12,6);
				polyline(13,4,14,3,15,4,15,7,14,8,14,10,13,11,13,12,12,13,12,14);
				return;
			case DROPPER:
				xOffset = x; yOffset = y;
				g.setColor(foregroundColor);
				m(12,2); d(14,2);
				m(11,3); d(15,3);
				m(11,4); d(15,4);
				m(8,5); d(15,5);
				m(9,6); d(14,6);
				polyline(10,7,12,7,12,9);
				polyline(8,7,2,13,2,15,4,15,11,8);
				g.setColor(backgroundColor);
				polyline(-1,-1,18,-1,18,18,-1,18,-1,-1);
				return;
			case ANGLE:
				xOffset = x; yOffset = y+2;
				m(0,11); d(11,0); m(0,11); d(15,11); 
				m(10,11); d(10,8); m(9,7); d(9,6); dot(8,5);
				drawDot(11,-1); drawDot(15,10);
				return;
		}
	}
	
	void drawTriangle(int x, int y) {
		g.setColor(triangleColor);
		xOffset+=x; yOffset+=y;
		m(0,0); d(4,0); m(1,1); d(3,1); dot(2,2);
	}
	
	void drawDot(int x, int y) {
		g.fillRect(xOffset+x, yOffset+y, 2, 2);
	}

	void drawPoint(int x, int y) {
		g.setColor(toolColor);
		m(x-2,y); d(x+2,y);
		m(x,y-2); d(x,y+2);
		g.setColor(Roi.getColor());
		dot(x,y);
	}
	
	void drawIcon(Graphics g, int tool, int x, int y) {
		if (null==g) return;
		icon = icons[tool];
		if (icon==null) return;
		this.icon = icon;
		int x1, y1, x2, y2;
		pc = 0;
		while (true) {
			char command = icon.charAt(pc++);
			if (pc>=icon.length()) break;
			switch (command) {
				case 'B': x+=v(); y+=v(); break;  // reset base
				case 'R': g.drawRect(x+v(), y+v(), v(), v()); break;  // rectangle
				case 'F': g.fillRect(x+v(), y+v(), v(), v()); break;  // filled rectangle
				case 'O': g.drawOval(x+v(), y+v(), v(), v()); break;  // oval
				case 'V': case 'o': g.fillOval(x+v(), y+v(), v(), v()); break;  // filled oval
				case 'C': // set color
					int v1=v(), v2=v(), v3=v();
					int red=v1*16, green=v2*16, blue=v3*16;
					if (red>255) red=255; if (green>255) green=255; if (blue>255) blue=255;
					Color color = v1==1&&v2==2&&v3==3?foregroundColor:new Color(red,green,blue);
					g.setColor(color);
					break; 
				case 'L': g.drawLine(x+v(), y+v(), x+v(), y+v()); break; // line
				case 'D': g.fillRect(x+v(), y+v(), 1, 1); break; // dot
				case 'P': // polyline
					Polygon p = new Polygon();
					p.addPoint(x+v(), y+v());
					while (true) {
						x2=v(); if (x2==0) break;
						y2=v(); if (y2==0) break;
						p.addPoint(x+x2, y+y2);
					}
					g.drawPolyline(p.xpoints, p.ypoints, p.npoints);
					break;
				case 'G': case 'H':// polygon or filled polygon
					p = new Polygon();
					p.addPoint(x+v(), y+v());
					while (true) {
						x2=v(); y2=v();
						if (x2==0 && y2==0 && p.npoints>2)
							break;
						p.addPoint(x+x2, y+y2);
					}
					if (command=='G')
						g.drawPolygon(p.xpoints, p.ypoints, p.npoints);
					else
						g.fillPolygon(p.xpoints, p.ypoints, p.npoints);
					break;
				case 'T': // text (one character)
					x2 = x+v()-1;
					y2 = y+v();
					int size = v()*10+v()+1;
					char[] c = new char[1];
					c[0] = pc=icon.length()) break;
		}
		if (menus[tool]!=null && menus[tool].getItemCount()>0) { 
			xOffset = x; yOffset = y;
			drawTriangle(15, 15);
		}
	}
	
	int v() {
		if (pc>=icon.length()) return 0;
		char c = icon.charAt(pc++);
		switch (c) {
			case '0': return 0;
			case '1': return 1;
			case '2': return 2;
			case '3': return 3;
			case '4': return 4;
			case '5': return 5;
			case '6': return 6;
			case '7': return 7;
			case '8': return 8;
			case '9': return 9;
			case 'a': return 10;
			case 'b': return 11;
			case 'c': return 12;
			case 'd': return 13;
			case 'e': return 14;
			case 'f': return 15;
			case 'g': return 16;
			case 'h': return 17;
			default: return 0;
		}
	}
	
	private void showMessage(int tool) {
		if (tool>=UNUSED && tool=UNUSED && current=CUSTOM1)
			tool++;
		if (IJ.debugMode) IJ.log("Toolbar.setTool: "+tool);
		if ((tool==current&&!(tool==RECTANGLE||tool==OVAL||tool==POINT)) || tool<0 || tool>=getNumTools()-1)
			return;
		if (tool>=CUSTOM1&&tool<=getNumTools()-2) {
			if (names[tool]==null)
				names[tool] = "Spare tool"; // enable tool
			if (names[tool].indexOf("Action Tool")!=-1)
				return;
		}
		if (isLine(tool)) lineType = tool;
		setTool2(tool);
	}
		
	private void setTool2(int tool) {
		if (!isValidTool(tool)) return;
		String previousName = getToolName();
		current = tool;
		Graphics g = this.getGraphics();
		if (g==null)
			return;
		down[current] = true;
		if (current!=previous)
			down[previous] = false;
		if (Prefs.antialiasedTools) {
			Graphics2D g2d = (Graphics2D)g;
			g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		}
		drawButton(g, previous);
		drawButton(g, current);
		if (null==g) return;
		g.dispose();
		showMessage(current);
		previous = current;
		if (Recorder.record) {
			String name = getName(current);
			if (name!=null) {
				IJ.wait(100); // workaround for OSX/Java 8 bug
				Recorder.record("setTool", name);
			}
		}
		if (legacyMode)
			repaint();
		if (!previousName.equals(getToolName())) {
			IJ.notifyEventListeners(IJEventListener.TOOL_CHANGED);;
			repaint();
		}
	}
	
	boolean isValidTool(int tool) {
		if (tool<0 || tool>=getNumTools())
			return false;
		if (tool>=CUSTOM1 && toolBUTTON_WIDTH*12+GAP_SIZE)
			x -= GAP_SIZE;
		int index = x/BUTTON_WIDTH;
    	switch (index) {
			case 0: return RECTANGLE;
			case 1: return OVAL;
			case 2: return POLYGON;
			case 3: return FREEROI;
			case 4: return lineType;
			case 5: return ANGLE;
			case 6: return POINT;
			case 7: return WAND;
			case 8: return TEXT;
			case 9: return MAGNIFIER;
			case 10: return HAND;
			case 11: return DROPPER;
			default: return index + 3;
		}
    }
    
	private boolean inGap(int x) {
		return x>=(BUTTON_WIDTH*12) && x<(BUTTON_WIDTH*12+GAP_SIZE);
 	}

	public void mousePressed(MouseEvent e) {
		int x = e.getX();
		if (inGap(x))
			return;
 		int newTool = toolID(x);
		if (newTool==getNumTools()-1) {
			showSwitchPopupMenu(e);
			return;
		}
		if (!isValidTool(newTool))
			return;
		if (menus[newTool]!=null && menus[newTool].getItemCount()>0) {
            menus[newTool].show(e.getComponent(), e.getX(), e.getY());
			return;
		}
		boolean doubleClick = newTool==current && (System.currentTimeMillis()-mouseDownTime)<=DOUBLE_CLICK_THRESHOLD;
 		mouseDownTime = System.currentTimeMillis();
		if (!doubleClick) {
			mpPrevious = current;
			if (isMacroTool(newTool)) {
				String name = names[newTool];
				if (newTool==UNUSED || name.contains("Unused Tool"))
					return;
				if (name.indexOf("Action Tool")!=-1) {
					if (e.isPopupTrigger()||e.isMetaDown()) {
						name = name.endsWith(" ")?name:name+" ";
						tools[newTool].runMacroTool(name+"Options");
					} else {
						drawTool(newTool, true);
						IJ.wait(50);
						drawTool(newTool, false);
						runMacroTool(newTool);
					}
					return;
				} else {	
					name = name.endsWith(" ")?name:name+" ";
					tools[newTool].runMacroTool(name+"Selected");
				}
			}
			setTool2(newTool);
			boolean isRightClick = e.isPopupTrigger()||e.isMetaDown();
			if (current==RECTANGLE && isRightClick) {
				rectItem.setState(rectType==RECT_ROI);
				roundRectItem.setState(rectType==ROUNDED_RECT_ROI);
				rotatedRectItem.setState(rectType==ROTATED_RECT_ROI);
				if (IJ.isMacOSX()) IJ.wait(10);
				rectPopup.show(e.getComponent(),x,y);
				mouseDownTime = 0L;
			}
			if (current==OVAL && isRightClick) {
				ovalItem.setState(ovalType==OVAL_ROI);
				ellipseItem.setState(ovalType==ELLIPSE_ROI);
				brushItem.setState(ovalType==BRUSH_ROI);
				if (IJ.isMacOSX()) IJ.wait(10);
				ovalPopup.show(e.getComponent(),x,y);
				mouseDownTime = 0L;
			}
			if (current==POINT && isRightClick) {
				pointItem.setState(!multiPointMode);
				multiPointItem.setState(multiPointMode);
				if (IJ.isMacOSX()) IJ.wait(10);
				pointPopup.show(e.getComponent(),x,y);
				mouseDownTime = 0L;
			}
			if (isLine(current) && isRightClick) {
				straightLineItem.setState(lineType==LINE&&!arrowMode);
				polyLineItem.setState(lineType==POLYLINE);
				freeLineItem.setState(lineType==FREELINE);
				arrowItem.setState(lineType==LINE&&arrowMode);
				if (IJ.isMacOSX()) IJ.wait(10);
				linePopup.show(e.getComponent(),x,y);
				mouseDownTime = 0L;
			}
			if (isMacroTool(current) && isRightClick) {
				String name = names[current].endsWith(" ")?names[current]:names[current]+" ";
				tools[current].runMacroTool(name+"Options");
			}
			if (isPlugInTool(current) && isRightClick) {
				tools[current].showPopupMenu(e, this);
			}
		} else { //double click
			if (isMacroTool(current)) {
				String name = names[current].endsWith(" ")?names[current]:names[current]+" ";
				tools[current].runMacroTool(name+"Options");
				return;
			}
			if (isPlugInTool(current)) {
				tools[current].showOptionsDialog();
				return;
			}
			ImagePlus imp = WindowManager.getCurrentImage();
			switch (current) {
				case RECTANGLE:
					if (rectType==ROUNDED_RECT_ROI)
						IJ.doCommand("Rounded Rect Tool...");
					break;
				case OVAL:
					showBrushDialog();
					break;
				case MAGNIFIER:
					if (imp!=null) {
						ImageCanvas ic = imp.getCanvas();
						if (ic!=null) ic.unzoom();
					}
					break;
				case LINE: case POLYLINE: case FREELINE:
					if (current==LINE && arrowMode) {
						IJ.doCommand("Arrow Tool...");
					} else
						IJ.runPlugIn("ij.plugin.frame.LineWidthAdjuster", "");
					break;
				case ANGLE:
					showAngleDialog();
					break;
				case POINT:
					IJ.doCommand("Point Tool...");
					break;
				case WAND:
					IJ.doCommand("Wand Tool...");
					break;
				case TEXT:
					IJ.run("Fonts...");
					break;
				case DROPPER:
					IJ.doCommand("Color Picker...");
					setTool2(mpPrevious);
					break;
				default:
			}
		}
	}
	
	void showSwitchPopupMenu(MouseEvent e) {
		String path = IJ.getDir("macros")+"toolsets/";
		if (path==null)
			return;
		boolean applet = IJ.getApplet()!=null;
		File f = new File(path);
		String[] list;
		if (!applet && f.exists() && f.isDirectory()) {
			list = f.list();
			if (list==null) return;
		} else
			list = new String[0];
		switchPopup.removeAll();
        path = IJ.getDir("macros") + "StartupMacros.txt";
		f = new File(path);
		if (!f.exists()) {
			path = IJ.getDir("macros") + "StartupMacros.ijm";
			f = new File(path);
		}
		if (!applet && f.exists())
            addItem("Startup Macros");
        else
            addItem("StartupMacros*");
 		for (int i=0; i=5)
			pluginsMenu = menuBar.getMenu(5);
		if (pluginsMenu==null || !"Plugins".equals(pluginsMenu.getLabel()))
			return;
		n = pluginsMenu.getItemCount();
		Menu toolsMenu = null;
		for (int i=0; i=CUSTOM1 && tool=CUSTOM1 && toolTools submenu.\n"+
					" \n"+
					"Hold the shift key down while selecting a\n"+
					"toolset to view its source code.\n"+
					" \n"+
					"More macro toolsets are available at\n"+
					"  <"+IJ.URL+"/macros/toolsets/>\n"+
					" \n"+
					"Plugin tools can be downloaded from\n"+
					"the Tools section of the Plugins page at\n"+
					"  <"+IJ.URL+"/plugins/>\n"
					);
				return;
			} else if (label.endsWith("*")) {
                // load from ij.jar
                MacroInstaller mi = new MacroInstaller();
                label = label.substring(0, label.length()-1) + ".txt";
                path = "/macros/"+label;
                if (IJ.shiftKeyDown())
				    showCode(label, mi.openFromIJJar(path));
				else {
				    resetTools();
				    mi.installFromIJJar(path);
                }
            } else {
                // load from ImageJ/macros/toolsets
                if (label.equals("Startup Macros")) {
                	installStartupMacros();
                	return;
                } else if (label.endsWith(" "))
                    path = IJ.getDir("macros")+"toolsets"+File.separator+label.substring(0, label.length()-1)+".ijm";
                else
                    path = IJ.getDir("macros")+"toolsets"+File.separator+label+".txt";
                try {
                    if (IJ.shiftKeyDown()) {
                        IJ.open(path);
                		IJ.setKeyUp(KeyEvent.VK_SHIFT);
                    } else
                        new MacroInstaller().run(path);
                } catch(Exception ex) {}
            }
		}
	}
	
	private void removeTools() {
		removeMacroTools();
		setTool(RECTANGLE);
		currentSet = "Startup Macros";
		resetPrefs();
		if (nExtraTools>0) {
			String name = names[getNumTools()-1];
			String icon = icons[getNumTools()-1];
			nExtraTools = 0;
			names[getNumTools()-1] = name;
			icons[getNumTools()-1] = icon;
			ps = new Dimension(BUTTON_WIDTH*NUM_BUTTONS-(BUTTON_WIDTH-GAP_SIZE)+nExtraTools*BUTTON_WIDTH, BUTTON_HEIGHT);
			IJ.getInstance().pack();
		}
	}
	
	private void resetPrefs() {
		for (int i=0; i<7; i++) {
			String key = TOOL_KEY+(i/10)%10+i%10;
			if (!Prefs.get(key, "").equals(""))
				Prefs.set(key, "");
		}
	}
	
	public static void restoreTools() {
		Toolbar tb = Toolbar.getInstance();
		if (tb!=null) {
			if (tb.getToolId()>=UNUSED)
				tb.setTool(RECTANGLE);
			tb.installStartupMacros();
		}
	}

	private 	void installStartupMacros() {
		resetTools();
		String path = IJ.getDir("macros")+"StartupMacros.txt";
		File f = new File(path);
		if (!f.exists()) {
			path = IJ.getDir("macros")+"StartupMacros.ijm";
			f = new File(path);
		}
		if (!f.exists()) {
			path = IJ.getDir("macros")+"StartupMacros.fiji.ijm";
			f = new File(path);
		}
		if (!f.exists()) {
			IJ.error("StartupMacros not found in\n \n"+IJ.getDir("macros"));
			return;
		}
		if (IJ.shiftKeyDown()) {
			IJ.open(path);
			IJ.setKeyUp(KeyEvent.VK_SHIFT);
		} else {
			try {
				MacroInstaller mi = new MacroInstaller();
				mi.installFile(path);
			} catch
				(Exception ex) {}
		}
	}

	public void actionPerformed(ActionEvent e) {
		MenuItem item = (MenuItem)e.getSource();
		String cmd = e.getActionCommand();
		PopupMenu popup = (PopupMenu)item.getParent();
		int tool = -1;
		for (int i=CUSTOM1; i=0 && (toolTip.length()-index)>4;
		int tool =-1;
		for (int i=CUSTOM1; i<=getNumTools()-2; i++) {
			if (names[i]==null || toolTip.startsWith(names[i])) {
				tool = i;
				break;
			}			
		}
		if (tool==CUSTOM1)
			legacyMode = toolTip.startsWith("Select and Transform Tool"); //TrakEM2
		if (tool==-1 && (nExtraTools0 && toolTip.charAt(index-1)==' ')
				names[tool] = toolTip.substring(0, index-1);
			else
				names[tool] = toolTip.substring(0, index);
		} else {
			if (toolTip.endsWith("-"))
				toolTip = toolTip.substring(0, toolTip.length()-1);
			else if (toolTip.endsWith("- "))
				toolTip = toolTip.substring(0, toolTip.length()-2);
			names[tool] = toolTip;
		}
        if (tool==current && (names[tool].indexOf("Action Tool")!=-1||names[tool].indexOf("Unused Tool")!=-1))
        	setTool(RECTANGLE);
        if (names[tool].endsWith(" Menu Tool"))
            installMenu(tool);
        if (IJ.debugMode) IJ.log("Toolbar.addTool: "+tool+" "+toolTip);
		return tool;
	}
    
    void installMenu(int tool) {
        Program pgm = macroInstaller.getProgram();
        Hashtable h = pgm.getMenus();
        if (h==null) return;
        String[] commands = (String[])h.get(names[tool]);
        if (commands==null)
        	return;
		if (menus[tool]==null) {
			menus[tool] = new PopupMenu("");
			if (Menus.getFontSize()!=0)
				menus[tool].setFont(Menus.getFont());
			add(menus[tool] );
		} else
			menus[tool].removeAll();
        for (int i=0; i0 || custom1Name==null)
				setPrefs(tool);
		}
	}
	
	private void setPrefs(int id) {
		if (doNotSavePrefs)
			return;
		boolean ok = isBuiltInTool(names[id]);
		String prefsName = instance.names[id];
		if (!ok) {
			String name = names[id];
			int i = name.indexOf(" (");  // remove any hint in parens
			if (i>0) {
				name = name.substring(0, i);
				prefsName=name;
			}
		}
		int index = id - CUSTOM1;
		String key = TOOL_KEY + (index/10)%10 + index%10;
		Prefs.set(key, prefsName);
	}
	
	private boolean isBuiltInTool(String name) {
		for (int i=0; i=CUSTOM1)
				instance.setTool(RECTANGLE);
			instance.resetTools();
			instance.repaint();
		}
	}

	/** Adds a plugin tool to the first available toolbar slot,
		or to the last slot if the toolbar is full. */
	public static void addPlugInTool(PlugInTool tool) {
		if (instance==null) return;
		String nameAndIcon = tool.getToolName()+" - "+tool.getToolIcon();
		instance.addingSingleTool = true;
		int id = instance.addTool(nameAndIcon);
		instance.addingSingleTool = false;
		if (id!=-1) {
			instance.tools[id] = tool;
			if (instance.menus[id]!=null)
				instance.menus[id].removeAll();
			instance.repaintTool(id);	
			if (!instance.installingStartupTool)
				instance.setTool(id);
			else
				instance.installingStartupTool = false;
			instance.setPrefs(id);
		}
	}

	public static PlugInTool getPlugInTool() {
		PlugInTool tool = null;
		if (instance==null)
			return null;
		if (current2;
		return rtn;
	}
	
	public static boolean installStartupMacrosTools() {
		String customTool0 = Prefs.get(Toolbar.TOOL_KEY+"00", "");
		return customTool0.equals("") || Character.isDigit(customTool0.charAt(0));
	}
	
	public int getNumTools() {
		return NUM_TOOLS + nExtraTools;
	}

	//public void repaint() {
	//	super.repaint();
	//}

}

 

Ads help maintain this website.