Package ij.gui

Source Code of ij.gui.ImageCanvas

package ij.gui;

import java.awt.*;
import java.util.Properties;
import java.awt.image.*;
import ij.process.ImageProcessor;
import ij.measure.*;
import ij.plugin.frame.Recorder;
import ij.plugin.frame.RoiManager;
import ij.macro.*;
import ij.*;
import ij.util.*;
import java.awt.event.*;
import java.util.*;

/** This is a Canvas used to display images in a Window. */
public class ImageCanvas extends Canvas implements MouseListener, MouseMotionListener, Cloneable {

  protected static Cursor defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
  protected static Cursor handCursor = new Cursor(Cursor.HAND_CURSOR);
  protected static Cursor moveCursor = new Cursor(Cursor.MOVE_CURSOR);
  protected static Cursor crosshairCursor = new Cursor(Cursor.CROSSHAIR_CURSOR);

  public static boolean usePointer = Prefs.usePointerCursor;
 
  protected ImagePlus imp;
  protected boolean imageUpdated;
  protected Rectangle srcRect;
  protected int imageWidth, imageHeight;
  protected int xMouse; // current cursor offscreen x location
  protected int yMouse; // current cursor offscreen y location
 
  private boolean showCursorStatus = true;
  private int sx2, sy2;
  private boolean disablePopupMenu;
  private boolean showAllROIs;
  private static Color zoomIndicatorColor;
  private static Font smallFont, largeFont;
  private Rectangle[] labelRects;
    private boolean maxBoundsReset;
    private Vector displayList;
    private boolean labelListItems;
    private Color listColor;
    private BasicStroke listStroke;
    private static final int LIST_OFFSET = 100000;
    private static Color showAllColor = Prefs.getColor(Prefs.SHOW_ALL_COLOR, new Color(128, 255, 255));
    private static Color labelColor;
    private int resetMaxBoundsCount;
   
  protected ImageJ ij;
  protected double magnification;
  protected int dstWidth, dstHeight;

  protected int xMouseStart;
  protected int yMouseStart;
  protected int xSrcStart;
  protected int ySrcStart;
  protected int flags;
 
  private Image offScreenImage;
  private int offScreenWidth = 0;
  private int offScreenHeight = 0;
 
 
  public ImageCanvas(ImagePlus imp) {
    this.imp = imp;
    ij = IJ.getInstance();
    int width = imp.getWidth();
    int height = imp.getHeight();
    imageWidth = width;
    imageHeight = height;
    srcRect = new Rectangle(0, 0, imageWidth, imageHeight);
    setDrawingSize(imageWidth, (int)(imageHeight));
    magnification = 1.0;
     addMouseListener(this);
     addMouseMotionListener(this);
     addKeyListener(ij)// ImageJ handles keyboard shortcuts
    setFocusTraversalKeysEnabled(false);
  }
   
  void updateImage(ImagePlus imp) {
    this.imp = imp;
    int width = imp.getWidth();
    int height = imp.getHeight();
    imageWidth = width;
    imageHeight = height;
    srcRect = new Rectangle(0, 0, imageWidth, imageHeight);
    setDrawingSize(imageWidth, (int)imageHeight);
    magnification = 1.0;
  }

  /** Update this ImageCanvas to have the same zoom and scale settings as the one specified. */
  void update(ImageCanvas ic) {
    if (ic==null || ic==this || ic.imp==null)
      return;
    if (ic.imp.getWidth()!=imageWidth || ic.imp.getHeight()!=imageHeight)
      return;
    srcRect = new Rectangle(ic.srcRect.x, ic.srcRect.y, ic.srcRect.width, ic.srcRect.height);
    setMagnification(ic.magnification);
    setDrawingSize(ic.dstWidth, ic.dstHeight);
  }

  public void setDrawingSize(int width, int height) {
      dstWidth = width;
      dstHeight = height;
    setSize(dstWidth, dstHeight);
  }
   
  /** ImagePlus.updateAndDraw calls this method to get paint
    to update the image from the ImageProcessor. */
  public void setImageUpdated() {
    imageUpdated = true;
  }

  public void update(Graphics g) {
    paint(g);
  }

    public void paint(Graphics g) {
    Roi roi = imp.getRoi();
    if (roi != null) {
      roi.updatePaste();
      if (Prefs.doubleBuffer && !IJ.isMacOSX())
        {paintDoubleBuffered(g); return;}
    }
    try {
      if (imageUpdated) {
        imageUpdated = false;
        imp.updateImage();
      }
      Java2.setBilinearInterpolation(g, Prefs.interpolateScaledImages);
      Image img = imp.getImage();
      if (img!=null)
         g.drawImage(img, 0, 0, (int)(srcRect.width*magnification), (int)(srcRect.height*magnification),
        srcRect.x, srcRect.y, srcRect.x+srcRect.width, srcRect.y+srcRect.height, null);
      if (showAllROIs) showAllROIs(g);
      if (displayList!=null) drawDisplayList(g);
      if (roi != null) roi.draw(g);
      if (srcRect.width<imageWidth || srcRect.height<imageHeight)
        drawZoomIndicator(g);
      if (IJ.debugMode) showFrameRate(g);
    }
    catch(OutOfMemoryError e) {IJ.outOfMemory("Paint");}
    }
   
