/** * */ package cz.cuni.mff.peckam.java.origamist.gui.common; import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.InputMethodListener; import java.awt.event.KeyListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.media.j3d.GraphicsConfigTemplate3D; import javax.swing.JPanel; import javax.swing.SwingUtilities; import com.sun.j3d.exp.swing.JCanvas3D; import cz.cuni.mff.peckam.java.origamist.model.Origami; import cz.cuni.mff.peckam.java.origamist.model.Step; import cz.cuni.mff.peckam.java.origamist.modelstate.ModelState; import cz.cuni.mff.peckam.java.origamist.utils.ParametrizedCallable; /** * The panel for rendering a step. * * Provides the following properties: * <ul> * <li>pickMode</li> * <li>zoom</li> * </ul> * * @author Martin Pecka */ public class StepRenderer extends JPanel { /** */ private static final long serialVersionUID = 9198803673578003101L; /** The origami diagram we are rendering. */ protected Origami origami = null; /** The step this renderer is rendering. */ protected Step step = null; /** The canvas the model is rendered to. */ protected JCanvas3D canvas; /** The controller that performs step rendering onto canvas. */ protected StepViewingCanvasController canvasController = null; /** * */ public StepRenderer() { setLayout(new BorderLayout()); setOpaque(false); canvas = createCanvas(); canvas.setOpaque(false); canvas.setResizeMode(JCanvas3D.RESIZE_DELAYED); add(canvas, BorderLayout.CENTER); canvas.setSize(new Dimension(20, 20)); if (getWidth() > 0 && getHeight() > 0) canvas.setSize(getWidth(), getHeight()); canvas.getOffscreenCanvas3D().addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { canvas.getOffscreenCanvas3D().repaint(); revalidate(); repaint(); } }); canvasController = createCanvasController(canvas); canvasController.addPropertyChangeListener(StepViewingCanvasController.STEP_PROPERTY, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { repaint(); } }); } }); canvasController.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()); } }); } /** * @param origami * @param step */ public StepRenderer(Origami origami, Step step) { this(); setOrigami(origami); setStep(step); } /** * Create a new canvas controller. * * @param canvas The canvas to be controlled. * @return The canvas controller. */ protected StepViewingCanvasController createCanvasController(JCanvas3D canvas) { StepViewingCanvasController canvasController = new StepViewingCanvasController(canvas.getOffscreenCanvas3D()); return canvasController; } /** * @return A new and set-up canvas. */ protected JCanvas3D createCanvas() { // Subclassing JCanvas3D is needed to call the protected method. JCanvas3D canvas = new JCanvas3D(new GraphicsConfigTemplate3D()) { /** */ private static final long serialVersionUID = 1159847610761430144L; { // This call is needed because it is a workaround for the offscreen canvas not being notified of AWT // events with no registered listeners. enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK); } }; return canvas; } /** * @return the origami */ public Origami getOrigami() { return origami; } /** * @param origami the origami to set */ public void setOrigami(Origami origami) { this.origami = origami; canvasController.setOrigami(origami); if (origami != null) { setBackground(origami.getPaper().getColor().getBackground()); } else { setBackground(Color.GRAY); // TODO some more convenient behavior } } /** * @return the step */ public Step getStep() { return step; } /** * @param step the step to set */ public void setStep(final Step step) { this.setStep(step, null); } /** * @param step the step to set * @param afterSetCallback The callback to call after the step is changed. Will be run outside EDT. */ public void setStep(final Step step, final Runnable afterSetCallback) { setStep(step, afterSetCallback, null); } /** * @param step the step to set * @param afterSetCallback The callback to call after the step is changed. Will be run outside EDT. * @param exceptionCallback The callback to call if the setting thread encounters an * {@link InvalidOperationException}. Will be run outside EDT. */ public void setStep(final Step step, final Runnable afterSetCallback, final ParametrizedCallable<?, ? super Exception> exceptionCallback) { this.step = step; if (step != null && step.getAttachedTo() == null) { return; } if (getWidth() > 0 && getHeight() > 0) canvas.setSize(getWidth(), getHeight()); canvasController.setStep(step, afterSetCallback, exceptionCallback); } /** * @return The model state of the current step. */ protected ModelState getModelState() { return step != null ? step.getModelState(false) : null; } /** * @return The overall zoom of the displayed object (as percentage - 0 to 100). */ public double getCompositeZoom() { return canvasController.getCompositeZoom(); } /** * @return the zoom */ public double getZoom() { return canvasController.getZoom(); } /** * @param zoom the zoom to set */ public void setZoom(double zoom) { if (!isEnabled()) return; canvasController.setZoom(zoom); } /** * Increase zoom by 10%. */ public void incZoom() { setZoom(getZoom() + 10d); } /** * Decrease zoom by 10%. */ public void decZoom() { setZoom(getZoom() - 10d); } /** * @return The canvas. */ public JCanvas3D getCanvas() { return canvas; } /** * @return The controller that performs step rendering onto canvas. */ public StepViewingCanvasController getCanvasController() { return canvasController; } /** * @param l * @see java.awt.Component#addKeyListener(java.awt.event.KeyListener) */ public synchronized void addKeyListener(KeyListener l) { canvas.addKeyListener(l); canvasController.addKeyListener(l); } /** * @param l * @see java.awt.Component#addMouseListener(java.awt.event.MouseListener) */ public synchronized void addMouseListener(java.awt.event.MouseListener l) { canvas.addMouseListener(l); canvasController.addMouseListener(l); } /** * @param l * @see java.awt.Component#addMouseMotionListener(java.awt.event.MouseMotionListener) */ public synchronized void addMouseMotionListener(MouseMotionListener l) { canvas.addMouseMotionListener(l); canvasController.addMouseMotionListener(l); } /** * @param l * @see java.awt.Component#addMouseWheelListener(java.awt.event.MouseWheelListener) */ public synchronized void addMouseWheelListener(MouseWheelListener l) { canvas.addMouseWheelListener(l); canvasController.addMouseWheelListener(l); } /** * @param l * @see java.awt.Component#addInputMethodListener(java.awt.event.InputMethodListener) */ public synchronized void addInputMethodListener(InputMethodListener l) { canvas.addInputMethodListener(l); canvasController.addInputMethodListener(l); } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { super.addPropertyChangeListener(listener); canvasController.addPropertyChangeListener(listener); } @Override public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { super.addPropertyChangeListener(propertyName, listener); canvasController.addPropertyChangeListener(propertyName, listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { super.removePropertyChangeListener(listener); canvasController.removePropertyChangeListener(listener); } @Override public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { super.removePropertyChangeListener(propertyName, listener); canvasController.removePropertyChangeListener(propertyName, listener); } }