Java source code of 'jhplot.jadraw.JaTextBox'

/*

 * Title: japlot.jaxodraw
 * Description: Graphical user interface for drawing Feynman diagrams
 * @author Daniele Binosi 
 * @author Lukas Theussl  

 Copyright (C) 2003-2006,  Daniele Binosi and Lukas Theussl

 See the file LICENSE in the source distribution home directory
 for a full copy of the GPL (GNU General Public License).

    This file is part of japlot.jaxodraw.

    japlot.jaxodraw 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.

    japlot.jaxodraw 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 */
package jhplot.jadraw;

import graph.RTextLine;

import japlot.JaTextOptionsPanel;
import japlot.jaxodraw.*;

import java.awt.Color;
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import org.freehep.graphics2d.VectorGraphics;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import jplot.Translate;

/**
 * Text label which can be either one text line or multiline. The text is in
 * box.
 * 
 * @author S.Chekanov
 * 
 */

public class JaTextBox extends JaFillObject {

	private String textString;
	private RTextLine rtext;
	private String stext; // short version
	private String[] multitext;

	/** The font of this label object. */
	private Font textFont;
	private int rotAngle;
	private boolean isMultiline;
	private static boolean first = true;
	private static double sH, sW, sD;
	private float[] ypos;
	private float[] xpos;

	private Color shadowColor;
	private int shadowXOffset;
	private int shadowYOffset;
	private boolean isShadow;
	private int     type;
        private int padX;
        private int padY;

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * Constructor: sets the width, height, getRelw() and getRelh() to a default
	 * value of 25.
	 */
	public JaTextBox() {
		setColor(Color.black);
		setFillColor(new Color(235, 255, 255));
		setRelw(100);
		setRelh(30);
		textString = null;
		multitext = null;
		isMultiline = false;
		xpos = null;
		ypos = null;
		this.textFont = new Font("Dialog", Font.BOLD, 16);
		rtext = new RTextLine();

		shadowColor = Color.gray;
		shadowXOffset = 5;
		shadowYOffset = 5;
		isShadow = true;
		type=0;
                padX=0;
                padY=0; 
	}

	
	
	
	/**
	 * Get identification number for this text object
	 * @return identification number
	 */
	
	public int getType() {
		return type;
	}
	
	
	/**
	 * Set identification number for this text object
	 * @param type identification number
	 */
	public void setType(int type) {
		this.type = type;
	}
	

        /**
         * Set pad ID in X
         * @param pad pad id
         */
        public void setPadX(int pad) {
                this.padX = pad;
        }



        /**
         * Get pad ID in X
         * @return pad ID
         */
        public int getPadX() {
                return padX;
        }


   /**
         * Set pad ID in Y
         * @param pad pad id
         */
        public void setPadY(int pad) {
                this.padY = pad;
        }


        /**
         * Get pad ID in Y
         * @return pad ID
         */
        public int getPadY() {
                return padY;
        }

	
	
	
	
	/**
	 * Is box with shadow?
	 * 
	 * @return true if multiline
	 */
	public boolean isShadow() {
		return isShadow;
	}

	/**
	 * Is this multiline text?
	 * 
	 * @return true if multiline
	 */
	public boolean isMultiline() {
		return isMultiline;
	}

	/**
	 * Set multiline text
	 * 
	 * @param multitext
	 *            input text
	 */
	public void setMultiText(String[] multitext) {
		this.multitext = multitext;
		isMultiline = true;
		textString = null;
		ypos = new float[multitext.length];
		xpos = new float[multitext.length];

	}

	/**
	 * Get color of shadow
	 * 
	 * @return color
	 */

	public Color getShadowColor() {
		return shadowColor;
	}

	/**
	 * Get shadow offset in X
	 * 
	 * @return offset
	 */

	public int getShadowXOffset() {
		return shadowXOffset;
	}

	/**
	 * Get shadow offset in Y
	 * 
	 * @return
	 */
	public int getShadowYOffset() {
		return shadowYOffset;
	}

	/**
	 * Set shadow offset in X
	 * 
	 * @param shadowXOffset
	 */

