/* * ScaleAxisPainter.java * * Copyright (C) 2006-2014 Andrew Rambaut * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package figtree.treeviewer.painters; import figtree.treeviewer.ScaleAxis; import figtree.treeviewer.TreePane; import figtree.treeviewer.decorators.Decorator; import figtree.treeviewer.treelayouts.RectilinearTreeLayout; import figtree.treeviewer.treelayouts.RadialTreeLayout; import jebl.evolution.trees.Tree; import jebl.util.Attributable; import jam.controlpalettes.ControlPalette; import java.awt.*; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.text.NumberFormat; import java.util.Collection; import java.util.Set; /** * @author Andrew Rambaut * @version $Id$ * * $HeadURL$ * * $LastChangedBy$ * $LastChangedDate$ * $LastChangedRevision$ */ public class ScaleAxisPainter extends LabelPainter<TreePane> implements ScalePainter { private double majorTickSpacing = 1.0; private double minorTickSpacing = 0.5; public ScaleAxisPainter() { super(null); } public void setTreePane(TreePane treePane) { this.treePane = treePane; } public void setAutomatic(boolean automatic) { if (automatic) { treePane.setAutomaticScale(); majorTickSpacing = treePane.getMajorTickSpacing(); minorTickSpacing = treePane.getMinorTickSpacing(); } else { treePane.setTickSpacing(majorTickSpacing, minorTickSpacing); } } public void setAxisReversed(final boolean isAxisReversed) { treePane.setAxisReversed(isAxisReversed); } public void setAxisSpacing(double majorTickSpacing, double minorTickSpacing) { treePane.setTickSpacing(majorTickSpacing, minorTickSpacing); } public double getAxisOrigin() { return 0.0; } public void setAxisOrigin(double axisOrigin) { // } public double getMajorTickSpacing() { return majorTickSpacing; } public double getMinorTickSpacing() { return minorTickSpacing; } public Rectangle2D calibrate(Graphics2D g2, TreePane treePane) { Font oldFont = g2.getFont(); g2.setFont(getFont()); FontMetrics fm = g2.getFontMetrics(); double labelHeight = fm.getHeight(); preferredWidth = treePane.getTreeBounds().getWidth(); preferredHeight = labelHeight + topMargin + bottomMargin + scaleBarStroke.getLineWidth() + majorTickSize; if (!(treePane.getTreeLayout() instanceof RectilinearTreeLayout)) { // if the tree layout is not rectilinear, we are not going to display // an axis at the moment so make the height 0. preferredHeight = 0.0; } tickLabelOffset = (float) (fm.getAscent() + topMargin + bottomMargin + majorTickSize) + scaleBarStroke.getLineWidth(); g2.setFont(oldFont); return new Rectangle2D.Double(0.0, 0.0, preferredWidth, preferredHeight); } public void paint(Graphics2D g2, TreePane treePane, Justification justification, Rectangle2D bounds) { Font oldFont = g2.getFont(); Paint oldPaint = g2.getPaint(); Stroke oldStroke = g2.getStroke(); if (TreePane.DEBUG_OUTLINE) { g2.setPaint(Color.red); g2.draw(bounds); } if (treePane.getTreeLayout() instanceof RadialTreeLayout) { // Unless the layout is the rectilinear or polar one, the grid won't make sense... return; } if (getBackground() != null) { g2.setPaint(getBackground()); g2.fill(bounds); } if (getBorderPaint() != null && getBorderStroke() != null) { g2.setPaint(getBorderPaint()); g2.setStroke(getBorderStroke()); g2.draw(bounds); } g2.setFont(getFont()); g2.setPaint(getForeground()); g2.setStroke(getScaleBarStroke()); paintAxis(g2, bounds); g2.setFont(oldFont); g2.setPaint(oldPaint); g2.setStroke(oldStroke); } /** * Get the maximum width of the labels of an axis * @param g2 * @return */ protected double getMaxTickLabelWidth(Graphics2D g2) { String label; double width; double maxWidth = 0; ScaleAxis axis = treePane.getScaleAxis(); if (axis.getLabelFirst()) { // Draw first minor tick as a major one (with a label) label = axis.getFormatter().format(axis.getMinorTickValue(0, -1)); width = g2.getFontMetrics().stringWidth(label); if (maxWidth < width) maxWidth = width; } int n = axis.getMajorTickCount(); for (int i = 0; i < n; i++) { label = axis.getFormatter().format(axis.getMajorTickValue(i)); width = g2.getFontMetrics().stringWidth(label); if (maxWidth < width) maxWidth = width; } if (axis.getLabelLast()) { // Draw first minor tick as a major one (with a label) label = axis.getFormatter().format(axis.getMinorTickValue(0, n - 1)); width = g2.getFontMetrics().stringWidth(label); if (maxWidth < width) maxWidth = width; } return maxWidth; } protected void paintAxis(Graphics2D g2, Rectangle2D axisBounds) { ScaleAxis axis = treePane.getScaleAxis(); g2.setPaint(getForeground()); g2.setStroke(getScaleBarStroke()); double minX = treePane.scaleOnAxis(axis.getMinAxis()); double maxX = treePane.scaleOnAxis(axis.getMaxAxis()); Line2D line = new Line2D.Double(minX, axisBounds.getY() + topMargin, maxX, axisBounds.getY() + topMargin); g2.draw(line); int n1 = axis.getMajorTickCount(); int n2, i, j; n2 = axis.getMinorTickCount(-1); if (axis.getLabelFirst()) { // Draw first minor tick as a major one (with a label) paintMajorTick(g2, axisBounds, axis, axis.getMinorTickValue(0, -1)); for (j = 1; j < n2; j++) { paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, -1)); } } else { for (j = 0; j < n2; j++) { paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, -1)); } } for (i = 0; i < n1; i++) { paintMajorTick(g2, axisBounds, axis, axis.getMajorTickValue(i)); n2 = axis.getMinorTickCount(i); if (i == (n1-1) && axis.getLabelLast()) { // Draw last minor tick as a major one paintMajorTick(g2, axisBounds, axis, axis.getMinorTickValue(0, i)); for (j = 1; j < n2; j++) { paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, i)); } } else { for (j = 0; j < n2; j++) { paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, i)); } } } } protected void paintMajorTick(Graphics2D g2, Rectangle2D axisBounds, ScaleAxis axis, double value) { g2.setPaint(getForeground()); g2.setStroke(getScaleBarStroke()); // String label = axis.getFormatter().format(value); String label = getNumberFormat().format(value); double pos = treePane.scaleOnAxis(value); Line2D line = new Line2D.Double(pos, axisBounds.getMinY() + topMargin, pos, axisBounds.getMinY() + majorTickSize + topMargin); g2.draw(line); g2.setPaint(getForeground()); double width = g2.getFontMetrics().stringWidth(label); g2.drawString(label, (float)(pos - (width / 2)), (float)(axisBounds.getMinY() + tickLabelOffset + topMargin)); } protected void paintMinorTick(Graphics2D g2, Rectangle2D axisBounds, double value) { g2.setPaint(getForeground()); g2.setStroke(getScaleBarStroke()); double pos = treePane.scaleOnAxis(value); Line2D line = new Line2D.Double(pos, axisBounds.getMinY() + topMargin, pos, axisBounds.getMinY() + minorTickSize + topMargin); g2.draw(line); } public double getPreferredWidth() { return preferredWidth; } public double getPreferredHeight() { return preferredHeight; } public double getHeightBound() { return preferredHeight + tickLabelOffset; } public BasicStroke getScaleBarStroke() { return scaleBarStroke; } public void setScaleBarStroke(BasicStroke scaleBarStroke) { this.scaleBarStroke = scaleBarStroke; firePainterChanged(); } public void setControlPalette(ControlPalette controlPalette) { // nothing to do } public String[] getAttributes() { return new String[0]; } public void setupAttributes(Collection<? extends Tree> trees) { // nothing to do... } @Override public String getDisplayAttribute() { throw new UnsupportedOperationException("getDisplayAttribute not implmented"); } public void setDisplayAttribute(String displayAttribute) { throw new UnsupportedOperationException("setDisplayAttribute not implemented in ScaleAxisPainter"); } public void setTextDecorator(Decorator textDecorator) { } public Set<Attributable> getAttributableItems() { return null; } private BasicStroke scaleBarStroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); private double topMargin = 4.0; private double bottomMargin = 4.0; private double majorTickSize = 5.0; private double minorTickSize = 2.0; private double tickLabelOffset = 4.0; private double preferredHeight; private double preferredWidth; protected TreePane treePane; }