package org.andrewberman.evogame; import java.awt.event.MouseEvent; import java.awt.geom.Rectangle2D; import java.util.HashMap; import org.andrewberman.ui.Point; import org.andrewberman.ui.menu.Menu; import org.andrewberman.ui.menu.MenuItem; import org.andrewberman.ui.tween.PropertyTween; import org.andrewberman.ui.tween.Tween; import org.andrewberman.ui.tween.TweenFunction; import org.andrewberman.ui.tween.TweenQuad; import org.phylowidget.PhyloWidget; import org.phylowidget.tree.PhyloNode; import processing.core.PApplet; import processing.core.PImage; public class DragDropImage extends Menu { abstract class Followable { Object o; public Followable(Object o) { this.o = o; } public abstract float getHeight(); public abstract float getWidth(); public abstract float getX(); public abstract float getY(); } static int LONG = 30; static HashMap<PhyloNode, DragDropImage> nodeToImage; static int SHORT = 15; static float SIZE = 128; float aspectRatio; private float downMouseX; private float downMouseY; private float downPosX; private float downPosY; private boolean dragging; Followable f; boolean firstFrame = true; public float h; Tween hTween; private PImage img; String imgString; String targetNodeLabel; boolean isOpen = false; PhyloNode lastHoverTarget; private Rectangle2D.Float rectF = new Rectangle2D.Float(); float SHRINK = 0.5f; public float w; Tween wTween; public DragDropImage(PApplet app) { super(app); TweenFunction tw = TweenQuad.tween; // Tween tw = TweenFriction.tween(.25f); wTween = new PropertyTween(this, "w", tw, Tween.OUT, width, width, SHORT); hTween = new PropertyTween(this, "h", tw, Tween.OUT, height, height, SHORT); } public DragDropImage(PApplet app, String img, String targetNodeLabel) { this(app); setImage(img); this.targetNodeLabel = targetNodeLabel; } void attach(final PhyloNode n) { // File f = new File(imgString); // n.setAnnotation("img", f.toURL().toString()); // hidden = true; n.setAnnotation("img", "asdf"); if (nodeToImage == null) nodeToImage = new HashMap<PhyloNode,DragDropImage>(); nodeToImage.put(n, this); aTween.continueTo(1, SHORT); f = new Followable(n) { public float getHeight() { return n.range.render.getTextSize() / aspectRatio; } public float getWidth() { return n.range.render.getTextSize(); } public float getX() { return n.getX() + n.range.render.getNodeRadius() * 1.05f + getWidth() / 2f; } public float getY() { return n.getY(); } }; } public boolean isAttachedToCorrectNode() { if (f == null) return false; PhyloNode n = (PhyloNode) f.o; if (n.getLabel().toLowerCase().equals(targetNodeLabel)) return true; return false; } @Override protected boolean containsPoint(Point pt) { float w = wTween.getPosition(); float h = hTween.getPosition(); rectF.setRect(x - w / 2, y - h / 2, w, h); return rectF.contains(pt); } @Override public MenuItem create(String label) { return null; } void detach() { PhyloNode n = (PhyloNode) f.o; n.setAnnotation("img", null); if (nodeToImage == null) nodeToImage = new HashMap<PhyloNode,DragDropImage>(); nodeToImage.remove(n); f = null; } @Override public synchronized void draw() { super.draw(); wTween.update(); hTween.update(); // If we're attached to the node. if (f != null && !dragging) { x = f.getX(); y = f.getY(); wTween.continueTo(f.getWidth(), SHORT); hTween.continueTo(f.getHeight(), SHORT); return; } // Attached, but being dragged away. if (f != null && dragging) { // Check the distance and detach if far enough away. float fx = f.getX(); float fy = f.getY(); double distance = Math.sqrt((y - fy) * (y - fy) + (x - fx) * (x - fx)); if (distance > 20) detach(); return; } // Just dragging. if (dragging) { aTween.continueTo(0.5f, LONG); } else { aTween.continueTo(1f, LONG); } if (isOverTarget()) { wTween.continueTo(width * SHRINK, SHORT); hTween.continueTo(height * SHRINK, SHORT); PhyloNode n = getTarget(); if (n != null) n.setAnnotation("img", ""); lastHoverTarget = getTarget(); } else { if (lastHoverTarget != null) { lastHoverTarget.setAnnotation("img", null); lastHoverTarget = null; } wTween.continueTo(width, SHORT); hTween.continueTo(height, SHORT); } } public void setTargetNodeLabel(String s) { this.targetNodeLabel = s.toLowerCase(); } @Override public synchronized void drawMyself() { int color = canvas.color(255, 0, 0); if (isAttached()) { int clr = 0; if (isAttachedToCorrectNode()) clr = canvas.color(0, 255, 0); else clr = canvas.color(255, 0, 0); canvas.rectMode(canvas.CENTER); canvas.strokeWeight(3); canvas.stroke(clr); canvas.noFill(); canvas.rect(x, y, w, h); canvas.rectMode(canvas.CORNER); } if (img == null) { canvas.fill(color); canvas.rect(x, y, w, h); } else { canvas.imageMode(canvas.CENTER); canvas.smooth(); canvas.image(img, x, y, w, h); canvas.noSmooth(); canvas.imageMode(canvas.CORNER); } canvas.noTint(); } PhyloNode getTarget() { return null; // return EvoGameApplet.ui.getHoveredNode(); } boolean isAttached() { return (f != null); } @Override public boolean isOpen() { return true; } boolean isOverTarget() { PhyloNode n = getTarget(); if (n != null && dragging) { // Check for whether there's already an image on that node. if (nodeToImage != null && nodeToImage.containsKey(n) && nodeToImage.get(n) != this) return false; return true; } return false; } @Override public synchronized void layout() { super.layout(); menu.zSort(); // setSize(w,h); } void recalcSize() { float w = img.width; float h = img.height; if (w > SIZE) { float ratio = SIZE / w; w *= ratio; h *= ratio; } if (h > SIZE) { float ratio = SIZE / h; h *= ratio; w *= ratio; } // setSize(w,h); // setSize(w,h); aspectRatio = w / h; width = w; height = h; wTween.continueTo(w); hTween.continueTo(h); } public void setImage(String filename) { String base = "../../src/org/andrewberman/evogame/"; PImage img = null; // img = EvoGameApplet.p.loadImage(base + filename); // imgString = base + filename; // if (img == null) // { // // Load it up from the actual filename. // img = EvoGameApplet.p.loadImage(filename); // imgString = filename; // if (img == null) // { String path = EvoGameApplet.p.getDocumentBase().toString(); int ind = path.lastIndexOf("/"); if (ind != -1) path = path.substring(0,ind); // if (PhyloWidget.cfg.debug) // System.out.println(path); img = EvoGameApplet.p.loadImage(path+"/"+filename); // } // } // Image img = ImageIO.read(in); this.img = img; aspectRatio = (float) img.width / (float) img.height; recalcSize(); wTween.fforward(); hTween.fforward(); } public void setTree(String tree) { EvoGameApplet.p.changeSetting("tree", tree); } public void setNextMenu(String menu) { EvoGameApplet.nextMenu = menu; } @Override public void setOptions() { super.setOptions(); useHandCursor = true; modalFocus = false; focusOnShow = false; consumeEvents = false; } @Override protected void visibleMouseEvent(MouseEvent e, Point tempPt) { super.visibleMouseEvent(e, tempPt); // if (mouseInside || dragging) // setCursor(Cursor.HAND_CURSOR); // // if (!mouseInside && !dragging) // return; if (e.getID() == MouseEvent.MOUSE_RELEASED) { if (isOpen) { close(); isOpen = false; } if (isOverTarget() && dragging) { PhyloNode n = getTarget(); attach(n); } } if (e.getID() == MouseEvent.MOUSE_PRESSED) { downMouseX = tempPt.x; downMouseY = tempPt.y; downPosX = tempPt.x; downPosY = tempPt.y; if (mouseInside) { open(); isOpen = true; e.consume(); } } if (!mouseInside && !dragging) return; if (e.getID() == MouseEvent.MOUSE_DRAGGED) { if (isOpen) { // z = 0; dragging = true; float dX = tempPt.x - downMouseX; float dY = tempPt.y - downMouseY; setPosition(downPosX + dX, downPosY + dY); } } else { dragging = false; // z = -1; // UIGlobals.g.event().zSort(); } } }