	public void setShadowXOffset(int shadowXOffset) {
		this.shadowXOffset = shadowXOffset;
	}

	/**
	 * Set shadow offset in Y
	 * 
	 * @param shadowYOffset
	 */

	public void setShadowYOffset(int shadowYOffset) {
		this.shadowYOffset = shadowYOffset;
	}

	/**
	 * Get multiline text
	 * 
	 * @return text
	 */
	public String[] getMultiText() {
		return multitext;
	}

	/**
	 * Returns the textFont property of this text object.
	 * 
	 * @return The textFont property of this text object.
	 */
	public final Font getFont() {
		return textFont;
	}

	/**
	 * Sets the textFont property of this text object.
	 * 
	 * @param font
	 *            The textFont property of this text object.
	 */
	public final void setFont(Font font) {
		this.textFont = font;
		rtext.setFont(this.textFont);
	}

	/**
	 * Sets the shadow to the box.
	 * 
	 * @param shadow
	 *            true if shadow is needed
	 */

	public final void setShadow(boolean shadow) {
		this.isShadow = shadow;
	}

	/**
	 * Sets a shadow size.
	 * 
	 * @param size
	 *            size in pixels
	 */
	public final void setShadowSize(int size) {
		shadowXOffset = size;
		shadowYOffset = size;
	}

	/**
	 * Returns the rotAngle property of this text object.
	 * 
	 * @return The rotAngle property of this text object.
	 */
	public final int getRotAngle() {
		return rotAngle;
	}

	/**
	 * Sets the rotAngle property of this text object.
	 * 
	 * @param angle
	 *            The rotAngle property of this text object.
	 */
	public final void setRotAngle(int angle) {
		this.rotAngle = angle;
	}

	/**
	 * Returns the textString property of this text object.
	 * 
	 * @return The textString property of this text object.
	 */
	public final String getText() {
		return textString;
	}

	/**
	 * Parse the text
	 */
	private final void parseText() {
		if (textString == null)
			return;
		rtext.setFont(getFont());
		rtext.setColor(getColor());
		rtext.setText(Translate.decode(textString));
		stext = Translate.shrink(textString);
		first = true;
	}

	/**
	 * Sets the textString property of this text object.
	 * 
	 * @param string
	 *            The textString property of this text object.
	 */
	public final void setText(String string) {
		this.multitext = null;
		this.textString = string;
		isMultiline = false;
		parseText();
	}

	/**
	 * Returns an exact copy of this Label.
	 * 
	 * @return A copy of this Label.
	 */
	public final JaObject copy() {
		JaTextBox temp = new JaTextBox();
		temp.setX(getX());
		temp.setY(getY());
		temp.setType(type);
                temp.setPadX(padX);
                temp.setPadY(padY); 
		temp.setShadow(isShadow);
		temp.setShadowXOffset(shadowXOffset);
		temp.setShadowYOffset(shadowYOffset);
		if (isMultiline) temp.setMultiText(multitext);
		temp.setColor(getColor());
		temp.setFillColor(getFillColor());
		temp.setStroke(getStroke());
		temp.setRotAngle(getRotAngle());
		if (isMultiline ==false) temp.setText(textString);
		temp.setFont(getFont());
		temp.setSize(getWidth(), getHeight(), getRelw(), getRelh());
		temp.setBoundingBox(getBoundingBox());

		return temp;
	}

	/**
	 * Returns true if all serializable variables of this JaObject and those of
	 * the specified one are equal.
	 * 
	 * @param comp
	 *            A JaObject to compare with.
	 * @return True if the objects are equal, false otherwise.
	 */
	public final boolean isCopy(JaObject comp) {
		boolean isCopy = false;

		if (comp instanceof JaTextBox) {
			JaTextBox temp = (JaTextBox) comp;
			if ((temp.getX() == getX()) && (temp.getY() == getY())
					&& (temp.getColor().equals(getColor()))
					&& (temp.getFillColor().equals(getFillColor()))
					&& (temp.getText().equals(getText()))
					&& (temp.getFont().equals(getFont()))
					&& (temp.getStroke() == getStroke())
					&&  temp.getType() == getType()
					&& (temp.getRelw() == getRelw())
					&& (temp.getRelh() == getRelh())) {
				isCopy = true;
			}
		}

		return isCopy;

	}

