package net.sf.openrocket.gui.print.components; import net.sf.openrocket.gui.print.PrintUnit; import net.sf.openrocket.gui.print.PrintableComponent; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; /** * This class creates a Swing ruler. The ruler has both vertical and horizontal rules, as well as divisions for both * inches and centimeters. */ public class Rule extends PrintableComponent { public static enum Orientation { TOP, BOTTOM } public static final int TINIEST_TICK_LENGTH = 3; public static final int MINOR_TICK_LENGTH = 6; public static final int MID_MAJOR_TICK_LENGTH = 9; public static final int MAJOR_TICK_LENGTH = 14; private Orientation orientation; /** * Constructor. * * @param theOrientation defines if the horizontal ruler should be on the top or bottom; the vertical is always * left justified */ public Rule(Orientation theOrientation) { orientation = theOrientation; int dim = (int) PrintUnit.INCHES.toPoints(2) + 32; setSize(dim, dim); } /** * Render the component onto a graphics context. * * @param g the opaque graphics context */ @Override public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; double div = PrintUnit.INCHES.toPoints(1) / 8; //1/8 inch increment final int width = (int) PrintUnit.INCHES.toPoints(2); int x = 20; int y = x + 20; boolean inchOutSide = true; g2.translate(getOffsetX(), getOffsetY()); if (orientation == Orientation.TOP) { Font f = g.getFont(); g.setFont(f.deriveFont(f.getSize() - 2f)); g.drawString("in cm", x - MAJOR_TICK_LENGTH, y + width + 20); g.drawString("in", x + width + 4, y + 4); g.drawString("cm", x + width + 4, y + 18); y += 6; drawVerticalRule(g2, true, inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8); drawHorizontalRule(g2, true, !inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8); div = PrintUnit.MILLIMETERS.toPoints(1); //mm increment drawVerticalRule(g2, true, !inchOutSide, x, y, width, 0, 0, div * 5, div * 10); drawHorizontalRule(g2, true, inchOutSide, x, y, width, 0, 0, div * 5, div * 10); } else { Font f = g.getFont(); g.setFont(f.deriveFont(f.getSize() - 2f)); g.drawString("in cm", x - MAJOR_TICK_LENGTH, y); g.drawString("cm", x + width + 6, y + width + 4); g.drawString("in", x + width + 6, y + width + 18); y += 6; //Draw Inches first, with 1/2", 1/4", and 1/8" tick marks. drawVerticalRule(g2, false, inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8); drawHorizontalRule(g2, true, inchOutSide, x, y + width, width, 0, div * 2, div * 4, div * 8); div = PrintUnit.MILLIMETERS.toPoints(1); //mm increment //Draw cm (10mm) and 1/2 cm (5mm) marks drawVerticalRule(g2, false, !inchOutSide, x, y, width, 0, 0, div * 5, div * 10); drawHorizontalRule(g2, true, !inchOutSide, x, y + width, width, 0, 0, div * 5, div * 10); } } /** * Draw a horizontal ruler. * * @param g the graphics context * @param vertexAtLeft true if the horizontal/vertical vertex is oriented to the top * @param drawTicksDown true if the ruler should draw interval tick marks to the underside of the solid ruler line * @param x starting x position of the ruler * @param y starting y position of the rule * @param length the number of points in length to extend the vertical ruler * @param tinyEveryX the number of points for each tiny division tick line; if zero or negative tiny will not be * drawn * @param minorEveryX the number of points for each minor division tick line; if zero or negative minor will not * be drawn * @param midMajorEveryX the number of points for each mid-major division tick line * @param majorEveryX the number of points for each major division tick line (this is typically the inch or cm * distance in points). */ private void drawHorizontalRule(Graphics2D g, boolean vertexAtLeft, boolean drawTicksDown, int x, int y, int length, double tinyEveryX, double minorEveryX, double midMajorEveryX, double majorEveryX) { //Draw solid horizontal line g.setColor(Color.black); g.drawLine(x, y, x + length, y); int tiniest = drawTicksDown ? TINIEST_TICK_LENGTH : -1 * TINIEST_TICK_LENGTH; int minor = drawTicksDown ? MINOR_TICK_LENGTH : -1 * MINOR_TICK_LENGTH; int mid = drawTicksDown ? MID_MAJOR_TICK_LENGTH : -1 * MID_MAJOR_TICK_LENGTH; int major = drawTicksDown ? MAJOR_TICK_LENGTH : -1 * MAJOR_TICK_LENGTH; //Draw vertical rule ticks for the horizontal ruler //Draw minor ticks int initial = x; int end = initial + length; double increment = tinyEveryX; boolean lessThanEqual = true; if (!vertexAtLeft) { initial = x + length; end = x; lessThanEqual = false; } if (tinyEveryX > 0) { if (!vertexAtLeft) { increment = -1 * increment; } for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) { g.drawLine((int) xtick, y, (int) xtick, y + tiniest); } } //Draw minor ticks if (minorEveryX > 0) { if (!vertexAtLeft) { increment = -1 * minorEveryX; } else { increment = minorEveryX; } for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) { g.drawLine((int) xtick, y, (int) xtick, y + minor); } } //Draw mid-major ticks if (midMajorEveryX > 0) { if (!vertexAtLeft) { increment = -1 * midMajorEveryX; } else { increment = midMajorEveryX; } for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) { g.drawLine((int) xtick, y, (int) xtick, y + mid); } } if (!vertexAtLeft) { increment = -1 * majorEveryX; } else { increment = majorEveryX; } //Draw major ticks for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) { g.drawLine((int) xtick, y, (int) xtick, y + major); } } /** * Draw a vertical ruler. * * @param g the graphics context * @param vertexAtTop true if the horizontal/vertical vertex is oriented to the top * @param drawTicksRight true if the ruler should draw interval tick marks to the right side of the solid ruler * line * @param x starting x position of the ruler * @param y starting y position of the rule * @param length the number of points in length to extend the vertical ruler * @param tinyEveryY the number of points for each tiny division tick line; if zero or negative tiny will not be * drawn * @param minorEveryY the number of points for each minor division tick line; if zero or negative minor will not * be drawn * @param midMajorEveryY the number of points for each mid-major division tick line * @param majorEveryY the number of points for each major division tick line (this is typically the inch or cm * distance in points). */ private void drawVerticalRule(Graphics2D g, boolean vertexAtTop, boolean drawTicksRight, int x, int y, int length, double tinyEveryY, double minorEveryY, double midMajorEveryY, double majorEveryY) { int tiniest = drawTicksRight ? TINIEST_TICK_LENGTH : -1 * TINIEST_TICK_LENGTH; int minor = drawTicksRight ? MINOR_TICK_LENGTH : -1 * MINOR_TICK_LENGTH; int mid = drawTicksRight ? MID_MAJOR_TICK_LENGTH : -1 * MID_MAJOR_TICK_LENGTH; int major = drawTicksRight ? MAJOR_TICK_LENGTH : -1 * MAJOR_TICK_LENGTH; //Draw solid vertical line g.setColor(Color.black); g.drawLine(x, y, x, y + length); //Draw horizontal rule ticks for the vertical ruler //Draw tiny ticks int initial = y; int end = initial + length; double increment = tinyEveryY; boolean lessThanEqual = true; if (!vertexAtTop) { initial = y + length; end = y; lessThanEqual = false; } if (tinyEveryY > 0) { if (!vertexAtTop) { increment = -1 * increment; } for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) { g.drawLine(x, (int) tick, x - tiniest, (int) tick); } } //Draw minor ticks if (minorEveryY > 0) { if (!vertexAtTop) { increment = -1 * minorEveryY; } else { increment = minorEveryY; } for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) { g.drawLine(x, (int) tick, x - minor, (int) tick); } } //Draw mid-major ticks if (!vertexAtTop) { increment = -1 * midMajorEveryY; } else { increment = midMajorEveryY; } for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) { g.drawLine(x, (int) tick, x - mid, (int) tick); } //Draw major ticks if (!vertexAtTop) { increment = -1 * majorEveryY; } else { increment = majorEveryY; } for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) { g.drawLine(x, (int) tick, x - major, (int) tick); } } }