    void showAllROIs(Graphics g) {
    RoiManager rm=RoiManager.getInstance();
    if (rm==null) return;
    initGraphics(g, null);
    Hashtable rois = rm.getROIs();
    java.awt.List list = rm.getList();
    int n = list.getItemCount();
    if (labelRects==null || labelRects.length!=n)
      labelRects = new Rectangle[n];
    for (int i=0; i<n; i++) {
      String label = list.getItem(i);
      Roi roi = (Roi)rois.get(label);
      if (roi==null) continue;
      if (Prefs.showAllSliceOnly && imp.getStackSize()>1) {
        int slice = getSliceNumber(roi.getName());
        if (slice==-1 || slice==imp.getCurrentSlice())
          drawRoi(g, roi, i);
      } else
        drawRoi(g, roi, i);
    }
    }
   
  int getSliceNumber(String label) {
    if (label==null) return -1;
    int slice = -1;
    if (label.length()>4 && label.charAt(4)=='-' && label.length()>=14)
      slice = (int)Tools.parseDouble(label.substring(0,4),-1);
    return slice;
  }

    void drawDisplayList(Graphics g) {
    initGraphics(g, listColor);
      int n = displayList.size();
      for (int i=0; i<n; i++)
        drawRoi(g, (Roi)displayList.elementAt(i), labelListItems?i+LIST_OFFSET:-1);
      if (listStroke!=null) ((Graphics2D)g).setStroke(new BasicStroke());
    }
   
    void initGraphics(Graphics g, Color c) {
    if (smallFont==null) {
      smallFont = new Font("SansSerif", Font.PLAIN, 9);
      largeFont = new Font("SansSerif", Font.PLAIN, 12);
    }
    if (labelColor==null) {
      int red = showAllColor.getRed();
      int green = showAllColor.getGreen();
      int blue = showAllColor.getBlue();
      if ((red+green+blue)/3<128)
        labelColor = Color.white;
      else
        labelColor = Color.black;
    }
    if (c!=null) {
      g.setColor(c);
      if (listStroke!=null) ((Graphics2D)g).setStroke(listStroke);
    } else
      g.setColor(showAllColor);
    }
   
    void drawRoi(Graphics g, Roi roi, int index) {
    if (roi.getType()==Roi.COMPOSITE) {
      roi.setImage(imp);
      Color c = roi.getColor();
      if (index==-1 && listColor!=null)
        roi.setColor(listColor);
      else
        roi.setColor(showAllColor);
      roi.draw(g);
      roi.setColor(c);
      if (index>=0) drawRoiLabel(g, index, roi.getBounds());
    } else {
      Color c = index==-1?roi.getInstanceColor():null;
      Color saveg = null;
      if (c!=null) {
        saveg = g.getColor();
        g.setColor(c);
      }
      Polygon p = roi.getPolygon();
      int x1=0, y1=0, x2=0, y2=0;
      for (int j=0; j<p.npoints; j++) {
        x2 = screenX(p.xpoints[j]);
        y2 = screenY(p.ypoints[j]);
        if (j>0) g.drawLine(x1, y1, x2, y2);
        x1=x2; y1=y2;
      }
      if (roi.isArea()&&p.npoints>0) {
        int x0 = screenX(p.xpoints[0]);
        int y0 = screenY(p.ypoints[0]);
        g.drawLine(x1, y1, x0, y0);
      }
      if (index>=0) drawRoiLabel(g, index, roi.getBounds());
      if (saveg!=null) g.setColor(saveg);
    }
    }
   
  void drawRoiLabel(Graphics g, int index, Rectangle r) {
    int x = screenX(r.x);
    int y = screenY(r.y);
    double mag = getMagnification();
    int width = (int)(r.width*mag);
    int height = (int)(r.height*mag);
    int size = width>40 && height>40?12:9;
    if (size==12)
      g.setFont(largeFont);
    else
      g.setFont(smallFont);
    boolean drawingList = index >= LIST_OFFSET;
    if (drawingList) index -= LIST_OFFSET;
    String label = "" + (index+1);
    FontMetrics metrics = g.getFontMetrics();
    int w = metrics.stringWidth(label);
    x = x + width/2 - w/2;
    y = y + height/2 + Math.max(size/2,6);
    int h =  metrics.getHeight();
    g.fillRoundRect(x-1, y-h+2, w+1, h-3, 5, 5);
    if (!drawingList)
      labelRects[index] = new Rectangle(x-1, y-h+2, w+1, h-3);
    g.setColor(labelColor);
    g.drawString(label, x, y-2);
    g.setColor(showAllColor);
  }

  void drawZoomIndicator(Graphics g) {
    int x1 = 10;
    int y1 = 10;
    double aspectRatio = (double)imageHeight/imageWidth;
    int w1 = 64;
    if (aspectRatio>1.0)
      w1 = (int)(w1/aspectRatio);
    int h1 = (int)(w1*aspectRatio);
    if (w1<4) w1 = 4;
    if (h1<4) h1 = 4;
    int w2 = (int)(w1*((double)srcRect.width/imageWidth));
    int h2 = (int)(h1*((double)srcRect.height/imageHeight));
    if (w2<1) w2 = 1;
    if (h2<1) h2 = 1;
    int x2 = (int)(w1*((double)srcRect.x/imageWidth));
    int y2 = (int)(h1*((double)srcRect.y/imageHeight));
    if (zoomIndicatorColor==null)
      zoomIndicatorColor = new Color(128, 128, 255);
    g.setColor(zoomIndicatorColor);
    g.drawRect(x1, y1, w1, h1);
    if (w2*h2<=200 || w2<10 || h2<10)
      g.fillRect(x1+x2, y1+y2, w2, h2);
    else
      g.drawRect(x1+x2, y1+y2, w2, h2);
  }

