package ij.gui;
import ij.*;
import ij.measure.Calibration;
import ij.plugin.frame.SyncWindows;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
public class StackWindow extends ImageWindow implements Runnable, AdjustmentListener, ActionListener, MouseWheelListener {
protected Scrollbar sliceSelector; protected ScrollbarWithLabel cSelector, zSelector, tSelector;
protected Thread thread;
protected volatile boolean done;
protected volatile int slice;
protected ScrollbarWithLabel animationSelector;
boolean hyperStack;
int nChannels=1, nSlices=1, nFrames=1;
int c=1, z=1, t=1;
public StackWindow(ImagePlus imp) {
this(imp, null);
}
public StackWindow(ImagePlus imp, ImageCanvas ic) {
super(imp, ic);
addScrollbars(imp);
addMouseWheelListener(this);
if (sliceSelector==null && this.getClass().getName().indexOf("Image5D")!=-1)
sliceSelector = new Scrollbar(); pack();
ic = imp.getCanvas();
if (ic!=null)
ic.setMaxBounds();
if (IJ.isMacro() && !isVisible()) imp.setDeactivated(); show();
if (IJ.isMacro())
imp.waitTillActivated();
int previousSlice = imp.getCurrentSlice();
if (previousSlice>1 && previousSlice<=imp.getStackSize())
imp.setSlice(previousSlice);
else
imp.setSlice(1);
thread = new Thread(this, "zSelector");
thread.start();
}
void addScrollbars(ImagePlus imp) {
ImageStack s = imp.getStack();
int stackSize = s.getSize();
int sliderHeight = 0;
nSlices = stackSize;
hyperStack = imp.getOpenAsHyperStack();
int[] dim = imp.getDimensions();
int nDimensions = 2+(dim[2]>1?1:0)+(dim[3]>1?1:0)+(dim[4]>1?1:0);
if (nDimensions<=3 && dim[2]!=nSlices)
hyperStack = false;
if (hyperStack) {
nChannels = dim[2];
nSlices = dim[3];
nFrames = dim[4];
}
if (nSlices==stackSize) hyperStack = false;
if (nChannels*nSlices*nFrames!=stackSize) hyperStack = false;
if (cSelector!=null||zSelector!=null||tSelector!=null)
removeScrollbars();
ImageJ ij = IJ.getInstance();
if (nChannels>1) {
cSelector = new ScrollbarWithLabel(this, 1, 1, 1, nChannels+1, 'c');
add(cSelector);
sliderHeight += cSelector.getPreferredSize().height + ImageWindow.VGAP;
if (ij!=null) cSelector.addKeyListener(ij);
cSelector.addAdjustmentListener(this);
cSelector.setFocusable(false); cSelector.setUnitIncrement(1);
cSelector.setBlockIncrement(1);
}
if (nSlices>1) {
char label = nChannels>1||nFrames>1?'z':'t';
if (stackSize==dim[2] && imp.isComposite()) label = 'c';
zSelector = new ScrollbarWithLabel(this, 1, 1, 1, nSlices+1, label);
if (label=='t') animationSelector = zSelector;
add(zSelector);
sliderHeight += zSelector.getPreferredSize().height + ImageWindow.VGAP;
if (ij!=null) zSelector.addKeyListener(ij);
zSelector.addAdjustmentListener(this);
zSelector.setFocusable(false);
int blockIncrement = nSlices/10;
if (blockIncrement<1) blockIncrement = 1;
zSelector.setUnitIncrement(1);
zSelector.setBlockIncrement(blockIncrement);
sliceSelector = zSelector.bar;
}
if (nFrames>1) {
animationSelector = tSelector = new ScrollbarWithLabel(this, 1, 1, 1, nFrames+1, 't');
add(tSelector);
sliderHeight += tSelector.getPreferredSize().height + ImageWindow.VGAP;
if (ij!=null) tSelector.addKeyListener(ij);
tSelector.addAdjustmentListener(this);
tSelector.setFocusable(false);
int blockIncrement = nFrames/10;
if (blockIncrement<1) blockIncrement = 1;
tSelector.setUnitIncrement(1);
tSelector.setBlockIncrement(blockIncrement);
}
ImageWindow win = imp.getWindow();
if (win!=null)
win.setSliderHeight(sliderHeight);
}
public synchronized void setSlidersEnabled(final boolean b) {
EventQueue.invokeLater(new Runnable() {
public void run() {
if (sliceSelector != null) sliceSelector.setEnabled(b);
if (cSelector != null) cSelector.setEnabled(b);
if (zSelector != null) zSelector.setEnabled(b);
if (tSelector != null) tSelector.setEnabled(b);
if (animationSelector != null) animationSelector.setEnabled(b);
}
});
}
public synchronized void adjustmentValueChanged(AdjustmentEvent e) {
if (!running2 || imp.isHyperStack()) {
if (e.getSource()==cSelector) {
c = cSelector.getValue();
if (c==imp.getChannel()&&e.getAdjustmentType()==AdjustmentEvent.TRACK) return;
} else if (e.getSource()==zSelector) {
z = zSelector.getValue();
int slice = hyperStack?imp.getSlice():imp.getCurrentSlice();
if (z==slice&&e.getAdjustmentType()==AdjustmentEvent.TRACK) return;
} else if (e.getSource()==tSelector) {
t = tSelector.getValue();
if (t==imp.getFrame()&&e.getAdjustmentType()==AdjustmentEvent.TRACK) return;
}
slice = (t-1)*nChannels*nSlices + (z-1)*nChannels + c;
notify();
}
if (!running)
syncWindows(e.getSource());
}
private void syncWindows(Object source) {
if (SyncWindows.getInstance()==null)
return;
if (source==cSelector)
SyncWindows.setC(this, cSelector.getValue());
else if (source==zSelector) {
int stackSize = imp.getStackSize();
if (imp.getNChannels()==stackSize)
SyncWindows.setC(this, zSelector.getValue());
else if (imp.getNFrames()==stackSize)
SyncWindows.setT(this, zSelector.getValue());
else
SyncWindows.setZ(this, zSelector.getValue());
} else if (source==tSelector)
SyncWindows.setT(this, tSelector.getValue());
else
throw new RuntimeException("Unknownsource:"+source);
}
public void actionPerformed(ActionEvent e) {
}
public void mouseWheelMoved(MouseWheelEvent e) {
synchronized(this) {
int rotation = e.getWheelRotation();
boolean ctrl = (e.getModifiers()&Event.CTRL_MASK)!=0;
if ((ctrl||IJ.shiftKeyDown()) && ic!=null) {
Point loc = ic.getCursorLoc();
int x = ic.screenX(loc.x);
int y = ic.screenY(loc.y);
if (rotation<0)
ic.zoomIn(x,y);
else
ic.zoomOut(x,y);
return;
}
if (hyperStack) {
if (rotation>0)
IJ.run(imp, "Next Slice [>]", "");
else if (rotation<0)
IJ.run(imp, "Previous Slice [<]", "");
} else {
int slice = imp.getCurrentSlice() + rotation;
if (slice<1)
slice = 1;
else if (slice>imp.getStack().getSize())
slice = imp.getStack().getSize();
setSlice(imp,slice);
imp.updateStatusbarValue();
SyncWindows.setZ(this, slice);
}
}
}
public boolean close() {
if (!super.close())
return false;
synchronized(this) {
done = true;
notify();
}
return true;
}
public void showSlice(int index) {
if (imp!=null && index>=1 && index<=imp.getStackSize()) {
setSlice(imp,index);
SyncWindows.setZ(this, index);
}
}
public void updateSliceSelector() {
if (hyperStack || zSelector==null || imp==null)
return;
int stackSize = imp.getStackSize();
int max = zSelector.getMaximum();
if (max!=(stackSize+1))
zSelector.setMaximum(stackSize+1);
EventQueue.invokeLater(new Runnable() {
public void run() {
if (imp!=null && zSelector!=null)
zSelector.setValue(imp.getCurrentSlice());
}
});
}
public void run() {
while (!done) {
synchronized(this) {
try {wait();}
catch(InterruptedException e) {}
}
if (done) return;
if (slice>0) {
int s = slice;
slice = 0;
if (s!=imp.getCurrentSlice()) {
imp.updatePosition(c, z, t);
setSlice(imp,s);
}
}
}
}
public String createSubtitle() {
String subtitle = super.createSubtitle();
if (!hyperStack || imp.getStackSize()==1)
return subtitle;
String s="";
int[] dim = imp.getDimensions(false);
int channels=dim[2], slices=dim[3], frames=dim[4];
if (channels>1) {
s += "c:"+imp.getChannel()+"/"+channels;
if (slices>1||frames>1) s += " ";
}
if (slices>1) {
s += "z:"+imp.getSlice()+"/"+slices;
if (frames>1) s += " ";
}
if (frames>1)
s += "t:"+imp.getFrame()+"/"+frames;
if (running2) return s;
int index = subtitle.indexOf(";");
if (index!=-1) {
int index2 = subtitle.indexOf("(");
if (index2>=0 && index2<index && subtitle.length()>index2+4 && !subtitle.substring(index2+1, index2+4).equals("ch:")) {
index = index2;
s = s + " ";
}
subtitle = subtitle.substring(index, subtitle.length());
} else
subtitle = "";
return s + subtitle;
}
public boolean isHyperStack() {
return hyperStack && getNScrollbars()>0;
}
public void setPosition(int channel, int slice, int frame) {
if (cSelector!=null && channel!=c) {
c = channel;
cSelector.setValue(channel);
SyncWindows.setC(this, channel);
}
if (zSelector!=null && slice!=z) {
z = slice;
zSelector.setValue(slice);
SyncWindows.setZ(this, slice);
}
if (tSelector!=null && frame!=t) {
t = frame;
tSelector.setValue(frame);
SyncWindows.setT(this, frame);
}
this.slice = (t-1)*nChannels*nSlices + (z-1)*nChannels + c;
imp.updatePosition(c, z, t);
if (this.slice>0) {
int s = this.slice;
this.slice = 0;
if (s!=imp.getCurrentSlice())
imp.setSlice(s);
}
}
private void setSlice(ImagePlus imp, int n) {
if (imp.isLocked()) {
IJ.beep();
IJ.showStatus("Image is locked");
} else
imp.setSlice(n);
}
public boolean validDimensions() {
int c = imp.getNChannels();
int z = imp.getNSlices();
int t = imp.getNFrames();
int size = imp.getStackSize();
if (c==size && c*z*t==size && nSlices==size && nChannels*nSlices*nFrames==size)
return true;
if (c!=nChannels||z!=nSlices||t!=nFrames||c*z*t!=size)
return false;
else
return true;
}
public void setAnimate(boolean b) {
if (running2!=b && animationSelector!=null)
animationSelector.updatePlayPauseIcon();
running2 = b;
}
public boolean getAnimate() {
return running2;
}
public int getNScrollbars() {
int n = 0;
if (cSelector!=null) n++;
if (zSelector!=null) n++;
if (tSelector!=null) n++;
return n;
}
void removeScrollbars() {
if (cSelector!=null) {
remove(cSelector);
cSelector.removeAdjustmentListener(this);
cSelector = null;
}
if (zSelector!=null) {
remove(zSelector);
zSelector.removeAdjustmentListener(this);
zSelector = null;
}
if (tSelector!=null) {
remove(tSelector);
tSelector.removeAdjustmentListener(this);
tSelector = null;
}
}
}