|
ImageWindow |
|
package ij.gui; import java.awt.*; import java.awt.image.*; import java.util.Properties; import java.awt.event.*; import ij.*; import ij.process.*; import ij.io.*; import ij.measure.*; import ij.plugin.frame.Recorder; import ij.macro.Interpreter; /** A frame for displaying images. */ public class ImageWindow extends Frame implements FocusListener, WindowListener, WindowStateListener, MouseWheelListener { public static final int MIN_WIDTH = 128; public static final int MIN_HEIGHT = 32; protected ImagePlus imp; protected ImageJ ij; protected ImageCanvas ic; private double initialMagnification = 1; private int newWidth, newHeight; protected boolean closed; private boolean newCanvas; private static Rectangle maxWindow; private boolean unzoomWhenMinimizing = true; Rectangle maxBounds; private static final int XINC = 8; private static final int YINC = 12; private static final int TEXT_GAP = 10; private static int xbase = -1; private static int ybase; private static int xloc; private static int yloc; private static int count; private static boolean centerOnScreen; private int textGap = centerOnScreen?0:TEXT_GAP; /** This variable is set false if the user presses the escape key or closes the window. */ public boolean running; /** This variable is set false if the user clicks in this window, presses the escape key, or closes the window. */ public boolean running2; public ImageWindow(String title) { super(title); } public ImageWindow(ImagePlus imp) { this(imp, null); } public ImageWindow(ImagePlus imp, ImageCanvas ic) { super(imp.getTitle()); if (Prefs.blackCanvas && getClass().getName().equals("ij.gui.ImageWindow")) { setForeground(Color.white); setBackground(Color.black); } else { setForeground(Color.black); if (IJ.isLinux()) setBackground(ImageJ.backgroundColor); else setBackground(Color.white); } ij = IJ.getInstance(); this.imp = imp; if (ic==null) {ic=new ImageCanvas(imp); newCanvas=true;} this.ic = ic; ImageWindow previousWindow = imp.getWindow(); setLayout(new ImageLayout(ic)); add(ic); addFocusListener(this); addWindowListener(this); addWindowStateListener(this); addKeyListener(ij); setFocusTraversalKeysEnabled(false); if (!(this instanceof StackWindow)) addMouseWheelListener(this); setResizable(true); WindowManager.addWindow(this); imp.setWindow(this); if (previousWindow!=null) { if (newCanvas) setLocationAndSize(false); else ic.update(previousWindow.getCanvas()); Point loc = previousWindow.getLocation(); setLocation(loc.x, loc.y); if (!(this instanceof StackWindow)) { pack(); show(); } boolean unlocked = imp.lockSilently(); boolean changes = imp.changes; imp.changes = false; previousWindow.close(); imp.changes = changes; if (unlocked) imp.unlock(); WindowManager.setCurrentWindow(this); } else { setLocationAndSize(false); if (ij!=null && !IJ.isMacintosh()) { Image img = ij.getIconImage(); if (img!=null) try {setIconImage(img);} catch (Exception e) {} } if (centerOnScreen) { GUI.center(this); centerOnScreen = false; } if (Interpreter.isBatchMode()) { WindowManager.setTempCurrentImage(imp); Interpreter.addBatchModeImage(imp); } else show(); } } private void setLocationAndSize(boolean updating) { int width = imp.getWidth(); int height = imp.getHeight(); if (maxWindow==null) maxWindow = getMaxWindow(); if (WindowManager.getWindowCount()<=1) xbase = -1; if (width>maxWindow.width/2 && xbase>maxWindow.x+5+XINC*6) xbase = -1; if (xbase==-1) { count = 0; xbase = maxWindow.x + 5; if (width*2<=maxWindow.width) xbase = maxWindow.x+maxWindow.width/2-width/2; ybase = maxWindow.y; xloc = xbase; yloc = ybase; } int x = xloc; int y = yloc; xloc += XINC; yloc += YINC; count++; if (count%6==0) { xloc = xbase; yloc = ybase; } int sliderHeight = (this instanceof StackWindow)?20:0; int screenHeight = maxWindow.height-sliderHeight; double mag = 1; while (xbase+XINC*4+width*mag>maxWindow.width || ybase+height*mag>screenHeight) { double mag2 = ImageCanvas.getLowerZoomLevel(mag); if (mag2==mag) break; mag = mag2; } if (mag<1.0) { initialMagnification = mag; ic.setDrawingSize((int)(width*mag), (int)(height*mag)); } ic.setMagnification(mag); if (y+height*mag>screenHeight) y = ybase; if (!updating) setLocation(x, y); if (Prefs.open100Percent && ic.getMagnification()<1.0) { while(ic.getMagnification()<1.0) ic.zoomIn(0, 0); setSize(Math.min(width, maxWindow.width-x), Math.min(height, screenHeight-y)); validate(); } else pack(); maxBounds = getMaximumBounds(); if (!IJ.isLinux()) setMaximizedBounds(maxBounds); } Rectangle getMaxWindow() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); Rectangle maxWindow = ge.getMaximumWindowBounds(); Dimension ijSize = ij!=null?ij.getSize():new Dimension(0,0); maxWindow.y += ijSize.height; maxWindow.height -= ijSize.height; return maxWindow; } public double getInitialMagnification() { return initialMagnification; } /** Override Container getInsets() to make room for some text above the image. */ public Insets getInsets() { Insets insets = super.getInsets(); double mag = ic.getMagnification(); int extraWidth = (int)((MIN_WIDTH - imp.getWidth()*mag)/2.0); if (extraWidth<0) extraWidth = 0; int extraHeight = (int)((MIN_HEIGHT - imp.getHeight()*mag)/2.0); if (extraHeight<0) extraHeight = 0; insets = new Insets(insets.top+textGap+extraHeight, insets.left+extraWidth, insets.bottom+extraHeight, insets.right+extraWidth); return insets; } /** Draws the subtitle. */ public void drawInfo(Graphics g) { if (textGap!=0) { Insets insets = super.getInsets(); if (imp instanceof CompositeImage) g.setColor(((CompositeImage)imp).getChannelColor()); g.drawString(createSubtitle(), 5, insets.top+TEXT_GAP); } } /** Creates the subtitle. */ public String createSubtitle() { String s=""; int nSlices = imp.getStackSize(); if (nSlices>1) { ImageStack stack = imp.getStack(); int currentSlice = imp.getCurrentSlice(); s += currentSlice+"/"+nSlices; boolean isLabel = false; String label = stack.getShortSliceLabel(currentSlice); if (label!=null && label.length()>0) s += " (" + label + ")"; if ((this instanceof StackWindow) && running2) { return s; } s += "; "; } int type = imp.getType(); Calibration cal = imp.getCalibration(); if (cal.pixelWidth!=1.0 || cal.pixelHeight!=1.0) s += IJ.d2s(imp.getWidth()*cal.pixelWidth,2) + "x" + IJ.d2s(imp.getHeight()*cal.pixelHeight,2) + " " + cal.getUnits() + " (" + imp.getWidth() + "x" + imp.getHeight() + "); "; else s += imp.getWidth() + "x" + imp.getHeight() + " pixels; "; int size = (imp.getWidth()*imp.getHeight()*imp.getStackSize())/1024; switch (type) { case ImagePlus.GRAY8: case ImagePlus.COLOR_256: s += "8-bit"; break; case ImagePlus.GRAY16: s += "16-bit"; size *= 2; break; case ImagePlus.GRAY32: s += "32-bit"; size *= 4; break; case ImagePlus.COLOR_RGB: s += "RGB"; size *= 4; break; } if (imp.isInvertedLut()) s += " (inverting LUT)"; if (size>=10000) s += "; " + (int)Math.round(size/1024.0) + "MB"; else if (size>=1024) { double size2 = size/1024.0; s += "; " + IJ.d2s(size2,(int)size2==size2?0:1) + "MB"; } else s += "; " + size + "K"; return s; } public void paint(Graphics g) { //if (IJ.debugMode) IJ.log("wPaint: " + imp.getTitle()); drawInfo(g); Rectangle r = ic.getBounds(); int extraWidth = MIN_WIDTH - r.width; int extraHeight = MIN_HEIGHT - r.height; if (extraWidth<=0 && extraHeight<=0 && !Prefs.noBorder && !IJ.isLinux()) g.drawRect(r.x-1, r.y-1, r.width+1, r.height+1); } /** Removes this window from the window list and disposes of it. Returns false if the user cancels the "save changes" dialog. */ public boolean close() { boolean isRunning = running || running2; running = running2 = false; if (isRunning) IJ.wait(500); if (ij==null || IJ.getApplet()!=null || Interpreter.isBatchMode() || IJ.macroRunning()) imp.changes = false; if (imp.changes) { String msg; String name = imp.getTitle(); if (name.length()>22) msg = "Save changes to\n" + "\"" + name + "\"?"; else msg = "Save changes to \"" + name + "\"?"; YesNoCancelDialog d = new YesNoCancelDialog(this, "ImageJ", msg); if (d.cancelPressed()) return false; else if (d.yesPressed()) { FileSaver fs = new FileSaver(imp); if (!fs.save()) return false; } } closed = true; if (WindowManager.getWindowCount()==0) {xloc = 0; yloc = 0;} WindowManager.removeWindow(this); setVisible(false); if (ij!=null && ij.quitting()) // this may help avoid thread deadlocks return true; dispose(); imp.flush(); return true; } public ImagePlus getImagePlus() { return imp; } void setImagePlus(ImagePlus imp) { this.imp = imp; repaint(); } public void updateImage(ImagePlus imp) { if (imp!=this.imp) throw new IllegalArgumentException("imp!=this.imp"); this.imp = imp; ic.updateImage(imp); setLocationAndSize(true); pack(); repaint(); } public ImageCanvas getCanvas() { return ic; } static ImagePlus getClipboard() { return ImagePlus.getClipboard(); } public Rectangle getMaximumBounds() { int width = imp.getWidth(); int height = imp.getHeight(); maxWindow = getMaxWindow(); Insets insets = getInsets(); int extraHeight = insets.top+insets.bottom; if (this instanceof StackWindow) extraHeight += 25; //if (IJ.isWindows()) extraHeight += 20; double maxHeight = maxWindow.height-extraHeight; double maxWidth = maxWindow.width; double mAspectRatio = maxWidth/maxHeight; double iAspectRatio = (double)width/height; int wWidth, wHeight; if (iAspectRatio>=mAspectRatio) { wWidth = (int)maxWidth; wHeight = (int)(maxWidth/iAspectRatio); } else { wHeight = (int)maxHeight; wWidth = (int)(maxHeight*iAspectRatio); } int xloc = (int)(maxWidth-wWidth)/2; if (xloc<0) xloc = 0; return new Rectangle(xloc, maxWindow.y, wWidth, wHeight+extraHeight); } public void maximize() { if (maxBounds==null) return; int width = imp.getWidth(); int height = imp.getHeight(); Insets insets = getInsets(); int extraHeight = insets.top+insets.bottom+5; if (this instanceof StackWindow) extraHeight += 25; double mag = Math.floor((maxBounds.height-extraHeight)*100.0/height)/100.0; double aspectRatio = (double)width/height; if (mag>ic.getMagnification() || aspectRatio<0.5 || aspectRatio>2.0) { ic.setMagnification2(mag); ic.setSrcRect(new Rectangle(0, 0, width, height)); ic.setDrawingSize((int)(width*mag), (int)(height*mag)); validate(); unzoomWhenMinimizing = true; } else unzoomWhenMinimizing = false; } public void minimize() { if (unzoomWhenMinimizing) ic.unzoom(); unzoomWhenMinimizing = true; } /** Has this window been closed? */ public boolean isClosed() { return closed; } public void focusGained(FocusEvent e) { //IJ.log("focusGained: "+imp.getTitle()); if (!Interpreter.isBatchMode() && ij!=null && !ij.quitting()) WindowManager.setCurrentWindow(this); } public void windowActivated(WindowEvent e) { //IJ.log("windowActivated: "+imp.getTitle()); ImageJ ij = IJ.getInstance(); boolean quitting = ij!=null && ij.quitting(); if (IJ.isMacintosh() && ij!=null && !quitting) { IJ.wait(10); // may be needed for Java 1.4 on OS X setMenuBar(Menus.getMenuBar()); } imp.setActivated(); // notify ImagePlus that image has been activated if (!closed && !quitting && !Interpreter.isBatchMode()) WindowManager.setCurrentWindow(this); } public void windowClosing(WindowEvent e) { //IJ.log("windowClosing: "+imp.getTitle()+" "+closed); if (closed) return; if (ij!=null) { WindowManager.setCurrentWindow(this); IJ.doCommand("Close"); } else { setVisible(false); dispose(); WindowManager.removeWindow(this); } } public void windowStateChanged(WindowEvent e) { int oldState = e.getOldState(); int newState = e.getNewState(); //IJ.log("WSC: "+getBounds()+" "+oldState+" "+newState); if ((oldState & Frame.MAXIMIZED_BOTH) == 0 && (newState & Frame.MAXIMIZED_BOTH) != 0) maximize(); else if ((oldState & Frame.MAXIMIZED_BOTH) != 0 && (newState & Frame.MAXIMIZED_BOTH) == 0) minimize(); } public void windowClosed(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void focusLost(FocusEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowOpened(WindowEvent e) {} public void mouseWheelMoved(MouseWheelEvent event) { int rotation = event.getWheelRotation(); int width = imp.getWidth(); int height = imp.getHeight(); Rectangle srcRect = ic.getSrcRect(); int xstart = srcRect.x; int ystart = srcRect.y; if (IJ.spaceBarDown() || srcRect.height==height) { srcRect.x += rotation*Math.max(width/200, 1); if (srcRect.x<0) srcRect.x = 0; if (srcRect.x+srcRect.width>width) srcRect.x = width-srcRect.width; } else { srcRect.y += rotation*Math.max(height/200, 1); if (srcRect.y<0) srcRect.y = 0; if (srcRect.y+srcRect.height>height) srcRect.y = height-srcRect.height; } if (srcRect.x!=xstart || srcRect.y!=ystart) ic.repaint(); } /** Copies the current ROI to the clipboard. The entire image is copied if there is no ROI. */ public void copy(boolean cut) { imp.copy(cut); } public void paste() { imp.paste(); } /** This method is called by ImageCanvas.mouseMoved(MouseEvent). @see ij.gui.ImageCanvas#mouseMoved */ public void mouseMoved(int x, int y) { imp.mouseMoved(x, y); } public String toString() { return imp.getTitle(); } /** Causes the next image to be opened to be centered on the screen and displayed without informational text above the image. */ public static void centerNextImage() { centerOnScreen = true; } /** Overrides the setBounds() method in Component so we can find out when the window is resized. */ //public void setBounds(int x, int y, int width, int height) { // super.setBounds(x, y, width, height); // ic.resizeSourceRect(width, height); //} } //class ImageWindow
|
ImageWindow |
|