  // Use double buffer to reduce flicker when drawing complex ROIs.
  // Author: Erik Meijering
  void paintDoubleBuffered(Graphics g) {
    final int srcRectWidthMag = (int)(srcRect.width*magnification);
    final int srcRectHeightMag = (int)(srcRect.height*magnification);
    if (offScreenImage==null || offScreenWidth!=srcRectWidthMag || offScreenHeight!=srcRectHeightMag) {
      offScreenImage = createImage(srcRectWidthMag, srcRectHeightMag);
      offScreenWidth = srcRectWidthMag;
      offScreenHeight = srcRectHeightMag;
    }
    Roi roi = imp.getRoi();
    try {
      if (imageUpdated) {
        imageUpdated = false;
        imp.updateImage();
      }
      Graphics offScreenGraphics = offScreenImage.getGraphics();
      Java2.setBilinearInterpolation(offScreenGraphics, Prefs.interpolateScaledImages);
      Image img = imp.getImage();
      if (img!=null)
        offScreenGraphics.drawImage(img, 0, 0, srcRectWidthMag, srcRectHeightMag,
          srcRect.x, srcRect.y, srcRect.x+srcRect.width, srcRect.y+srcRect.height, null);
      if (showAllROIs) showAllROIs(offScreenGraphics);
      if (displayList!=null) drawDisplayList(offScreenGraphics);
      if (roi!=null) roi.draw(offScreenGraphics);
      if (srcRect.width<imageWidth ||srcRect.height<imageHeight)
        drawZoomIndicator(offScreenGraphics);
      if (IJ.debugMode) showFrameRate(offScreenGraphics);
      g.drawImage(offScreenImage, 0, 0, null);
    }
    catch(OutOfMemoryError e) {IJ.outOfMemory("Paint");}
  }

    long firstFrame;
    int frames, fps;
       
  void showFrameRate(Graphics g) {
    frames++;
    if (System.currentTimeMillis()>firstFrame+1000) {
      firstFrame=System.currentTimeMillis();
      fps = frames;
      frames=0;
    }
    g.setColor(Color.white);
    g.fillRect(10, 12, 50, 15);
    g.setColor(Color.black);
    g.drawString((int)(fps+0.5) + " fps", 10, 25);
  }

    public Dimension getPreferredSize() {
        return new Dimension(dstWidth, dstHeight);
    }

    int count;
   
    /*
    public Graphics getGraphics() {
       Graphics g = super.getGraphics();
    IJ.write("getGraphics: "+count++);
    if (IJ.altKeyDown())
      throw new IllegalArgumentException("");
      return g;
    }
    */

  /** Returns the current cursor location. */
  public Point getCursorLoc() {
    return new Point(xMouse, yMouse);
  }

  /** Returns the mouse event modifiers. */
  public int getModifiers() {
    return flags;
  }

  /** Sets the cursor based on the current tool and cursor location. */
  public void setCursor(int sx, int sy, int ox, int oy) {
    xMouse = ox;
    yMouse = oy;
    Roi roi = imp.getRoi();
    ImageWindow win = imp.getWindow();
    if (win==null)
      return;
    if (IJ.spaceBarDown()) {
      setCursor(handCursor);
      return;
    }
    int id = Toolbar.getToolId();
    switch (Toolbar.getToolId()) {
      case Toolbar.MAGNIFIER:
        setCursor(moveCursor);
        break;
      case Toolbar.HAND:
        setCursor(handCursor);
        break;
      default//selection tool
        if (id==Toolbar.SPARE1 || id>=Toolbar.SPARE2) {
          if (Prefs.usePointerCursor) setCursor(defaultCursor); else setCursor(crosshairCursor);
        } else if (roi!=null && roi.getState()!=roi.CONSTRUCTING && roi.isHandle(sx, sy)>=0)
          setCursor(handCursor);
        else if (Prefs.usePointerCursor || (roi!=null && roi.getState()!=roi.CONSTRUCTING && roi.contains(ox, oy)))
          setCursor(defaultCursor);
        else
          setCursor(crosshairCursor);
    }
  }
   
  /**Converts a screen x-coordinate to an offscreen x-coordinate.*/
  public int offScreenX(int sx) {
    return srcRect.x + (int)(sx/magnification);
  }
   
  /**Converts a screen y-coordinate to an offscreen y-coordinate.*/
  public int offScreenY(int sy) {
    return srcRect.y + (int)(sy/magnification);
  }
 
  /**Converts a screen x-coordinate to a floating-point offscreen x-coordinate.*/
  public double offScreenXD(int sx) {
    return srcRect.x + sx/magnification;
  }
   
  /**Converts a screen y-coordinate to a floating-point offscreen y-coordinate.*/
  public double offScreenYD(int sy) {
    return srcRect.y + sy/magnification;

  }
 
  /**Converts an offscreen x-coordinate to a screen x-coordinate.*/
  public int screenX(int ox) {
    return  (int)((ox-srcRect.x)*magnification);
  }
 
  /**Converts an offscreen y-coordinate to a screen y-coordinate.*/
  public int screenY(int oy) {
    return  (int)((oy-srcRect.y)*magnification);
  }

  /**Converts a floating-point offscreen x-coordinate to a screen x-coordinate.*/
  public int screenXD(double ox) {
    return  (int)((ox-srcRect.x)*magnification);
  }
 
  /**Converts a floating-point offscreen x-coordinate to a screen x-coordinate.*/
  public int screenYD(double oy) {
    return  (int)((oy-srcRect.y)*magnification);
  }

  public double getMagnification() {
    return magnification;
  }
   
  public void setMagnification(double magnification) {
    setMagnification2(magnification);
  }
   
  void setMagnification2(double magnification) {
    if (magnification>32.0) magnification = 32.0;
    if (magnification<0.03125) magnification = 0.03125;
    this.magnification = magnification;
    imp.setTitle(imp.getTitle());
  }

