package org.phylowidget.ui; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Polygon; import java.awt.Shape; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.util.HashMap; import java.util.List; import org.andrewberman.ui.Point; import org.andrewberman.ui.menu.Menu; import org.andrewberman.ui.menu.MenuItem; import org.phylowidget.PWContext; import org.phylowidget.PhyloTree; import org.phylowidget.render.RenderConstants; import org.phylowidget.tree.PhyloNode; import processing.core.PApplet; public class NodeUncollapser extends Menu{ PWContext pwContext; PhyloNode node; Shape s; private Shape origShape; public static HashMap<PhyloNode,NodeUncollapser> map = new HashMap<PhyloNode,NodeUncollapser>(); public NodeUncollapser(PApplet app, PhyloNode node) { super(app); pwContext = (PWContext) context; this.node = node; Polygon p = new Polygon(); p.addPoint(0, 10); p.addPoint(13,0); p.addPoint(0,-10); origShape = p; s = origShape; map.put(node,this); } @Override public boolean isOpen() { return true; } public static boolean containsNode(PhyloNode n) { return map.containsKey(n); } @Override public void draw() { super.draw(); // Remove ourselves if the node is no longer collapsed. if (!node.getTree().isCollapsed(node)) { System.out.println("No longer collapsed!"); dispose(); } // Remove ourselves if node is no longer in tree, or tree is null. if (!node.getTree().containsVertex(node)) { System.out.println("Doesn't contain!"); dispose(); } // Update our position to match the node. float dotWidth = node.range.render.getNodeRadius(); float rowHeight = node.range.render.getTextSize(); float spacing = node.range.render.getNodeOffset(node) + rowHeight*RenderConstants.labelSpacing*2; // float spacing = rowHeight * RenderConstants.labelSpacing*2 + dotWidth; float dx = (float) (spacing * Math.cos(node.getAngle())); float dy = (float) (spacing * Math.sin(node.getAngle())); AffineTransform at = AffineTransform.getTranslateInstance(node.getX()+dx,node.getY()+dy); at.rotate(node.getAngle()); float scale = rowHeight * .3f; scale = Math.max(scale,5); scale /= 10; at.scale(scale, scale); s = at.createTransformedShape(origShape); setPosition(node.getX()+dx, node.getY()+dy); setHidden(false); PhyloNode parent = (PhyloNode) node.getParent(); while (parent != null) { PhyloTree tree = parent.getTree(); if (tree != null && tree.isCollapsed(parent)) { setHidden(true); } parent = (PhyloNode) parent.getParent(); } } @Override public void performAction() { super.performAction(); pwContext.getPW().setMessage(""); node.getTree().uncollapseNode(node); pwContext.ui().layout(); dispose(); } @Override protected void drawMyself() { super.drawMyself(); canvas.stroke(100); canvas.noFill(); canvas.strokeWeight(2); buff.g2.setColor(new Color(255,255,0)); buff.g2.fill(s); if (mouseInside) { buff.g2.setStroke(new BasicStroke(1f)); buff.g2.setColor(new Color(0,0,0)); } else { buff.g2.setStroke(new BasicStroke(.5f)); buff.g2.setColor(new Color(0,140,200)); } buff.g2.draw(s); } boolean mouseJustLeft = false; @Override protected void itemMouseEvent(MouseEvent e, Point pt) { super.itemMouseEvent(e, pt); if (mouseInside) { List<PhyloNode> kids = node.getTree().getChildrenOf(node); int numLeaves = 0; for (PhyloNode n : kids) { numLeaves += n.getNumLeaves(); } pwContext.getPW().setMessage("Click to uncollapse "+numLeaves+" leaf nodes."); } if (!mouseInside && !mouseJustLeft) { mouseJustLeft = true; } if (mouseJustLeft) { mouseJustLeft = false; pwContext.getPW().setMessage(""); } } @Override public void dispose() { map.remove(node); super.dispose(); } @Override protected boolean containsPoint(Point pt) { return s.contains(pt.x, pt.y); } @Override public MenuItem create(String label) { return null; } }