/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ImmutableTextDescriptor.java
*
* Copyright (c) 2003 Sun Microsystems and Static Free Software
*
* 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.EditingPreferences;
import java.util.HashMap;
/**
* This class describes how variable text appears.
* <P>
* This class should be thread-safe
*/
public class TextDescriptor extends AbstractTextDescriptor {
/** the text descriptor is displayable */
private final Display display;
/** the bits of the text descriptor */
private final long bits;
/** the color of the text descriptor */
private final int colorIndex;
/** cache of all TextDescriptors */
private static final HashMap<TextDescriptor, TextDescriptor> allDescriptors = new HashMap<TextDescriptor, TextDescriptor>();
/** empty text descriptor. Size is relative 1.0. isDisplay is true. */
public static final TextDescriptor EMPTY = newTextDescriptor(new MutableTextDescriptor());
/**
* The constructor creates canonized copy of anotherTextDescriptor.
* @param descriptor another descriptor.
*/
private TextDescriptor(AbstractTextDescriptor descriptor) {
Display display = descriptor.getDisplay();
long bits = descriptor.lowLevelGet();
// Convert invalid VTPOSITION to default VTPOSCENT
if (((bits & VTPOSITION) >> VTPOSITIONSH) > VTPOSBOXED) {
bits = (bits & ~VTPOSITION) | (VTPOSCENT << VTPOSITIONSH);
}
// Convert VTDISPLAYNAMEVALINH and VTDISPLAYNAMEVALINHALL to VTDISPLAYNAMEVALUE
if ((bits & VTDISPLAYPART) != 0) {
bits = (bits & ~VTDISPLAYPART) | (VTDISPLAYNAMEVALUE << VTDISPLAYPARTSH);
}
// Convert zero VTSIZE to RelSize(1)
if ((bits & VTSIZE) == 0) {
bits |= (4L << Size.TXTQGRIDSH) << VTSIZESH;
}
// clear unused bits if non-displayable
if (display == Display.NONE) {
bits &= VTSEMANTIC;
}
// clear signs of zero-offsets
boolean zeroXOff = (bits & VTXOFF) == 0;
boolean zeroYOff = (bits & VTYOFF) == 0;
if (zeroXOff) {
bits &= ~VTXOFFNEG;
}
if (zeroYOff) {
bits &= ~VTYOFFNEG;
}
if (zeroXOff && zeroYOff) {
bits &= ~VTOFFSCALE;
}
this.display = display;
this.bits = bits;
this.colorIndex = display != Display.NONE ? descriptor.getColorIndex() : 0;
}
private Object readResolve() {
return getUniqueTextDescriptor(this);
}
public static TextDescriptor newTextDescriptor(AbstractTextDescriptor td) {
if (td instanceof TextDescriptor) {
return (TextDescriptor) td;
}
return getUniqueTextDescriptor(td);
}
private static TextDescriptor getUniqueTextDescriptor(AbstractTextDescriptor td) {
TextDescriptor cacheTd = allDescriptors.get(td);
if (cacheTd != null) {
return cacheTd;
}
TextDescriptor itd = new TextDescriptor(td);
if (!itd.equals(td)) {
// is canonized text descriptor already here ?
cacheTd = allDescriptors.get(itd);
if (cacheTd != null) {
return cacheTd;
}
}
allDescriptors.put(itd, itd);
return itd;
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by displayable flag.
* Displayable Variables are shown with the object.
* @param state true, if new TextDescriptor is displayable.
* @return TextDescriptor which differs from this TextDescriptor by displayable flag.
*/
public TextDescriptor withDisplay(boolean state) {
if (isDisplay() == state) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setDisplay(state ? Display.SHOWN : Display.NONE);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by displayable mode.
* Displayable Variables are shown with the object.
* @param display new displayable mode.
* @return TextDescriptor which differs from this TextDescriptor by displayable mode.
*/
public TextDescriptor withDisplay(Display display) {
if (getDisplay() == display) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setDisplay(display);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by position.
* 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.
* @param p the text position of new TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by position.
* @throws NullPointerException if p is null.
*/
public TextDescriptor withPos(Position p) {
if (p == null) {
throw new NullPointerException();
}
if (getPos() == p) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setPos(p);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by text size.
* New size is absolute size (in points).
* The size must be between 1 and 63 points.
* @param s the point size of new TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by text size.
*/
public TextDescriptor withAbsSize(int s) {
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setAbsSize(s);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by text size.
* New size is a relative size (in units).
* The size must be between 0.25 and 127.75 grid units (in .25 increments).
* @param s the unit size of new TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by text size.
*/
public TextDescriptor withRelSize(double s) {
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setRelSize(s);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by text font.
* @param f the text font of new TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by text font.
*/
public TextDescriptor withFace(int f) {
if (getFace() == f) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setFace(f);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by rotation.
* There are only 4 rotations: 0, 90 degrees, 180 degrees, and 270 degrees.
* @param r the text rotation of new TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by rotation.
*/
public TextDescriptor withRotation(Rotation r) {
if (r == null) {
r = Rotation.ROT0;
}
if (getRotation() == r) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setRotation(r);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by dislay part.
* @param dispPos the text display part of new TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by dislay part.
* @throws NullPointerException if dispPos is null
*/
public TextDescriptor withDispPart(DispPos dispPos) {
if (dispPos == null) {
throw new NullPointerException();
}
if (getDispPart() == dispPos) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setDispPart(dispPos);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by italic flag.
* @param state true if text of new TextDescriptor is italic.
* @return TextDescriptor which differs from this TextDescriptor by italic flag.
*/
public TextDescriptor withItalic(boolean state) {
if (isItalic() == state) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setItalic(state);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by bold flag.
* @param state true if text of new TextDescriptor is bold.
* @return TextDescriptor which differs from this TextDescriptor by bold flag.
*/
public TextDescriptor withBold(boolean state) {
if (isBold() == state) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setBold(state);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by underline flag.
* @param state true if text of new TextDescriptor is underlined.
* @return TextDescriptor which differs from this TextDescriptor by underline flag.
*/
public TextDescriptor withUnderline(boolean state) {
if (isUnderline() == state) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setUnderline(state);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by interior flag.
* Interior text is not seen at higher levels of the hierarchy.
* @param state true if text with new TextDescriptor is interior.
* @return TextDescriptor which differs from this TextDescriptor by interior flag.
*/
public TextDescriptor withInterior(boolean state) {
if (isInterior() == state) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setInterior(state);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by inheritable flag.
* 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.
* @param state true if Variable with new TextDescriptor is inheritable.
* @return TextDescriptor which differs from this TextDescriptor by inheritable flag.
*/
public TextDescriptor withInherit(boolean state) {
if (isInherit() == state) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setInherit(state);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which deffers from this TextDescriptor by parameter flag.
* Parameters are those Variables that have values on instances which are
* passed down the hierarchy into the contents.
* Parameters can only exist on Cell objects.
* @param state true if Variable with new TextDescriptor is parameter.
* @return TextDescriptor which deffers from this TextDescriptor by parameter flag.
*/
public TextDescriptor withParam(boolean state) {
if (isParam() == state) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setParam(state);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by
* X and Y offsets of the text in the Variable's TextDescriptor.
* The values are scaled by 4, so a value of 3 indicates a shift of 0.75 and a value of 4 shifts by 1.
* @param xd the X offset of the text in new Variable's TextDescriptor.
* @param yd the Y offset of the text in new Variable's TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by
* X and Y offsets of the text in the Variable's TextDescriptor.
*/
public TextDescriptor withOff(double xd, double yd) {
if (getXOff() == xd && getYOff() == yd) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setOff(xd, yd);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by unit.
* Unit describe 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.
* @param u the Unit of new TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by unit.
*/
public TextDescriptor withUnit(Unit u) {
if (u == null) {
u = Unit.NONE;
}
if (getUnit() == u) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setUnit(u);
return newTextDescriptor(td);
}
/**
* Returns TextDescriptor which differs from this TextDescriptor by colorIndex.
* 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.
* @param colorIndex color index of new TextDescriptor.
* @return TextDescriptor which differs from this TextDescriptor by colorIndex.
*/
public TextDescriptor withColorIndex(int colorIndex) {
if (getColorIndex() == colorIndex) {
return this;
}
MutableTextDescriptor td = new MutableTextDescriptor(this);
td.setColorIndex(colorIndex);
return newTextDescriptor(td);
}
public TextDescriptor withDisplayWithoutParam() {
if (isDisplay() && !isParam()) {
return this;
}
MutableTextDescriptor mtd = new MutableTextDescriptor(this);
mtd.setDisplay(Display.SHOWN);
mtd.setParam(false);
return newTextDescriptor(mtd);
}
public static int cacheSize() {
return allDescriptors.size();
}
/**
* Method to return mode how this TextDescriptor is displayable.
* @return Display mode how this TextDescriptor is displayable.
*/
@Override
public Display getDisplay() {
return display;
}
/**
* 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.
*/
@Override
public long lowLevelGet() {
return bits;
}
/**
* 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.
*/
@Override
public int getColorIndex() {
return colorIndex;
}
/**
* Method to return a displayable TextDescriptor that is a default for Variables on NodeInsts.
* @return a new TextDescriptor that can be stored in a Variable on a NodeInsts.
*/
public static TextDescriptor getNodeTextDescriptor() {
return EditingPreferences.getThreadEditingPreferences().getTextDescriptor(TextDescriptor.TextType.NODE, true);
}
/**
* Method to return a displayable TextDescriptor that is a default for Variables on ArcInsts.
* @return a new TextDescriptor that can be stored in a Variable on a ArcInsts.
*/
public static TextDescriptor getArcTextDescriptor() {
return EditingPreferences.getThreadEditingPreferences().getTextDescriptor(TextDescriptor.TextType.ARC, true);
}
/**
* Method to return a displayable TextDescriptor that is a default for Variables on Exports.
* @return a new TextDescriptor that can be stored in a Variable on a Exports.
*/
public static TextDescriptor getExportTextDescriptor() {
return EditingPreferences.getThreadEditingPreferences().getTextDescriptor(TextDescriptor.TextType.EXPORT, true);
}
/**
* Method to return a displayable TextDescriptor that is a default for Variables on PortInsts.
* @return a new TextDescriptor that can be stored in a Variable on a PortInsts.
*/
public static TextDescriptor getPortInstTextDescriptor() {
return EditingPreferences.getThreadEditingPreferences().getTextDescriptor(TextDescriptor.TextType.PORT, true);
}
/**
* Method to return a displayable TextDescriptor that is a default for Variables on Annotations.
* @return a new TextDescriptor that can be stored in a Variable on a Annotations.
*/
public static TextDescriptor getAnnotationTextDescriptor() {
return EditingPreferences.getThreadEditingPreferences().getTextDescriptor(TextDescriptor.TextType.ANNOTATION, true);
}
/**
* Method to return a displayable TextDescriptor that is a default for Variables on Cell Instance Names.
* @return a new TextDescriptor that can be stored in a Variable on a Cell Instance Names.
*/
public static TextDescriptor getInstanceTextDescriptor() {
return EditingPreferences.getThreadEditingPreferences().getTextDescriptor(TextDescriptor.TextType.INSTANCE, true);
}
/**
* Method to return a displayable TextDescriptor that is a default for Variables on Cell Variables.
* @return a new TextDescriptor that can be stored in a Variable on a Cell Variables.
*/
public static TextDescriptor getCellTextDescriptor() {
return EditingPreferences.getThreadEditingPreferences().getTextDescriptor(TextDescriptor.TextType.CELL, true);
}
}