	/**
	 * Determines where on this JaObject a mouse click has ocurred.
	 * 
	 * @param clickX
	 *            The x position of the point where the mouse click ocurred.
	 * @param clickY
	 *            The y position of the point where the mouse click ocurred.
	 * @param editmode
	 *            The current edit mode as defined in JaxoMainPanel.
	 * @return An integer specifying whether the click ocurred on one of the
	 *         handles and if yes, on which.
	 */
	public final int getGrabbedHandle(int clickX, int clickY, int editmode) {
		if ((editmode == MOVE) || (editmode == COPY)) {
			if ((clickX >= (getX() + getWidth()))
					&& (clickX <= (getX() + getWidth() + LENGTH))
					&& (clickY >= (getY() + getHeight()))
					&& (clickY <= (getY() + getHeight() + LENGTH))) {
				return SELECT_BODY;
			}

			if ((clickX >= (getX() - LENGTH)) && (clickX <= getX())
					&& (clickY >= (getY() + getHeight()))
					&& (clickY <= (getY() + getHeight() + LENGTH))) {
				return SELECT_BODY;
			}

			if ((clickX >= (getX() + getWidth()))
					&& (clickX <= (getX() + getWidth() + LENGTH))
					&& (clickY >= (getY() - LENGTH)) && (clickY <= getY())) {
				return SELECT_BODY;
			}

			if ((clickX >= (getX() - LENGTH)) && (clickX <= getX())
					&& (clickY >= (getY() - LENGTH)) && (clickY <= getY())) {
				return SELECT_BODY;
			}

			return SELECT_NONE;
		}

		if (editmode == RESIZE) {
			if ((clickX >= (getX() + getWidth()))
					&& (clickX <= (getX() + getWidth() + LENGTH))
					&& (clickY >= (getY() + getHeight()))
					&& (clickY <= (getY() + getHeight() + LENGTH))) {
				return SELECT_LR;
			}

			if ((clickX >= (getX() - LENGTH)) && (clickX <= getX())
					&& (clickY >= (getY() + getHeight()))
					&& (clickY <= (getY() + getHeight() + LENGTH))) {
				return SELECT_LL;
			}

			if ((clickX >= (getX() + getWidth()))
					&& (clickX <= (getX() + getWidth() + LENGTH))
					&& (clickY >= (getY() - LENGTH)) && (clickY <= getY())) {
				return SELECT_UR;
			}

			if ((clickX >= (getX() - LENGTH)) && (clickX <= getX())
					&& (clickY >= (getY() - LENGTH)) && (clickY <= getY())) {
				return SELECT_UL;
			}

			return SELECT_NONE;
		}

		return SELECT_NONE;
	}

	/**
	 * Draws the handles of this box object.
	 * 
	 * @param g2
	 *            The current graphics context.
	 */
	public final void drawHandles(VectorGraphics g2) {
		g2.setColor(JaxoColor.RED);
		g2.setStroke(new BasicStroke(1.0f));

		int x = getX();
		int y = getY();
		int width = getWidth();
		int height = getHeight();

		g2.drawRect(x - LENGTH, y - LENGTH, LENGTH, LENGTH);
		g2.drawRect(x - LENGTH, y + height, LENGTH, LENGTH);
		g2.drawRect(x + width, y - LENGTH, LENGTH, LENGTH);
		g2.drawRect(x + width, y + height, LENGTH, LENGTH);

		if (this.isMarked()) {
			g2.setColor(JaxoColor.GRAYSCALE150);
			g2.fillRect(x - LENGTH + 1, y - LENGTH + 1, LENGTH - 1, LENGTH - 1);
			g2.fillRect(x - LENGTH + 1, y + height + 1, LENGTH - 1, LENGTH - 1);
			g2.fillRect(x + width + 1, y - LENGTH + 1, LENGTH - 1, LENGTH - 1);
			g2.fillRect(x + width + 1, y + height + 1, LENGTH - 1, LENGTH - 1);
		}
	}