  public Rectangle getSrcRect() {
    return srcRect;
  }
 
  void setSrcRect(Rectangle srcRect) {
    this.srcRect = srcRect;
  }
   
  /** Enlarge the canvas if the user enlarges the window. */
  void resizeCanvas(int width, int height) {
    ImageWindow win = imp.getWindow();
    //IJ.log("resizeCanvas: "+srcRect+" "+imageWidth+"  "+imageHeight+" "+width+"  "+height+" "+dstWidth+"  "+dstHeight+" "+win.maxBounds);
    if (!maxBoundsReset&& (width>dstWidth||height>dstHeight)&&win!=null&&win.maxBounds!=null&&width!=win.maxBounds.width-10) {
      if (resetMaxBoundsCount!=0)
        resetMaxBounds(); // Works around problem that prevented window from being larger than maximized size
      resetMaxBoundsCount++;
    }
    if (IJ.altKeyDown())
      {fitToWindow(); return;}
    if (srcRect.width<imageWidth || srcRect.height<imageHeight) {
      if (width>imageWidth*magnification)
        width = (int)(imageWidth*magnification);
      if (height>imageHeight*magnification)
        height = (int)(imageHeight*magnification);
      setDrawingSize(width, height);
      srcRect.width = (int)(dstWidth/magnification);
      srcRect.height = (int)(dstHeight/magnification);
      if ((srcRect.x+srcRect.width)>imageWidth)
        srcRect.x = imageWidth-srcRect.width;
      if ((srcRect.y+srcRect.height)>imageHeight)
        srcRect.y = imageHeight-srcRect.height;
      repaint();
    }
    //IJ.log("resizeCanvas2: "+srcRect+" "+dstWidth+"  "+dstHeight+" "+width+"  "+height);
  }
 
  public void fitToWindow() {
      ImageWindow win = imp.getWindow();
      if (win==null) return;
      Rectangle bounds = win.getBounds();
      Insets insets = win.getInsets();
      int sliderHeight = (win instanceof StackWindow)?20:0;
      double xmag = (double)(bounds.width-10)/srcRect.width;
      double ymag = (double)(bounds.height-(10+insets.top+sliderHeight))/srcRect.height;
      setMagnification(Math.min(xmag, ymag));
      srcRect = new Rectangle(0, 0, imageWidth, imageHeight);
      setDrawingSize((int)(imageWidth*magnification), (int)(imageHeight*magnification));
  }
   
  void setMaxBounds() {
    if (maxBoundsReset) {
      maxBoundsReset = false;
      ImageWindow win = imp.getWindow();
      if (win!=null && !IJ.isLinux() && win.maxBounds!=null) {
        win.setMaximizedBounds(win.maxBounds);
        win.setMaxBoundsTime = System.currentTimeMillis();
      }
    }
  }

  void resetMaxBounds() {
    ImageWindow win = imp.getWindow();
    if (win!=null && (System.currentTimeMillis()-win.setMaxBoundsTime)>500L) {
      win.setMaximizedBounds(win.maxWindowBounds);
      maxBoundsReset = true;
    }
  }
 
  private static final double[] zoomLevels = {
    1/72.0, 1/48.0, 1/32.0, 1/24.0, 1/16.0, 1/12.0,
    1/8.0, 1/6.0, 1/4.0, 1/3.0, 1/2.0, 0.75, 1.0, 1.5,
    2.0, 3.0, 4.0, 6.0, 8.0, 12.0, 16.0, 24.0, 32.0 };
 
  public static double getLowerZoomLevel(double currentMag) {
    double newMag = zoomLevels[0];
    for (int i=0; i<zoomLevels.length; i++) {
    if (zoomLevels[i] < currentMag)
      newMag = zoomLevels[i];
    else
      break;
    }
    return newMag;
  }

  public static double getHigherZoomLevel(double currentMag) {
    double newMag = 32.0;
    for (int i=zoomLevels.length-1; i>=0; i--) {
      if (zoomLevels[i]>currentMag)
        newMag = zoomLevels[i];
      else
        break;
    }
    return newMag;
  }

  /** Zooms in by making the window bigger. If it can't
    be made bigger, then make the source rectangle
    (srcRect) smaller and center it at (x,y). */
  public void zoomIn(int x, int y) {
    if (magnification>=32) return;
    double newMag = getHigherZoomLevel(magnification);
    int newWidth = (int)(imageWidth*newMag);
    int newHeight = (int)(imageHeight*newMag);
    Dimension newSize = canEnlarge(newWidth, newHeight);
    if (newSize!=null) {
      setDrawingSize(newSize.width, newSize.height);
      if (newSize.width!=newWidth || newSize.height!=newHeight)
        adjustSourceRect(newMag, x, y);
      else
        setMagnification(newMag);
      imp.getWindow().pack();
    } else
      adjustSourceRect(newMag, x, y);
    repaint();
    if (srcRect.width<imageWidth || srcRect.height<imageHeight)
      resetMaxBounds();
  }
 
  void adjustSourceRect(double newMag, int x, int y) {
    //IJ.log("adjustSourceRect1: "+newMag+" "+dstWidth+"  "+dstHeight);
    int w = (int)Math.round(dstWidth/newMag);
    if (w*newMag<dstWidth) w++;
    int h = (int)Math.round(dstHeight/newMag);
    if (h*newMag<dstHeight) h++;
    x = offScreenX(x);
    y = offScreenY(y);
    Rectangle r = new Rectangle(x-w/2, y-h/2, w, h);
    if (r.x<0) r.x = 0;
    if (r.y<0) r.y = 0;
    if (r.x+w>imageWidth) r.x = imageWidth-w;
    if (r.y+h>imageHeight) r.y = imageHeight-h;
    srcRect = r;
    setMagnification(newMag);
    //IJ.log("adjustSourceRect2: "+srcRect+" "+dstWidth+"  "+dstHeight);
  }
 
