diff --git a/.gitignore b/.gitignore index 9c5e51e11..152dfc193 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ Mesquite_Folder/ +# Workspace files # +################### +*.iml + # Compiled source # ################### *.com @@ -36,3 +40,7 @@ Mesquite_Folder/ .Trashes ehthumbs.db Thumbs.db + +# Build products # +################## +Resources/Mesquite* diff --git a/Source/mesquite/lib/MesquiteTree.java b/Source/mesquite/lib/MesquiteTree.java index 2828cdf97..5142c89b0 100644 --- a/Source/mesquite/lib/MesquiteTree.java +++ b/Source/mesquite/lib/MesquiteTree.java @@ -1743,6 +1743,25 @@ public int numberOfNodesInClade(int node) { count++; //count node itself return count; } + + public Vector nodesInClade(int node) { + Vector nodes = new Vector(); + String[] parsedNodes = nodesInCladeAsString(node,null).split(","); + for (String nodeString : parsedNodes) { + nodes.add(Integer.parseInt(nodeString)); + } + return nodes; + } + + private String nodesInCladeAsString(int node, String nodes) { + if (nodes == null) { + nodes = String.valueOf(node); + } + for (int d = firstDaughterOfNode(node); nodeExists(d); d = nextSisterOfNode(d)) { + nodes = nodesInCladeAsString(d, nodes) + "," + d; + } + return nodes; + } /*-----------------------------------------*/ /** Returns number of terminal taxa in clade.*/ public int numberOfTerminalsInClade(int node) { @@ -5583,7 +5602,16 @@ public String getNodeLabel(int node){ return label[node]; } /*-----------------------------------------*/ - /** Returns whether the node has a label */ + public void setStringPropertyOnNode(String propName, String propVal, int node){ + this.setAssociatedObject(new NameReference(propName),node, propVal); + } + /*-----------------------------------------*/ + /** Gets the node label of the node */ + public String getStringPropertyOnNode(String prop, int node){ + ObjectArray props = this.getAssociatedObjects(node); + return ""; + } + /** Returns whether the node has a label */ public boolean nodeHasLabel(int node){ return (label!=null && nodeExists(node) && label[node]!=null) || (nodeIsTerminal(node)); } diff --git a/Source/mesquite/lib/StringUtil.java b/Source/mesquite/lib/StringUtil.java index 2032bb8b6..a344b40f8 100644 Binary files a/Source/mesquite/lib/StringUtil.java and b/Source/mesquite/lib/StringUtil.java differ diff --git a/Source/mesquite/lib/TreeDisplay.java b/Source/mesquite/lib/TreeDisplay.java index 432f535e8..6ee44e3e6 100644 --- a/Source/mesquite/lib/TreeDisplay.java +++ b/Source/mesquite/lib/TreeDisplay.java @@ -146,7 +146,17 @@ public Color getBranchColor(int N){ } } - public Composite setBranchTransparency(Graphics g, int N){ + public int getBranchWidth(int node){ + long result = tree.getAssociatedLong(NameReference.getNameReference("width"), node); + + if (result == MesquiteLong.unassigned) { + return 0; + } + return (int) result; + } + + + public Composite setBranchTransparency(Graphics g, int N){ if (!showBranchColors) return null; if (tree.anySelected() && !tree.getSelected(N)) { diff --git a/Source/mesquite/lib/TreeDrawing.java b/Source/mesquite/lib/TreeDrawing.java index b98c07b0c..fed5aab35 100644 --- a/Source/mesquite/lib/TreeDrawing.java +++ b/Source/mesquite/lib/TreeDrawing.java @@ -14,6 +14,7 @@ package mesquite.lib; import java.awt.*; +import java.awt.geom.Line2D; import mesquite.lib.duties.*; import mesquite.trees.lib.TaxonPolygon; @@ -37,7 +38,13 @@ public abstract class TreeDrawing { public final static int MINNODEWIDTH = 6; public final static int ACCEPTABLETOUCHWIDTH = 10; public final static boolean SHOWTOUCHPOLYS = false; - public int[] x; //x positions of nodes + public final static int UP = 0; + public final static int DOWN = 1; + public final static int RIGHT = 2; + public final static int LEFT = 3; + public final static int ALLNODES = -1; + + public int[] x; //x positions of nodes public int[] y; //y positions of nodes public double[] z; //z positions of nodes (closeness to viewer, smaller numbers closer) public int[] lineBaseX; //base of line on which to draw labels etc. @@ -94,6 +101,10 @@ public void resetNumNodes(int numNodes){ } } + public void setProperty(int node, String property, String value) { + MesquiteModule.mesquiteTrunk.logln("setProperty called on "+property+", but this property does not exist in "+this.getClass().toString()); + } + public int getDrawnRoot(){ return drawnRoot; } @@ -139,7 +150,136 @@ public int getNodeValueTextBaseY(int node, int edgewidth, int stringwidth, int f public abstract void fillBranch(Tree tree, int N, Graphics g); - /*_________________________________________________*/ + public void rotateFromUp(Polygon poly, Point origin, int to_orientation) { + poly.translate(-origin.x,-origin.y); + for(int i=0;i 0) { + old_angle = Math.PI * 0.5; + radius = old_y; + } else if (old_y < 0) { + old_angle = Math.PI * 1.5; + radius = -old_y; + } + } else if (old_y == 0) { + if (old_x >= 0) { + radius = old_x; + } else { + radius = -old_x; + old_angle = Math.PI; + } + } else { + double t = old_y/old_x; + old_angle = Math.atan(t); + radius = Math.sqrt((old_x*old_x)+(old_y*old_y)); + } + double new_angle = angle - old_angle; + poly.xpoints[i] = (int)(radius * (Math.cos(new_angle))); + poly.ypoints[i] = (int)(radius * (Math.sin(new_angle))); + } + poly.translate(origin.x,origin.y); + poly.invalidate(); + } + + public void rotateLine2D(Line2D.Double line, Point origin, double angle) { + + Polygon poly = new Polygon(); + poly.addPoint((int)line.x1,(int)line.y1); + poly.addPoint((int)line.x2,(int)line.y2); + poly.translate(-origin.x,-origin.y); + for(int i=0;i 0) { + old_angle = Math.PI * 0.5; + radius = old_y; + } else if (old_y < 0) { + old_angle = Math.PI * 1.5; + radius = -old_y; + } + } else if (old_y == 0) { + if (old_x >= 0) { + radius = old_x; + } else { + radius = -old_x; + old_angle = Math.PI; + } + } else { + double t = old_y/old_x; + old_angle = Math.atan(t); + radius = Math.sqrt((old_x*old_x)+(old_y*old_y)); + } + double new_angle = angle - old_angle; + poly.xpoints[i] = (int)(radius * (Math.cos(new_angle))); + poly.ypoints[i] = (int)(radius * (Math.sin(new_angle))); + } + poly.translate(origin.x,origin.y); + poly.invalidate(); + line.x1 = poly.xpoints[0]; + line.x2 = poly.xpoints[1]; + line.y1 = poly.ypoints[0]; + line.y2 = poly.ypoints[1]; + } + + + public Point pointRotatedFromUp(int to_orientation, Point origin, Point point) { + int old_x = point.x-origin.x; + int old_y = point.y-origin.y; + Point result = new Point(old_x,old_y); + if (to_orientation == RIGHT) { + result.move(-old_y,old_x); + } else if (to_orientation == DOWN) { + result.move(-old_x, -old_y); + } else if (to_orientation == LEFT) { + result.move(old_y, -old_x); + } + result.translate(origin.x, origin.y); + return result; + } + + public Point pointRotatedToUp(int from_orientation, Point origin, Point point) { + int old_x = point.x-origin.x; + int old_y = point.y-origin.y; + Point result = new Point(old_x,old_y); + if (from_orientation == RIGHT) { + result.move(old_y, -old_x); + } else if (from_orientation == DOWN) { + result.move(-old_x, -old_y); + } else if (from_orientation == LEFT) { + result.move(-old_y, old_x); + } + result.translate(origin.x, origin.y); + return result; + } + + /*_________________________________________________*/ /** Does the basic inverting of the color of a branch **/ public void fillBranchInverted (Tree tree, int N, Graphics g) { if (GraphicsUtil.useXORMode(g, true)) { diff --git a/Source/mesquite/trees/BasicDrawTaxonNames/BasicDrawTaxonNames.java b/Source/mesquite/trees/BasicDrawTaxonNames/BasicDrawTaxonNames.java index c2fa34d78..e1abedba7 100644 --- a/Source/mesquite/trees/BasicDrawTaxonNames/BasicDrawTaxonNames.java +++ b/Source/mesquite/trees/BasicDrawTaxonNames/BasicDrawTaxonNames.java @@ -439,11 +439,16 @@ else if (taxonNumber>=taxa.getNumTaxa()) { //check all extras to see if they want to add anything boolean underlined = false; Color taxonColor; - if (!tree.anySelected() || tree.getSelected(N)) - taxonColor = fontColor; - else + if (!tree.anySelected() || tree.getSelected(N)) { + long result = tree.getAssociatedLong(NameReference.getNameReference("taxoncolor"), N); + if (result == MesquiteLong.unassigned) { + taxonColor = fontColor; + } else { + taxonColor = ColorDistribution.getStandardColor((int) result); + } + } else { taxonColor = fontColorLight; - + } if (partitions!=null && (colorPartition.getValue() || shadePartition.getValue())){ TaxaGroup mi = (TaxaGroup)partitions.getProperty(taxonNumber); if (mi!=null) { diff --git a/Source/mesquite/trees/BasicTreeDrawCoordinator/BasicTreeDrawCoordinator.java b/Source/mesquite/trees/BasicTreeDrawCoordinator/BasicTreeDrawCoordinator.java index f097e0c51..b6f0d248a 100644 --- a/Source/mesquite/trees/BasicTreeDrawCoordinator/BasicTreeDrawCoordinator.java +++ b/Source/mesquite/trees/BasicTreeDrawCoordinator/BasicTreeDrawCoordinator.java @@ -674,7 +674,8 @@ public void paint(Graphics g) { if (ownerModule == null || ownerModule.isDoomed()) return; setShowBranchColors(ownerDrawModule.showBranchColors.getValue()); - if (MesquiteWindow.checkDoomed(this)) + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + if (MesquiteWindow.checkDoomed(this)) return; setDrawingInProcess(true); int initialPending = repaintsPending; diff --git a/Source/mesquite/trees/BasicTreeWindowMaker/BasicTreeWindowMaker.java b/Source/mesquite/trees/BasicTreeWindowMaker/BasicTreeWindowMaker.java index 15eb78e33..15fa86b49 100644 --- a/Source/mesquite/trees/BasicTreeWindowMaker/BasicTreeWindowMaker.java +++ b/Source/mesquite/trees/BasicTreeWindowMaker/BasicTreeWindowMaker.java @@ -2359,7 +2359,10 @@ public Object doCommand(String commandName, String arguments, CommandChecker che else if (checker.compare(this.getClass(), "Returns the tree info panel", null, commandName, "getInfoPanel")) { return treeInfoPanel; } - else if (checker.compare(this.getClass(), "Returns analyses at nodes as a table", null, commandName, "getAsTable")) { + else if (checker.compare(this.getClass(), "Returns the tree pane size", null, commandName, "getTreePaneSize")) { + return new Dimension(getTreePaneWidth(),getTreePaneHeight()); + } + else if (checker.compare(this.getClass(), "Returns analyses at nodes as a table", null, commandName, "getAsTable")) { if (treeDisplay == null) return null; String s = treeDisplay.getTableVersion(); diff --git a/Source/mesquite/trees/NodeLocsStandard/NodeLocsStandard.java b/Source/mesquite/trees/NodeLocsStandard/NodeLocsStandard.java index dd21f6887..d5c810b40 100644 --- a/Source/mesquite/trees/NodeLocsStandard/NodeLocsStandard.java +++ b/Source/mesquite/trees/NodeLocsStandard/NodeLocsStandard.java @@ -39,12 +39,26 @@ public class NodeLocsStandard extends NodeLocsVH { static final int stretchfactor = 1; static final int scaling = 2; + String scaleTitle; + int scaleBorderWidth; + String scaleBorderLineStyle; + String scaleBorderColor; + String scaleFont; + int scaleFontSize; + String scaleFontFace; + Color scaleColor = Color.cyan; + Color scaleCounterColor = Color.blue; + + // double namesAngle = MesquiteDouble.unassigned; int ROOTSIZE = 20; MesquiteMenuItemSpec fixedScalingMenuItem, showScaleMenuItem, broadScaleMenuItem; MesquiteMenuItemSpec offFixedScalingMenuItem, stretchMenuItem, evenMenuItem; + /**MesquiteMenuItemSpec scaleColorMenuItem, scaleBorderWidthMenuItem, scaleBorderColorMenuItem, scaleBorderLineStyleMenuItem; + MesquiteMenuItemSpec scaleTitleMenuItem,scaleFontMenuItem,scaleFontFaceMenuItem; */ + NameReference triangleNameRef; MesquiteBoolean center; boolean[] fixedSettings = null; @@ -274,6 +288,40 @@ else if (checker.compare(this.getClass(), "Turns off fixed scaling", null, comma resetContainingMenuBar(); parametersChanged(); } + + else if (checker.compare(this.getClass(), "Sets scale color", "[scale color]", commandName, "scaleColor")) { + //Debugg.println("*Scale color got" + parser.getFirstToken(arguments)); + scaleColor = ColorDistribution.getStandardColor(MesquiteInteger.fromString(arguments)); + scaleCounterColor = Color.BLACK; //ColorDistribution.getContrasting(scaleColor); + } + else if (checker.compare(this.getClass(), "Sets scale border width", "[border width in pixels]", commandName, "scaleBorderWidth")) { + //Debugg.println("*Scale border width got" + parser.getFirstToken(arguments)); + scaleBorderWidth = MesquiteInteger.fromString(arguments); + } + else if (checker.compare(this.getClass(), "Sets scale border color", "[border color]", commandName, "scaleBorderColor")) { + //Debugg.println("*Scale border color got" + parser.getFirstToken(arguments)); + scaleBorderColor = parser.getFirstToken(arguments); + } + else if (checker.compare(this.getClass(), "Sets scale border style", "[border line style]", commandName, "scaleBorderLineStyle")) { + //Debugg.println("Scale border style got" + parser.getFirstToken(arguments)); + scaleBorderLineStyle = parser.getFirstToken(arguments); + } + else if (checker.compare(this.getClass(), "Sets scale title", "[title string]", commandName, "scaleTitle")) { + //Debugg.println("Scale title got" + parser.getFirstToken(arguments)); + scaleTitle = arguments; + } + else if (checker.compare(this.getClass(), "Sets scale font", "[font family]", commandName, "scaleFont")) { + //Debugg.println("*Scale font got" + parser.getFirstToken(arguments)); + scaleFont = parser.getFirstToken(arguments); + } + else if (checker.compare(this.getClass(), "Sets scale font size", "[font size]", commandName, "scaleFontSize")) { + //Debugg.println("*Scale font size got" + parser.getFirstToken(arguments)); + scaleFontSize = MesquiteInteger.fromString(arguments); + } + else if (checker.compare(this.getClass(), "Sets scale font face", "[font face]", commandName, "scaleFontFace")) { + //Debugg.println("Scale font face got" + parser.getFirstToken(arguments)); + scaleFontFace = parser.getFirstToken(arguments); + } else return super.doCommand(commandName, arguments, checker); return null; @@ -1166,7 +1214,8 @@ public void drawGrid(double totalTreeHeight, double totalScaleHeight, double sca boolean rulerOnly = false; int rulerWidth = 8; Color c=g.getColor(); - g.setColor(Color.cyan); + //Debugg.println("Scalecolor is " + scaleColor); + g.setColor(scaleColor); int scaleBuffer = 28; TreeDrawing treeDrawing = treeDisplay.getTreeDrawing(); int buffer = 8; @@ -1185,9 +1234,10 @@ public void drawGrid(double totalTreeHeight, double totalScaleHeight, double sca leftEdge = rightEdge - 10; while ( thisHeight>=0) { if (countTenths % 10 == 0) - g.setColor(Color.blue); + g.setColor(scaleCounterColor); else - g.setColor(Color.cyan); + g.setColor(scaleColor); + //Debugg.println("Scalecolor is " + scaleColor); thisHeight -= hundredthHeight; if (rulerOnly) g.drawLine(rightEdge-rulerWidth, (int)(base- (thisHeight*scaling)), rightEdge, (int)(base- (thisHeight*scaling))); @@ -1211,9 +1261,10 @@ else if (treeDisplay.getOrientation()==TreeDisplay.DOWN) { base += (totalTreeHeight - fixedDepth)*scaling; while ( thisHeight>=0) { if (countTenths % 10 == 0) - g.setColor(Color.blue); + g.setColor(scaleCounterColor); else - g.setColor(Color.cyan); + g.setColor(scaleColor); + //Debugg.println("Scalecolor is " + scaleColor); thisHeight -= hundredthHeight; if (rulerOnly) g.drawLine(rightEdge-rulerWidth, (int)(base+ (thisHeight*scaling)), rightEdge, (int)(base+ (thisHeight*scaling))); @@ -1238,9 +1289,10 @@ else if (treeDisplay.getOrientation()==TreeDisplay.LEFT) { double base = (totalScaleHeight-totalTreeHeight)*scaling +treeDisplay.getTreeDrawing().x[drawnRoot]; while ( thisHeight>=0) { if (countTenths % 10 == 0) - g.setColor(Color.blue); + g.setColor(scaleCounterColor); else - g.setColor(Color.cyan); + g.setColor(scaleColor); + //Debugg.println("Scalecolor is " + scaleColor); thisHeight -= hundredthHeight; if (rulerOnly) g.drawLine((int)(base- (thisHeight*scaling)), rightEdge, (int)(base- (thisHeight*scaling)), rightEdge-rulerWidth); @@ -1266,9 +1318,10 @@ else if (treeDisplay.getOrientation()==TreeDisplay.RIGHT) { base += (totalTreeHeight - fixedDepth)*scaling; while ( thisHeight>=0) { if (countTenths % 10 == 0) - g.setColor(Color.blue); + g.setColor(scaleCounterColor); else - g.setColor(Color.cyan); + g.setColor(scaleColor); + //Debugg.println("Scalecolor is " + scaleColor); thisHeight -= hundredthHeight; if (rulerOnly) g.drawLine((int)(base+ (thisHeight*scaling)), rightEdge-rulerWidth, (int)(base+ (thisHeight*scaling)), rightEdge); diff --git a/Source/mesquite/trees/StyledSquareTree/StyledSquareTree.java b/Source/mesquite/trees/StyledSquareTree/StyledSquareTree.java new file mode 100644 index 000000000..c12e6222b --- /dev/null +++ b/Source/mesquite/trees/StyledSquareTree/StyledSquareTree.java @@ -0,0 +1,663 @@ +/* Mesquite source code. Copyright 1997-2011 W. Maddison and D. Maddison. +Version 2.75, September 2011. +Disclaimer: The Mesquite source code is lengthy and we are few. There are no doubt inefficiencies and goofs in this code. +The commenting leaves much to be desired. Please approach this source code with the spirit of helping out. +Perhaps with your help we can be more than a few, and make Mesquite better. + +Mesquite is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. +Mesquite's web site is http://mesquiteproject.org + +This source code and its compiled class files are free and modifiable under the terms of +GNU Lesser General Public License. (http://www.gnu.org/copyleft/lesser.html) + */ +package mesquite.trees.StyledSquareTree; + +import java.awt.geom.Line2D; +import java.util.*; +import java.awt.*; + +import mesquite.lib.*; +import mesquite.lib.duties.*; + +/* ======================================================================== */ +public class StyledSquareTree extends DrawTree { + public void getEmployeeNeeds(){ //This gets called on startup to harvest information; override this and inside, call registerEmployeeNeed + EmployeeNeed e = registerEmployeeNeed(NodeLocsVH.class, getName() + " needs the locations of nodes to be calculated.", + "The calculator for node locations is chosen automatically or initially"); + } + NodeLocsVH nodeLocsTask; + MesquiteString orientationName; + Vector drawings; + int defaultBranchWidth = 2; + int defaultStemWidth = 2; + int defaultBranchColor; + int orientation; + MesquiteString nodeLocsName; + MesquiteBoolean simpleTriangle = new MesquiteBoolean(true); + + /*.................................................................................................................*/ + public boolean startJob(String arguments, Object condition, boolean hiredByName) { + drawings = new Vector(); + nodeLocsTask= (NodeLocsVH)hireNamedEmployee(NodeLocsVH.class, "#NodeLocsStandard"); + if (nodeLocsTask == null) + return sorry(getName() + " couldn't start because no node location module was obtained."); + nodeLocsName = new MesquiteString(nodeLocsTask.getName()); + if (numModulesAvailable(NodeLocsVH.class)>1){ + MesquiteSubmenuSpec mss = addSubmenu(null, "Node Locations Calculator", makeCommand("setNodeLocs", this), NodeLocsVH.class); + mss.setSelected(nodeLocsName); + } + + MesquiteSubmenuSpec orientationSubmenu = addSubmenu(null, "Orientation"); + orientation = nodeLocsTask.getDefaultOrientation(); + orientationName = new MesquiteString("Up"); + if (orientation != TreeDisplay.UP && orientation != TreeDisplay.DOWN && orientation != TreeDisplay.LEFT && orientation != TreeDisplay.RIGHT) + orientation = TreeDisplay.UP; + orientationName.setValue(orient(orientation)); + orientationSubmenu.setSelected(orientationName); + addItemToSubmenu(null, orientationSubmenu, "Up", makeCommand("orientUp", this)); + addItemToSubmenu(null, orientationSubmenu, "Right", makeCommand("orientRight", this)); + addItemToSubmenu(null, orientationSubmenu, "Down", makeCommand("orientDown", this)); + addItemToSubmenu(null, orientationSubmenu, "Left", makeCommand("orientLeft", this)); + addMenuItem( "Branch Width...", makeCommand("setEdgeWidth", this)); + addMenuItem( "Stem Width...", makeCommand("setStemWidth", this)); + // addCheckMenuItem(null, "Simple Triangle for Triangled Clades", makeCommand("toggleSimpleTriangle", this), simpleTriangle); + return true; + } + + public void employeeQuit(MesquiteModule m){ + iQuit(); + } + public TreeDrawing createTreeDrawing(TreeDisplay treeDisplay, int numTaxa) { + StyledSquareTreeDrawing treeDrawing = new StyledSquareTreeDrawing (treeDisplay, numTaxa, this); + if (legalOrientation(treeDisplay.getOrientation())){ + orientationName.setValue(orient(treeDisplay.getOrientation())); + orientation = treeDisplay.getOrientation(); + } + drawings.addElement(treeDrawing); + return treeDrawing; + } + public boolean legalOrientation (int orientation){ + return (orientation == TreeDisplay.UP || orientation == TreeDisplay.DOWN || orientation == TreeDisplay.RIGHT || orientation == TreeDisplay.LEFT); + } + /*.................................................................................................................*/ + public String orient (int orientation){ + if (orientation == TreeDisplay.UP) + return "Up"; + else if (orientation == TreeDisplay.DOWN) + return "Down"; + else if (orientation == TreeDisplay.RIGHT) + return "Right"; + else if (orientation == TreeDisplay.LEFT) + return "Left"; + else return "other"; + } + /*.................................................................................................................*/ + public Snapshot getSnapshot(MesquiteFile file) { + Snapshot temp = new Snapshot(); + temp.addLine("setNodeLocs", nodeLocsTask); + temp.addLine("setEdgeWidth " + defaultBranchWidth); + temp.addLine("setStemWidth " + defaultStemWidth); + if (orientation == TreeDisplay.UP) + temp.addLine("orientUp"); + else if (orientation == TreeDisplay.DOWN) + temp.addLine("orientDown"); + else if (orientation == TreeDisplay.LEFT) + temp.addLine("orientLeft"); + else if (orientation == TreeDisplay.RIGHT) + temp.addLine("orientRight"); + return temp; + } + /*.................................................................................................................*/ + public Object doCommand(String commandName, String arguments, CommandChecker checker) { + boolean reorient = false; + if (checker.compare(this.getClass(), "Sets the node locations calculator", "[name of module]", commandName, "setNodeLocs")) { + NodeLocsVH temp = (NodeLocsVH)replaceEmployee(NodeLocsVH.class, arguments, "Node Locations Calculator", nodeLocsTask); + if (temp != null) { + nodeLocsTask = temp; + nodeLocsName.setValue(nodeLocsTask.getName()); + parametersChanged(); + } + return nodeLocsTask; + } else if (checker.compare(this.getClass(), "Sets the thickness of branches", "[width in pixels]", commandName, "setEdgeWidth")) { + int newWidth = MesquiteInteger.fromString(arguments); + if (!MesquiteInteger.isCombinable(newWidth)) + newWidth = MesquiteInteger.queryInteger(containerOfModule(), "Set branch width", "Branch Width:", defaultBranchWidth, 1, 99); + if ((newWidth != defaultBranchWidth) && (newWidth > 0)) { + defaultBranchWidth = newWidth; + if (drawings == null) return null; + for (Enumeration e = drawings.elements(); e.hasMoreElements();) { + StyledSquareTreeDrawing treeDrawing = (StyledSquareTreeDrawing) e.nextElement(); + treeDrawing.setProperty(TreeDrawing.ALLNODES,"branchwidth",String.valueOf(defaultBranchWidth)); + } + if (!MesquiteThread.isScripting()) parametersChanged(); + } + } else if (checker.compare(this.getClass(), "Sets the thickness of the branch stems", "[width in pixels]", commandName, "setStemWidth")) { + int newWidth= MesquiteInteger.fromString(arguments) ; + if (!MesquiteInteger.isCombinable(newWidth)) + newWidth = MesquiteInteger.queryInteger(containerOfModule(), "Set stem width", "Stem Width:", defaultStemWidth, 1, 99); + if ((newWidth != defaultStemWidth) && (newWidth > 0)){ + defaultStemWidth = newWidth; + if (drawings == null) return null; + for (Enumeration e = drawings.elements(); e.hasMoreElements();) { + StyledSquareTreeDrawing treeDrawing = (StyledSquareTreeDrawing) e.nextElement(); + treeDrawing.setProperty(TreeDrawing.ALLNODES,"stemwidth",String.valueOf(defaultStemWidth)); + } + if (!MesquiteThread.isScripting()) parametersChanged(); + } + } else if (checker.compare(this.getClass(), "Sets the color of the branches", "[color]", commandName, "setBranchColor")) { + int newColor= MesquiteInteger.fromString(arguments); + if (drawings == null) return null; + for (Enumeration e = drawings.elements(); e.hasMoreElements();) { + StyledSquareTreeDrawing treeDrawing = (StyledSquareTreeDrawing) e.nextElement(); + defaultBranchColor = newColor; + treeDrawing.setProperty(TreeDrawing.ALLNODES,"branchcolor",String.valueOf(newColor)); + } + if (!MesquiteThread.isScripting()) parametersChanged(); + } else if (checker.compare(this.getClass(), "Gets the thickness of the branch stems", "[width in pixels]", commandName, "getStemWidth")) { + return String.valueOf(defaultStemWidth); + } else if (checker.compare(this.getClass(), "Gets the thickness of the branches", "[width in pixels]", commandName, "getBranchWidth")) { + return String.valueOf(defaultBranchWidth); + } else if (checker.compare(this.getClass(), "Returns the module calculating node locations", null, commandName, "getNodeLocsEmployee")) { + return nodeLocsTask; + } else if (checker.compare(this.getClass(), "Orients the tree drawing so that the terminal taxa are on top", null, commandName, "orientUp")) { + orientation = TreeDisplay.UP; + reorient = true; + } else if (checker.compare(this.getClass(), "Orients the tree drawing so that the terminal taxa are at the bottom", null, commandName, "orientDown")) { + orientation = TreeDisplay.DOWN; + reorient = true; + } else if (checker.compare(this.getClass(), "Orients the tree drawing so that the terminal taxa are at right", null, commandName, "orientRight")) { + orientation = TreeDisplay.RIGHT; + reorient = true; + } else if (checker.compare(this.getClass(), "Orients the tree drawing so that the terminal taxa are at left", null, commandName, "orientLeft")) { + orientation = TreeDisplay.LEFT; + reorient = true; + } else if (checker.compare(this.getClass(), "Sets whether to draw triangled clades as simple triangles or not.", "", commandName, "toggleSimpleTriangle")) { + boolean current = simpleTriangle.getValue(); + simpleTriangle.toggleValue(parser.getFirstToken(arguments)); + if (current!=simpleTriangle.getValue()) { + Enumeration e = drawings.elements(); + while (e.hasMoreElements()) { + Object obj = e.nextElement(); + StyledSquareTreeDrawing treeDrawing = (StyledSquareTreeDrawing)obj; + treeDrawing.setSimpleTriangle(simpleTriangle.getValue()); + } + parametersChanged(); + } + } else { + return super.doCommand(commandName, arguments, checker); + } + + if (reorient) { + Enumeration e = drawings.elements(); + while (e.hasMoreElements()) { + StyledSquareTreeDrawing treeDrawing = (StyledSquareTreeDrawing) e.nextElement(); + treeDrawing.reorient(orientation); + if (treeDrawing.treeDisplay != null) + orientation = treeDrawing.treeDisplay.getOrientation(); + } + orientationName.setValue(orient(orientation)); + parametersChanged(); + } + return null; + } + /*.................................................................................................................*/ + public String getName() { + return "Styled square tree"; + } + /*.................................................................................................................*/ + /** returns whether this module is requesting to appear as a primary choice */ + public boolean requestPrimaryChoice(){ + return true; + } + /*.................................................................................................................*/ + public String getVersion() { + return null; + } + /*.................................................................................................................*/ + + /** returns an explanation of what the module does.*/ + public String getExplanation() { + return "Draws trees with styled square branches (\"phenogram\")" ; + } + /*.................................................................................................................*/ + +} + + +/* ======================================================================== */ +class StyledSquareTreeDrawing extends TreeDrawing { + public Shape[] branchPolys; + + public StyledSquareTree ownerModule; + private int branchwidth = 2; + private int defaultBranchWidth = 2; + private int stemwidth = 2; + int oldNumTaxa = 0; + private boolean ready=false; + NameReference triangleNameRef; + BasicStroke defaultStroke; + + + public StyledSquareTreeDrawing(TreeDisplay treeDisplay, int numTaxa, StyledSquareTree ownerModule) { + super(treeDisplay, MesquiteTree.standardNumNodeSpaces(numTaxa)); + treeDisplay.setMinimumTaxonNameDistance(branchwidth, 5); //better if only did this if tracing on + this.ownerModule = ownerModule; + this.treeDisplay = treeDisplay; + triangleNameRef = NameReference.getNameReference("triangled"); + try{ + defaultStroke = new BasicStroke(); + } + catch (Throwable t){ + MesquiteMessage.notifyUser(ownerModule.getName() + " couldn't start because Graphics2D is not available. " + t.toString()); + } + + oldNumTaxa = numTaxa; + ready = true; + } + + public void resetNumNodes(int numNodes){ + super.resetNumNodes(numNodes); + branchPolys = new Line2D.Double[numNodes]; + + for (int i=0; i1) { + for (int i=1; i<=tree.numberOfParentsOfNode(node); i++) { + int anc =tree.parentOfNode(node, i); + if (anc!= tree.motherOfNode(node)) { + g.drawLine(x[node],y[node], x[tree.parentOfNode(node, i)],y[tree.parentOfNode(node, i)]); + g.drawLine(x[node]+1,y[node], x[tree.parentOfNode(node, i)]+1,y[tree.parentOfNode(node, i)]); + g.drawLine(x[node],y[node]+1, x[tree.parentOfNode(node, i)],y[tree.parentOfNode(node, i)]+1); + g.drawLine(x[node]+1,y[node]+1, x[tree.parentOfNode(node, i)]+1,y[tree.parentOfNode(node, i)]+1); + } + } + } + } + if (tree.getAssociatedBit(triangleNameRef, node) && treeDisplay.getSimpleTriangle()) { + Polygon triangle = new Polygon(); + int leftTerminal = tree.leftmostTerminalOfNode(node); + int rightTerminal = tree.rightmostTerminalOfNode(node); + triangle.addPoint(x[node],y[node]); + triangle.addPoint(x[leftTerminal],y[leftTerminal]); + triangle.addPoint(x[rightTerminal],y[rightTerminal]); + triangle.addPoint(x[node],y[node]); + ((Graphics2D)g).setStroke(new BasicStroke(branchwidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND)); + ((Graphics2D)g).draw(triangle); + } else { + for (int d = tree.firstDaughterOfNode(node); tree.nodeExists(d); d = tree.nextSisterOfNode(d)) { + drawOneBranch(tree, g, d); + } + if (tree.numberOfDaughtersOfNode(node) > 1) { // if this node has daughters, draw the stem bar. + ((Graphics2D)g).fill(stemLine(tree, node)); + } + } + } + } + + /*_________________________________________________*/ + public void drawTree(Tree tree, int drawnRoot, Graphics g) { + if (MesquiteTree.OK(tree)) { + if (treeDisplay == null) + return; + if (tree.getNumNodeSpaces()!=numNodes) + resetNumNodes(tree.getNumNodeSpaces()); + g.setColor(treeDisplay.branchColor); + drawOneBranch(tree, g, drawnRoot); + } + } + /*_________________________________________________*/ + public void recalculatePositions(Tree tree) { + if (MesquiteTree.OK(tree)) { + if (tree.getNumNodeSpaces()!=numNodes) + resetNumNodes(tree.getNumNodeSpaces()); + if (!tree.nodeExists(getDrawnRoot())) + setDrawnRoot(tree.getRoot()); + calcBranches(tree, getDrawnRoot()); + } + } + /*_________________________________________________*/ + /** Draw highlight for branch node with current color of graphics context */ + public void drawHighlight(Tree tree, int node, Graphics g, boolean flip){ + Color tC = g.getColor(); + if (flip) + g.setColor(Color.red); + else + g.setColor(Color.blue); + if (isDOWN() || isUP()){ + ((Graphics2D)g).fill(nodePoly(node)); + } + else { + ((Graphics2D)g).fill(nodePoly(node)); + } + g.setColor(tC); + } + /*_________________________________________________*/ + public void fillTerminalBox(Tree tree, int node, Graphics g) { + Rectangle box; + int ew = branchwidth -1; + if (isUP()) + box = new Rectangle(x[node], y[node]-ew-3, ew, ew); + else if (isDOWN()) + box = new Rectangle(x[node], y[node]+1, ew, ew); + else if (isRIGHT()) + box = new Rectangle(x[node]+1, y[node], ew, ew); + else if (isLEFT()) + box = new Rectangle(x[node]-ew-3, y[node], ew, ew); + else + box = new Rectangle(x[node], y[node], ew, ew); + g.fillRect(box.x, box.y, box.width, box.height); + g.setColor(treeDisplay.getBranchColor(node)); + g.drawRect(box.x, box.y, box.width, box.height); + } + /*_________________________________________________*/ + public void fillTerminalBoxWithColors(Tree tree, int node, ColorDistribution colors, Graphics g){ + Rectangle box; + int numColors = colors.getNumColors(); + int ew = branchwidth -1; + if (isUP()) + box = new Rectangle(x[node], y[node]-ew-3, ew, ew); + else if (isDOWN()) + box = new Rectangle(x[node], y[node]+1, ew, ew); + else if (isRIGHT()) + box = new Rectangle(x[node]+1, y[node], ew, ew); + else if (isLEFT()) + box = new Rectangle(x[node]-ew-3, y[node], ew, ew); + else + box = new Rectangle(x[node], y[node], ew, ew); + for (int i=0; i=0 && node < branchPolys.length) { + return treeDisplay.getVisRect() == null || branchPolys[node].intersects(treeDisplay.getVisRect()); + } + } + catch (Throwable t){ + } + return false; + } + /*_________________________________________________*/ + public void fillBranch(Tree tree, int node, Graphics g) { + if ((tree.getRooted() || tree.getRoot()!=node) && !ancestorIsTriangled(tree, node)){ + ((Graphics2D)g).fill(nodePoly(node)); + } + } + + /** Fill branch N with indicated set of colors as a sequence, e.g. for stochastic character mapping. This is not abstract because many tree drawers would have difficulty implementing it */ + public void fillBranchWithColorSequence(Tree tree, int node, ColorEventVector colors, Graphics g){ + if ((tree.getRooted() || tree.getRoot()!=node) && !ancestorIsTriangled(tree, node) && branchIsVisible(node)) { + Color c = g.getColor(); + int numEvents = colors.size(); + g.setColor(Color.lightGray); + fillBranch(tree, node, g); + for (int i=numEvents-1; i>=0; i--) { + ColorEvent e = (ColorEvent)colors.elementAt(i); + Shape outlined = nodePoly(node); + g.setColor(e.getColor()); + ((Graphics2D)g).draw(outlined); + g.setColor(Color.black); + ((Graphics2D)g).setStroke(new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER)); + ((Graphics2D)g).draw(outlined); + } + if (c!=null) g.setColor(c); + } + } + /*_________________________________________________*/ + public void fillBranchWithColors(Tree tree, int node, ColorDistribution colors, Graphics g) { + if ((tree.getRooted() || tree.getRoot()!=node) && !ancestorIsTriangled(tree, node) && branchIsVisible(node)) { + Color c = g.getColor(); + int numColors = colors.getNumColors(); + for (int i=0; i