	/**
	 * The method that draws this Label.
	 * 
	 * @param g2
	 *            The graphics context where the Label has to be drawn.
	 * @param drawToScreen
	 *            A boolean variable that indicates whether the drawing is done
	 *            on the screen or somewhere else. This is used for
	 *            exporting/printing, where the object handles should not be
	 *            painted, even if they are visible on the screen.
	 */
	public final void jaxoDraw(VectorGraphics g2, boolean drawToScreen) {

		if (multitext == null && textString == null)
			return;

		if (multitext != null && multitext[0].equals("UNDEFINED"))
			return;

		GeneralPath gp = getGeneralPath();
		gp.reset();
		double wid = 0;

		if (first && isMultiline == false) {
			FontMetrics fm = g2.getFontMetrics(getFont());
			sH = 1.2 * fm.getHeight();
			wid = fm.stringWidth(stext);
			sW = 1.2 * wid;
			sD = 0.1 * wid;
			setRelw((int) sW);
			setRelh((int) sH);
			first = false;
		}

		if (isMultiline) {
			FontMetrics fm = g2.getFontMetrics(getFont());
			sH = 1.1 * fm.getHeight();
			wid = fm.stringWidth(multitext[0]);
			sW = 1.1 * wid;
			sD = 0.1 * wid;
			double HH = 0;
			double xmax = 0;
			for (int i = 0; i < multitext.length; i++) {
				wid = fm.stringWidth(multitext[i]);
				if (wid > xmax)
					xmax = wid;
				xpos[i] = (float) (getX() + sD);
				ypos[i] = (float) (getY() + sH + HH);
				HH = HH + sH;
			}
			sW = 1.2 * xmax;
			setRelw((int) sW);
			setRelh((int) (HH + 0.25 * sH));

		}

		if (isShadow == true) {
			Rectangle2D shadow = new Rectangle2D.Float();
			shadow.setFrame(getX() + shadowXOffset, getY() + shadowYOffset,
					getWidth(), getHeight());
			g2.setColor(shadowColor);
			g2.fill(shadow);
			// gp.reset();
			// gp.append(shadow, false);
		} // end shadow

		Rectangle2D box = new Rectangle2D.Float();
		box.setFrame(getX(), getY(), getWidth(), getHeight());
		gp.append(box, false);
		g2.setColor(getFillColor());
		g2.setStroke(new BasicStroke(1.0f));
		g2.fill(gp);
		gp.reset();
		gp.append(box, false);
		g2.setColor(getColor());
		g2.setStroke(new BasicStroke(getStroke()));
		g2.draw(gp);

		if (isMultiline) {

			for (int i = 0; i < multitext.length; i++) {
				RTextLine dtex = new RTextLine();
				dtex.setColor(getColor());
				dtex.setFont(getFont());
				dtex.setText(Translate.decode(multitext[i]));
				dtex.draw(g2, (int) xpos[i], (int) ypos[i]);
			}
		} else {
			float x = (float) (getX() + sD);
			float y = (float) (getY() + 0.75 * getHeight());
			// double theta = Math.toRadians(rotAngle);
			// g2.rotate(theta, x, y);
			// rtext.setRotation((int) rotAngle);
			// rtext.setColor(getColor());
			rtext.draw(g2, (int) x, (int) y);
			// g2.rotate(-theta, x, y);
		}

		Rectangle2D bb = gp.getBounds2D();
		double[] bbox = { bb.getMinX(), bb.getMinY(),
				bb.getMaxX() + 0.5 * shadowXOffset,
				bb.getMaxY() + 0.5 * shadowYOffset };
		setBoundingBox(bbox);
	}