  protected Dimension canEnlarge(int newWidth, int newHeight) {
    if ((flags&Event.SHIFT_MASK)!=0 || IJ.shiftKeyDown())
      return null;
    ImageWindow win = imp.getWindow();
    if (win==null) return null;
    Rectangle r1 = win.getBounds();

    Insets insets = win.getInsets();
    Point loc = getLocation();
    if (loc.x>insets.left+5 || loc.y>insets.top+5) {
      r1.width = newWidth+insets.left+insets.right+10;
      r1.height = newHeight+insets.top+insets.bottom+10;
      if (win instanceof StackWindow) r1.height+=20;
    } else {
      r1.width = r1.width - dstWidth + newWidth+10;
      r1.height = r1.height - dstHeight + newHeight+10;
    }
    Rectangle max = win.getMaxWindow();
    boolean fitsHorizontally = r1.x+r1.width<max.x+max.width;
    boolean fitsVertically = r1.y+r1.height<max.y+max.height;
    if (fitsHorizontally && fitsVertically)
      return new Dimension(newWidth, newHeight);
    else if (fitsVertically && newHeight<dstWidth)
      return new Dimension(dstWidth, newHeight);
    else if (fitsHorizontally && newWidth<dstHeight)
      return new Dimension(newWidth, dstHeight);
    else
      return null;
  }
   
  /**Zooms out by making the source rectangle (srcRect) 
    larger and centering it on (x,y). If we can't make it larger, 
    then make the window smaller.*/
  public void zoomOut(int x, int y) {
    if (magnification<=0.03125)
      return;
    double oldMag = magnification;
    double newMag = getLowerZoomLevel(magnification);
    double srcRatio = (double)srcRect.width/srcRect.height;
    double imageRatio = (double)imageWidth/imageHeight;
    double initialMag = imp.getWindow().getInitialMagnification();
    if (Math.abs(srcRatio-imageRatio)>0.05) {
      double scale = oldMag/newMag;
      int newSrcWidth = (int)Math.round(srcRect.width*scale);
      int newSrcHeight = (int)Math.round(srcRect.height*scale);
      if (newSrcWidth>imageWidth) newSrcWidth=imageWidth;
      if (newSrcHeight>imageHeight) newSrcHeight=imageHeight;
      int newSrcX = srcRect.x - (newSrcWidth - srcRect.width)/2;
      int newSrcY = srcRect.y - (newSrcHeight - srcRect.height)/2;
      if (newSrcX<0) newSrcX = 0;
      if (newSrcY<0) newSrcY = 0;
      srcRect = new Rectangle(newSrcX, newSrcY, newSrcWidth, newSrcHeight);
      //IJ.log(newMag+" "+srcRect+" "+dstWidth+" "+dstHeight);
      int newDstWidth = (int)(srcRect.width*newMag);
      int newDstHeight = (int)(srcRect.height*newMag);
      setMagnification(newMag);
      setMaxBounds();
      //IJ.log(newDstWidth+" "+dstWidth+" "+newDstHeight+" "+dstHeight);
      if (newDstWidth<dstWidth || newDstHeight<dstHeight) {
        //IJ.log("pack");
        setDrawingSize(newDstWidth, newDstHeight);
        imp.getWindow().pack();
      } else
        repaint();
      return;
    }
    if (imageWidth*newMag>dstWidth) {
      int w = (int)Math.round(dstWidth/newMag);
      if (w*newMag<dstWidth) w++;
      int h = (int)Math.round(dstHeight/newMag);
      if (h*newMag<dstHeight) h++;
      x = offScreenX(x);
      y = offScreenY(y);
      Rectangle r = new Rectangle(x-w/2, y-h/2, w, h);
      if (r.x<0) r.x = 0;
      if (r.y<0) r.y = 0;
      if (r.x+w>imageWidth) r.x = imageWidth-w;
      if (r.y+h>imageHeight) r.y = imageHeight-h;
      srcRect = r;
    } else {
      srcRect = new Rectangle(0, 0, imageWidth, imageHeight);
      setDrawingSize((int)(imageWidth*newMag), (int)(imageHeight*newMag));
      //setDrawingSize(dstWidth/2, dstHeight/2);
      imp.getWindow().pack();
    }
    //IJ.write(newMag + " " + srcRect.x+" "+srcRect.y+" "+srcRect.width+" "+srcRect.height+" "+dstWidth + " " + dstHeight);
    setMagnification(newMag);
    //IJ.write(srcRect.x + " " + srcRect.width + " " + dstWidth);
    setMaxBounds();
    repaint();
  }

  public void unzoom() {
    double imag = imp.getWindow().getInitialMagnification();
    if (magnification==imag)
      return;
    srcRect = new Rectangle(0, 0, imageWidth, imageHeight);
    ImageWindow win = imp.getWindow();
    setDrawingSize((int)(imageWidth*imag), (int)(imageHeight*imag));
    setMagnification(imag);
        setMaxBounds();
    win.pack();
    setMaxBounds();
    repaint();
  }
   
