/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: AbstractTextDescriptor.java
*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) 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 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.database.variable;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.tool.user.User;
import com.sun.electric.util.math.DBMath;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* This class describes how variable text appears.
* <P>
* This class should be thread-safe
*/
abstract class AbstractTextDescriptor implements Serializable {
/*private*/ static final long VTPOSITION = 017L; /* 0: position of text relative to point */
/*private*/ static final int VTPOSITIONSH = 0; /* 0: right shift of VTPOSITION */
/*private*/ static final int VTPOSCENT = 0; /* 0: text centered about point */
/*private*/ static final int VTPOSUP = 1; /* 0: text centered above point */
/*private*/ static final int VTPOSDOWN = 2; /* 0: text centered below point */
/*private*/ static final int VTPOSLEFT = 3; /* 0: text centered to left of point */
/*private*/ static final int VTPOSRIGHT = 4; /* 0: text centered to right of point */
/*private*/ static final int VTPOSUPLEFT = 5; /* 0: text centered to upper-left of point */
/*private*/ static final int VTPOSUPRIGHT = 6; /* 0: text centered to upper-right of point */
/*private*/ static final int VTPOSDOWNLEFT = 7; /* 0: text centered to lower-left of point */
/*private*/ static final int VTPOSDOWNRIGHT = 8; /* 0: text centered to lower-right of point */
/*private*/ static final int VTPOSBOXED = 9; /* 0: text centered and limited to object size */
/*private*/ static final long VTDISPLAYPART = 060L; /* 0: bits telling what to display */
/*private*/ static final int VTDISPLAYPARTSH = 4; /* 0: right shift of VTDISPLAYPART */
/*private*/ static final int VTDISPLAYVALUE = 0; /* 0: display value */
/*private*/ static final int VTDISPLAYNAMEVALUE = 2; /* 0: display name and value */
/*private*/ static final int VTDISPLAYNAMEVALINH = 1; /* 0: display name, value, 1-level inherit */
/*private*/ static final int VTDISPLAYNAMEVALINHALL = 3; /* 0: display name, value, any inherit */
/*private*/ static final long VTITALIC = 0100L; /* 0: set for italic text */
/*private*/ static final long VTBOLD = 0200L; /* 0: set for bold text */
/*private*/ static final long VTUNDERLINE = 0400L; /* 0: set for underline text */
/*private*/ static final long VTISPARAMETER = 01000L; /* 0: attribute is parameter (nodeinst only) */
/*private*/ static final long VTINTERIOR = 02000L; /* 0: text only appears inside cell */
/*private*/ static final long VTINHERIT = 04000L; /* 0: set to inherit value from proto to inst */
/*private*/ static final long VTXOFF = 07770000L; /* 0: X offset of text */
/*private*/ static final int VTXOFFSH = 12; /* 0: right shift of VTXOFF */
/*private*/ static final long VTXOFFNEG = 010000000L; /* 0: set if X offset is negative */
/*private*/ static final long VTYOFF = 017760000000L; /* 0: Y offset of text */
/*private*/ static final int VTYOFFSH = 22; /* 0: right shift of VTYOFF */
/*private*/ static final long VTYOFFNEG = 020000000000L; /* 0: set if Y offset is negative */
/*private*/ static final int VTOFFMASKWID = 9; /* 0: Width of VTXOFF and VTYOFF */
/*private*/ static final long VTSIZE = 077777L << 32; /* 1: size of text */
/*private*/ static final int VTSIZESH = 0 + 32; /* 1: right shift of VTSIZE */
/*private*/ static final long VTFACE = 017700000L << 32; /* 1: face of text */
/*private*/ static final int VTFACESH = 15 + 32; /* 1: right shift of VTFACE */
/*private*/ static final int VTMAXFACE = 127; /* 1: maximum value of VTFACE field */
/*private*/ static final long VTROTATION = 060000000L << 32; /* 1: rotation of text */
/*private*/ static final int VTROTATIONSH = 22 + 32; /* 1: right shift of VTROTATION */
/*private*/ static final long VTOFFSCALE = 03700000000L << 32; /* 1: scale of text offset */
/*private*/ static final int VTOFFSCALESH = 24 + 32; /* 1: right shift of VTOFFSCALE */
/*private*/ static final long VTUNITS = 034000000000L << 32; /* 1: units of text */
/*private*/ static final int VTUNITSHMASK = 07; /* 1: mask of this value after being shifted down */
/*private*/ static final int VTUNITSSH = 29 + 32; /* 1: right shift of VTUNITS */
/*private*/ static final int VTUNITSNONE = 0; /* 1: units: none */
/*private*/ static final int VTUNITSRES = 1; /* 1: units: resistance */
/*private*/ static final int VTUNITSCAP = 2; /* 1: units: capacitance */
/*private*/ static final int VTUNITSIND = 3; /* 1: units: inductance */
/*private*/ static final int VTUNITSCUR = 4; /* 1: units: current */
/*private*/ static final int VTUNITSVOLT = 5; /* 1: units: voltage */
/*private*/ static final int VTUNITSDIST = 6; /* 1: units: distance */
/*private*/ static final int VTUNITSTIME = 7; /* 1: units: time */
/*private*/ static final int VTOFFMAX = (1 << VTOFFMASKWID) - 1; /* 0: Maximal value of unshifted VTXOFF and VTYOFF */
/*private*/ static final int VTSCALEMAX = (int) (VTOFFSCALE >> VTOFFSCALESH); /* 1: Maximal value of unshifted VTOFFSCALE */
/** Semantic bits - those bits which are meaningful in non-displayable text descriptors. */
static long VTSEMANTIC = VTISPARAMETER | VTINTERIOR | VTINHERIT | VTUNITS;
// Variable flags in C Electric
/** display variable (uses textdescript field) */ /*private*/ static final int VDISPLAY = 0100;
/** enumeration which represents text visibility .*/
public enum Display {
/** Non-displayable variable */
NONE,
/** Displayable variable which is temporary hidden */
HIDDEN,
/** Displayable variable which is shown */
SHOWN;
};
/**
* Position is a typesafe enum class that describes the text position of a Variable.
* The Position describes the "anchor point" of the text,
* which is the point on the text that is attached to the object and does not move.
* For example, when the Position is CENT, then the center of the text is fixed,
* and as the text grows, it expands uniformly about the center.
* When the Position is UP, the text is centered above the anchor point, and as the text grows
* it expands upward from the bottom-center point.
*/
public static class Position {
private final String name;
private final int index;
private final Poly.Type pt;
private static final List<Position> positions = new ArrayList<Position>();
private Position(String name, int index, Poly.Type pt) {
this.name = name;
this.index = index;
this.pt = pt;
positions.add(index, this);
}
/**
* Method to return the integer equivalent of this Position.
* @return the integer equivalent of this Position.
*/
public int getIndex() {
return index;
}
/**
* Method to return the Poly.Type to use for this Position.
* The Poly.Type will vary through the 9 "anchor point" locations:
* center, left, right, up, down, up-left, up-right, down-left, down-right.
* @return the Poly.Type to use for this Position.
*/
public Poly.Type getPolyType() {
return pt;
}
/**
* Return Position moved in specified direction.
* @param dx if positive move right, if negative move left.
* @param dy if positive move up, if negative move down.
* @return the moved position.
*/
public Position align(int dx, int dy) {
Position p = this;
if (dx > 0) {
if (p == CENT || p == RIGHT || p == LEFT) {
p = RIGHT;
} else if (p == UP || p == UPRIGHT || p == UPLEFT) {
p = UPRIGHT;
} else if (p == DOWN || p == DOWNRIGHT || p == DOWNLEFT) {
p = DOWNRIGHT;
}
} else if (dx < 0) {
if (p == CENT || p == RIGHT || p == LEFT) {
p = LEFT;
} else if (p == UP || p == UPRIGHT || p == UPLEFT) {
p = UPLEFT;
} else if (p == DOWN || p == DOWNRIGHT || p == DOWNLEFT) {
p = DOWNLEFT;
}
}
if (dy > 0) {
if (p == CENT || p == UP || p == DOWN) {
p = UP;
} else if (p == RIGHT || p == UPRIGHT || p == DOWNRIGHT) {
p = UPRIGHT;
} else if (p == LEFT || p == UPLEFT || p == DOWNLEFT) {
p = UPLEFT;
}
} else if (dy < 0) {
if (p == CENT || p == UP || p == DOWN) {
p = DOWN;
} else if (p == RIGHT || p == UPRIGHT || p == DOWNRIGHT) {
p = DOWNRIGHT;
} else if (p == LEFT || p == UPLEFT || p == DOWNLEFT) {
p = DOWNLEFT;
}
}
return p;
}
/**
* Method to return the Position to use for the given Poly.Type.
* The Poly.Type will vary through the 9 "anchor point" locations:
* center, left, right, up, down, up-left, up-right, down-left, down-right.
* @return the Position to use for the given Poly.Type.
*/
public static Position getPosition(Poly.Type type) {
for (Position pos : positions) {
if (type == pos.pt) {
return pos;
}
}
return CENT;
}
/**
* Method to return the number Positions.
* @return the number of Positions.
*/
public static int getNumPositions() {
return positions.size();
}
/**
* Method to return the Position at a given index.
* @param index the Position number desired.
* @return the Position at a given index.
*/
public static Position getPositionAt(int index) {
return positions.get(index);
}
/**
* Get an iterator over all Positions
*/
public static Iterator<Position> getPositions() {
return Collections.unmodifiableList(positions).iterator();
}
/**
* Returns a printable version of this Position.
* @return a printable version of this Position.
*/
public String toString() {
return name;
}
/**
* Describes text centered at a point.
*/
public static final Position CENT = new Position("centered", VTPOSCENT, Poly.Type.TEXTCENT);
/**
* Describes text centered above a point.
*/
public static final Position UP = new Position("bottom", VTPOSUP, Poly.Type.TEXTBOT);
/**
* Describes text centered below a point.
*/
public static final Position DOWN = new Position("top", VTPOSDOWN, Poly.Type.TEXTTOP);
/**
* Describes text centered to left of a point.
*/
public static final Position LEFT = new Position("right", VTPOSLEFT, Poly.Type.TEXTRIGHT);
/**
* Describes text centered to right of a point.
*/
public static final Position RIGHT = new Position("left", VTPOSRIGHT, Poly.Type.TEXTLEFT);
/**
* Describes text centered to upper-left of a point.
*/
public static final Position UPLEFT = new Position("lower-right", VTPOSUPLEFT, Poly.Type.TEXTBOTRIGHT);
/**
* Describes text centered to upper-right of a point.
*/
public static final Position UPRIGHT = new Position("lower-left", VTPOSUPRIGHT, Poly.Type.TEXTBOTLEFT);
/**
* Describes text centered to lower-left of a point.
*/
public static final Position DOWNLEFT = new Position("upper-right", VTPOSDOWNLEFT, Poly.Type.TEXTTOPRIGHT);
/**
* Describes text centered to lower-right of a point.
*/
public static final Position DOWNRIGHT = new Position("upper-left", VTPOSDOWNRIGHT, Poly.Type.TEXTTOPLEFT);
/**
* Describes text centered and limited to the object size.
* This means that the text may shrink in size or clip letters if necessary.
*/
public static final Position BOXED = new Position("boxed", VTPOSBOXED, Poly.Type.TEXTBOX);
}
/**
* DispPos is a typesafe enum class that describes text's display position on a Variable.
*/
public static class DispPos {
private final String name;
private final int index;
private static final List<DispPos> positions = new ArrayList<DispPos>();
private DispPos(String name, int index) {
this.name = name;
this.index = index;
positions.add(this);
}
/**
* Method to return the integer equivalent of this DispPos.
* @return the integer equivalent of this DispPos.
*/
public int getIndex() {
return index;
}
/**
* Method to return the name of this DispPos.
* It is used in popup menus.
* @return the name of this DispPos.
*/
public String getName() {
return name;
}
/**
* Method to return the number DispPos.
* @return the number DispPos.
*/
public static int getNumShowStyles() {
return positions.size();
}
/**
* Method to return the DispPos at a given index.
* @param index the DispPos number desired.
* @return the DispPos at a given index.
*/
public static DispPos getShowStylesAt(int index) {
for (DispPos d : positions) {
if (d.index == index) {
return d;
}
}
return NAMEVALUE;
}
/**
* Get an iterator over all show styles.
* @return an iterator over the list of show styles
*/
public static Iterator<DispPos> getShowStyles() {
return Collections.unmodifiableList(positions).iterator();
}
/**
* Returns a printable version of this DispPos.
* @return a printable version of this DispPos.
*/
public String toString() {
return name;
}
/**
* Describes a Variable that displays its value.
*/
public static final DispPos VALUE = new DispPos("value", VTDISPLAYVALUE);
/**
* Describes a Variable that displays its name, value, 1-level inherit.
* The form of the display is "ATTR=VALUE;def=DEFAULT";
*/
//public static final DispPos NAMEVALINH = new DispPos("name=inherit;def=value", VTDISPLAYNAMEVALINH);
/**
* Describes a Variable that displays its name and value.
* The form of the display is "ATTR=VALUE";
*/
public static final DispPos NAMEVALUE = new DispPos("name=value", VTDISPLAYNAMEVALUE);
/**
* Describes a Variable that displays its name, value, any inherit.
* The form of the display is "ATTR=VALUE;def=DEFAULT";
*/
//public static final DispPos NAMEVALINHALL = new DispPos("name=inheritAll;def=value", VTDISPLAYNAMEVALINHALL);
}
/**
* Size is a class that describes text's size on a Variable.
* Text size can be absolute (in points) or relative (in quarter grid units).
*/
public static class Size {
/** The minimu size of text (in points). */
public static final int TXTMINPOINTS = 1;
/** The maximum size of text (in points). */
public static final int TXTMAXPOINTS = 63;
/** The minimu size of text (in grid units). */
public static final double TXTMINQGRID = 0.25;
/** The maximum size of text (in grid units). */
public static final double TXTMAXQGRID = 127.75;
/** Default font size. */
private static final int DEFAULT_FONT_SIZE = 14;
/*private*/ static final int TXTQGRIDSH = 6;
private final boolean absolute;
private final double size;
private final int bits;
private Size(double size, boolean absolute) {
this.size = size;
this.absolute = absolute;
if (absolute) {
this.bits = (int) size;
} else {
this.bits = ((int) (size * 4.0)) << TXTQGRIDSH;
}
}
/**
* Method to return bits associated with this text Size.
* @return bits associated with this text Size.
*/
/*private*/ int getBits() {
return bits;
}
/**
* Method to return a Size object that describes a relative text size (in grid units).
* The size must be between 1 and 63 points.
* @param size the size in units.
* Returns null if the size is invalid.
*/
public static Size newAbsSize(int size) {
if (size < TXTMINPOINTS || size > TXTMAXPOINTS) {
return null;
}
return new Size(size, true);
}
/**
* Method to return a Size object that describes an absolute point text size.
* The size must be between 0.25 and 127.75 grid units (in .25 increments).
* @param size the size in points.
* Returns null if the size is invalid.
*/
public static Size newRelSize(double size) {
if (size < TXTMINQGRID || size > TXTMAXQGRID) {
return null;
}
return new Size(size, false);
}
/**
* Method to return text Size value (in points or units).
* @return the text Size value (in points or units).
*/
public double getSize() {
return size;
}
/**
* Method to tell whether this text Size is absolute or relative.
* @return true if this text size is absolute
*/
public boolean isAbsolute() {
return absolute;
}
/**
* Method to tell whether this Size is the same as another.
* @return true if they are equal.
*/
public boolean equals(Object that) {
if (that instanceof Size) {
Size other = (Size) that;
return this.absolute == other.absolute && DBMath.doublesEqual(this.size, other.size);
}
return false;
}
/**
* Returns a printable version of this Size.
* @return a printable version of this Size.
*/
public String toString() {
return "Text Size";
}
}
/**
* Rotation is a typesafe enum class that describes text's rotation in a Variable.
*/
public static class Rotation {
private final int angle;
private final int index;
private final String name;
private static final List<Rotation> rotations = new ArrayList<Rotation>();
private Rotation(int angle, int index, String name) {
this.angle = angle;
this.index = index;
this.name = name;
rotations.add(index, this);
}
/**
* Method to return the integer equivalent of this DispPos.
* This is zero-based.
* @return the integer equivalent of this DispPos.
*/
public int getIndex() {
return index;
}
/**
* Method to return the description of this DispPos.
* It appears in popup menus.
* @return the description of this DispPos.
*/
public String getDescription() {
return name;
}
/**
* Get the angle of this rotation.
* @return the angle of this rotation.
*/
public int getAngle() {
return angle;
}
/**
* Get the Rotation for the given angle.
* @param angle the angle.
* @return a Rotation for the given angle, or null if non exists.
*/
public static Rotation getRotation(int angle) {
for (Rotation rot : rotations) {
if (rot.getAngle() == angle) {
return rot;
}
}
return null;
}
/**
* Method to return the number Rotations.
* @return the number Rotations.
*/
public static int getNumRotations() {
return rotations.size();
}
/**
* Method to return the Rotation at a given index.
* @param index the Rotation number desired.
* @return the Rotation at a given index.
*/
public static Rotation getRotationAt(int index) {
return rotations.get(index);
}
/**
* Get an iterator over all rotations
* @return an iterator over all rotations
*/
public static Iterator<Rotation> getRotations() {
return Collections.unmodifiableList(rotations).iterator();
}
/**
* Returns a printable version of this Rotation.
* @return a printable version of this Rotation.
*/
public String toString() {
return "Text Rotation " + angle;
}
/** Describes a Rotation of 0 degrees. */
public static final Rotation ROT0 =
new Rotation(0, 0, "None");
/** Describes a Rotation of 90 degrees. */
public static final Rotation ROT90 =
new Rotation(90, 1, "90 degrees counterclockwise");
/** Describes a Rotation of 180 degrees. */
public static final Rotation ROT180 =
new Rotation(180, 2, "180 degrees");
/** Describes a Rotation of 270 degrees. */
public static final Rotation ROT270 =
new Rotation(270, 3, "90 degrees clockwise");
}
/**
* Unit is a typesafe enum class that describes text's units on a Variable.
*/
public static class Unit {
private final String description, name, postfixChar;
private final int index;
private static final List<Unit> units = new ArrayList<Unit>();
private Unit(String description, int index, String name, String postfixChar) {
this.description = description;
this.index = index;
this.name = name;
this.postfixChar = postfixChar;
units.add(index, this);
}
/**
* Method to return the integer equivalent of this Unit.
* This is zero-based.
* @return the integer equivalent of this Unit.
*/
public int getIndex() {
return index;
}
/**
* Method to return the description of this Unit.
* It appears in popup menus.
* For example, the name of the Time unit is "time".
* @return the description of this Unit.
*/
public String getDescription() {
return description;
}
/**
* Method to return the name of this Unit.
* For example, the name of the Time unit is "Second".
* @return the description of this Unit.
*/
public String getName() {
return name;
}
/**
* Method to return the characters to add to the end of this Unit.
* For example, distance uses "m" for meters.
* @return the characters to add to the end of this Unit.
*/
public String getPostfixChar() {
return postfixChar;
}
/**
* Method to return the number Units.
* @return the number Units.
*/
public static int getNumUnits() {
return units.size();
}
/**
* Method to return the Unit at a given index.
* @param index the Unit number desired.
* @return the Unit at a given index.
*/
public static Unit getUnitAt(int index) {
return units.get(index);
}
/**
* Get an iterator over all units.
* @return an iterator over the list of unit types.
*/
public static Iterator<Unit> getUnits() {
return Collections.unmodifiableList(units).iterator();
}
/**
* Returns a printable version of this Unit.
* @return a printable version of this Unit.
*/
public String toString() {
return name;
}
/** Describes no units. */
public static final Unit NONE = new Unit("none", VTUNITSNONE, "", "");
/** Describes resistance units. */
public static final Unit RESISTANCE = new Unit("resistance", VTUNITSRES, "Ohm", "o");
/** Describes capacitance units. */
public static final Unit CAPACITANCE = new Unit("capacitance", VTUNITSCAP, "Farad", "f");
/** Describes inductance units. */
public static final Unit INDUCTANCE = new Unit("inductance", VTUNITSIND, "Henry", "h");
/** Describes current units. */
public static final Unit CURRENT = new Unit("current", VTUNITSCUR, "Ampere", "a");
/** Describes voltage units. */
public static final Unit VOLTAGE = new Unit("voltage", VTUNITSVOLT, "Volt", "v");
/** Describes distance units. */
public static final Unit DISTANCE = new Unit("distance", VTUNITSDIST, "Meter", "m");
/** Describes time units. */
public static final Unit TIME = new Unit("time", VTUNITSTIME, "Second", "s");
}
/**
* ActiveFont is a class that describes fonts currently in use.
*/
public static class ActiveFont {
private String fontName;
private int index;
private static int indexCount = 0;
private static final Map<String, ActiveFont> fontMap = new HashMap<String, ActiveFont>();
private static final List<ActiveFont> fontList = new ArrayList<ActiveFont>();
private ActiveFont(String fontName) {
indexCount++;
this.index = indexCount;
this.fontName = fontName;
fontMap.put(fontName, this);
fontList.add(this);
}
/**
* Method to return the maximum index value for ActiveFonts.
* @return the maximum index value.
* ActiveFonts will have indices ranging from 1 to this value.
*/
public static int getMaxIndex() {
return indexCount;
}
/**
* Method to return the index for this ActiveFont.
* @return the index of this ActiveFont.
* The index value is 1-based, because font 0 is the "default font".
*/
public int getIndex() {
return index;
}
/**
* Method to return the font name associated with this ActiveFont.
* @return the font name associated with this ActiveFont.
*/
public String getName() {
return fontName;
}
/**
* Method to return the ActiveFont with a given name.
* @param fontName the name of the font.
* @return an ActiveFont object. If there is no ActiveFont
* associated with this fontname, one is created.
*/
public static ActiveFont findActiveFont(String fontName) {
ActiveFont af = fontMap.get(fontName);
if (af != null) {
return af;
}
if (indexCount >= VTMAXFACE) {
System.out.println("Too many fonts. Using default instead of " + fontName);
return null;
}
return new ActiveFont(fontName);
}
/**
* Method to return the ActiveFont with a given index.
* @param index the index number (1-based) of the ActiveFont.
* @return the ActiveFont with this index. Returns null if there is none.
*/
public static ActiveFont findActiveFont(int index) {
if (index <= 0) {
return null;
}
if (index > fontList.size()) {
return null;
}
ActiveFont af = fontList.get(index - 1);
return af;
}
/**
* Returns a printable version of this ActiveFont.
* @return a printable version of this ActiveFont.
*/
public String toString() {
return fontName;
}
}
AbstractTextDescriptor() {
}
public enum TextType {
/**
* Text that resides on nodes.
* This text includes the node name and any parameters or attributes on it.
*/
NODE("Node", 4),
/**
* Text that resides on arcs.
* This text includes the arc name and any parameters or attributes on it.
*/
ARC("Arc", 4),
/**
* Text that resides on ports.
* This text includes the port name and any parameters or attributes on it.
*/
PORT("Port", 4),
/**
* Text that resides on exports.
* This text includes the export name and any parameters or attributes on it.
*/
EXPORT("Export", 8),
/**
* Annotation text.
* Annotation text is not attached to any node or arc, but appears to move freely about the cell.
* In implementation, they are displayable Variables on Generic:invisible-pin nodes.
*/
ANNOTATION("Annotation", 4),
/**
* The name of on cell instances.
* The default is "true".
* @return true if the system should draw the name of on cell instances.
*/
INSTANCE("Instance", 16),
/**
* Text that resides on the cell.
* This includes the current cell's parameters or attributes (for example, spice templates).
*/
CELL("Cell", 4);
private final String purpose;
private final TextDescriptor factoryTextDescriptor;
public String getKey(String prefix) {
return prefix + purpose;
}
public TextDescriptor getFactoryTextDescriptor() {
return factoryTextDescriptor;
}
private TextType(String purpose, int initialSize) {
this.purpose = purpose;
MutableTextDescriptor mtd = new MutableTextDescriptor();
mtd.setRelSize(initialSize * 0.25);
mtd.setDisplay(true);
factoryTextDescriptor = TextDescriptor.newTextDescriptor(mtd);
}
}
/**
* Returns a hash code for this <code>TextDescriptor</code>.
* @return a hash code value for this TextDescriptor.
*/
@Override
public int hashCode() {
return lowLevelGet0() ^ lowLevelGet1() ^ getColorIndex() ^ getDisplay().hashCode();
}
/**
* Compares this text descriptor to the specified object.
* The result is <code>true</code> if and only if the argument is not
* <code>null</code> and is a <code>TextDescriptor</code> object with
* the same fields.
*
* @param anObject the object to compare this <code>TextDescriptor</code>
* against.
* @return <code>true</code> if the <code>TextDescriptor</code> are equal;
* <code>false</code> otherwise.
*/
@Override
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof AbstractTextDescriptor) {
AbstractTextDescriptor td = (AbstractTextDescriptor) anObject;
return lowLevelGet() == td.lowLevelGet() && getColorIndex() == td.getColorIndex()
&& getDisplay() == td.getDisplay();
}
return false;
}
/**
* Low-level method to get the bits in the TextDescriptor.
* These bits are a collection of flags that are more sensibly accessed
* through special methods.
* This general access to the bits is required because the ELIB
* file format stores it as a full integer.
* This should not normally be called by any other part of the system.
* @return the bits in the TextDescriptor.
*/
public abstract long lowLevelGet();
/**
* Low-level method to get the first word of the bits in the TextDescriptor.
* These bits are a collection of flags that are more sensibly accessed
* through special methods.
* This general access to the bits is required because the ELIB
* file format stores it as a full integer.
* This should not normally be called by any other part of the system.
* @return the first word of the bits in the TextDescriptor.
*/
public int lowLevelGet0() {
return (int) lowLevelGet();
}
/**
* Low-level method to get the second word of the bits in the TextDescriptor.
* These bits are a collection of flags that are more sensibly accessed
* through special methods.
* This general access to the bits is required because the ELIB
* file format stores it as a full integer.
* This should not normally be called by any other part of the system.
* @return the second word of the bits in the TextDescriptor.
*/
public int lowLevelGet1() {
return (int) (lowLevelGet() >> 32);
}
private int getField(long mask, int shift) {
return (int) ((lowLevelGet() & mask) >> shift);
}
private boolean isFlag(long mask) {
return (lowLevelGet() & mask) != 0;
}
/**
* Method to return mode how this TextDescriptor is displayable.
* @return Display mode how this TextDescriptor is displayable.
*/
public abstract Display getDisplay();
/**
* Method to return true if this TextDescriptor is displayable.
* @return true if this TextDescriptor is displayable.
*/
public boolean isDisplay() {
return getDisplay() == Display.SHOWN;
}
/**
* Method to return the text position of the TextDescriptor.
* The text position describes the "anchor point" of the text,
* which is the point on the text that is attached to the object and does not move.
* @return the text position of the TextDescriptor.
*/
public Position getPos() {
int pos = getField(VTPOSITION, VTPOSITIONSH);
if (pos >= Position.getNumPositions()) {
pos = 0;
}
return Position.getPositionAt(pos);
}
/**
* Returns true if this ImmutableTextDescriptor describes absolute text.
* Text may be either absolute text (in points) or relative text (in quarter units).
* @return true if this ImmutableTextDescriptor describes absolute text.
*/
public boolean isAbsoluteSize() {
int textSize = getField(VTSIZE, VTSIZESH);
return textSize > 0 && textSize <= Size.TXTMAXPOINTS;
}
/**
* Method to return the text size of the text in this TextDescriptor.
* This is a Size object that can describe either absolute text (in points)
* or relative text (in quarter units).
* @return the text size of the text in this TextDescriptor.
*/
public Size getSize() {
int textSize = getField(VTSIZE, VTSIZESH);
if (textSize == 0) {
return Size.newRelSize(1);
}
if (textSize <= Size.TXTMAXPOINTS) {
return Size.newAbsSize(textSize);
}
int sizeValue = textSize >> Size.TXTQGRIDSH;
double size = sizeValue * 0.25;
return Size.newRelSize(size);
}
public static int getDefaultFontSize() {
return Size.DEFAULT_FONT_SIZE;
}
/**
* Method to find the true size in points for this TextDescriptor in a given EditWindow0.
* If the TextDescriptor is already Absolute (in points) nothing needs to be done.
* Otherwise, the scale of the EditWindow0 is used to determine the acutal point size.
* @param wnd the EditWindow0 in which drawing will occur.
* @return the point size of the text described by this TextDescriptor.
*/
public double getTrueSize(EditWindow0 wnd) {
if (wnd != null) {
return getTrueSize(wnd.getScale(), wnd);
}
int textSize = getField(VTSIZE, VTSIZESH);
double trueSize = textSize > 0 && textSize <= Size.TXTMAXPOINTS ? textSize : Size.DEFAULT_FONT_SIZE;
return trueSize * User.getGlobalTextScale();
}
/**
* Method to find the true size in points for this TextDescriptor in a given scale.
* If the TextDescriptor is already Absolute (in points) nothing needs to be done.
* Otherwise, the scale is used to determine the acutal point size.
* @param scale scale to draw.
* @param wnd the EditWindow0 in which drawing will occur.
* @return the point size of the text described by this TextDescriptor.
*/
public double getTrueSize(double scale, EditWindow0 wnd) {
double trueSize;
int textSize = getField(VTSIZE, VTSIZESH);
if (textSize == 0) {
// relative 1
trueSize = scale;
} else if (textSize <= Size.TXTMAXPOINTS) {
// absolute
trueSize = textSize;
} else {
// relative
trueSize = (textSize >> Size.TXTQGRIDSH) * 0.25 * scale;
}
return trueSize * (wnd == null ? User.getGlobalTextScale() : wnd.getGlobalTextScale());
}
/**
* Method to return the text font of the TextDescriptor.
* @return the text font of the TextDescriptor.
*/
public int getFace() {
return getField(VTFACE, VTFACESH);
}
/**
* Method to get a Font to use for this TextDescriptor in a given EditWindow.
* @param wnd the EditWindow0 in which drawing will occur.
* @param minimalTextSize Return null for texts smaller than this
* @return the Font to use (returns null if the text is too small to display).
*/
public Font getFont(EditWindow0 wnd, int minimalTextSize) {
int fontStyle = Font.PLAIN;
String fontName = wnd == null ? User.getDefaultFont() : wnd.getDefaultFont();
int size = (int) getTrueSize(wnd);
if (size <= 0) {
size = 1;
}
if (size < minimalTextSize) {
return null;
}
if (isItalic()) {
fontStyle |= Font.ITALIC;
}
if (isBold()) {
fontStyle |= Font.BOLD;
}
int fontIndex = getFace();
if (fontIndex != 0) {
TextDescriptor.ActiveFont af = TextDescriptor.ActiveFont.findActiveFont(fontIndex);
if (af != null) {
fontName = af.getName();
}
}
Font font = new Font(fontName, fontStyle, size);
return font;
}
/**
* Method to get a default Font to use.
* @param wnd the EditWindow0 to use with font information (may be null).
* @return the Font to use (returns null if the text is too small to display).
*/
public static Font getDefaultFont(EditWindow0 wnd) {
String fontName = wnd == null ? User.getDefaultFont() : wnd.getDefaultFont();
return new Font(fontName, Font.PLAIN, TextDescriptor.getDefaultFontSize());
}
/**
* Method to convert a string and descriptor to a GlyphVector.
* @param text the string to convert.
* @param font the Font to use.
* @return a GlyphVector describing the text.
*/
public static GlyphVector getGlyphs(String text, Font font) {
// make a glyph vector for the desired text
FontRenderContext frc = new FontRenderContext(null, false, false);
GlyphVector gv = font.createGlyphVector(frc, text);
return gv;
}
/**
* Method to return the text rotation of the TextDescriptor.
* There are only 4 rotations: 0, 90 degrees, 180 degrees, and 270 degrees.
* @return the text rotation of the TextDescriptor.
*/
public Rotation getRotation() {
return Rotation.getRotationAt(getField(VTROTATION, VTROTATIONSH));
}
/**
* Method to return the text display part of the TextDescriptor.
* @return the text display part of the TextDescriptor.
*/
public DispPos getDispPart() {
return DispPos.getShowStylesAt(getField(VTDISPLAYPART, VTDISPLAYPARTSH));
}
/**
* Method to return true if the text in the TextDescriptor is italic.
* @return true if the text in the TextDescriptor is italic.
*/
public boolean isItalic() {
return isFlag(VTITALIC);
}
/**
* Method to return true if the text in the TextDescriptor is bold.
* @return true if the text in the TextDescriptor is bold.
*/
public boolean isBold() {
return isFlag(VTBOLD);
}
/**
* Method to return true if the text in the TextDescriptor is underlined.
* @return true if the text in the TextDescriptor is underlined.
*/
public boolean isUnderline() {
return isFlag(VTUNDERLINE);
}
/**
* Method to return true if the text in the TextDescriptor is interior.
* Interior text is not seen at higher levels of the hierarchy.
* @return true if the text in the TextDescriptor is interior.
*/
public boolean isInterior() {
return isFlag(VTINTERIOR);
}
/**
* Method to return true if the text in the TextDescriptor is inheritable.
* Inheritable variables copy their contents from prototype to instance.
* Only Variables on NodeProto and PortProto objects can be inheritable.
* When a NodeInst is created, any inheritable Variables on its NodeProto are automatically
* created on that NodeInst.
* @return true if the text in the TextDescriptor is inheritable.
*/
public boolean isInherit() {
return isFlag(VTINHERIT);
}
/**
* Method to return true if the text in the TextDescriptor is a parameter.
* Parameters are those Variables that have values on instances which are
* passed down the hierarchy into the contents.
* Parameters can only exist on NodeInst objects.
* @return true if the text in the TextDescriptor is a parameter.
*/
public boolean isParam() {
return isFlag(VTISPARAMETER);
}
/**
* Method to return the X offset of the text in the TextDescriptor.
* @return the X offset of the text in the TextDescriptor.
*/
public double getXOff() {
int offset = getField(VTXOFF, VTXOFFSH);
if (isFlag(VTXOFFNEG)) {
offset = -offset;
}
int scale = getOffScale() + 1;
return ((double) offset * scale / 4);
}
/**
* Method to return the Y offset of the text in the TextDescriptor.
* @return the Y offset of the text in the TextDescriptor.
*/
public double getYOff() {
int offset = getField(VTYOFF, VTYOFFSH);
if (isFlag(VTYOFFNEG)) {
offset = -offset;
}
int scale = getOffScale() + 1;
return ((double) offset * scale / 4);
}
/** Method to return the offset scale of the text in the text descriptor. */
private int getOffScale() {
return getField(VTOFFSCALE, VTOFFSCALESH);
}
/**
* Method to return the Unit of the TextDescriptor.
* Unit describes the type of real-world unit to apply to the value.
* For example, if this value is in volts, the Unit tells whether the value
* is volts, millivolts, microvolts, etc.
* @return the Unit of the TextDescriptor.
*/
public Unit getUnit() {
return Unit.getUnitAt(getField(VTUNITS, VTUNITSSH) & VTUNITSHMASK);
}
/**
* Method to return the color index of the TextDescriptor.
* Color indices are more general than colors, because they can handle
* transparent layers, C-Electric-style opaque layers, and full color values.
* Methods in "EGraphics" manipulate color indices.
* @return the color index of the TextDescriptor.
*/
public abstract int getColorIndex();
}