	/**
	 * The LaTeX command that is necessary to draw the given Label using the
	 * axodraw.sty package.
	 * 
	 * @param scale
	 *            A scale factor to translate Java coordinates to LaTeX
	 *            coordinates.
	 * @param canvasDim
	 *            The current dimension of the canvas.
	 * @return The corresponding axodraw LaTeX command.
	 */
	public final String latexCommand(float scale, Dimension canvasDim) {
		int canvasHeight = canvasDim.height;

		Point2D lowerCorner = getLaTexLowerCorner(scale, canvasHeight);
		Point2D upperCorner = getLaTexUpperCorner(scale, canvasHeight);

		String command = "";

		if (((int) lowerCorner.getX() == (int) upperCorner.getX())
				&& ((int) lowerCorner.getY() == (int) upperCorner.getY())) {
			command = "%";
		} else {
			if (JaxoColor.isGrayScale(getFillColor())) {
				String grayScale = JaxoColor.getGreyScale(getFillColor());

				command = "\\GBox" + "(" + D_FORMAT.format(lowerCorner.getX())
						+ "," + D_FORMAT.format(lowerCorner.getY()) + ")" + "("
						+ D_FORMAT.format(upperCorner.getX()) + ","
						+ D_FORMAT.format(upperCorner.getY()) + ")" + "{"
						+ grayScale + "}";
			} else {
				String tlc = JaxoColor.getColorName(getColor());
				String tfc = JaxoColor.getColorName(getFillColor());

				command = "\\CBox" + "(" + D_FORMAT.format(lowerCorner.getX())
						+ "," + D_FORMAT.format(lowerCorner.getY()) + ")" + "("
						+ D_FORMAT.format(upperCorner.getX()) + ","
						+ D_FORMAT.format(upperCorner.getY()) + ")" + "{" + tlc
						+ "}" + "{" + tfc + "}";
			}
		}

		return command;
	}

	/**
	 * Rescales this Label by the scale factor scale, keeping the point (orx,
	 * ory) fixed.
	 * 
	 * @param orx
	 *            The x - coordinate of the fixed point
	 * @param ory
	 *            The y - coordinate of the fixed point
	 * @param scale
	 *            The scale parameter
	 */
	public final void rescaleObject(int orx, int ory, float scale) {
		// int oldWidth = this.getSize().width;
		// int oldHeight = this.getSize().height;
		// int newWidth = (int) Math.round(oldWidth * scale);
		// int newHeight = (int) Math.round(oldHeight * scale);
		int newRelWidth = (int) Math.round(this.getRelSize().width * scale);
		int newRelHeight = (int) Math.round(this.getRelSize().height * scale);

		Point2D newP = this.scalePoint(orx, ory, scale, this.getX(), this
				.getY());

		this.setX((int) Math.round(newP.getX()));
		this.setY((int) Math.round(newP.getY()));

		// this.setWAndH(newWidth, newHeight);
		this.setRelWAndH(newRelWidth, newRelHeight);
	}

	// ///////////////////////////////////////////////////////////////////////
	//
	// private auxiliary methods //
	//
	// ///////////////////////////////////////////////////////////////////////
	private Point2D getLaTexLowerCorner(float scaleFactor, int canvasHeight) {
		Point2D lowerCornerVec = new Point2D.Float();
		float x1;
		float y1;

		x1 = getX();
		y1 = getY() + getHeight();

		lowerCornerVec.setLocation(x1 / scaleFactor, (canvasHeight - y1)
				/ scaleFactor);

		return lowerCornerVec;
	}

	private Point2D getLaTexUpperCorner(float scaleFactor, int canvasHeight) {
		Point2D upperCornerVec = new Point2D.Float();
		float x1;
		float y1;

		x1 = getX() + getWidth();
		y1 = getY();

		upperCornerVec.setLocation(x1 / scaleFactor, (canvasHeight - y1)
				/ scaleFactor);

		return upperCornerVec;
	}

	/**
	 * Brings up the edit panel that allows to change the parameters of this
	 * object.
	 * 
	 * @return True if the editing actually changed the object, false if the
	 *         object has not been changed.
	 */
	public final boolean editPanel() {
		JaTextOptionsPanel boxop = new JaTextOptionsPanel(this);

		return boxop.hasChanged();
	}
}