diff --git a/modules/DesktopPreview/src/main/java/org/gephi/desktop/preview/PreviewSketch.java b/modules/DesktopPreview/src/main/java/org/gephi/desktop/preview/PreviewSketch.java index 0b8afca5ef727058604b20180b71bc0fa8868c0f..d134e486d0ee1c1ab354aa4f0338e869323b694f 100644 --- a/modules/DesktopPreview/src/main/java/org/gephi/desktop/preview/PreviewSketch.java +++ b/modules/DesktopPreview/src/main/java/org/gephi/desktop/preview/PreviewSketch.java @@ -42,19 +42,39 @@ package org.gephi.desktop.preview; import java.awt.Graphics; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.JPanel; +import javax.swing.SwingUtilities; import org.gephi.preview.api.PreviewController; +import org.gephi.preview.api.PreviewMouseEvent; import org.gephi.preview.api.ProcessingTarget; +import org.gephi.preview.api.Vector; import org.openide.util.Lookup; /** * * @author mbastian */ -public class PreviewSketch extends JPanel { +public class PreviewSketch extends JPanel implements MouseListener, MouseWheelListener, MouseMotionListener { + private static final int WHEEL_TIMER = 500; + //Data private final PreviewController previewController; private final ProcessingTarget target; + //Geometry + private final Vector ref = new Vector(); + private final Vector lastMove = new Vector(); + //Utils + private final RefreshLoop refreshLoop = new RefreshLoop(); + private Timer wheelTimer; + private boolean inited; public PreviewSketch(ProcessingTarget target) { this.target = target; @@ -65,11 +85,170 @@ public class PreviewSketch extends JPanel { protected void paintComponent(Graphics g) { super.paintComponent(g); + if (!inited) { + //Listeners + addMouseListener(this); + addMouseMotionListener(this); + addMouseWheelListener(this); + inited = true; + } + if (target.getWidth() != getWidth() || target.getHeight() != getHeight()) { - System.out.println("Resizing to " + getWidth() + " " + getHeight()); target.resize(getWidth(), getHeight()); } g.drawImage(target.getImage(), 0, 0, this); } + + public void setMoving(boolean moving) { + target.setMoving(moving); + } + + @Override + public void mouseClicked(MouseEvent e) { + if (previewController.sendMouseEvent(buildPreviewMouseEvent(e, PreviewMouseEvent.Type.CLICKED))) { + refreshLoop.refreshSketch(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + previewController.sendMouseEvent(buildPreviewMouseEvent(e, PreviewMouseEvent.Type.PRESSED)); + ref.set(e.getX(), e.getY()); + + refreshLoop.refreshSketch(); + } + + @Override + public void mouseReleased(MouseEvent e) { + if (!previewController.sendMouseEvent(buildPreviewMouseEvent(e, PreviewMouseEvent.Type.RELEASED))) { + lastMove.set(target.getTranslate()); + setMoving(false); + } + + refreshLoop.refreshSketch(); + } + + @Override + public void mouseEntered(MouseEvent e) { + } + + @Override + public void mouseExited(MouseEvent e) { + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + if (e.getUnitsToScroll() == 0) { + return; + } + float way = -e.getUnitsToScroll() / Math.abs(e.getUnitsToScroll()); + target.setScaling(target.getScaling() * (way > 0 ? 2f : 0.5f)); + setMoving(true); + if (wheelTimer != null) { + wheelTimer.cancel(); + wheelTimer = null; + } + wheelTimer = new Timer(); + wheelTimer.schedule(new TimerTask() { + @Override + public void run() { + setMoving(false); + refreshLoop.refreshSketch(); + wheelTimer = null; + } + }, WHEEL_TIMER); + refreshLoop.refreshSketch(); + } + + @Override + public void mouseDragged(MouseEvent e) { + if (!previewController.sendMouseEvent(buildPreviewMouseEvent(e, PreviewMouseEvent.Type.DRAGGED))) { + setMoving(true); + Vector trans = target.getTranslate(); + trans.set(e.getX(), e.getY()); + trans.sub(ref); + trans.div(target.getScaling()); // ensure const. moving speed whatever the zoom is + trans.add(lastMove); + + refreshLoop.refreshSketch(); + } + } + + @Override + public void mouseMoved(MouseEvent e) { + } + + private Vector screenPositionToModelPosition(Vector screenPos) { + Vector center = new Vector(getWidth() / 2f, getHeight() / 2f); + Vector scaledCenter = Vector.mult(center, target.getScaling()); + Vector scaledTrans = Vector.sub(center, scaledCenter); + + Vector modelPos = new Vector(screenPos.x, screenPos.y); + modelPos.sub(scaledTrans); + modelPos.div(target.getScaling()); + modelPos.sub(target.getTranslate()); + return modelPos; + } + + private PreviewMouseEvent buildPreviewMouseEvent(MouseEvent evt, PreviewMouseEvent.Type type) { + int mouseX = evt.getX(); + int mouseY = evt.getY(); + PreviewMouseEvent.Button button = PreviewMouseEvent.Button.LEFT; + if (SwingUtilities.isMiddleMouseButton(evt)) { + button = PreviewMouseEvent.Button.MIDDLE; + } else if (SwingUtilities.isLeftMouseButton(evt)) { + button = PreviewMouseEvent.Button.LEFT; + } else if (SwingUtilities.isRightMouseButton(evt)) { + button = PreviewMouseEvent.Button.RIGHT; + } + + Vector pos = screenPositionToModelPosition(new Vector(mouseX, mouseY)); + + return new PreviewMouseEvent((int) pos.x, (int) pos.y, type, button, null); + } + + private class RefreshLoop { + + private final long DELAY = 100; + private final AtomicBoolean running = new AtomicBoolean(); + private final AtomicBoolean refresh = new AtomicBoolean(); + //Timer + private long timeout = DELAY * 10; + private Timer timer; + + public RefreshLoop() { + super(); + } + + public void refreshSketch() { + refresh.set(true); + if (!running.getAndSet(true)) { + startTimer(); + } + } + + private void startTimer() { + timer = new Timer("PreviewRefreshLoop", true); + timer.schedule(new TimerTask() { + @Override + public void run() { + if (refresh.getAndSet(false)) { + target.refresh(); + repaint(); + } else if (timeout == 0) { + timeout = DELAY * 10; + stopTimer(); + } else { + timeout -= DELAY; + } + } + }, 0, DELAY); + } + + private void stopTimer() { + timer.cancel(); + running.set(false); + } + } } diff --git a/modules/DesktopPreview/src/main/java/org/gephi/desktop/preview/PreviewTopComponent.java b/modules/DesktopPreview/src/main/java/org/gephi/desktop/preview/PreviewTopComponent.java index 248448aeaba92102f255431a6cb2767a7556c1e3..4a6729197ea6d06264e6a5086723b98fc311e41e 100644 --- a/modules/DesktopPreview/src/main/java/org/gephi/desktop/preview/PreviewTopComponent.java +++ b/modules/DesktopPreview/src/main/java/org/gephi/desktop/preview/PreviewTopComponent.java @@ -178,6 +178,7 @@ public final class PreviewTopComponent extends TopComponent implements PropertyC } public void initTarget(PreviewUIModel previewUIModel) { + System.out.println("INIT T"); // inits the preview applet if (previewUIModel != null && target == null) { PreviewController previewController = Lookup.getDefault().lookup(PreviewController.class); diff --git a/modules/PreviewAPI/src/main/java/org/gephi/preview/ProcessingGraphics.java b/modules/PreviewAPI/src/main/java/org/gephi/preview/ProcessingGraphics.java index 7af7a56d2cfdf51d60f575180f24b551efdf2053..fedbced75e0cbf1a535e757b3c19c73e6d2982b4 100644 --- a/modules/PreviewAPI/src/main/java/org/gephi/preview/ProcessingGraphics.java +++ b/modules/PreviewAPI/src/main/java/org/gephi/preview/ProcessingGraphics.java @@ -67,18 +67,18 @@ public class ProcessingGraphics { private final PreviewController previewController = Lookup.getDefault().lookup(PreviewController.class); private PreviewModel model; private RenderTarget target; + private boolean inited; //Drawing private final Image image; private final int width; private final int height; private final Graphics2D g2; - private final Vector ref = new Vector(); private final Vector trans = new Vector(); - private final Vector lastMove = new Vector(); private float scaling; private Color background = Color.WHITE; public ProcessingGraphics(int width, int height) { + System.out.println("Creating new graphcis " + width + " " + height); this.width = width; this.height = height; GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); @@ -98,11 +98,9 @@ public class ProcessingGraphics { background = model.getProperties().getColorValue(PreviewProperty.BACKGROUND_COLOR); initAppletLayout(); - g2.clearRect(0, 0, width, height); g2.setTransform(new AffineTransform()); - if (background != null) { g2.setColor(background); g2.fillRect(0, 0, width, height); @@ -123,6 +121,18 @@ public class ProcessingGraphics { } } + public Vector getTranslate() { + return trans; + } + + public float getScaling() { + return scaling; + } + + public void setScaling(float scaling) { + this.scaling = scaling; + } + public Graphics2D getGraphics() { return g2; } @@ -144,7 +154,7 @@ public class ProcessingGraphics { */ private void initAppletLayout() { // graphSheet.setMargin(MARGIN); - if (model != null && model.getDimensions() != null && model.getTopLeftPosition() != null) { + if (!inited && model != null && model.getDimensions() != null && model.getTopLeftPosition() != null) { // initializes zoom Dimension dimensions = model.getDimensions(); @@ -161,7 +171,9 @@ public class ProcessingGraphics { Vector scaledCenter = Vector.add(topLeftVector, semiBox); trans.set(center); trans.sub(scaledCenter); - lastMove.set(trans); +// lastMove.set(trans); + + inited = true; } } } diff --git a/modules/PreviewAPI/src/main/java/org/gephi/preview/ProcessingRenderTargetBuilder.java b/modules/PreviewAPI/src/main/java/org/gephi/preview/ProcessingRenderTargetBuilder.java index 70592ff403d37dc18f55c226dcc67b5e6ce7b693..2efe0df9fa52554f2eb074fa1b7a0c790cfee316 100644 --- a/modules/PreviewAPI/src/main/java/org/gephi/preview/ProcessingRenderTargetBuilder.java +++ b/modules/PreviewAPI/src/main/java/org/gephi/preview/ProcessingRenderTargetBuilder.java @@ -45,8 +45,10 @@ import java.awt.Graphics2D; import java.awt.Image; import org.gephi.preview.api.PreviewController; import org.gephi.preview.api.PreviewModel; +import org.gephi.preview.api.PreviewProperty; import org.gephi.preview.api.ProcessingTarget; import org.gephi.preview.api.RenderTarget; +import org.gephi.preview.api.Vector; import org.gephi.preview.spi.RenderTargetBuilder; import org.openide.util.Lookup; import org.openide.util.lookup.ServiceProvider; @@ -65,9 +67,9 @@ public class ProcessingRenderTargetBuilder implements RenderTargetBuilder { if (width != null && height != null) { width = Math.max(1, width); height = Math.max(1, height); - return new ProcessingTargetImpl(width, height); + return new ProcessingTargetImpl(previewModel, width, height); } else { - return new ProcessingTargetImpl(1, 1); + return new ProcessingTargetImpl(previewModel, 1, 1); } } @@ -79,11 +81,13 @@ public class ProcessingRenderTargetBuilder implements RenderTargetBuilder { public static class ProcessingTargetImpl extends AbstractRenderTarget implements ProcessingTarget { private final PreviewController previewController; + private final PreviewModel previewModel; private ProcessingGraphics graphics; - public ProcessingTargetImpl(int width, int height) { + public ProcessingTargetImpl(PreviewModel model, int width, int height) { graphics = new ProcessingGraphics(width, height); previewController = Lookup.getDefault().lookup(PreviewController.class); + previewModel = model; } @Override @@ -114,6 +118,26 @@ public class ProcessingRenderTargetBuilder implements RenderTargetBuilder { return graphics.getHeight(); } + @Override + public Vector getTranslate() { + return graphics.getTranslate(); + } + + @Override + public float getScaling() { + return graphics.getScaling(); + } + + @Override + public void setScaling(float scaling) { + graphics.setScaling(scaling); + } + + @Override + public void setMoving(boolean moving) { + previewModel.getProperties().putValue(PreviewProperty.MOVING, moving); + } + @Override public void refresh() { if (graphics != null) { diff --git a/modules/PreviewAPI/src/main/java/org/gephi/preview/api/ProcessingTarget.java b/modules/PreviewAPI/src/main/java/org/gephi/preview/api/ProcessingTarget.java index d0b81698da221908bad002045e3d603445485cde..0dd3dfa5739545d5b7a3b34cac4e79826b38b248 100644 --- a/modules/PreviewAPI/src/main/java/org/gephi/preview/api/ProcessingTarget.java +++ b/modules/PreviewAPI/src/main/java/org/gephi/preview/api/ProcessingTarget.java @@ -95,6 +95,14 @@ public interface ProcessingTarget extends RenderTarget { public void resize(int width, int height); + public void setMoving(boolean moving); + + public Vector getTranslate(); + + public float getScaling(); + + public void setScaling(float scaling); + /** * Redraw the Processing canvas */