  protected void scroll(int sx, int sy) {
    int ox = xSrcStart + (int)(sx/magnification)//convert to offscreen coordinates
    int oy = ySrcStart + (int)(sy/magnification);
    //IJ.log("scroll: "+ox+" "+oy+" "+xMouseStart+" "+yMouseStart);
    int newx = xSrcStart + (xMouseStart-ox);
    int newy = ySrcStart + (yMouseStart-oy);
    if (newx<0) newx = 0;
    if (newy<0) newy = 0;
    if ((newx+srcRect.width)>imageWidth) newx = imageWidth-srcRect.width;
    if ((newy+srcRect.height)>imageHeight) newy = imageHeight-srcRect.height;
    srcRect.x = newx;
    srcRect.y = newy;
    //IJ.log(sx+"  "+sy+"  "+newx+"  "+newy+"  "+srcRect);
    imp.draw();
    Thread.yield();
 
 
  Color getColor(int index){
    IndexColorModel cm = (IndexColorModel)imp.getProcessor().getColorModel();
    //IJ.write(""+index+" "+(new Color(cm.getRGB(index))));
    return new Color(cm.getRGB(index));
  }
 
  protected void setDrawingColor(int ox, int oy, boolean setBackground) {
    //IJ.write("setDrawingColor: "+setBackground+this);
    int type = imp.getType();
    int[] v = imp.getPixel(ox, oy);
    switch (type) {
      case ImagePlus.GRAY8: {
        if (setBackground)
          setBackgroundColor(getColor(v[0]));
        else
          setForegroundColor(getColor(v[0]));
        break;
      }
      case ImagePlus.GRAY16: case ImagePlus.GRAY32: {
        double min = imp.getProcessor().getMin();
        double max = imp.getProcessor().getMax();
        double value = (type==ImagePlus.GRAY32)?Float.intBitsToFloat(v[0]):v[0];
        int index = (int)(255.0*((value-min)/(max-min)));
        if (index<0) index = 0;
        if (index>255) index = 255;
        if (setBackground)
          setBackgroundColor(getColor(index));
        else
          setForegroundColor(getColor(index));
        break;
      }
      case ImagePlus.COLOR_RGB: case ImagePlus.COLOR_256: {
        Color c = new Color(v[0], v[1], v[2]);
        if (setBackground)
          setBackgroundColor(c);
        else
          setForegroundColor(c);
        break;
      }
    }
    Color c;
    if (setBackground)
      c = Toolbar.getBackgroundColor();
    else {
      c = Toolbar.getForegroundColor();
      imp.setColor(c);
    }
    IJ.showStatus("("+c.getRed()+", "+c.getGreen()+", "+c.getBlue()+")");
  }
 
  private void setForegroundColor(Color c) {
    Toolbar.setForegroundColor(c);
    if (Recorder.record)
      Recorder.record("setForegroundColor", c.getRed(), c.getGreen(), c.getBlue());
  }

  private void setBackgroundColor(Color c) {
    Toolbar.setBackgroundColor(c);
    if (Recorder.record)
      Recorder.record("setBackgroundColor", c.getRed(), c.getGreen(), c.getBlue());
  }

  public void mousePressed(MouseEvent e) {
    if (ij==null) return;
    showCursorStatus = true;
    int toolID = Toolbar.getToolId();
    ImageWindow win = imp.getWindow();
    if (win!=null && win.running2 && toolID!=Toolbar.MAGNIFIER) {
      win.running2 = false;
      return;
    }
   
    int x = e.getX();
    int y = e.getY();
    flags = e.getModifiers();
    //IJ.log("Mouse pressed: " + e.isPopupTrigger() + "  " + ij.modifiers(flags));   
    //if (toolID!=Toolbar.MAGNIFIER && e.isPopupTrigger()) {
    if (toolID!=Toolbar.MAGNIFIER && (e.isPopupTrigger() || (flags & Event.META_MASK)!=0)) {
      handlePopupMenu(e);
      return;
    }

    int ox = offScreenX(x);
    int oy = offScreenY(y);
    xMouse = ox; yMouse = oy;
    if (IJ.spaceBarDown()) {
      // temporarily switch to "hand" tool of space bar down
      setupScroll(ox, oy);
      return;
    }
    if (showAllROIs) {
      Roi roi = imp.getRoi();
      if (!(roi!=null && (roi.contains(ox, oy)||roi.isHandle(x, y)>=0)) && roiManagerSelect(x, y))
         return;
    }

    switch (toolID) {
      case Toolbar.MAGNIFIER:
        if (IJ.shiftKeyDown())
          zoomToSelection(ox, oy);
        else if ((flags & (Event.ALT_MASK|Event.META_MASK|Event.CTRL_MASK))!=0)
          zoomOut(x, y);
        else
          zoomIn(x, y);
        break;
      case Toolbar.HAND:
        setupScroll(ox, oy);
        break;
      case Toolbar.DROPPER:
        setDrawingColor(ox, oy, IJ.altKeyDown());
        break;
      case Toolbar.WAND:
        Roi roi = imp.getRoi();
        if (roi!=null && roi.contains(ox, oy)) {
          Rectangle r = roi.getBounds();
          if (r.width==imageWidth && r.height==imageHeight)
            imp.killRoi();
          else if (!e.isAltDown()) {
            handleRoiMouseDown(e);
            return;
          }
        }
        if (roi!=null) {
          int handle = roi.isHandle(x, y);
          if (handle>=0) {
            roi.mouseDownInHandle(handle, x, y);
            return;
          }
        }
        setRoiModState(e, roi, -1);
        int npoints = IJ.doWand(ox, oy);
        if (Recorder.record && npoints>0)
          Recorder.record("doWand", ox, oy);
        break;
      case Toolbar.OVAL:
        if (Toolbar.getBrushSize()>0)
          new RoiBrush();
        else
          handleRoiMouseDown(e);
        break;
      case Toolbar.SPARE1: case Toolbar.SPARE2: case Toolbar.SPARE3:
      case Toolbar.SPARE4: case Toolbar.SPARE5: case Toolbar.SPARE6:
      case Toolbar.SPARE7: case Toolbar.SPARE8: case Toolbar.SPARE9:
        Toolbar.getInstance().runMacroTool(toolID);
        break;
      default//selection tool
        handleRoiMouseDown(e);
    }
  }
 
  void zoomToSelection(int x, int y) {
    IJ.setKeyUp(IJ.ALL_KEYS);
    String macro =
      "args = split(getArgument);\n"+
      "x1=parseInt(args[0]); y1=parseInt(args[1]); flags=20;\n"+
      "while (flags&20!=0) {\n"+
        "getCursorLoc(x2, y2, z, flags);\n"+
        "if (x2>=x1) x=x1; else x=x2;\n"+
        "if (y2>=y1) y=y1; else y=y2;\n"+
        "makeRectangle(x, y, abs(x2-x1), abs(y2-y1));\n"+
        "wait(10);\n"+
      "}\n"+
      "run('To Selection');\n";
    new MacroRunner(macro, x+" "+y);
  }

    boolean roiManagerSelect(int x, int y) {
    RoiManager rm=RoiManager.getInstance();
    if (rm==null) return false;
    Hashtable rois = rm.getROIs();
    java.awt.List list = rm.getList();
    int n = list.getItemCount();
    if (labelRects==null || labelRects.length!=n) return false;
    for (int i=0; i<n; i++) {
      if (labelRects[i]!=null && labelRects[i].contains(x,y)) {
        //rm.select(i);
        // this needs to run on a separate thread, at least on OS X
        new ij.macro.MacroRunner("roiManager('select', "+i+"); roiManager('update');");
        return true;
      }
    }
    return false;
    }

  protected void setupScroll(int ox, int oy) {
    xMouseStart = ox;
    yMouseStart = oy;
    xSrcStart = srcRect.x;
    ySrcStart = srcRect.y;
  }

  protected void handlePopupMenu(MouseEvent e) {
    if (disablePopupMenu) return;
    if (IJ.debugMode) IJ.log("show popup: " + (e.isPopupTrigger()?"true":"false"));
    int x = e.getX();
    int y = e.getY();
    Roi roi = imp.getRoi();
    if (roi!=null && (roi.getType()==Roi.POLYGON || roi.getType()==Roi.POLYLINE || roi.getType()==Roi.ANGLE)
    && roi.getState()==roi.CONSTRUCTING) {
      roi.handleMouseUp(x, y); // simulate double-click to finalize
      roi.handleMouseUp(x, y); // polygon or polyline selection
      return;
    }
    PopupMenu popup = Menus.getPopupMenu();
    if (popup!=null) {
      add(popup);
      if (IJ.isMacOSX()) IJ.wait(10);
      popup.show(this, x, y);
    }
  }
 
  public void mouseExited(MouseEvent e) {
    //autoScroll(e);
    ImageWindow win = imp.getWindow();
    if (win!=null)
      setCursor(defaultCursor);
    IJ.showStatus("");
  }

  /*
  public void autoScroll(MouseEvent e) {
    Roi roi = imp.getRoi();
    if (roi==null || roi.getState()!=roi.CONSTRUCTING || srcRect.width>=imageWidth || srcRect.height>=imageHeight
    || !(roi.getType()==Roi.POLYGON || roi.getType()==Roi.POLYLINE || roi.getType()==Roi.ANGLE))
      return;
    int sx = e.getX();
    int sy = e.getY();
    xMouseStart = srcRect.x+srcRect.width/2;
    yMouseStart = srcRect.y+srcRect.height/2;
    Rectangle r = roi.getBounds();
    Dimension size = getSize();
    int deltax=0, deltay=0;
    if (sx<0)
      deltax = srcRect.width/4;
    else if (sx>size.width)
      deltax = -srcRect.width/4;
    if (sy<0)
      deltay = srcRect.height/4;
    else if (sy>size.height)
      deltay = -srcRect.height/4;
    //IJ.log("autoscroll: "+sx+" "+sy+" "+deltax+" "+deltay+" "+r);
    scroll(screenX(xMouseStart+deltax), screenY(yMouseStart+deltay));
  }
  */

  public void mouseDragged(MouseEvent e) {
    int x = e.getX();
    int y = e.getY();
    xMouse = offScreenX(x);
    yMouse = offScreenY(y);
    flags = e.getModifiers();
    //IJ.log("mouseDragged: "+flags);
    if (flags==0// workaround for Mac OS 9 bug
      flags = InputEvent.BUTTON1_MASK;
    if (Toolbar.getToolId()==Toolbar.HAND || IJ.spaceBarDown())
      scroll(x, y);
    else {
      IJ.setInputEvent(e);
      Roi roi = imp.getRoi();
      if (roi != null)
        roi.handleMouseDrag(x, y, flags);
    }
  }

  void handleRoiMouseDown(MouseEvent e) {
    int sx = e.getX();
    int sy = e.getY();
    int ox = offScreenX(sx);
    int oy = offScreenY(sy);
    Roi roi = imp.getRoi();
    int handle = roi!=null?roi.isHandle(sx, sy):-1;   
    setRoiModState(e, roi, handle);
    if (roi!=null) {
      Rectangle r = roi.getBounds();
      int type = roi.getType();
      if (type==Roi.RECTANGLE && r.width==imp.getWidth() && r.height==imp.getHeight()
      && roi.getPasteMode()==Roi.NOT_PASTING) {
        imp.killRoi();
        return;
      }
      if (handle>=0) {
        roi.mouseDownInHandle(handle, sx, sy);
        return;
      }
      if (roi.contains(ox, oy)) {
        if (roi.modState==Roi.NO_MODS)
          roi.handleMouseDown(sx, sy);
        else {
          imp.killRoi();
          imp.createNewRoi(sx,sy);
        }
        return;
      }
      if ((type==Roi.POLYGON || type==Roi.POLYLINE || type==Roi.ANGLE)
      && roi.getState()==roi.CONSTRUCTING)
        return;
      int tool = Toolbar.getToolId();
      if ((tool==Toolbar.POLYGON||tool==Toolbar.POLYLINE||tool==Toolbar.ANGLE)&& !(IJ.shiftKeyDown()||IJ.altKeyDown())) {
        imp.killRoi();
        return;
      }
    }
    imp.createNewRoi(sx,sy);
  }
 
  void setRoiModState(MouseEvent e, Roi roi, int handle) {
    if (roi==null || (handle>=0 && roi.modState==Roi.NO_MODS))
      return;
    if (roi.state==Roi.CONSTRUCTING)
      return;
    int tool = Toolbar.getToolId();
    if (tool>Toolbar.FREEROI && tool!=Toolbar.WAND && tool!=Toolbar.POINT)
      {roi.modState = Roi.NO_MODS; return;}
    if (e.isShiftDown())
      roi.modState = Roi.ADD_TO_ROI;
    else if (e.isAltDown())
      roi.modState = Roi.SUBTRACT_FROM_ROI;
    else
      roi.modState = Roi.NO_MODS;
    //IJ.log("setRoiModState: "+roi.modState+" "+ roi.state);
  }
 
  /** Disable/enable popup menu. */
  public void disablePopupMenu(boolean status) {
    disablePopupMenu = status;
  }

  public void setShowAllROIs(boolean showAllROIs) {
    this.showAllROIs = showAllROIs;
  }

  public boolean getShowAllROIs() {
    return showAllROIs;
  }
 
  /** Returns the color used for "Show All" mode. */
  public static Color getShowAllColor() {
      return showAllColor;
  }

  /** Sets the color used used for "Show All" mode. */
  public static void setShowAllColor(Color c) {
    if (c==null) return;
    showAllColor = c;
    labelColor = null;
    ImagePlus img = WindowManager.getCurrentImage();
    if (img!=null) {
      ImageCanvas ic = img.getCanvas();
      if (ic!=null && ic.getShowAllROIs()) img.draw();
    }
  }

  public void setDisplayList(Vector list) {
    displayList = list;
    listColor = null;
    if (list!=null&&list.size()>0&&((Roi)list.elementAt(0)).getInstanceColor()!=null)
      labelListItems = false;
    else
      labelListItems = true;
    repaint();
  }

  public void setDisplayList(Shape shape, Color color, BasicStroke stroke) {
    if (shape==null)
      {setDisplayList(null); return;}
    Roi roi = new ShapeRoi(shape);
    roi.setInstanceColor(color);
    Vector list = new Vector();
    list.addElement(roi);
    displayList = list;
    labelListItems = false;
    listColor = color;
    listStroke = stroke;
    repaint();
  }
 
  public Vector getDisplayList() {
    return displayList;
  }

  /** Called by IJ.showStatus() to prevent status bar text from
    being overwritten until the cursor moves at least 12 pixels. */
  public void setShowCursorStatus(boolean status) {
    showCursorStatus = status;
    if (status==true)
      sx2 = sy2 = -1000;
    else {
      sx2 = screenX(xMouse);
      sy2 = screenY(yMouse);
    }
  }

  public void mouseReleased(MouseEvent e) {
    flags = e.getModifiers();
    flags &= ~InputEvent.BUTTON1_MASK; // make sure button 1 bit is not set
    flags &= ~InputEvent.BUTTON2_MASK; // make sure button 2 bit is not set
    flags &= ~InputEvent.BUTTON3_MASK; // make sure button 3 bit is not set
    Roi roi = imp.getRoi();
    if (roi != null) {
      Rectangle r = roi.getBounds();
      int type = roi.getType();
      if ((r.width==0 || r.height==0)
      && !(type==Roi.POLYGON||type==Roi.POLYLINE||type==Roi.ANGLE||type==Roi.LINE)
      && !(roi instanceof TextRoi)
      && roi.getState()==roi.CONSTRUCTING
      && type!=roi.POINT)
        imp.killRoi();
      else
        roi.handleMouseUp(e.getX(), e.getY());
    }
  }

  public void mouseMoved(MouseEvent e) {
    if (ij==null) return;
    int sx = e.getX();
    int sy = e.getY();
    int ox = offScreenX(sx);
    int oy = offScreenY(sy);
    flags = e.getModifiers();
    setCursor(sx, sy, ox, oy);
    IJ.setInputEvent(e);
    Roi roi = imp.getRoi();
    if (roi!=null && (roi.getType()==Roi.POLYGON || roi.getType()==Roi.POLYLINE || roi.getType()==Roi.ANGLE)
    && roi.getState()==roi.CONSTRUCTING) {
      PolygonRoi pRoi = (PolygonRoi)roi;
      pRoi.handleMouseMove(ox, oy);
    } else {
      if (ox<imageWidth && oy<imageHeight) {
        ImageWindow win = imp.getWindow();
        // Cursor must move at least 12 pixels before text
        // displayed using IJ.showStatus() is overwritten.
        if ((sx-sx2)*(sx-sx2)+(sy-sy2)*(sy-sy2)>144)
          showCursorStatus = true;
        if (win!=null&&showCursorStatus) win.mouseMoved(ox, oy);
      } else
        IJ.showStatus("");

    }
  }
 
  public void mouseClicked(MouseEvent e) {}
  public void mouseEntered(MouseEvent e) {}

}
TOP

Related Classes of ij.gui.ImageCanvas

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.