/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Icy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.canvas;
import icy.action.CanvasActions;
import icy.action.GeneralActions;
import icy.action.RoiActions;
import icy.action.WindowActions;
import icy.canvas.CanvasLayerEvent.LayersEventType;
import icy.canvas.IcyCanvasEvent.IcyCanvasEventType;
import icy.canvas.Layer.LayerListener;
import icy.common.CollapsibleEvent;
import icy.common.UpdateEventHandler;
import icy.common.listener.ChangeListener;
import icy.common.listener.ProgressListener;
import icy.gui.util.GuiUtil;
import icy.gui.viewer.MouseImageInfosPanel;
import icy.gui.viewer.TNavigationPanel;
import icy.gui.viewer.Viewer;
import icy.gui.viewer.ViewerEvent;
import icy.gui.viewer.ViewerListener;
import icy.gui.viewer.ZNavigationPanel;
import icy.image.IcyBufferedImage;
import icy.image.colormodel.IcyColorModel;
import icy.image.lut.LUT;
import icy.image.lut.LUTEvent;
import icy.image.lut.LUTEvent.LUTEventType;
import icy.image.lut.LUTListener;
import icy.main.Icy;
import icy.painter.Overlay;
import icy.painter.OverlayWrapper;
import icy.painter.Painter;
import icy.plugin.PluginDescriptor;
import icy.plugin.PluginLoader;
import icy.plugin.interface_.PluginCanvas;
import icy.roi.ROI;
import icy.sequence.DimensionId;
import icy.sequence.Sequence;
import icy.sequence.SequenceEvent;
import icy.sequence.SequenceEvent.SequenceEventType;
import icy.sequence.SequenceListener;
import icy.system.IcyExceptionHandler;
import icy.system.thread.ThreadUtil;
import icy.type.point.Point5D;
import icy.util.ClassUtil;
import icy.util.EventUtil;
import icy.util.OMEUtil;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.event.ChangeEvent;
import plugins.kernel.canvas.Canvas2DPlugin;
import plugins.kernel.canvas.VtkCanvasPlugin;
/**
* @author Fabrice de Chaumont & Stephane Dallongeville<br>
* <br>
* An IcyCanvas is a basic Canvas used into the viewer. It contains a visual representation
* of the sequence and provides some facilities as basic transformation and view
* synchronization.<br>
* Also IcyCanvas receives key events from Viewer when they are not consumed.<br>
* <br>
* By default transformations are applied in following order :<br>
* Rotation, Translation then Scaling.<br>
* The rotation transformation is relative to canvas center.<br>
* <br>
* Free feel to implement and override this design or not. <br>
* <br>
* (Canvas2D and Canvas3D derives from IcyCanvas)<br>
*/
public abstract class IcyCanvas extends JPanel implements KeyListener, ViewerListener, SequenceListener, LUTListener,
ChangeListener, LayerListener
{
protected class IcyCanvasImageOverlay extends Overlay
{
public IcyCanvasImageOverlay()
{
super((getSequence() == null) ? "Image" : getSequence().getName(), OverlayPriority.IMAGE_NORMAL);
// we fix the image overlay
canBeRemoved = false;
readOnly = false;
}
@Override
public void paint(Graphics2D g, Sequence sequence, IcyCanvas canvas)
{
// default lazy implementation (very slow)
if (g != null)
g.drawImage(getCurrentImage(), null, 0, 0);
}
}
/**
* Returns all {@link PluginCanvas} plugins (kernel plugin are returned first).
*/
public static List<PluginDescriptor> getCanvasPlugins()
{
// get all canvas plugins
final List<PluginDescriptor> result = PluginLoader.getPlugins(PluginCanvas.class);
// VTK is not loaded ?
if (!Icy.isVtkLibraryLoaded())
{
// remove VtkCanvas
final int ind = PluginDescriptor.getIndex(result, VtkCanvasPlugin.class.getName());
if (ind != -1)
result.remove(ind);
}
// sort plugins list
Collections.sort(result, new Comparator<PluginDescriptor>()
{
@Override
public int compare(PluginDescriptor o1, PluginDescriptor o2)
{
return Integer.valueOf(getOrder(o1)).compareTo(Integer.valueOf(getOrder(o2)));
}
int getOrder(PluginDescriptor p)
{
if (p.getClassName().equals(Canvas2DPlugin.class.getName()))
return 0;
if (p.getClassName().equals(VtkCanvasPlugin.class.getName()))
return 1;
return 10;
}
});
return result;
}
/**
* Returns all {@link PluginCanvas} plugins class name (kernel plugin are returned first).
*/
public static List<String> getCanvasPluginNames()
{
// get all canvas plugins
final List<PluginDescriptor> plugins = getCanvasPlugins();
final List<String> result = new ArrayList<String>();
for (PluginDescriptor plugin : plugins)
result.add(plugin.getClassName());
return result;
}
/**
* Returns the plugin class name corresponding to the specified Canvas class name.<br>
* Returns <code>null</code> if we can't find a corresponding plugin.
*/
public static String getPluginClassName(String canvasClassName)
{
for (PluginDescriptor plugin : IcyCanvas.getCanvasPlugins())
{
final String className = getCanvasClassName(plugin);
// we found the corresponding plugin
if (canvasClassName.equals(className))
// get plugin class name
return plugin.getClassName();
}
return null;
}
/**
* Returns the canvas class name corresponding to the specified {@link PluginCanvas} plugin.<br>
* Returns <code>null</code> if we can't retrieve the corresponding canvas class name.
*/
public static String getCanvasClassName(PluginDescriptor plugin)
{
try
{
if (plugin != null)
{
final PluginCanvas pluginCanvas = (PluginCanvas) plugin.getPluginClass().newInstance();
// return canvas class name
return pluginCanvas.getCanvasClassName();
}
}
catch (Exception e)
{
IcyExceptionHandler.showErrorMessage(e, true);
}
return null;
}
/**
* Returns the canvas class name corresponding to the specified {@link PluginCanvas} class name. <br>
* Returns <code>null</code> if we can't find retrieve the corresponding canvas class name.
*/
public static String getCanvasClassName(String pluginClassName)
{
return getCanvasClassName(PluginLoader.getPlugin(pluginClassName));
}
// /**
// * Return the class name of all {@link PluginCanvas}.
// */
// public static List<String> getCanvasPlugins()
// {
// // get all canvas plugins
// final List<PluginDescriptor> plugins = PluginLoader.getPlugins(PluginCanvas.class);
// final List<String> result = new ArrayList<String>();
//
// // we want the default 2D and 3D canvas to be first
// result.add(Canvas2DPlugin.class.getName());
// if (Icy.isVtkLibraryLoaded())
// result.add(VtkCanvasPlugin.class.getName());
//
// for (PluginDescriptor plugin : plugins)
// {
// final String className = plugin.getClassName();
//
// // ignore default canvas as they have been already added
// if (Canvas2DPlugin.class.getName().equals(className))
// continue;
// if (VtkCanvasPlugin.class.getName().equals(className))
// continue;
//
// CollectionUtil.addUniq(result, plugin.getClassName());
// }
//
// return result;
// }
/**
* Create a {@link IcyCanvas} object from its class name or {@link PluginCanvas} class name.<br>
* Throws an exception if an error occurred (canvas class was not found or it could not be
* creatd).
*
* @param viewer
* {@link Viewer} to which to canvas is attached.
* @throws ClassCastException
* if the specified class name is not a canvas plugin or canvas class name
* @throws Exception
* if the specified canvas cannot be created for some reasons
*/
public static IcyCanvas create(String className, Viewer viewer) throws ClassCastException, Exception
{
// search for the specified className
final Class<?> clazz = ClassUtil.findClass(className);
final Class<? extends PluginCanvas> pluginCanvasClazz;
try
{
// we first check if we have a IcyCanvas Plugin class here
pluginCanvasClazz = clazz.asSubclass(PluginCanvas.class);
}
catch (ClassCastException e0)
{
// check if this is a IcyCanvas class
final Class<? extends IcyCanvas> canvasClazz = clazz.asSubclass(IcyCanvas.class);
// get constructor (Viewer)
final Constructor<? extends IcyCanvas> constructor = canvasClazz.getConstructor(new Class[] {Viewer.class});
// build canvas
return constructor.newInstance(new Object[] {viewer});
}
// create canvas from plugin
return pluginCanvasClazz.newInstance().createCanvas(viewer);
}
public static void addVisibleLayerToList(final Layer layer, ArrayList<Layer> list)
{
if ((layer != null) && (layer.isVisible()))
list.add(layer);
}
private static final long serialVersionUID = -8461229450296203011L;
public static final String PROPERTY_LAYERS_VISIBLE = "layersVisible";
/**
* Navigations bar
*/
final protected ZNavigationPanel zNav;
final protected TNavigationPanel tNav;
/**
* The panel where mouse informations are displayed
*/
protected final MouseImageInfosPanel mouseInfPanel;
/**
* The panel contains all settings and informations data such as<br>
* scale factor, rendering mode...
* Will be retrieved by the inspector to get information on the current canvas.
*/
protected JPanel panel;
/**
* attached viewer
*/
protected final Viewer viewer;
/**
* layers visible flag
*/
protected boolean layersVisible;
/**
* synchronization group :<br>
* 0 = unsynchronized
* 1 = full synchronization group 1
* 2 = full synchronization group 2
* 3 = view synchronization group (T and Z navigation are not synchronized)
* 4 = slice synchronization group (only T and Z navigation are synchronized)
*/
protected int syncId;
/**
* Overlay/Layer used to display sequence image
*/
protected final Overlay imageOverlay;
protected final Layer imageLayer;
/**
* Layers attached to canvas<br>
* There are representing sequence overlays with some visualization properties
*/
protected final Map<Overlay, Layer> layers;
/**
* Priority ordered layers.
*/
protected List<Layer> orderedLayers;
/**
* internal updater
*/
protected final UpdateEventHandler updater;
/**
* listeners
*/
protected final List<IcyCanvasListener> listeners;
protected final List<CanvasLayerListener> layerListeners;
/**
* Current X position (should be -1 when canvas handle multi X dimension view).
*/
protected int posX;
/**
* Current Y position (should be -1 when canvas handle multi Y dimension view).
*/
protected int posY;
/**
* Current Z position (should be -1 when canvas handle multi Z dimension view).
*/
protected int posZ;
/**
* Current T position (should be -1 when canvas handle multi T dimension view).
*/
protected int posT;
/**
* Current C position (should be -1 when canvas handle multi C dimension view).
*/
protected int posC;
/**
* Current mouse position (canvas coordinate space)
*/
protected Point mousePos;
/**
* internals
*/
protected LUT lut;
protected boolean synchMaster;
protected boolean orderedLayersOutdated;
private Runnable guiUpdater;
/**
* Constructor
*
* @param viewer
*/
public IcyCanvas(Viewer viewer)
{
super();
// default
this.viewer = viewer;
layersVisible = true;
layers = new HashMap<Overlay, Layer>();
orderedLayers = new ArrayList<Layer>();
syncId = 0;
synchMaster = false;
orderedLayersOutdated = false;
updater = new UpdateEventHandler(this, false);
// default position
mousePos = new Point(0, 0);
posX = -1;
posY = -1;
posZ = -1;
posT = -1;
posC = -1;
// GUI stuff
panel = new JPanel();
listeners = new ArrayList<IcyCanvasListener>();
layerListeners = new ArrayList<CanvasLayerListener>();
// Z navigation
zNav = new ZNavigationPanel();
zNav.addChangeListener(new javax.swing.event.ChangeListener()
{
@Override
public void stateChanged(ChangeEvent e)
{
// set the new Z position
setPositionZ(zNav.getValue());
}
});
// T navigation
tNav = new TNavigationPanel();
tNav.addChangeListener(new javax.swing.event.ChangeListener()
{
@Override
public void stateChanged(ChangeEvent e)
{
// set the new T position
setPositionT(tNav.getValue());
}
});
// mouse info panel
mouseInfPanel = new MouseImageInfosPanel();
// default canvas layout
setLayout(new BorderLayout());
add(zNav, BorderLayout.WEST);
add(GuiUtil.createPageBoxPanel(tNav, mouseInfPanel), BorderLayout.SOUTH);
// asynchronous updater for GUI
guiUpdater = new Runnable()
{
@Override
public void run()
{
ThreadUtil.invokeNow(new Runnable()
{
@Override
public void run()
{
// update sliders bounds if needed
updateZNav();
updateTNav();
// adjust X position if needed
final int maxX = getMaxPositionX();
final int curX = getPositionX();
if ((curX != -1) && (curX > maxX))
setPositionX(maxX);
// adjust Y position if needed
final int maxY = getMaxPositionY();
final int curY = getPositionY();
if ((curY != -1) && (curY > maxY))
setPositionY(maxY);
// adjust C position if needed
final int maxC = getMaxPositionC();
final int curC = getPositionC();
if ((curC != -1) && (curC > maxC))
setPositionC(maxC);
// adjust Z position if needed
final int maxZ = getMaxPositionZ();
final int curZ = getPositionZ();
if ((curZ != -1) && (curZ > maxZ))
setPositionZ(maxZ);
// adjust T position if needed
final int maxT = getMaxPositionT();
final int curT = getPositionT();
if ((curT != -1) && (curT > maxT))
setPositionT(maxT);
// refresh mouse panel informations (data values can have changed)
mouseInfPanel.updateInfos(IcyCanvas.this);
}
});
}
};
// create image overlay
imageOverlay = createImageOverlay();
// create layers from overlays
beginUpdate();
try
{
// first add image layer
imageLayer = addLayer(getImageOverlay());
final Sequence sequence = getSequence();
if (sequence != null)
{
// then add sequence overlays to layer list
for (Overlay overlay : sequence.getOverlays())
addLayer(overlay);
}
else
System.err.println("Sequence null when canvas created");
}
finally
{
endUpdate();
}
// add listeners
viewer.addListener(this);
final Sequence seq = getSequence();
if (seq != null)
seq.addListener(this);
// set lut (no event wanted here)
lut = null;
setLut(viewer.getLut(), false);
}
/**
* Called by the viewer when canvas is closed to release some resources.<br/>
* Be careful to not restore previous state here (as the colormap) because generally <code>shutdown</code> is called
* <b>after</b> the creation of the other canvas.
*/
public void shutDown()
{
// remove navigation panel listener
zNav.removeAllChangeListener();
tNav.removeAllChangeListener();
// remove listeners
if (lut != null)
lut.removeListener(this);
final Sequence seq = getSequence();
if (seq != null)
seq.removeListener(this);
viewer.removeListener(this);
// remove all layers
beginUpdate();
try
{
for (Layer layer : getLayers())
removeLayer(layer);
}
finally
{
endUpdate();
}
// release layers
orderedLayers.clear();
// remove all IcyCanvas & Layer listeners
listeners.clear();
layerListeners.clear();
}
/**
* Force canvas refresh
*/
public abstract void refresh();
protected Overlay createImageOverlay()
{
// default image overlay
return new IcyCanvasImageOverlay();
}
/**
* Returns the {@link Overlay} used to display the current sequence image
*/
public Overlay getImageOverlay()
{
return imageOverlay;
}
/**
* Returns the {@link Layer} object used to display the current sequence image
*/
public Layer getImageLayer()
{
return imageLayer;
}
/**
* @deprecated Use {@link #isLayersVisible()} instead.
*/
@Deprecated
public boolean getDrawLayers()
{
return isLayersVisible();
}
/**
* @deprecated Use {@link #setLayersVisible(boolean)} instead.
*/
@Deprecated
public void setDrawLayers(boolean value)
{
setLayersVisible(value);
}
/**
* Return true if layers are visible on the canvas.
*/
public boolean isLayersVisible()
{
return layersVisible;
}
/**
* Make layers visible on this canvas (default = true).
*/
public void setLayersVisible(boolean value)
{
if (layersVisible != value)
{
layersVisible = value;
layersVisibleChanged();
firePropertyChange(PROPERTY_LAYERS_VISIBLE, !value, value);
}
}
/**
* Global layers visibility changed
*/
protected void layersVisibleChanged()
{
final Component comp = getViewComponent();
if (comp != null)
comp.repaint();
}
/**
* @return the viewer
*/
public Viewer getViewer()
{
return viewer;
}
/**
* @return the sequence
*/
public Sequence getSequence()
{
return viewer.getSequence();
}
/**
* @return the main view component
*/
public abstract Component getViewComponent();
/**
* @return the Z navigation bar panel
*/
public ZNavigationPanel getZNavigationPanel()
{
return zNav;
}
/**
* @return the T navigation bar panel
*/
public TNavigationPanel getTNavigationPanel()
{
return tNav;
}
/**
* @return the mouse image informations panel
*/
public MouseImageInfosPanel getMouseImageInfosPanel()
{
return mouseInfPanel;
}
/**
* @return the LUT
*/
public LUT getLut()
{
// ensure we have the good lut
setLut(viewer.getLut(), true);
return lut;
}
/**
* set canvas LUT
*/
private void setLut(LUT lut, boolean event)
{
if (this.lut != lut)
{
if (this.lut != null)
this.lut.removeListener(this);
this.lut = lut;
// add listener to the new lut
if (lut != null)
lut.addListener(this);
// launch a lutChanged event if wanted
if (event)
lutChanged(new LUTEvent(lut, -1, LUTEventType.COLORMAP_CHANGED));
}
}
/**
* @deprecated Use {@link #customizeToolbar(JToolBar)} instead.
*/
@SuppressWarnings("unused")
@Deprecated
public void addViewerToolbarComponents(JToolBar toolBar)
{
}
/**
* Called by the parent viewer when building the toolbar.<br>
* This way the canvas can customize it by adding specific command for instance.<br>
*
* @param toolBar
* the parent toolbar to customize
*/
public void customizeToolbar(JToolBar toolBar)
{
addViewerToolbarComponents(toolBar);
}
/**
* Returns the setting panel of this canvas.<br>
* The setting panel is displayed in the inspector so user can change canvas parameters.
*/
public JPanel getPanel()
{
return panel;
}
/**
* Returns all layers attached to this canvas.<br/>
*
* @param sorted
* If <code>true</code> the returned list is sorted on the layer priority.<br>
* Sort operation is cached so the method could take sometime when sort cache need to be
* rebuild.
*/
public List<Layer> getLayers(boolean sorted)
{
if (sorted)
{
// need to rebuild sorted layer list ?
if (orderedLayersOutdated)
{
// build and sort the list
synchronized (layers)
{
orderedLayers = new ArrayList<Layer>(layers.values());
}
Collections.sort(orderedLayers);
orderedLayersOutdated = false;
}
return new ArrayList<Layer>(orderedLayers);
}
synchronized (layers)
{
return new ArrayList<Layer>(layers.values());
}
}
/**
* Returns all layers attached to this canvas.<br/>
* The returned list is sorted on the layer priority.<br>
* Sort operation is cached so the method could take sometime when cache need to be rebuild.
*/
public List<Layer> getLayers()
{
return getLayers(true);
}
/**
* Returns all visible layers (visible property set to <code>true</code>) attached to this
* canvas.
*
* @param sorted
* If <code>true</code> the returned list is sorted on the layer priority.<br>
* Sort operation is cached so the method could take sometime when sort cache need to be
* rebuild.
*/
public List<Layer> getVisibleLayers(boolean sorted)
{
final List<Layer> olayers = getLayers(sorted);
final List<Layer> result = new ArrayList<Layer>(olayers.size());
for (Layer l : olayers)
if (l.isVisible())
result.add(l);
return result;
}
/**
* Returns all visible layers (visible property set to <code>true</code>) attached to this
* canvas.<br/>
* The list is sorted on the layer priority.
*/
public ArrayList<Layer> getVisibleLayers()
{
return (ArrayList<Layer>) getVisibleLayers(true);
}
/**
* @deprecated Use {@link #getLayers()} instead (sorted on Layer priority).
*/
@Deprecated
public List<Layer> getOrderedLayersForEvent()
{
return getLayers();
}
/**
* @deprecated Use {@link #getVisibleLayers()} instead (sorted on Layer priority).
*/
@Deprecated
public List<Layer> getVisibleOrderedLayersForEvent()
{
return getVisibleLayers();
}
/**
* @deprecated Use {@link #getOverlays()} instead.
*/
@Deprecated
public List<Painter> getLayersPainter()
{
final ArrayList<Painter> result = new ArrayList<Painter>();
for (Overlay overlay : getOverlays())
{
if (overlay instanceof OverlayWrapper)
result.add(((OverlayWrapper) overlay).getPainter());
else
result.add(overlay);
}
return result;
}
/**
* Directly returns a {@link Set} of all Overlay displayed by this canvas.
*/
public Set<Overlay> getOverlays()
{
synchronized (layers)
{
return new HashSet<Overlay>(layers.keySet());
}
}
/**
* @return the SyncId
*/
public int getSyncId()
{
return syncId;
}
/**
* Set the synchronization group id (0 means unsynchronized).<br>
*
* @return <code>false</code> if the canvas do not support synchronization group.
* @param id
* the syncId to set
*/
public boolean setSyncId(int id)
{
if (!isSynchronizationSupported())
return false;
if (this.syncId != id)
{
this.syncId = id;
// notify sync has changed
updater.changed(new IcyCanvasEvent(this, IcyCanvasEventType.SYNC_CHANGED));
}
return true;
}
/**
* Return true if this canvas support synchronization
*/
public boolean isSynchronizationSupported()
{
// default (override it when supported)
return false;
}
/**
* Return true if this canvas is synchronized
*/
public boolean isSynchronized()
{
return syncId > 0;
}
/**
* Return true if current canvas is synchronized and is currently the synchronize leader.
*/
public boolean isSynchMaster()
{
return synchMaster;
}
/**
* @deprecated Use {@link #isSynchMaster()} instead.
*/
@Deprecated
public boolean isSynchHeader()
{
return isSynchMaster();
}
/**
* Return true if current canvas is synchronized and it's not the synchronize master
*/
public boolean isSynchSlave()
{
if (isSynchronized())
{
if (isSynchMaster())
return false;
// search for a master in synchronized canvas
for (IcyCanvas cnv : getSynchronizedCanvas())
if (cnv.isSynchMaster())
return true;
}
return false;
}
/**
* Return true if this canvas is synchronized on view (offset, zoom and rotation).
*/
public boolean isSynchOnView()
{
return (syncId == 1) || (syncId == 2) || (syncId == 3);
}
/**
* Return true if this canvas is synchronized on slice (T and Z position)
*/
public boolean isSynchOnSlice()
{
return (syncId == 1) || (syncId == 2) || (syncId == 4);
}
/**
* Return true if this canvas is synchronized on cursor (mouse cursor)
*/
public boolean isSynchOnCursor()
{
return (syncId > 0);
}
/**
* Return true if we get the synchronizer master from synchronized canvas
*/
protected boolean getSynchMaster()
{
return getSynchMaster(getSynchronizedCanvas());
}
/**
* @deprecated Use {@link #getSynchMaster()} instead.
*/
@Deprecated
protected boolean getSynchHeader()
{
return getSynchMaster();
}
/**
* Return true if we get the synchronizer master from specified canvas list.
*/
protected boolean getSynchMaster(List<IcyCanvas> canvasList)
{
for (IcyCanvas canvas : canvasList)
if (canvas.isSynchMaster())
return canvas == this;
// no master found so we are master
synchMaster = true;
return true;
}
/**
* @deprecated Use {@link #getSynchMaster(List)} instead.
*/
@Deprecated
protected boolean getSynchHeader(List<IcyCanvas> canvasList)
{
return getSynchMaster(canvasList);
}
/**
* Release synchronizer master
*/
protected void releaseSynchMaster()
{
synchMaster = false;
}
/**
* @deprecated Use {@link #releaseSynchMaster()} instead.
*/
@Deprecated
protected void releaseSynchHeader()
{
releaseSynchMaster();
}
/**
* Return the list of canvas which are synchronized with the current one
*/
private List<IcyCanvas> getSynchronizedCanvas()
{
final List<IcyCanvas> result = new ArrayList<IcyCanvas>();
if (isSynchronized())
{
final List<Viewer> viewers = Icy.getMainInterface().getViewers();
for (int i = viewers.size() - 1; i >= 0; i--)
{
final IcyCanvas cnv = viewers.get(i).getCanvas();
if ((cnv == this) || (cnv.getSyncId() != syncId))
viewers.remove(i);
}
for (Viewer v : viewers)
{
final IcyCanvas cnv = v.getCanvas();
// only permit same class
if (cnv.getClass().isInstance(this))
result.add(cnv);
}
}
return result;
}
/**
* Synchronize views of specified list of canvas
*/
protected void synchronizeCanvas(List<IcyCanvas> canvasList, IcyCanvasEvent event, boolean processAll)
{
final IcyCanvasEventType type = event.getType();
final DimensionId dim = event.getDim();
// position synchronization
if (isSynchOnSlice())
{
if (processAll || (type == IcyCanvasEventType.POSITION_CHANGED))
{
// no information about dimension --> set all
if (processAll || (dim == DimensionId.NULL))
{
final int x = getPositionX();
final int y = getPositionY();
final int z = getPositionZ();
final int t = getPositionT();
final int c = getPositionC();
for (IcyCanvas cnv : canvasList)
{
if (x != -1)
cnv.setPositionX(x);
if (y != -1)
cnv.setPositionY(y);
if (z != -1)
cnv.setPositionZ(z);
if (t != -1)
cnv.setPositionT(t);
if (c != -1)
cnv.setPositionC(c);
}
}
else
{
for (IcyCanvas cnv : canvasList)
{
final int pos = getPosition(dim);
if (pos != -1)
cnv.setPosition(dim, pos);
}
}
}
}
// view synchronization
if (isSynchOnView())
{
if (processAll || (type == IcyCanvasEventType.SCALE_CHANGED))
{
// no information about dimension --> set all
if (processAll || (dim == DimensionId.NULL))
{
final double sX = getScaleX();
final double sY = getScaleY();
final double sZ = getScaleZ();
final double sT = getScaleT();
final double sC = getScaleC();
for (IcyCanvas cnv : canvasList)
{
cnv.setScaleX(sX);
cnv.setScaleY(sY);
cnv.setScaleZ(sZ);
cnv.setScaleT(sT);
cnv.setScaleC(sC);
}
}
else
{
for (IcyCanvas cnv : canvasList)
cnv.setScale(dim, getScale(dim));
}
}
if (processAll || (type == IcyCanvasEventType.ROTATION_CHANGED))
{
// no information about dimension --> set all
if (processAll || (dim == DimensionId.NULL))
{
final double rotX = getRotationX();
final double rotY = getRotationY();
final double rotZ = getRotationZ();
final double rotT = getRotationT();
final double rotC = getRotationC();
for (IcyCanvas cnv : canvasList)
{
cnv.setRotationX(rotX);
cnv.setRotationY(rotY);
cnv.setRotationZ(rotZ);
cnv.setRotationT(rotT);
cnv.setRotationC(rotC);
}
}
else
{
for (IcyCanvas cnv : canvasList)
cnv.setRotation(dim, getRotation(dim));
}
}
// process offset in last as it can be limited depending destination scale value
if (processAll || (type == IcyCanvasEventType.OFFSET_CHANGED))
{
// no information about dimension --> set all
if (processAll || (dim == DimensionId.NULL))
{
final int offX = getOffsetX();
final int offY = getOffsetY();
final int offZ = getOffsetZ();
final int offT = getOffsetT();
final int offC = getOffsetC();
for (IcyCanvas cnv : canvasList)
{
cnv.setOffsetX(offX);
cnv.setOffsetY(offY);
cnv.setOffsetZ(offZ);
cnv.setOffsetT(offT);
cnv.setOffsetC(offC);
}
}
else
{
for (IcyCanvas cnv : canvasList)
cnv.setOffset(dim, getOffset(dim));
}
}
}
// cursor synchronization
if (isSynchOnCursor())
{
// mouse synchronization
if (processAll || (type == IcyCanvasEventType.MOUSE_IMAGE_POSITION_CHANGED))
{
// no information about dimension --> set all
if (processAll || (dim == DimensionId.NULL))
{
final double mipX = getMouseImagePosX();
final double mipY = getMouseImagePosY();
final double mipZ = getMouseImagePosZ();
final double mipT = getMouseImagePosT();
final double mipC = getMouseImagePosC();
for (IcyCanvas cnv : canvasList)
{
cnv.setMouseImagePosX(mipX);
cnv.setMouseImagePosY(mipY);
cnv.setMouseImagePosZ(mipZ);
cnv.setMouseImagePosT(mipT);
cnv.setMouseImagePosC(mipC);
}
}
else
{
for (IcyCanvas cnv : canvasList)
cnv.setMouseImagePos(dim, getMouseImagePos(dim));
}
}
}
}
/**
* Get position for specified dimension
*/
public int getPosition(DimensionId dim)
{
switch (dim)
{
case X:
return getPositionX();
case Y:
return getPositionY();
case Z:
return getPositionZ();
case T:
return getPositionT();
case C:
return getPositionC();
}
return 0;
}
/**
* @return current X (-1 if all selected)
*/
public int getPositionX()
{
return -1;
}
/**
* @return current Y (-1 if all selected)
*/
public int getPositionY()
{
return -1;
}
/**
* @return current Z (-1 if all selected)
*/
public int getPositionZ()
{
return posZ;
}
/**
* @return current T (-1 if all selected)
*/
public int getPositionT()
{
return posT;
}
/**
* @return current C (-1 if all selected)
*/
public int getPositionC()
{
return posC;
}
/**
* Returns the 5D canvas position (-1 mean that the complete dimension is selected)
*/
public Point5D.Integer getPosition5D()
{
return new Point5D.Integer(getPositionX(), getPositionY(), getPositionZ(), getPositionT(), getPositionC());
}
/**
* @return current Z (-1 if all selected)
* @deprecated uses getPositionZ() instead
*/
@Deprecated
public int getZ()
{
return getPositionZ();
}
/**
* @return current T (-1 if all selected)
* @deprecated uses getPositionT() instead
*/
@Deprecated
public int getT()
{
return getPositionT();
}
/**
* @return current C (-1 if all selected)
* @deprecated uses getPositionC() instead
*/
@Deprecated
public int getC()
{
return getPositionC();
}
/**
* Get maximum position for specified dimension
*/
public double getMaxPosition(DimensionId dim)
{
switch (dim)
{
case X:
return getMaxPositionX();
case Y:
return getMaxPositionY();
case Z:
return getMaxPositionZ();
case T:
return getMaxPositionT();
case C:
return getMaxPositionC();
}
return 0;
}
/**
* Get maximum X value
*/
public int getMaxPositionX()
{
final Sequence sequence = getSequence();
// have to test this as we release sequence reference on closed
if (sequence == null)
return 0;
return Math.max(0, getImageSizeX() - 1);
}
/**
* Get maximum Y value
*/
public int getMaxPositionY()
{
final Sequence sequence = getSequence();
// have to test this as we release sequence reference on closed
if (sequence == null)
return 0;
return Math.max(0, getImageSizeY() - 1);
}
/**
* Get maximum Z value
*/
public int getMaxPositionZ()
{
final Sequence sequence = getSequence();
// have to test this as we release sequence reference on closed
if (sequence == null)
return 0;
return Math.max(0, getImageSizeZ() - 1);
}
/**
* Get maximum T value
*/
public int getMaxPositionT()
{
final Sequence sequence = getSequence();
// have to test this as we release sequence reference on closed
if (sequence == null)
return 0;
return Math.max(0, getImageSizeT() - 1);
}
/**
* Get maximum C value
*/
public int getMaxPositionC()
{
final Sequence sequence = getSequence();
// have to test this as we release sequence reference on closed
if (sequence == null)
return 0;
return Math.max(0, getImageSizeC() - 1);
}
/**
* Get the maximum 5D position for the canvas.
*
* @see #getPosition5D()
*/
public Point5D.Integer getMaxPosition5D()
{
return new Point5D.Integer(getMaxPositionX(), getMaxPositionY(), getMaxPositionZ(), getMaxPositionT(),
getMaxPositionC());
}
/**
* @deprecated Use {@link #getMaxPosition(DimensionId)} instead
*/
@Deprecated
public double getMax(DimensionId dim)
{
return getMaxPosition(dim);
}
/**
* @deprecated Use {@link #getMaxPositionX()} instead
*/
@Deprecated
public int getMaxX()
{
return getMaxPositionX();
}
/**
* @deprecated Use {@link #getMaxPositionY()} instead
*/
@Deprecated
public int getMaxY()
{
return getMaxPositionY();
}
/**
* @deprecated Use {@link #getMaxPositionZ()} instead
*/
@Deprecated
public int getMaxZ()
{
return getMaxPositionZ();
}
/**
* @deprecated Use {@link #getMaxPositionT()} instead
*/
@Deprecated
public int getMaxT()
{
return getMaxPositionT();
}
/**
* @deprecated Use {@link #getMaxPositionC()} instead
*/
@Deprecated
public int getMaxC()
{
return getMaxPositionC();
}
/**
* Get canvas view size for specified Dimension
*/
public int getCanvasSize(DimensionId dim)
{
switch (dim)
{
case X:
return getCanvasSizeX();
case Y:
return getCanvasSizeY();
case Z:
return getCanvasSizeZ();
case T:
return getCanvasSizeT();
case C:
return getCanvasSizeC();
}
// size not supported
return -1;
}
/**
* Returns the canvas view size X.
*/
public int getCanvasSizeX()
{
final Component comp = getViewComponent();
int res = 0;
if (comp != null)
{
// by default we use view component width
res = comp.getWidth();
// preferred width if size not yet set
if (res == 0)
res = comp.getPreferredSize().width;
}
return res;
}
/**
* Returns the canvas view size Y.
*/
public int getCanvasSizeY()
{
final Component comp = getViewComponent();
int res = 0;
if (comp != null)
{
// by default we use view component width
res = comp.getHeight();
// preferred width if size not yet set
if (res == 0)
res = comp.getPreferredSize().height;
}
return res;
}
/**
* Returns the canvas view size Z.
*/
public int getCanvasSizeZ()
{
// by default : no Z dimension
return 1;
}
/**
* Returns the canvas view size T.
*/
public int getCanvasSizeT()
{
// by default : no T dimension
return 1;
}
/**
* Returns the canvas view size C.
*/
public int getCanvasSizeC()
{
// by default : no C dimension
return 1;
}
/**
* Returns the mouse position (in canvas coordinate space).
*/
public Point getMousePos()
{
return (Point) mousePos.clone();
}
/**
* Get mouse image position for specified Dimension
*/
public double getMouseImagePos(DimensionId dim)
{
switch (dim)
{
case X:
return getMouseImagePosX();
case Y:
return getMouseImagePosY();
case Z:
return getMouseImagePosZ();
case T:
return getMouseImagePosT();
case C:
return getMouseImagePosC();
}
return 0;
}
/**
* mouse X image position
*/
public double getMouseImagePosX()
{
// default implementation
return getPositionX();
}
/**
* mouse Y image position
*/
public double getMouseImagePosY()
{
// default implementation
return getPositionY();
}
/**
* mouse Z image position
*/
public double getMouseImagePosZ()
{
// default implementation
return getPositionZ();
}
/**
* mouse T image position
*/
public double getMouseImagePosT()
{
// default implementation
return getPositionT();
}
/**
* mouse C image position
*/
public double getMouseImagePosC()
{
// default implementation
return getPositionC();
}
/**
* Returns the 5D mouse image position
*/
public Point5D.Double getMouseImagePos5D()
{
return new Point5D.Double(getMouseImagePosX(), getMouseImagePosY(), getMouseImagePosZ(), getMouseImagePosT(),
getMouseImagePosC());
}
/**
* Get offset for specified Dimension
*/
public int getOffset(DimensionId dim)
{
switch (dim)
{
case X:
return getOffsetX();
case Y:
return getOffsetY();
case Z:
return getOffsetZ();
case T:
return getOffsetT();
case C:
return getOffsetC();
}
return 0;
}
/**
* X offset
*/
public int getOffsetX()
{
return 0;
}
/**
* Y offset
*/
public int getOffsetY()
{
return 0;
}
/**
* Z offset
*/
public int getOffsetZ()
{
return 0;
}
/**
* T offset
*/
public int getOffsetT()
{
return 0;
}
/**
* C offset
*/
public int getOffsetC()
{
return 0;
}
/**
* Returns the 5D offset.
*/
public Point5D.Integer getOffset5D()
{
return new Point5D.Integer(getOffsetX(), getOffsetY(), getOffsetZ(), getOffsetT(), getOffsetC());
}
/**
* X image offset
*
* @deprecated use getOffsetX() instead
*/
@Deprecated
public int getImageOffsetX()
{
return 0;
}
/**
* Y image offset
*
* @deprecated use getOffsetY() instead
*/
@Deprecated
public int getImageOffsetY()
{
return 0;
}
/**
* Z image offset
*
* @deprecated use getOffsetZ() instead
*/
@Deprecated
public int getImageOffsetZ()
{
return 0;
}
/**
* T image offset
*
* @deprecated use getOffsetT() instead
*/
@Deprecated
public int getImageOffsetT()
{
return 0;
}
/**
* C image offset
*
* @deprecated use getOffsetC() instead
*/
@Deprecated
public int getImageOffsetC()
{
return 0;
}
/**
* X canvas offset
*
* @deprecated use getOffsetX() instead
*/
@Deprecated
public int getCanvasOffsetX()
{
return 0;
}
/**
* Y canvas offset
*
* @deprecated use getOffsetY() instead
*/
@Deprecated
public int getCanvasOffsetY()
{
return 0;
}
/**
* Z canvas offset
*
* @deprecated use getOffsetZ() instead
*/
@Deprecated
public int getCanvasOffsetZ()
{
return 0;
}
/**
* T canvas offset
*
* @deprecated use getOffsetT() instead
*/
@Deprecated
public int getCanvasOffsetT()
{
return 0;
}
/**
* C canvas offset
*
* @deprecated use getOffsetC() instead
*/
@Deprecated
public int getCanvasOffsetC()
{
return 0;
}
/**
* X scale factor
*
* @deprecated use getScaleX() instead
*/
@Deprecated
public double getScaleFactorX()
{
return getScaleX();
}
/**
* Y scale factor
*
* @deprecated use getScaleY() instead
*/
@Deprecated
public double getScaleFactorY()
{
return getScaleY();
}
/**
* Z scale factor
*
* @deprecated use getScaleZ() instead
*/
@Deprecated
public double getScaleFactorZ()
{
return getScaleZ();
}
/**
* T scale factor
*
* @deprecated use getScaleT() instead
*/
@Deprecated
public double getScaleFactorT()
{
return getScaleT();
}
/**
* C scale factor
*
* @deprecated use getScaleC() instead
*/
@Deprecated
public double getScaleFactorC()
{
return getScaleC();
}
/**
* Get scale factor for specified Dimension
*/
public double getScale(DimensionId dim)
{
switch (dim)
{
case X:
return getScaleX();
case Y:
return getScaleY();
case Z:
return getScaleZ();
case T:
return getScaleT();
case C:
return getScaleC();
}
return 1d;
}
/**
* X scale factor
*/
public double getScaleX()
{
return 1d;
}
/**
* Y scale factor
*/
public double getScaleY()
{
return 1d;
}
/**
* Z scale factor
*/
public double getScaleZ()
{
return 1d;
}
/**
* T scale factor
*/
public double getScaleT()
{
return 1d;
}
/**
* C scale factor
*/
public double getScaleC()
{
return 1d;
}
/**
* Get rotation angle (radian) for specified Dimension
*/
public double getRotation(DimensionId dim)
{
switch (dim)
{
case X:
return getRotationX();
case Y:
return getRotationY();
case Z:
return getRotationZ();
case T:
return getRotationT();
case C:
return getRotationC();
}
return 1d;
}
/**
* X rotation angle (radian)
*/
public double getRotationX()
{
return 0d;
}
/**
* Y rotation angle (radian)
*/
public double getRotationY()
{
return 0d;
}
/**
* Z rotation angle (radian)
*/
public double getRotationZ()
{
return 0d;
}
/**
* T rotation angle (radian)
*/
public double getRotationT()
{
return 0d;
}
/**
* C rotation angle (radian)
*/
public double getRotationC()
{
return 0d;
}
/**
* Get image size for specified Dimension
*/
public int getImageSize(DimensionId dim)
{
switch (dim)
{
case X:
return getImageSizeX();
case Y:
return getImageSizeY();
case Z:
return getImageSizeZ();
case T:
return getImageSizeT();
case C:
return getImageSizeC();
}
return 0;
}
/**
* Get image size X
*/
public int getImageSizeX()
{
final Sequence seq = getSequence();
if (seq != null)
return seq.getSizeX();
return 0;
}
/**
* Get image size Y
*/
public int getImageSizeY()
{
final Sequence seq = getSequence();
if (seq != null)
return seq.getSizeY();
return 0;
}
/**
* Get image size Z
*/
public int getImageSizeZ()
{
final Sequence seq = getSequence();
if (seq != null)
return seq.getSizeZ();
return 0;
}
/**
* Get image size T
*/
public int getImageSizeT()
{
final Sequence seq = getSequence();
if (seq != null)
return seq.getSizeT();
return 0;
}
/**
* Get image size C
*/
public int getImageSizeC()
{
final Sequence seq = getSequence();
if (seq != null)
return seq.getSizeC();
return 0;
}
/**
* Get image size in canvas pixel coordinate for specified Dimension
*
* @deprecated doesn't take rotation transformation in account.<br>
* Use IcyCanvasXD.getImageCanvasSize(..) instead
*/
@Deprecated
public int getImageCanvasSize(DimensionId dim)
{
switch (dim)
{
case X:
return getImageCanvasSizeX();
case Y:
return getImageCanvasSizeY();
case Z:
return getImageCanvasSizeZ();
case T:
return getImageCanvasSizeT();
case C:
return getImageCanvasSizeC();
}
return 0;
}
/**
* Get image size X in canvas pixel coordinate
*
* @deprecated doesn't take rotation transformation in account.<br>
* Use IcyCanvasXD.getImageCanvasSize(..) instead
*/
@Deprecated
public int getImageCanvasSizeX()
{
return imageToCanvasDeltaX(getImageSizeX());
}
/**
* Get image size Y in canvas pixel coordinate
*
* @deprecated doesn't take rotation transformation in account.<br>
* Use IcyCanvasXD.getImageCanvasSize(..) instead
*/
@Deprecated
public int getImageCanvasSizeY()
{
return imageToCanvasDeltaY(getImageSizeY());
}
/**
* Get image size Z in canvas pixel coordinate
*
* @deprecated doesn't take rotation transformation in account.<br>
* Use IcyCanvasXD.getImageCanvasSize(..) instead
*/
@Deprecated
public int getImageCanvasSizeZ()
{
return imageToCanvasDeltaZ(getImageSizeZ());
}
/**
* Get image size T in canvas pixel coordinate
*
* @deprecated doesn't take rotation transformation in account.<br>
* Use IcyCanvasXD.getImageCanvasSize(..) instead
*/
@Deprecated
public int getImageCanvasSizeT()
{
return imageToCanvasDeltaT(getImageSizeT());
}
/**
* Get image size C in canvas pixel coordinate
*
* @deprecated doesn't take rotation transformation in account.<br>
* Use IcyCanvasXD.getImageCanvasSize(..) instead
*/
@Deprecated
public int getImageCanvasSizeC()
{
return imageToCanvasDeltaC(getImageSizeC());
}
/**
* Set position for specified dimension
*/
public void setPosition(DimensionId dim, int value)
{
switch (dim)
{
case X:
setPositionX(value);
break;
case Y:
setPositionY(value);
break;
case Z:
setPositionZ(value);
break;
case T:
setPositionT(value);
break;
case C:
setPositionC(value);
break;
}
}
/**
* Set Z position
*
* @deprecated uses setPositionZ(int) instead
*/
@Deprecated
public void setZ(int z)
{
setPositionZ(z);
}
/**
* Set T position
*
* @deprecated uses setPositionT(int) instead
*/
@Deprecated
public void setT(int t)
{
setPositionT(t);
}
/**
* Set C position
*
* @deprecated uses setPositionC(int) instead
*/
@Deprecated
public void setC(int c)
{
setPositionC(c);
}
/**
* Set X position
*/
public void setPositionX(int x)
{
final int adjX = Math.max(-1, Math.min(x, getMaxPositionX()));
if (getPositionX() != adjX)
setPositionXInternal(adjX);
}
/**
* Set Y position
*/
public void setPositionY(int y)
{
final int adjY = Math.max(-1, Math.min(y, getMaxPositionY()));
if (getPositionY() != adjY)
setPositionYInternal(adjY);
}
/**
* Set Z position
*/
public void setPositionZ(int z)
{
final int adjZ = Math.max(-1, Math.min(z, getMaxPositionZ()));
if (getPositionZ() != adjZ)
setPositionZInternal(adjZ);
}
/**
* Set T position
*/
public void setPositionT(int t)
{
final int adjT = Math.max(-1, Math.min(t, getMaxPositionT()));
if (getPositionT() != adjT)
setPositionTInternal(adjT);
}
/**
* Set C position
*/
public void setPositionC(int c)
{
final int adjC = Math.max(-1, Math.min(c, getMaxPositionC()));
if (getPositionC() != adjC)
setPositionCInternal(adjC);
}
/**
* Set X position internal
*/
protected void setPositionXInternal(int x)
{
posX = x;
// common process on position change
positionChanged(DimensionId.X);
}
/**
* Set Y position internal
*/
protected void setPositionYInternal(int y)
{
posY = y;
// common process on position change
positionChanged(DimensionId.Y);
}
/**
* Set Z position internal
*/
protected void setPositionZInternal(int z)
{
posZ = z;
// common process on position change
positionChanged(DimensionId.Z);
}
/**
* Set T position internal
*/
protected void setPositionTInternal(int t)
{
posT = t;
// common process on position change
positionChanged(DimensionId.T);
}
/**
* Set C position internal
*/
protected void setPositionCInternal(int c)
{
posC = c;
// common process on position change
positionChanged(DimensionId.C);
}
/**
* Set mouse position (in canvas coordinate space).<br>
* The method returns <code>true</code> if the mouse position actually changed.
*/
public boolean setMousePos(int x, int y)
{
if ((mousePos.x != x) || (mousePos.y != y))
{
mousePos.x = x;
mousePos.y = y;
// mouse image position probably changed so this method should be overridden
// to implement the correct calculation for the mouse image position change
return true;
}
return false;
}
/**
* Set mouse position (in canvas coordinate space)
*/
public void setMousePos(Point point)
{
setMousePos(point.x, point.y);
}
/**
* Set mouse image position for specified dimension (required for synchronization)
*/
public void setMouseImagePos(DimensionId dim, double value)
{
switch (dim)
{
case X:
setMouseImagePosX(value);
break;
case Y:
setMouseImagePosY(value);
break;
case Z:
setMouseImagePosZ(value);
break;
case T:
setMouseImagePosT(value);
break;
case C:
setMouseImagePosC(value);
break;
}
}
/**
* Set mouse X image position
*/
public void setMouseImagePosX(double value)
{
if (getMouseImagePosX() != value)
// internal set
setMouseImagePosXInternal(value);
}
/**
* Set mouse Y image position
*/
public void setMouseImagePosY(double value)
{
if (getMouseImagePosY() != value)
// internal set
setMouseImagePosYInternal(value);
}
/**
* Set mouse Z image position
*/
public void setMouseImagePosZ(double value)
{
if (getMouseImagePosZ() != value)
// internal set
setMouseImagePosZInternal(value);
}
/**
* Set mouse T image position
*/
public void setMouseImagePosT(double value)
{
if (getMouseImagePosT() != value)
// internal set
setMouseImagePosTInternal(value);
}
/**
* Set mouse C image position
*/
public void setMouseImagePosC(double value)
{
if (getMouseImagePosC() != value)
// internal set
setMouseImagePosCInternal(value);
}
/**
* Set offset X internal
*/
protected void setMouseImagePosXInternal(double value)
{
// notify change
mouseImagePositionChanged(DimensionId.X);
}
/**
* Set offset Y internal
*/
protected void setMouseImagePosYInternal(double value)
{
// notify change
mouseImagePositionChanged(DimensionId.Y);
}
/**
* Set offset Z internal
*/
protected void setMouseImagePosZInternal(double value)
{
// notify change
mouseImagePositionChanged(DimensionId.Z);
}
/**
* Set offset T internal
*/
protected void setMouseImagePosTInternal(double value)
{
// notify change
mouseImagePositionChanged(DimensionId.T);
}
/**
* Set offset C internal
*/
protected void setMouseImagePosCInternal(double value)
{
// notify change
mouseImagePositionChanged(DimensionId.C);
}
/**
* Set offset for specified dimension
*/
public void setOffset(DimensionId dim, int value)
{
switch (dim)
{
case X:
setOffsetX(value);
break;
case Y:
setOffsetY(value);
break;
case Z:
setOffsetZ(value);
break;
case T:
setOffsetT(value);
break;
case C:
setOffsetC(value);
break;
}
}
/**
* Set offset X
*/
public void setOffsetX(int value)
{
if (getOffsetX() != value)
// internal set
setOffsetXInternal(value);
}
/**
* Set offset Y
*/
public void setOffsetY(int value)
{
if (getOffsetY() != value)
// internal set
setOffsetYInternal(value);
}
/**
* Set offset Z
*/
public void setOffsetZ(int value)
{
if (getOffsetZ() != value)
// internal set
setOffsetZInternal(value);
}
/**
* Set offset T
*/
public void setOffsetT(int value)
{
if (getOffsetT() != value)
// internal set
setOffsetTInternal(value);
}
/**
* Set offset C
*/
public void setOffsetC(int value)
{
if (getOffsetC() != value)
// internal set
setOffsetCInternal(value);
}
/**
* Set offset X internal
*/
protected void setOffsetXInternal(int value)
{
// notify change
offsetChanged(DimensionId.X);
}
/**
* Set offset Y internal
*/
protected void setOffsetYInternal(int value)
{
// notify change
offsetChanged(DimensionId.Y);
}
/**
* Set offset Z internal
*/
protected void setOffsetZInternal(int value)
{
// notify change
offsetChanged(DimensionId.Z);
}
/**
* Set offset T internal
*/
protected void setOffsetTInternal(int value)
{
// notify change
offsetChanged(DimensionId.T);
}
/**
* Set offset C internal
*/
protected void setOffsetCInternal(int value)
{
// notify change
offsetChanged(DimensionId.C);
}
/**
* Set scale factor for specified dimension
*/
public void setScale(DimensionId dim, double value)
{
switch (dim)
{
case X:
setScaleX(value);
break;
case Y:
setScaleY(value);
break;
case Z:
setScaleZ(value);
break;
case T:
setScaleT(value);
break;
case C:
setScaleC(value);
break;
}
}
/**
* Set scale factor X
*/
public void setScaleX(double value)
{
if (getScaleX() != value)
// internal set
setScaleXInternal(value);
}
/**
* Set scale factor Y
*/
public void setScaleY(double value)
{
if (getScaleY() != value)
// internal set
setScaleYInternal(value);
}
/**
* Set scale factor Z
*/
public void setScaleZ(double value)
{
if (getScaleZ() != value)
// internal set
setScaleZInternal(value);
}
/**
* Set scale factor T
*/
public void setScaleT(double value)
{
if (getScaleT() != value)
// internal set
setScaleTInternal(value);
}
/**
* Set scale factor C
*/
public void setScaleC(double value)
{
if (getScaleC() != value)
// internal set
setScaleCInternal(value);
}
/**
* Set scale factor X internal
*/
protected void setScaleXInternal(double value)
{
// notify change
scaleChanged(DimensionId.X);
}
/**
* Set scale factor Y internal
*/
protected void setScaleYInternal(double value)
{
// notify change
scaleChanged(DimensionId.Y);
}
/**
* Set scale factor Z internal
*/
protected void setScaleZInternal(double value)
{
// notify change
scaleChanged(DimensionId.Z);
}
/**
* Set scale factor T internal
*/
protected void setScaleTInternal(double value)
{
// notify change
scaleChanged(DimensionId.T);
}
/**
* Set scale factor C internal
*/
protected void setScaleCInternal(double value)
{
// notify change
scaleChanged(DimensionId.C);
}
/**
* Set rotation angle (radian) for specified dimension
*/
public void setRotation(DimensionId dim, double value)
{
switch (dim)
{
case X:
setRotationX(value);
break;
case Y:
setRotationY(value);
break;
case Z:
setRotationZ(value);
break;
case T:
setRotationT(value);
break;
case C:
setRotationC(value);
break;
}
}
/**
* Set X rotation angle (radian)
*/
public void setRotationX(double value)
{
if (getRotationX() != value)
// internal set
setRotationXInternal(value);
}
/**
* Set Y rotation angle (radian)
*/
public void setRotationY(double value)
{
if (getRotationY() != value)
// internal set
setRotationYInternal(value);
}
/**
* Set Z rotation angle (radian)
*/
public void setRotationZ(double value)
{
if (getRotationZ() != value)
// internal set
setRotationZInternal(value);
}
/**
* Set T rotation angle (radian)
*/
public void setRotationT(double value)
{
if (getRotationT() != value)
// internal set
setRotationTInternal(value);
}
/**
* Set C rotation angle (radian)
*/
public void setRotationC(double value)
{
if (getRotationC() != value)
// internal set
setRotationCInternal(value);
}
/**
* Set X rotation angle internal
*/
protected void setRotationXInternal(double value)
{
// notify change
rotationChanged(DimensionId.X);
}
/**
* Set Y rotation angle internal
*/
protected void setRotationYInternal(double value)
{
// notify change
rotationChanged(DimensionId.Y);
}
/**
* Set Z rotation angle internal
*/
protected void setRotationZInternal(double value)
{
// notify change
rotationChanged(DimensionId.Z);
}
/**
* Set T rotation angle internal
*/
protected void setRotationTInternal(double value)
{
// notify change
rotationChanged(DimensionId.T);
}
/**
* Set C rotation angle internal
*/
protected void setRotationCInternal(double value)
{
// notify change
rotationChanged(DimensionId.C);
}
/**
* Called when mouse image position changed
*/
public void mouseImagePositionChanged(DimensionId dim)
{
// handle with updater
updater.changed(new IcyCanvasEvent(this, IcyCanvasEventType.MOUSE_IMAGE_POSITION_CHANGED, dim));
}
/**
* Called when canvas offset changed
*/
public void offsetChanged(DimensionId dim)
{
// handle with updater
updater.changed(new IcyCanvasEvent(this, IcyCanvasEventType.OFFSET_CHANGED, dim));
}
/**
* Called when scale factor changed
*/
public void scaleChanged(DimensionId dim)
{
// handle with updater
updater.changed(new IcyCanvasEvent(this, IcyCanvasEventType.SCALE_CHANGED, dim));
}
/**
* Called when rotation angle changed
*/
public void rotationChanged(DimensionId dim)
{
// handle with updater
updater.changed(new IcyCanvasEvent(this, IcyCanvasEventType.ROTATION_CHANGED, dim));
}
/**
* Convert specified canvas delta X to image delta X.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageDeltaX(int value)
{
return value / getScaleX();
}
/**
* Convert specified canvas delta Y to image delta Y.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageDeltaY(int value)
{
return value / getScaleY();
}
/**
* Convert specified canvas delta Z to image delta Z.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageDeltaZ(int value)
{
return value / getScaleZ();
}
/**
* Convert specified canvas delta T to image delta T.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageDeltaT(int value)
{
return value / getScaleT();
}
/**
* Convert specified canvas delta C to image delta C.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageDeltaC(int value)
{
return value / getScaleC();
}
/**
* Convert specified canvas delta X to log image delta X.<br>
* The conversion is still affected by zoom ratio but with specified logarithm form.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageLogDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageLogDeltaX(int value, double logFactor)
{
final double scaleFactor = getScaleX();
// keep the zoom ratio but in a log perspective
return value / (scaleFactor / Math.pow(10, Math.log10(scaleFactor) / logFactor));
}
/**
* Convert specified canvas delta X to log image delta X.<br>
* The conversion is still affected by zoom ratio but with logarithm form.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageLogDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageLogDeltaX(int value)
{
return canvasToImageLogDeltaX(value, 5d);
}
/**
* Convert specified canvas delta Y to log image delta Y.<br>
* The conversion is still affected by zoom ratio but with specified logarithm form.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageLogDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageLogDeltaY(int value, double logFactor)
{
final double scaleFactor = getScaleY();
// keep the zoom ratio but in a log perspective
return value / (scaleFactor / Math.pow(10, Math.log10(scaleFactor) / logFactor));
}
/**
* Convert specified canvas delta Y to log image delta Y.<br>
* The conversion is still affected by zoom ratio but with logarithm form.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageLogDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageLogDeltaY(int value)
{
return canvasToImageLogDeltaY(value, 5d);
}
/**
* Convert specified canvas delta Z to log image delta Z.<br>
* The conversion is still affected by zoom ratio but with specified logarithm form.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageLogDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageLogDeltaZ(int value, double logFactor)
{
final double scaleFactor = getScaleZ();
// keep the zoom ratio but in a log perspective
return value / (scaleFactor / Math.pow(10, Math.log10(scaleFactor) / logFactor));
}
/**
* Convert specified canvas delta Z to log image delta Z.<br>
* The conversion is still affected by zoom ratio but with logarithm form.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.canvasToImageLogDelta(...) method instead for rotation transformed delta.
*/
public double canvasToImageLogDeltaZ(int value)
{
return canvasToImageLogDeltaZ(value, 5d);
}
/**
* Convert specified canvas X coordinate to image X coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.canvasToImage(...) instead
*/
@Deprecated
public double canvasToImageX(int value)
{
return canvasToImageDeltaX(value - getOffsetX());
}
/**
* Convert specified canvas Y coordinate to image Y coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.canvasToImage(...) instead
*/
@Deprecated
public double canvasToImageY(int value)
{
return canvasToImageDeltaY(value - getOffsetY());
}
/**
* Convert specified canvas Z coordinate to image Z coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.canvasToImage(...) instead
*/
@Deprecated
public double canvasToImageZ(int value)
{
return canvasToImageDeltaZ(value - getOffsetZ());
}
/**
* Convert specified canvas T coordinate to image T coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.canvasToImage(...) instead
*/
@Deprecated
public double canvasToImageT(int value)
{
return canvasToImageDeltaT(value - getOffsetT());
}
/**
* Convert specified canvas C coordinate to image C coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.canvasToImage(...) instead
*/
@Deprecated
public double canvasToImageC(int value)
{
return canvasToImageDeltaC(value - getOffsetC());
}
/**
* Convert specified image delta X to canvas delta X.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.imageToCanvasDelta(...) method instead for rotation transformed delta.
*/
public int imageToCanvasDeltaX(double value)
{
return (int) (value * getScaleX());
}
/**
* Convert specified image delta Y to canvas delta Y.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.imageToCanvasDelta(...) method instead for rotation transformed delta.
*/
public int imageToCanvasDeltaY(double value)
{
return (int) (value * getScaleY());
}
/**
* Convert specified image delta Z to canvas delta Z.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.imageToCanvasDelta(...) method instead for rotation transformed delta.
*/
public int imageToCanvasDeltaZ(double value)
{
return (int) (value * getScaleZ());
}
/**
* Convert specified image delta T to canvas delta T.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.imageToCanvasDelta(...) method instead for rotation transformed delta.
*/
public int imageToCanvasDeltaT(double value)
{
return (int) (value * getScaleT());
}
/**
* Convert specified image delta C to canvas delta C.<br>
* WARNING: Does not take in account the rotation transformation.<br>
* Use the IcyCanvasXD.imageToCanvasDelta(...) method instead for rotation transformed delta.
*/
public int imageToCanvasDeltaC(double value)
{
return (int) (value * getScaleC());
}
/**
* Convert specified image X coordinate to canvas X coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.imageToCanvas(...) instead
*/
@Deprecated
public int imageToCanvasX(double value)
{
return imageToCanvasDeltaX(value) + getOffsetX();
}
/**
* Convert specified image Y coordinate to canvas Y coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.imageToCanvas(...) instead
*/
@Deprecated
public int imageToCanvasY(double value)
{
return imageToCanvasDeltaY(value) + getOffsetY();
}
/**
* Convert specified image Z coordinate to canvas Z coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.imageToCanvas(...) instead
*/
@Deprecated
public int imageToCanvasZ(double value)
{
return imageToCanvasDeltaZ(value) + getOffsetZ();
}
/**
* Convert specified image T coordinate to canvas T coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.imageToCanvas(...) instead
*/
@Deprecated
public int imageToCanvasT(double value)
{
return imageToCanvasDeltaT(value) + getOffsetT();
}
/**
* Convert specified image C coordinate to canvas C coordinate
*
* @deprecated Cannot give correct result if rotation is applied so use
* IcyCanvasXD.imageToCanvas(...) instead
*/
@Deprecated
public int imageToCanvasC(double value)
{
return imageToCanvasDeltaC(value) + getOffsetC();
}
/**
* Helper to forward mouse press event to the overlays.
*
* @param event
* original mouse event
* @param pt
* mouse image position
*/
public void mousePressed(MouseEvent event, Point5D.Double pt)
{
final boolean globalVisible = isLayersVisible();
// send mouse event to overlays after so mouse canvas position is ok
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveMouseEventOnHidden())
layer.getOverlay().mousePressed(event, pt, this);
}
}
/**
* Helper to forward mouse press event to the overlays.
*
* @param event
* original mouse event
*/
public void mousePressed(MouseEvent event)
{
mousePressed(event, getMouseImagePos5D());
}
/**
* Helper to forward mouse release event to the overlays.
*
* @param event
* original mouse event
* @param pt
* mouse image position
*/
public void mouseReleased(MouseEvent event, Point5D.Double pt)
{
final boolean globalVisible = isLayersVisible();
// send mouse event to overlays after so mouse canvas position is ok
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveMouseEventOnHidden())
layer.getOverlay().mouseReleased(event, pt, this);
}
}
/**
* Helper to forward mouse release event to the overlays.
*
* @param event
* original mouse event
*/
public void mouseReleased(MouseEvent event)
{
mouseReleased(event, getMouseImagePos5D());
}
/**
* Helper to forward mouse click event to the overlays.
*
* @param event
* original mouse event
* @param pt
* mouse image position
*/
public void mouseClick(MouseEvent event, Point5D.Double pt)
{
final boolean globalVisible = isLayersVisible();
// send mouse event to overlays after so mouse canvas position is ok
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveMouseEventOnHidden())
layer.getOverlay().mouseClick(event, pt, this);
}
}
/**
* Helper to forward mouse click event to the overlays.
*
* @param event
* original mouse event
*/
public void mouseClick(MouseEvent event)
{
mouseClick(event, getMouseImagePos5D());
}
/**
* Helper to forward mouse move event to the overlays.
*
* @param event
* original mouse event
* @param pt
* mouse image position
*/
public void mouseMove(MouseEvent event, Point5D.Double pt)
{
final boolean globalVisible = isLayersVisible();
// send mouse event to overlays after so mouse canvas position is ok
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveMouseEventOnHidden())
layer.getOverlay().mouseMove(event, pt, this);
}
}
/**
* Helper to forward mouse mouse event to the overlays.
*
* @param event
* original mouse event
*/
public void mouseMove(MouseEvent event)
{
mouseMove(event, getMouseImagePos5D());
}
/**
* Helper to forward mouse drag event to the overlays.
*
* @param event
* original mouse event
* @param pt
* mouse image position
*/
public void mouseDrag(MouseEvent event, Point5D.Double pt)
{
final boolean globalVisible = isLayersVisible();
// send mouse event to overlays after so mouse canvas position is ok
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveMouseEventOnHidden())
layer.getOverlay().mouseDrag(event, pt, this);
}
}
/**
* Helper to forward mouse drag event to the overlays.
*
* @param event
* original mouse event
*/
public void mouseDrag(MouseEvent event)
{
mouseDrag(event, getMouseImagePos5D());
}
/**
* Helper to forward mouse enter event to the overlays.
*
* @param event
* original mouse event
* @param pt
* mouse image position
*/
public void mouseEntered(MouseEvent event, Point5D.Double pt)
{
final boolean globalVisible = isLayersVisible();
// send mouse event to overlays after so mouse canvas position is ok
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveMouseEventOnHidden())
layer.getOverlay().mouseEntered(event, pt, this);
}
}
/**
* Helper to forward mouse entered event to the overlays.
*
* @param event
* original mouse event
*/
public void mouseEntered(MouseEvent event)
{
mouseEntered(event, getMouseImagePos5D());
}
/**
* Helper to forward mouse exit event to the overlays.
*
* @param event
* original mouse event
* @param pt
* mouse image position
*/
public void mouseExited(MouseEvent event, Point5D.Double pt)
{
final boolean globalVisible = isLayersVisible();
// send mouse event to overlays after so mouse canvas position is ok
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveMouseEventOnHidden())
layer.getOverlay().mouseExited(event, pt, this);
}
}
/**
* Helper to forward mouse exited event to the overlays.
*
* @param event
* original mouse event
*/
public void mouseExited(MouseEvent event)
{
mouseExited(event, getMouseImagePos5D());
}
/**
* Helper to forward mouse wheel event to the overlays.
*
* @param event
* original mouse event
* @param pt
* mouse image position
*/
public void mouseWheelMoved(MouseWheelEvent event, Point5D.Double pt)
{
final boolean globalVisible = isLayersVisible();
// send mouse event to overlays after so mouse canvas position is ok
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveMouseEventOnHidden())
layer.getOverlay().mouseWheelMoved(event, pt, this);
}
}
/**
* Helper to forward mouse wheel event to the overlays.
*
* @param event
* original mouse event
*/
public void mouseWheelMoved(MouseWheelEvent event)
{
mouseWheelMoved(event, getMouseImagePos5D());
}
@Override
public void keyPressed(KeyEvent e)
{
final boolean globalVisible = isLayersVisible();
final Point5D.Double pt = getMouseImagePos5D();
// forward event to overlays
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveKeyEventOnHidden())
layer.getOverlay().keyPressed(e, pt, this);
}
if (!e.isConsumed())
{
switch (e.getKeyCode())
{
case KeyEvent.VK_0:
if (EventUtil.isShiftDown(e, true))
{
if (CanvasActions.globalDisableSyncAction.isEnabled())
{
CanvasActions.globalDisableSyncAction.execute();
e.consume();
}
}
else if (EventUtil.isNoModifier(e))
{
if (CanvasActions.disableSyncAction.isEnabled())
{
CanvasActions.disableSyncAction.execute();
e.consume();
}
}
break;
case KeyEvent.VK_1:
if (EventUtil.isShiftDown(e, true))
{
if (CanvasActions.globalSyncGroup1Action.isEnabled())
{
CanvasActions.globalSyncGroup1Action.execute();
e.consume();
}
}
else if (EventUtil.isNoModifier(e))
{
if (CanvasActions.syncGroup1Action.isEnabled())
{
CanvasActions.syncGroup1Action.execute();
e.consume();
}
}
break;
case KeyEvent.VK_2:
if (EventUtil.isShiftDown(e, true))
{
if (CanvasActions.globalSyncGroup2Action.isEnabled())
{
CanvasActions.globalSyncGroup2Action.execute();
e.consume();
}
}
else if (EventUtil.isNoModifier(e))
{
if (CanvasActions.syncGroup2Action.isEnabled())
{
CanvasActions.syncGroup2Action.execute();
e.consume();
}
}
break;
case KeyEvent.VK_3:
if (EventUtil.isShiftDown(e, true))
{
if (CanvasActions.globalSyncGroup3Action.isEnabled())
{
CanvasActions.globalSyncGroup3Action.execute();
e.consume();
}
}
else if (EventUtil.isNoModifier(e))
{
if (CanvasActions.syncGroup3Action.isEnabled())
{
CanvasActions.syncGroup3Action.execute();
e.consume();
}
}
break;
case KeyEvent.VK_4:
if (EventUtil.isShiftDown(e, true))
{
if (CanvasActions.globalSyncGroup4Action.isEnabled())
{
CanvasActions.globalSyncGroup4Action.execute();
e.consume();
}
}
else if (EventUtil.isNoModifier(e))
{
if (CanvasActions.syncGroup4Action.isEnabled())
{
CanvasActions.syncGroup4Action.execute();
e.consume();
}
}
break;
case KeyEvent.VK_G:
if (EventUtil.isShiftDown(e, true))
{
if (WindowActions.gridTileAction.isEnabled())
{
WindowActions.gridTileAction.execute();
e.consume();
}
}
break;
case KeyEvent.VK_H:
if (EventUtil.isShiftDown(e, true))
{
if (WindowActions.horizontalTileAction.isEnabled())
{
WindowActions.horizontalTileAction.execute();
e.consume();
}
}
break;
case KeyEvent.VK_A:
if (EventUtil.isMenuControlDown(e, true))
{
if (RoiActions.selectAllAction.isEnabled())
{
RoiActions.selectAllAction.execute();
e.consume();
}
}
break;
case KeyEvent.VK_V:
if (EventUtil.isShiftDown(e, true))
{
if (WindowActions.verticalTileAction.isEnabled())
{
WindowActions.verticalTileAction.execute();
e.consume();
}
}
else if (EventUtil.isMenuControlDown(e, true))
{
if (GeneralActions.pasteImageAction.isEnabled())
{
GeneralActions.pasteImageAction.execute();
e.consume();
}
else if (RoiActions.pasteAction.isEnabled())
{
RoiActions.pasteAction.execute();
e.consume();
}
}
else if (EventUtil.isAltDown(e, true))
{
if (RoiActions.pasteLinkAction.isEnabled())
{
RoiActions.pasteLinkAction.execute();
e.consume();
}
}
break;
case KeyEvent.VK_C:
if (EventUtil.isMenuControlDown(e, true))
{
// do this one first else copyImage hide it
if (RoiActions.copyAction.isEnabled())
{
// copy them to icy clipboard
RoiActions.copyAction.execute();
e.consume();
}
else if (GeneralActions.copyImageAction.isEnabled())
{
// copy image to system clipboard
GeneralActions.copyImageAction.execute();
e.consume();
}
}
else if (EventUtil.isAltDown(e, true))
{
if (RoiActions.copyLinkAction.isEnabled())
{
// copy link of selected ROI to clipboard
RoiActions.copyLinkAction.execute();
e.consume();
}
}
break;
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
final boolean globalVisible = isLayersVisible();
final Point5D.Double pt = getMouseImagePos5D();
// forward event to overlays
for (Layer layer : getLayers(true))
{
if ((globalVisible && layer.isVisible()) || layer.getReceiveKeyEventOnHidden())
layer.getOverlay().keyReleased(e, pt, this);
}
}
@Override
public void keyTyped(KeyEvent e)
{
}
/**
* Gets the image at position (t, z, c).
*/
public IcyBufferedImage getImage(int t, int z, int c)
{
if ((t == -1) || (z == -1))
return null;
final Sequence sequence = getSequence();
// have to test this as sequence reference can be release in viewer
if (sequence != null)
return sequence.getImage(t, z, c);
return null;
}
/**
* @deprecated Use {@link #getImage(int, int, int)} with C = -1 instead.
*/
@Deprecated
public IcyBufferedImage getImage(int t, int z)
{
return getImage(t, z, -1);
}
/**
* Get the current image.
*/
public IcyBufferedImage getCurrentImage()
{
return getImage(getPositionT(), getPositionZ(), getPositionC());
}
/**
* @deprecated use {@link #getRenderedImage(int, int, int, boolean)} instead
*/
@Deprecated
public final BufferedImage getRenderedImage(int t, int z, int c, int imageType, boolean canvasView)
{
return getRenderedImage(t, z, c, canvasView);
}
/**
* @deprecated use {@link #getRenderedSequence(boolean)} instead
*/
@Deprecated
public final Sequence getRenderedSequence(int imageType, boolean canvasView)
{
return getRenderedSequence(canvasView);
}
/**
* Returns a RGB or ARGB (depending support) BufferedImage representing the canvas view for
* image at position (t, z, c).<br>
* Free feel to the canvas to handle or not a specific dimension.
*
* @param t
* T position of wanted image (-1 for complete sequence)
* @param z
* Z position of wanted image (-1 for complete stack)
* @param c
* C position of wanted image (-1 for all channels)
* @param canvasView
* render with canvas view if true else use default sequence dimension
*/
public abstract BufferedImage getRenderedImage(int t, int z, int c, boolean canvasView);
/**
* @deprecated Use {@link #getRenderedImage(int, int, int, boolean)} instead.
*/
@Deprecated
public BufferedImage getRenderedImage(int t, int z, int c)
{
return getRenderedImage(t, z, c, true);
}
/**
* Return a sequence which contains rendered images.<br>
* Default implementation, override it if needed in your canvas.
*
* @param canvasView
* render with canvas view if true else use default sequence dimension
* @param progressListener
* progress listener which receive notifications about progression
*/
public Sequence getRenderedSequence(boolean canvasView, ProgressListener progressListener)
{
final Sequence seqIn = getSequence();
// create output sequence
final Sequence result = new Sequence();
if (seqIn != null)
{
// derive original metadata
result.setMetaData(OMEUtil.createOMEMetadata(seqIn.getMetadata()));
int t = getPositionT();
int z = getPositionZ();
int c = getPositionC();
final int sizeT = getImageSizeT();
final int sizeZ = getImageSizeZ();
final int sizeC = getImageSizeC();
int pos = 0;
int len = 1;
if (t != -1)
len *= sizeT;
if (z != -1)
len *= sizeZ;
if (c != -1)
len *= sizeC;
result.beginUpdate();
// This cause position changed event to not be sent during rendering.
// Painters have to take care of that, they should check the canvas position
// in the paint() method
beginUpdate();
try
{
if (t != -1)
{
for (t = 0; t < sizeT; t++)
{
if (z != -1)
{
for (z = 0; z < sizeZ; z++)
{
if (c != -1)
{
final List<BufferedImage> images = new ArrayList<BufferedImage>();
for (c = 0; c < sizeC; c++)
{
images.add(getRenderedImage(t, z, c, canvasView));
pos++;
if (progressListener != null)
progressListener.notifyProgress(pos, len);
}
result.setImage(t, z, IcyBufferedImage.createFrom(images));
}
else
{
result.setImage(t, z, getRenderedImage(t, z, -1, canvasView));
pos++;
if (progressListener != null)
progressListener.notifyProgress(pos, len);
}
}
}
else
{
result.setImage(t, 0, getRenderedImage(t, -1, -1, canvasView));
pos++;
if (progressListener != null)
progressListener.notifyProgress(pos, len);
}
}
}
else
{
if (z != -1)
{
for (z = 0; z < sizeZ; z++)
{
if (c != -1)
{
final ArrayList<BufferedImage> images = new ArrayList<BufferedImage>();
for (c = 0; c < sizeC; c++)
{
images.add(getRenderedImage(-1, z, c, canvasView));
pos++;
if (progressListener != null)
progressListener.notifyProgress(pos, len);
}
result.setImage(0, z, IcyBufferedImage.createFrom(images));
}
else
{
result.setImage(0, z, getRenderedImage(-1, z, -1, canvasView));
pos++;
if (progressListener != null)
progressListener.notifyProgress(pos, len);
}
}
}
else
{
if (c != -1)
{
final ArrayList<BufferedImage> images = new ArrayList<BufferedImage>();
for (c = 0; c < sizeC; c++)
{
images.add(getRenderedImage(-1, -1, c, canvasView));
pos++;
if (progressListener != null)
progressListener.notifyProgress(pos, len);
}
result.setImage(0, 0, IcyBufferedImage.createFrom(images));
}
else
{
result.setImage(0, 0, getRenderedImage(-1, -1, -1, canvasView));
pos++;
if (progressListener != null)
progressListener.notifyProgress(pos, len);
}
}
}
}
finally
{
endUpdate();
result.endUpdate();
}
}
return result;
}
/**
* @deprecated Use {@link #getRenderedSequence(boolean, ProgressListener)} instead.
*/
@Deprecated
public Sequence getRenderedSequence(boolean canvasView)
{
return getRenderedSequence(canvasView, null);
}
/**
* @deprecated Use {@link #getRenderedSequence(boolean, ProgressListener)} instead.
*/
@Deprecated
public Sequence getRenderedSequence()
{
return getRenderedSequence(true, null);
}
/**
* Return the number of "selected" samples
*/
public int getNumSelectedSamples()
{
final Sequence sequence = getSequence();
// have to test this as we release sequence reference on closed
if (sequence == null)
return 0;
final int base_len = getImageSizeX() * getImageSizeY() * getImageSizeC();
if (getPositionT() == -1)
{
if (getPositionZ() == -1)
return base_len * getImageSizeZ() * getImageSizeT();
return base_len * getImageSizeT();
}
if (getPositionZ() == -1)
return base_len * getImageSizeZ();
return base_len;
}
/**
* Returns the frame rate (given in frame per second) for play command (T navigation panel).
*/
public int getFrameRate()
{
return tNav.getFrameRate();
}
/**
* Sets the frame rate (given in frame per second) for play command (T navigation panel).
*/
public void setFrameRate(int fps)
{
tNav.setFrameRate(fps);
}
/**
* update Z slider state
*/
protected void updateZNav()
{
final int maxZ = getMaxPositionZ();
final int z = getPositionZ();
zNav.setMaximum(maxZ);
if (z != -1)
{
zNav.setValue(z);
zNav.setVisible(maxZ > 0);
}
else
zNav.setVisible(false);
}
/**
* update T slider state
*/
protected void updateTNav()
{
final int maxT = getMaxPositionT();
final int t = getPositionT();
tNav.setMaximum(maxT);
if (t != -1)
{
tNav.setValue(t);
tNav.setVisible(maxT > 0);
}
else
tNav.setVisible(false);
}
/**
* @deprecated Use {@link #getLayer(Overlay)} instead.
*/
@Deprecated
public Layer getLayer(Painter painter)
{
for (Layer layer : getLayers(false))
if (layer.getPainter() == painter)
return layer;
return null;
}
/**
* Find the layer corresponding to the specified Overlay
*/
public Layer getLayer(Overlay overlay)
{
return layers.get(overlay);
}
/**
* Find the layer corresponding to the specified ROI (use the ROI overlay internally).
*/
public Layer getLayer(ROI roi)
{
return getLayer(roi.getOverlay());
}
/**
* @deprecated Use {@link #hasLayer(Overlay)} instead.
*/
@Deprecated
public boolean hasLayer(Painter painter)
{
return getLayer(painter) != null;
}
/**
* Returns true if the canvas contains a layer for the specified {@link Overlay}.
*/
public boolean hasLayer(Overlay overlay)
{
synchronized (layers)
{
return layers.containsKey(overlay);
}
}
public boolean hasLayer(Layer layer)
{
final Overlay overlay = layer.getOverlay();
// faster to test from overlay
if (overlay != null)
return hasLayer(overlay);
synchronized (layers)
{
return layers.containsValue(layer);
}
}
/**
* @deprecated Use {@link #addLayer(Overlay)} instead.
*/
@Deprecated
public void addLayer(Painter painter)
{
if (!hasLayer(painter))
addLayer(new Layer(painter));
}
public Layer addLayer(Overlay overlay)
{
if (!hasLayer(overlay))
return addLayer(new Layer(overlay));
return null;
}
protected Layer addLayer(Layer layer)
{
if (layer != null)
{
// listen layer
layer.addListener(this);
// add to list
synchronized (layers)
{
layers.put(layer.getOverlay(), layer);
if (Layer.DEFAULT_NAME.equals(layer))
layer.setName("layer " + layers.size());
}
// added
layerAdded(layer);
}
return layer;
}
/**
* @deprecated Use {@link #removeLayer(Overlay)} instead.
*/
@Deprecated
public void removeLayer(Painter painter)
{
removeLayer(getLayer(painter));
}
/**
* Remove the layer for the specified {@link Overlay} from the canvas.<br/>
* Returns <code>true</code> if the method succeed.
*/
public boolean removeLayer(Overlay overlay)
{
final Layer layer;
// remove from list
synchronized (layers)
{
layer = layers.remove(overlay);
}
if (layer != null)
{
// stop listening layer
layer.removeListener(this);
// notify remove
layerRemoved(layer);
return true;
}
return false;
}
/**
* Remove the specified layer from the canvas.
*/
public void removeLayer(Layer layer)
{
removeLayer(layer.getOverlay());
}
/**
* Returns <code>true</code> if the specified overlay is visible in the canvas.<br>
*/
public boolean isVisible(Overlay overlay)
{
final Layer layer = getLayer(overlay);
if (layer != null)
return layer.isVisible();
return false;
}
/**
* @deprecated Use {@link #addLayerListener(CanvasLayerListener)} instead.
*/
@Deprecated
public void addLayersListener(CanvasLayerListener listener)
{
addLayerListener(listener);
}
/**
* @deprecated Use {@link #removeLayerListener(CanvasLayerListener)} instead.
*/
@Deprecated
public void removeLayersListener(CanvasLayerListener listener)
{
removeLayerListener(listener);
}
/**
* Add a layer listener
*
* @param listener
*/
public void addLayerListener(CanvasLayerListener listener)
{
if (listener != null)
layerListeners.add(listener);
}
/**
* Remove a layer listener
*
* @param listener
*/
public void removeLayerListener(CanvasLayerListener listener)
{
layerListeners.remove(listener);
}
protected void fireLayerChangedEvent(CanvasLayerEvent event)
{
for (CanvasLayerListener listener : new ArrayList<CanvasLayerListener>(layerListeners))
listener.canvasLayerChanged(event);
}
/**
* Add a IcyCanvas listener
*
* @param listener
*/
public void addCanvasListener(IcyCanvasListener listener)
{
listeners.add(listener);
}
/**
* Remove a IcyCanvas listener
*
* @param listener
*/
public void removeCanvasListener(IcyCanvasListener listener)
{
listeners.remove(listener);
}
protected void fireCanvasChangedEvent(IcyCanvasEvent event)
{
for (IcyCanvasListener listener : new ArrayList<IcyCanvasListener>(listeners))
listener.canvasChanged(event);
}
public void beginUpdate()
{
updater.beginUpdate();
}
public void endUpdate()
{
updater.endUpdate();
}
public boolean isUpdating()
{
return updater.isUpdating();
}
/**
* layer added
*
* @param layer
*/
protected void layerAdded(Layer layer)
{
// handle with updater
updater.changed(new CanvasLayerEvent(layer, LayersEventType.ADDED));
}
/**
* layer removed
*
* @param layer
*/
protected void layerRemoved(Layer layer)
{
// handle with updater
updater.changed(new CanvasLayerEvent(layer, LayersEventType.REMOVED));
}
/**
* layer has changed
*/
@Override
public void layerChanged(Layer layer, String propertyName)
{
// handle with updater
updater.changed(new CanvasLayerEvent(layer, LayersEventType.CHANGED, propertyName));
}
/**
* canvas changed (packed event).<br>
* do global changes processing here
*/
public void changed(IcyCanvasEvent event)
{
final IcyCanvasEventType eventType = event.getType();
// handle synchronized canvas
if (isSynchronized())
{
final List<IcyCanvas> synchCanvasList = getSynchronizedCanvas();
// this is the synchronizer master so dispatch view changes to others canvas
if (getSynchMaster(synchCanvasList))
{
try
{
// synchronize all events when the view has just been synchronized
final boolean synchAll = (eventType == IcyCanvasEventType.SYNC_CHANGED);
synchronizeCanvas(synchCanvasList, event, synchAll);
}
finally
{
releaseSynchMaster();
}
}
}
switch (eventType)
{
case POSITION_CHANGED:
final int curZ = getPositionZ();
final int curT = getPositionT();
final int curC = getPositionC();
switch (event.getDim())
{
case Z:
// ensure Z slider position
if (curZ != -1)
zNav.setValue(curZ);
break;
case T:
// ensure T slider position
if (curT != -1)
tNav.setValue(curT);
break;
case C:
// single channel mode
final int maxC = getMaxPositionC();
// disabled others channels
for (int c = 0; c <= maxC; c++)
getLut().getLutChannel(c).setEnabled((curC == -1) || (curC == c));
break;
case NULL:
// ensure Z slider position
if (curZ != -1)
zNav.setValue(curZ);
// ensure T slider position
if (curT != -1)
tNav.setValue(curT);
break;
}
// refresh mouse panel informations
mouseInfPanel.updateInfos(this);
break;
case MOUSE_IMAGE_POSITION_CHANGED:
// refresh mouse panel informations
mouseInfPanel.updateInfos(this);
break;
}
// notify listeners that canvas have changed
fireCanvasChangedEvent(event);
}
/**
* layer property has changed (packed event)
*/
protected void layerChanged(CanvasLayerEvent event)
{
final String property = event.getProperty();
// we need to rebuild sorted layer list
if ((event.getType() != LayersEventType.CHANGED) || (property == null) || (property == Layer.PROPERTY_PRIORITY))
orderedLayersOutdated = true;
// notify listeners that layers have changed
fireLayerChangedEvent(event);
}
/**
* position has changed<br>
*
* @param dim
* define the position which has changed
*/
protected void positionChanged(DimensionId dim)
{
// handle with updater
updater.changed(new IcyCanvasEvent(this, IcyCanvasEventType.POSITION_CHANGED, dim));
}
@Override
public void lutChanged(LUTEvent event)
{
final int curC = getPositionC();
// single channel mode ?
if (curC != -1)
{
final int channel = event.getComponent();
// channel is enabled --> change C position
if ((channel != -1) && getLut().getLutChannel(channel).isEnabled())
setPositionC(channel);
else
// ensure we have 1 channel enable
getLut().getLutChannel(curC).setEnabled(true);
}
lutChanged(event.getComponent());
}
/**
* lut changed
*
* @param component
*/
protected void lutChanged(int component)
{
}
/**
* sequence meta data has changed
*/
protected void sequenceMetaChanged(String metadataName)
{
}
/**
* sequence type has changed
*/
protected void sequenceTypeChanged()
{
}
/**
* sequence component bounds has changed
*
* @param colorModel
* @param component
*/
protected void sequenceComponentBoundsChanged(IcyColorModel colorModel, int component)
{
}
/**
* sequence component bounds has changed
*
* @param colorModel
* @param component
*/
protected void sequenceColorMapChanged(IcyColorModel colorModel, int component)
{
}
/**
* sequence data has changed
*
* @param image
* image which has changed (null if global data changed)
* @param type
* event type
*/
protected void sequenceDataChanged(IcyBufferedImage image, SequenceEventType type)
{
ThreadUtil.runSingle(guiUpdater);
}
/**
* @deprecated Use {@link #sequenceOverlayChanged(Overlay, SequenceEventType)} instead.
*/
@SuppressWarnings("unused")
@Deprecated
protected void sequencePainterChanged(Painter painter, SequenceEventType type)
{
// no more stuff here
}
/**
* Sequence overlay has changed
*
* @param overlay
* overlay which has changed
* @param type
* event type
*/
protected void sequenceOverlayChanged(Overlay overlay, SequenceEventType type)
{
switch (type)
{
case ADDED:
addLayer(overlay);
break;
case REMOVED:
removeLayer(overlay);
break;
case CHANGED:
// nothing to do here
break;
}
}
/**
* sequence roi has changed
*
* @param roi
* roi which has changed (null if global roi changed)
* @param type
* event type
*/
protected void sequenceROIChanged(ROI roi, SequenceEventType type)
{
// nothing here
}
@Override
public void viewerChanged(ViewerEvent event)
{
switch (event.getType())
{
case POSITION_CHANGED:
// ignore this event as we are launching it
break;
case LUT_CHANGED:
// set new lut
setLut(viewer.getLut(), true);
break;
case CANVAS_CHANGED:
// nothing to do
break;
}
}
@Override
public void viewerClosed(Viewer viewer)
{
// nothing to do here
}
@Override
public final void sequenceChanged(SequenceEvent event)
{
switch (event.getSourceType())
{
case SEQUENCE_META:
sequenceMetaChanged((String) event.getSource());
break;
case SEQUENCE_TYPE:
sequenceTypeChanged();
break;
case SEQUENCE_COMPONENTBOUNDS:
sequenceComponentBoundsChanged((IcyColorModel) event.getSource(), event.getParam());
break;
case SEQUENCE_COLORMAP:
sequenceColorMapChanged((IcyColorModel) event.getSource(), event.getParam());
break;
case SEQUENCE_DATA:
sequenceDataChanged((IcyBufferedImage) event.getSource(), event.getType());
break;
case SEQUENCE_OVERLAY:
final Overlay overlay = (Overlay) event.getSource();
sequenceOverlayChanged(overlay, event.getType());
// backward compatibility
@SuppressWarnings("deprecation")
final Painter painter;
if (overlay instanceof OverlayWrapper)
painter = ((OverlayWrapper) overlay).getPainter();
else
painter = overlay;
sequencePainterChanged(painter, event.getType());
break;
case SEQUENCE_ROI:
sequenceROIChanged((ROI) event.getSource(), event.getType());
break;
}
}
@Override
public void sequenceClosed(Sequence sequence)
{
// nothing to do here
}
@Override
public void onChanged(CollapsibleEvent event)
{
if (event instanceof CanvasLayerEvent)
layerChanged((CanvasLayerEvent) event);
if (event instanceof IcyCanvasEvent)
changed((IcyCanvasEvent) event);
}
}