All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.electric.tool.user.Highlight Maven / Gradle / Ivy

/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: Highlight.java
 *
 * Copyright (c) 2006, 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.tool.user;

import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.geometry.PolyBase;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.network.Netlist;
import com.sun.electric.database.network.Network;
import com.sun.electric.database.network.NetworkTool;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.text.Name;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Connection;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.DisplayedText;
import com.sun.electric.database.variable.ElectricObject;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.technologies.Artwork;
import com.sun.electric.tool.user.redisplay.AbstractLayerDrawing;
import com.sun.electric.tool.user.redisplay.ERaster;
import com.sun.electric.tool.user.ui.EditWindow;
import com.sun.electric.tool.user.ui.Util;
import com.sun.electric.tool.user.ui.ToolBar;
import com.sun.electric.util.math.AbstractFixpPoint;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.FixpTransform;
import com.sun.electric.util.math.GenMath;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.LineMetrics;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.*;

/**
 * A Highlight (or subclass thereof) includes a reference to something
 * to which the user's attention is being called (an ElectricObject,
 * some text, a region, etc) and enough information to render the
 * highlighting (boldness, etc) on any given window.  It is not
 * specific to any given EditWindow.
 */
public abstract class Highlight implements Cloneable{

	/** for drawing solid lines */		public static final BasicStroke solidLine = new BasicStroke(0);
	/** for drawing dotted lines */		public static final BasicStroke dottedLine = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] {1}, 0);
	/** for drawing dashed lines */		public static final BasicStroke dashedLine = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, new float[] {10}, 0);
	/** for drawing dashed lines */		public static final BasicStroke boldLine = new BasicStroke(3);

	/** The Cell containing the selection. */	protected final Cell cell;
	/** The color used when drawing */			protected final Color color;
    /** The highlight is an error */		    public final boolean isError;
	private static final int CROSSSIZE = 3;

	Highlight(Cell c, Color color, boolean isError)
	{
		this.cell = c;
		this.color = color;
        this.isError = isError;
	}

	public Cell getCell() { return cell; }

	public boolean isValid()
	{
		if (cell != null)
			if (!cell.isLinked()) return false;
		return true;
	}

    public boolean showInRaster() {
        return false;
    }

    // creating so HighlightEOBJ is not a public class
    public boolean isHighlightEOBJ() { return false; }

    // creating so HighlightText is not a public class
    public boolean isHighlightText() { return false; }

    public Object getObject() { return null; }

    public Variable.Key getVarKey() { return null; }

    // point variable, only useful for HighlightEOBJ?
    public int getPoint() { return -1; }

    @Override
    public Object clone()
    {
        try {
			return super.clone();
		}
		catch (CloneNotSupportedException e) {
            e.printStackTrace();
		}
        return null;
    }

    /**
	 * Method to tell whether two Highlights are the same.
	 * @param obj the Highlight to compare to this one.
	 * @param exact true to ensure that even ports are the same.
	 * @return true if the two refer to the same thing.
	 */
    public boolean sameThing(Highlight obj, boolean exact)
    {
        return false;
    }

    /**
	 * Method to tell whether this Highlight is text that stays with its node.
	 * The two possibilities are (1) text on invisible pins
	 * (2) export names, when the option to move exports with their labels is requested.
	 * @return true if this Highlight is text that should move with its node.
	 */
    public boolean nodeMovesWithText()
	{
		return false;
	}

    /** the highlight pattern will repeat itself rotationally every PULSATE_ROTATE_PERIOD milliseconds */
    private static final int PULSATE_ROTATE_PERIOD = 1000;

    /** the length of the rotating pattern */
    private static final int PULSATE_STRIPE_LENGTH = 30;

    /** the number of "segments" in each stripe; increasing this number slows down rendering*/
    private static final int PULSATE_STRIPE_SEGMENTS = 10;

    /**
	 * Method to display this Highlight in a window.
	 * @param wnd the window in which to draw this highlight.
	 * @param g_ the Graphics associated with the window.
	 */
	public void showHighlight(EditWindow wnd, Graphics g_, int highOffX, int highOffY, boolean onlyHighlight,
                              Color mainColor, Stroke primaryStroke)
    {
        if (!isValid()) return;
		g_.setColor(mainColor);
        Graphics2D g2 = (Graphics2D)g_;
        g2.setStroke(primaryStroke);
        if (User.isErrorHighlightingPulsate() && isError) {
            long now = System.currentTimeMillis();
            for(int i=0; i list, boolean wantNodes, boolean wantArcs) {;}

    static void getHighlightedEObjsInternal(Geometric geom, List list, boolean wantNodes, boolean wantArcs)
    {
        if (geom == null) return;
        if (!wantNodes && geom instanceof NodeInst) return;
        if (!wantArcs && geom instanceof ArcInst) return;

        if (list.contains(geom)) return;
        list.add(geom);
    }

    /**
	 * Method to return the Geometric object that is in this Highlight.
	 * If the highlight is a PortInst, an Export, or annotation text, its base NodeInst is returned.
	 * @return the Geometric object that is in this Highlight.
	 * Returns null if this Highlight is not on a Geometric.
	 */
    public Geometric getGeometric() { return null; }

    /**
	 * Method to return a List of all highlighted NodeInsts.
	 * Return a list with the highlighted NodeInsts.
	 */
	void getHighlightedNodes(Highlighter highlighter, Set set) {;}

    static void getHighlightedNodesInternal(Geometric geom, Set set)
    {
        if (geom == null || !(geom instanceof NodeInst)) return;
        NodeInst ni = (NodeInst)geom;
        set.add(ni);
    }

    /**
	 * Method to return a List of all highlighted ArcInsts.
	 * Return a list with the highlighted ArcInsts.
	 */
    void getHighlightedArcs(Highlighter highlighter, Set set) {;}

    static void getHighlightedArcsInternal(Geometric geom, Set set)
    {
        if (geom == null || !(geom instanceof ArcInst)) return;
        ArcInst ai = (ArcInst)geom;

        set.add(ai);
    }

    /**
	 * Method to return a set of the currently selected networks.
	 * Return a set of the currently selected networks.
	 * If there are no selected networks, the list is empty.
	 */
    void getHighlightedNetworks(Set nets, Netlist netlist) {;}

    /**
	 * Method to return a List of all highlighted text.
     * @param list list to populate.
	 * @param unique true to request that the text objects be unique,
	 * and not attached to another object that is highlighted.
	 * For example, if a node and an export on that node are selected,
	 * the export text will not be included if "unique" is true.
	 * Return a list with the Highlight objects that point to text.
	 */
    void getHighlightedText(List list, boolean unique, List getHighlights) {;}

    /**
	 * Method to return the bounds of the highlighted objects.
	 * @param wnd the window in which to get bounds.
	 * @return the bounds of the highlighted objects (null if nothing is highlighted).
	 */
    Rectangle2D getHighlightedArea(EditWindow wnd) { return null; }

    /**
	 * Method to return the ElectricObject associated with this Highlight object.
	 * @return the ElectricObject associated with this Highlight object.
	 */
    public ElectricObject getElectricObject() { return null; }

    /**
	 * Method to tell whether a point is over this Highlight.
	 * @param wnd the window being examined.
	 * @param x the X screen coordinate of the point.
	 * @param y the Y screen coordinate of the point.
	 * @param change true to update the highlight; false to leave things alone.
	 * @return (possible updated) this Highlight if the point is over this Highlight, null otherwise
	 */
    Highlight overHighlighted(EditWindow wnd, int x, int y, Highlighter highlighter, boolean change) { return null; }

    public String getInfo() { return null;}

    /**
     * Method to load an array of counts with the number of highlighted objects in a list.
     * arc = 0, node = 1, export = 2, text = 3, graphics = 4
     * @param list the list of highlighted objects.
     * @param counts the array of counts to set.
     * @return a NodeInst, if it is in the list.
     */
    public static NodeInst getInfoCommand(List list, int[] counts)
    {
        // information about the selected items
        NodeInst theNode = null;
        for(Highlight h : list)
        {
            ElectricObject eobj = h.getElectricObject();
            if (h.isHighlightEOBJ())
            {
                if (eobj instanceof NodeInst || eobj instanceof PortInst)
                {
                    counts[1]++;
                    if (eobj instanceof NodeInst) theNode = (NodeInst)eobj; else
                        theNode = ((PortInst)eobj).getNodeInst();
                } else if (eobj instanceof ArcInst)
                {
                    counts[0]++;
                }
            } else if (h.isHighlightText())
            {
            	if (h.getVarKey() == Export.EXPORT_NAME) counts[2]++; else
            	{
            		if (h.getElectricObject() instanceof NodeInst)
            			theNode = (NodeInst)h.getElectricObject();
                    counts[3]++;
            	}
            } else if (h instanceof HighlightArea)
            {
                counts[4]++;
            } else if (h instanceof HighlightLine)
            {
                counts[4]++;
            }
        }
        return theNode;
    }

    /**
	 * Method to draw an array of points as highlighting.
	 * @param wnd the window in which drawing is happening.
     * @param g the Graphics for the window.
     * @param points the array of points being drawn.
     * @param offX the X offset of the drawing.
     * @param offY the Y offset of the drawing.
     * @param opened true if the points are drawn "opened".
     * @param thickLine
     */
	public static void drawOutlineFromPoints(EditWindow wnd, Graphics g, Point2D[] points, int offX, int offY,
                                             boolean opened, boolean thickLine)
	{
		boolean onePoint = true;
		if (points.length <= 0)
			return;
		Point firstP = wnd.databaseToScreen(points[0].getX(), points[0].getY());
		for(int i=1; i= 0) && (x1 <= size.getLambdaFullWidth())) || ((x2 >= 0) && (x2 <= size.getLambdaFullWidth())) ||
//            ((y1 >= 0) && (y1 <= size.getHeight())) || ((y2 >= 0) && (y2 <= size.getHeight()))) {
//                g.drawLine(x1, y1, x2, y2);
//        }
    }


    /**
     * General purpose function to sort Highlight objects based on their getInfo output
     */
    public static class HighlightSorting implements Comparator
    {
        @Override
        public int compare(Highlight h1, Highlight h2)
        {
        	String h1Info = h1.getInfo();
        	String h2Info = h2.getInfo();
        	if (h1Info == null) h1Info = "";
        	if (h2Info == null) h2Info = "";
            return h1Info.compareTo(h2Info);
        }
    }

    /**
     *  A Highlight which calls the user's attention to a Point2D and includes a text message.
     */
    public static class Message extends Highlight
    {
    	/** The highlighted message. */								protected final String msg;
        /** Location of the message highlight */                    protected final Point2D loc;
        /** Corner of text: 0=lowerLeft, 1=upperLeft, 2=upperRight, 3=lowerRight */ protected final int corner;
        private final Color backgroundColor;

        Message(Cell c, String m, Point2D p, int co, Color backgroundColor)
        {
            super(c, null, false);
            this.msg = m;
            this.loc = p;
            this.corner = co;
            this.backgroundColor = backgroundColor;
        }

        @Override
        void internalDescribe(StringBuffer desc)
        {
            desc.append(msg);
        }

        @Override
        public String getInfo() { return msg; }

        @Override
        public void showInternalHighlight(EditWindow wnd, Graphics g, int highOffX, int highOffY,
                                          boolean onlyHighlight)
        {
            Point location = wnd.databaseToScreen(loc.getX(), loc.getY());
            int width=0, height=0;
            if (corner != 0 || backgroundColor != null)
            {
            	// determine the size of the text
    			Font font = g.getFont();
    			FontRenderContext frc = new FontRenderContext(null, true, true);
    			GlyphVector gv = font.createGlyphVector(frc, msg);
    			LineMetrics lm = font.getLineMetrics(msg, frc);
    			Rectangle2D rasRect = gv.getLogicalBounds();
    			width = (int)rasRect.getWidth();
    			height = (int)(lm.getHeight()+0.5);
            }
        	switch (corner)
        	{
        		case 1:		// put upper-left corner of text at drawing coordinate
        			location.y += height;
        			break;
        		case 2:		// put upper-right corner of text at drawing coordinate
        			location.y += height;
        			location.x -= width;
        			break;
        		case 3:		// put lower-right corner of text at drawing coordinate
        			location.y += height;
        			location.x -= width;
        			break;
        	}
            Color oldColor = g.getColor();
            Color mainColor;
            if (color != null) mainColor = color; else
            	mainColor = new Color(User.getColor(User.ColorPrefType.TEXT));
            int mainColorRed = mainColor.getRed() & 0xFF;
            int mainColorGreen = mainColor.getGreen() & 0xFF;
            int mainColorBlue = mainColor.getBlue() & 0xFF;
            Color shadowColor = new Color(255-mainColorRed, 255-mainColorGreen, 255-mainColorBlue);
            if (backgroundColor == null)
            {
	            g.setColor(shadowColor);
	            g.drawString(msg, location.x+1, location.y+1);
            } else
            {
            	g.setColor(backgroundColor);
            	g.fillRect(location.x, location.y-height, width, height);
            }
            g.setColor(mainColor);
            g.drawString(msg, location.x, location.y);
            g.setColor(oldColor);
        }

        @Override
        Rectangle2D getHighlightedArea(EditWindow wnd)
        {
            return new Rectangle2D.Double(loc.getX(), loc.getY(), 0, 0);
        }
    }
}

/**
 *  A Highlight which calls the user's attention to a Poly.
 */
class HighlightPoly extends Highlight
{
    /** The highlighted polygon */                              private final Poly polygon;
    HighlightPoly(Cell c, Poly p, Color col)
    {
        super(c, col, false);
        this.polygon = p;
    }

    @Override
    public void showInternalHighlight(EditWindow wnd, Graphics g, int highOffX, int highOffY,
                                      boolean onlyHighlight)
    {
        // switch colors if specified
        Color oldColor = null;
        if (color != null)
        {
            oldColor = g.getColor();
            g.setColor(color);
        }

        // draw poly
    	Point2D[] points = polygon.getPoints();
        if (polygon.getStyle() == Poly.Type.FILLED)
        {
        	int [] xPoints = new int[points.length];
        	int [] yPoints = new int[points.length];
    		for(int i=0; i list, boolean wantNodes, boolean wantArcs)
    {
        List inArea = Highlighter.findAllInArea(highlighter, cell, false, false, false, false, false, bounds, null);
        for(Highlight ah : inArea)
        {
            if (!(ah instanceof HighlightEOBJ)) continue;
            ElectricObject eobj = ((HighlightEOBJ)ah).eobj;
            if (eobj instanceof ArcInst) {
                if (wantArcs)
                    list.add((ArcInst)eobj);
            } else if (eobj instanceof NodeInst) {
                if (wantNodes)
                    list.add((NodeInst)eobj);
            } else if (eobj instanceof PortInst) {
                if (wantNodes)
                    list.add(((PortInst)eobj).getNodeInst());
            }
//					if (!wantNodes)
//					{
//						if (eobj instanceof NodeInst || eobj instanceof PortInst) continue;
//					}
//					if (!wantArcs && eobj instanceof ArcInst) continue;
//					if (eobj instanceof PortInst) eobj = ((PortInst)eobj).getNodeInst();
//					highlightedGeoms.add(eobj);
        }
    }

    @Override
    void getHighlightedNodes(Highlighter highlighter, Set set)
    {
        List inArea = Highlighter.findAllInArea(highlighter, cell, false, false, false, false, false,
                bounds, null);
        for(Highlight ah : inArea)
        {
            if (!(ah instanceof HighlightEOBJ)) continue;
            ElectricObject eobj = ((HighlightEOBJ)ah).eobj;
            if (eobj instanceof NodeInst)
                set.add((NodeInst)eobj);
            else if (eobj instanceof PortInst)
                set.add(((PortInst)eobj).getNodeInst());
        }
    }

    @Override
    void getHighlightedArcs(Highlighter highlighter, Set set)
    {
        List inArea = Highlighter.findAllInArea(highlighter, cell, false, false, false, false, false,
                bounds, null);
        for(Highlight ah : inArea)
        {
            if (!(ah instanceof HighlightEOBJ)) continue;
            ElectricObject eobj = ((HighlightEOBJ)ah).eobj;
            if (eobj instanceof ArcInst)
                set.add((ArcInst)eobj);
        }
    }

    @Override
    Rectangle2D getHighlightedArea(EditWindow wnd)
    {
        return bounds;
    }

    @Override
    public String getInfo()
    {
        String description = "Area from " + bounds.getMinX() + "<=X<=" + bounds.getMaxX() +
            " and " + bounds.getMinY() + "<=Y<=" + bounds.getMaxY();
        return description;
    }
}

/**
 *  A Highlight which calls the user's attention to an ElectricObject.
 */
class HighlightEOBJ extends Highlight
{
	/** The highlighted object. */								protected final ElectricObject eobj;
	/** For Highlighted networks, this prevents excess highlights */ private final boolean highlightConnected;
	/** The highlighted outline point (only for NodeInst). */	protected final int point;

	public HighlightEOBJ(ElectricObject e, Cell c, boolean connected, int p)
	{
		super(c, null, false);
		this.eobj = e;
		this.highlightConnected = connected;
		this.point = p;
	}

	public HighlightEOBJ(ElectricObject e, Cell c, boolean connected, int p, boolean isError)
	{
		super(c, null, isError);
		this.eobj = e;
		this.highlightConnected = connected;
		this.point = p;
	}

	public HighlightEOBJ(ElectricObject e, Cell c, boolean connected, int p, Color col)
	{
		super(c, col, false);
		this.eobj = e;
		this.highlightConnected = connected;
		this.point = p;
	}

	public HighlightEOBJ(HighlightEOBJ h, ElectricObject eobj, int p)
	{
		super(h.cell, h.color, h.isError);
		this.eobj = eobj;
		this.highlightConnected = h.highlightConnected;
		this.point = p;
	}

    @Override
	void internalDescribe(StringBuffer desc)
	{
		if (eobj instanceof PortInst) {
			desc.append(((PortInst)eobj).describe(true));
		}
		if (eobj instanceof NodeInst) {
			desc.append(((NodeInst)eobj).describe(true));
		}
		if (eobj instanceof ArcInst) {
			desc.append(((ArcInst)eobj).describe(true));
		}
	}

    @Override
	public ElectricObject getElectricObject() { return eobj; }

    @Override
	public boolean isHighlightEOBJ() { return true; }

    @Override
	public int getPoint() { return point; }

    @Override
	public boolean isValid()
	{
		if (!super.isValid()) return false;

//		if (eobj instanceof PortInst)
//			return ((PortInst)eobj).getNodeInst().isLinked();
		return eobj.isLinked();
	}

    @Override
    public boolean showInRaster() {
        return !isError && color == null && eobj instanceof NodeInst && point < 0;
    }

    @Override
    public boolean sameThing(Highlight obj, boolean exact)
	{
		if (this == obj) return (true);

		// Consider already obj==null
	    if (obj == null || getClass() != obj.getClass())
            return (false);

        ElectricObject realEObj = eobj;
        if (!exact && realEObj instanceof PortInst) realEObj = ((PortInst)realEObj).getNodeInst();

        HighlightEOBJ other = (HighlightEOBJ)obj;
        ElectricObject realOtherEObj = other.eobj;
        if (!exact && realOtherEObj instanceof PortInst) realOtherEObj = ((PortInst)realOtherEObj).getNodeInst();
        if (realEObj != realOtherEObj) return false;
        return true;
    }

    @Override
    public void showInternalHighlight(EditWindow wnd, Graphics g, int highOffX, int highOffY,
                                      boolean onlyHighlight)
    {
//        Graphics2D g2 = (Graphics2D)g;
//        highlightConnected = setConnected;
        if (eobj == null || !eobj.isLinked()) return;

		// switch colors if specified
        Color oldColor = null;
        if (color != null)
        {
            oldColor = g.getColor();
            g.setColor(color);
        }

        // highlight ArcInst
		if (eobj instanceof ArcInst)
		{
			ArcInst ai = (ArcInst)eobj;

//            if (!Job.acquireExamineLock(false)) return;
            try {
                // construct the polygons that describe the basic arc
                Poly poly = ai.makeLambdaPoly(ai.getGridBaseWidth(), Poly.Type.CLOSED);
                if (poly == null) return;
                drawOutlineFromPoints(wnd, g, poly.getPoints(), highOffX, highOffY, false, false);

                if (onlyHighlight)
                {
                    // this is the only thing highlighted: give more information about constraints
                    String constraints = "X";
                    if (ai.isRigid()) constraints = "R"; else
                    {
                        if (ai.isFixedAngle())
                        {
                            if (ai.isSlidable()) constraints = "FS"; else
                                constraints = "F";
                        } else if (ai.isSlidable()) constraints = "S";
                    }
                    Point p = wnd.databaseToScreen(ai.getTrueCenterX(), ai.getTrueCenterY());
                    Font font = wnd.getFont(null);
                    if (font != null)
                    {
                        GlyphVector gv = wnd.getGlyphs(constraints, font);
                        Rectangle2D glyphBounds = gv.getVisualBounds();
                        g.drawString(constraints, (int)(p.x - glyphBounds.getWidth()/2 + highOffX),
                            p.y + font.getSize()/2 + highOffY);
                    }
                }
//                Job.releaseExamineLock();
            } catch (Error e) {
//                Job.releaseExamineLock();
                throw e;
            }
			return;
		}

		// highlight NodeInst
		PortProto pp = null;
		ElectricObject realEObj = eobj;
        PortInst originalPi = null;
        if (realEObj instanceof PortInst)
		{
            originalPi = ((PortInst)realEObj);
            pp = originalPi.getPortProto();
			realEObj = ((PortInst)realEObj).getNodeInst();
		}
		if (realEObj instanceof NodeInst)
		{
			NodeInst ni = (NodeInst)realEObj;
			FixpTransform trans = ni.rotateOutAboutTrueCenter();

            int offX = highOffX;
            int offY = highOffY;
/*
			boolean drewOutline = false;
			if (!ni.isCellInstance())
			{
				// special case for outline nodes
				if (np.isHoldsOutline())
				{
					Point2D [] outline = ni.getTrace();
					if (outline != null)
					{
						int numPoints = outline.length;
						Point2D [] pointList = new Point2D.Double[numPoints];
						for(int i=0; i= 0)
			{
				EPoint [] points = ni.getTrace();
				if (points != null)
				{
					if (points.length <= point)
					{
						System.err.println("Invalid index " + point + " in trace point ");
						return;
					}
					
					// if this is a spline, highlight the true shape
					if (ni.getProto() == Artwork.tech().splineNode)
					{
						EPoint [] changedPoints = new EPoint[points.length];
						for(int i=0; i= 0 && points[prevPoint] != null)
						{
							prevPt = new Point2D.Double(ni.getAnchorCenterX() + points[prevPoint].getX(),
								ni.getAnchorCenterY() + points[prevPoint].getY());
							trans.transform(prevPt, prevPt);
							if (prevPt.getX() == thisPt.getX() && prevPt.getY() == thisPt.getY()) prevPoint = -1; else
							{
								Point cPrev = wnd.databaseToScreen(prevPt);
								drawLine(g, wnd, cThis.x + offX, cThis.y + offY, cPrev.x, cPrev.y);
							}
						}
						int nextPoint = point + 1;
						if (nextPoint >= points.length)
						{
							if (showWrap) nextPoint = 0; else
								nextPoint = -1;
						}
						if (nextPoint >= 0 && points[nextPoint] != null)
						{
							nextPt = new Point2D.Double(ni.getAnchorCenterX() + points[nextPoint].getX(),
								ni.getAnchorCenterY() + points[nextPoint].getY());
							trans.transform(nextPt, nextPt);
							if (nextPt.getX() == thisPt.getX() && nextPt.getY() == thisPt.getY()) nextPoint = -1; else
							{
								Point cNext = wnd.databaseToScreen(nextPt);
								drawLine(g, wnd, cThis.x + offX, cThis.y + offY, cNext.x, cNext.y);
							}
						}

						// draw arrows on the lines
						if (offX == 0 && offY == 0 && points.length > 2 && prevPt != null && nextPt != null)
						{
							double arrowLen = Double.MAX_VALUE;
							if (prevPoint >= 0) arrowLen = Math.min(thisPt.distance(prevPt), arrowLen);
							if (nextPoint >= 0) arrowLen = Math.min(thisPt.distance(nextPt), arrowLen);
							arrowLen /= 10;
							double angleOfArrow = Math.PI * 0.8;
							if (prevPoint >= 0)
							{
								Point2D prevCtr = new Point2D.Double((prevPt.getX()+thisPt.getX()) / 2,
									(prevPt.getY()+thisPt.getY()) / 2);
								double prevAngle = DBMath.figureAngleRadians(prevPt, thisPt);
								Point2D prevArrow1 = new Point2D.Double(prevCtr.getX() + Math.cos(prevAngle+angleOfArrow) * arrowLen,
									prevCtr.getY() + Math.sin(prevAngle+angleOfArrow) * arrowLen);
								Point2D prevArrow2 = new Point2D.Double(prevCtr.getX() + Math.cos(prevAngle-angleOfArrow) * arrowLen,
									prevCtr.getY() + Math.sin(prevAngle-angleOfArrow) * arrowLen);
								Point cPrevCtr = wnd.databaseToScreen(prevCtr);
								Point cPrevArrow1 = wnd.databaseToScreen(prevArrow1);
								Point cPrevArrow2 = wnd.databaseToScreen(prevArrow2);
								drawLine(g, wnd, cPrevCtr.x, cPrevCtr.y, cPrevArrow1.x, cPrevArrow1.y);
								drawLine(g, wnd, cPrevCtr.x, cPrevCtr.y, cPrevArrow2.x, cPrevArrow2.y);
							}

							if (nextPoint >= 0)
							{
								Point2D nextCtr = new Point2D.Double((nextPt.getX()+thisPt.getX()) / 2,
									(nextPt.getY()+thisPt.getY()) / 2);
								double nextAngle = DBMath.figureAngleRadians(thisPt, nextPt);
								Point2D nextArrow1 = new Point2D.Double(nextCtr.getX() + Math.cos(nextAngle+angleOfArrow) * arrowLen,
									nextCtr.getY() + Math.sin(nextAngle+angleOfArrow) * arrowLen);
								Point2D nextArrow2 = new Point2D.Double(nextCtr.getX() + Math.cos(nextAngle-angleOfArrow) * arrowLen,
									nextCtr.getY() + Math.sin(nextAngle-angleOfArrow) * arrowLen);
								Point cNextCtr = wnd.databaseToScreen(nextCtr);
								Point cNextArrow1 = wnd.databaseToScreen(nextArrow1);
								Point cNextArrow2 = wnd.databaseToScreen(nextArrow2);
								drawLine(g, wnd, cNextCtr.x, cNextCtr.y, cNextArrow1.x, cNextArrow1.y);
								drawLine(g, wnd, cNextCtr.x, cNextCtr.y, cNextArrow2.x, cNextArrow2.y);
							}
						}
					}

					// do not offset the node, just this point
					offX = offY = 0;
				}
			}

            // draw nodeInst outline
            if ((offX == 0 && offY == 0) || point < 0)
            {
                Poly niPoly = getNodeInstOutline(ni);
                boolean niOpened = (niPoly.getStyle() == Poly.Type.OPENED);
            	Point2D [] points = niPoly.getPoints();
            	drawOutlineFromPoints(wnd, g, points, offX, offY, niOpened, false);
            }

			// draw the selected port
			if (pp != null)
			{
                //@TODO MAYBE I need the main color
//				g.setColor(mainColor);
				Poly poly = ni.getShapeOfPort(pp);
				boolean opened = true;
				Point2D [] points = poly.getPoints();
				if (poly.getStyle() == Poly.Type.FILLED || poly.getStyle() == Poly.Type.CLOSED) opened = false;
				if (poly.getStyle() == Poly.Type.CIRCLE || poly.getStyle() == Poly.Type.THICKCIRCLE ||
					poly.getStyle() == Poly.Type.DISC)
				{
					double sX = points[0].distance(points[1]) * 2;
					Poly.Point [] pts = Artwork.fillEllipse(points[0], sX, sX, 0, 360);
					poly = new Poly(pts);
					poly.transform(ni.rotateOut());
					points = poly.getPoints();
				} else if (poly.getStyle() == Poly.Type.CIRCLEARC)
				{
					double [] angles = ni.getArcDegrees();
					double sX = points[0].distance(points[1]) * 2;
					Poly.Point [] pts = Artwork.fillEllipse(points[0], sX, sX, angles[0], angles[1]);
					poly = new Poly(pts);
					poly.transform(ni.rotateOut());
					points = poly.getPoints();
				}
				drawOutlineFromPoints(wnd, g, points, offX, offY, opened, false);
//				g.setColor(mainColor);

                // show name of port
                if (ni.isCellInstance() && (g instanceof Graphics2D))
				{
					// only show name if port is wired (because all other situations already show the port)
					boolean wired = false;
					for(Iterator cIt = ni.getConnections(); cIt.hasNext(); )
					{
						Connection con = cIt.next();
						if (con.getPortInst().getPortProto() == pp) { wired = true;   break; }
					}
					if (wired)
					{
	                    Font font = new Font(User.getDefaultFont(), Font.PLAIN, (int)(1.5*EditWindow.getDefaultFontSize()));
    	                GlyphVector v = wnd.getGlyphs(pp.getName(), font);
        	            Point2D point = wnd.databaseToScreen(poly.getCenterX(), poly.getCenterY());
            	        ((Graphics2D)g).drawGlyphVector(v, (float)point.getX()+offX, (float)point.getY()+offY);
					}
                }

                // if this is a port on an "example icon", show the equivalent port in the cell
//                if (ni.isIconOfParent())
//                {
//                	// find export in parent
//                	Export equiv = (Export)cell.findPortProto(pp.getName());
//                	if (equiv != null)
//                	{
//                		PortInst ePi = equiv.getOriginalPort();
//                		Poly ePoly = ePi.getPoly();
//						Point eP = wnd.databaseToScreen(ePoly.getCenterX(), ePoly.getCenterY());
//						Point p = wnd.databaseToScreen(poly.getCenterX(), poly.getCenterY());
//						drawLine(g, wnd, eP.x, eP.y, p.x + offX, p.y + offY);
//                	}
//                }
			}
		}

		// switch back to old color if switched
		if (oldColor != null)
			g.setColor(oldColor);
	}

    /**
     * highlight objects that are electrically connected to this object
     * unless specified not to. HighlightConnected is set to false by addNetwork when
     * it figures out what's connected and adds them manually. Because they are added
     * in addNetwork, we shouldn't try and add connected objects here.
     * @param g2
     * @param wnd
     */
    @Override
    void showHighlightsConnected(Graphics2D g2, EditWindow wnd) {
        if (!isValid() || !(eobj instanceof PortInst) || !highlightConnected) return;
        PortInst originalPi = (PortInst)eobj;
        Netlist netlist = cell.getNetlist();
        if (netlist == null) return;
        NodeInst ni = originalPi.getNodeInst();
        NodeInst originalNI = ni;
        PortProto pp = originalPi.getPortProto();
        if (ni.isIconOfParent())
        {
            // find export in parent
            Export equiv = (Export)cell.findPortProto(pp.getName());
            if (equiv != null)
            {
                originalPi = equiv.getOriginalPort();
                ni = originalPi.getNodeInst();
                pp = originalPi.getPortProto();
            }
        }
        Set networks = new HashSet();
        networks = NetworkTool.getNetworksOnPort(originalPi, netlist, networks);

        Set markObj = new HashSet();
        for(Iterator it = cell.getArcs(); it.hasNext(); )
        {
            ArcInst ai = it.next();
            Name arcName = ai.getNameKey();
            for (int i=0; i it = netlist.getNodables(); it.hasNext(); ) {
            Nodable no = it.next();
            NodeInst oNi = no.getNodeInst();
            if (oNi == originalNI) continue;
            if (markObj.contains(ni)) continue;

            boolean highlightNo = false;
            for(Iterator eIt = no.getProto().getPorts(); eIt.hasNext(); )
            {
                PortProto oPp = eIt.next();
                Name opName = oPp.getNameKey();
                for (int j=0; j it = cell.getArcs(); it.hasNext(); )
        {
            ArcInst ai = it.next();
            if (!markObj.contains(ai)) continue;
            Point c1 = wnd.databaseToScreen(ai.getHeadLocation());
            Point c2 = wnd.databaseToScreen(ai.getTailLocation());
            drawLine(g2, wnd, c1.x, c1.y, c2.x, c2.y);
        }

        // draw dots in all connected nodes
        g2.setStroke(solidLine);
        for (Iterator it = cell.getNodes(); it.hasNext(); )
        {
            NodeInst oNi = it.next();
            if (!markObj.contains(oNi)) continue;

            Point c = wnd.databaseToScreen(oNi.getTrueCenter());
            g2.fillOval(c.x-4, c.y-4, 8, 8);

            // connect the center dots to the input arcs
            Point2D nodeCenter = oNi.getTrueCenter();
            for(Iterator pIt = oNi.getConnections(); pIt.hasNext(); )
            {
                Connection con = pIt.next();
                ArcInst ai = con.getArc();
                if (!markObj.contains(ai)) continue;
                Point2D arcEnd = con.getLocation();
                if (arcEnd.getX() != nodeCenter.getX() || arcEnd.getY() != nodeCenter.getY())
                {
                    Point c1 = wnd.databaseToScreen(arcEnd);
                    Point c2 = wnd.databaseToScreen(nodeCenter);
                    //g2.setStroke(dottedLine);
                    //if (c1.distance(c2) < 15) g2.setStroke(solidLine);
                    drawLine(g2, wnd, c1.x, c1.y, c2.x, c2.y);
                }
            }
        }
        g2.setStroke(origStroke);
    }

    @Override
    public void showHighlight(FixpTransform outOfPlaceTransform, AbstractLayerDrawing  ald, ERaster raster) {
        if (eobj == null || !eobj.isLinked()) {
            return;
        }
        // highlight NodeInst
        NodeInst ni = (NodeInst) eobj;

        // switch colors if specified
        assert color == null;

        // draw nodeInst outline
        Poly niPoly = getNodeInstOutline(ni);
        boolean niOpened = (niPoly.getStyle() == Poly.Type.OPENED);
        drawOutlineFromPoints(outOfPlaceTransform, ald, raster, niPoly.getPoints(), 0, 0, niOpened, false);
    }

    /**
     * highlight objects that are electrically connected to this object
     * unless specified not to. HighlightConnected is set to false by addNetwork when
     * it figures out what's connected and adds them manually. Because they are added
     * in addNetwork, we shouldn't try and add connected objects here.
     * @param g2
     * @param wnd
     */
    @Override
    public void showHighlightsConnected(FixpTransform outOfPlaceTransform, AbstractLayerDrawing  ald, ERaster raster) {
        if (!isValid() || !(eobj instanceof PortInst) || !highlightConnected) return;
        PortInst originalPi = (PortInst)eobj;
        Netlist netlist = cell.getNetlist();
        if (netlist == null) return;
        NodeInst ni = originalPi.getNodeInst();
        NodeInst originalNI = ni;
        PortProto pp = originalPi.getPortProto();
        if (ni.isIconOfParent())
        {
            // find export in parent
            Export equiv = (Export)cell.findPortProto(pp.getName());
            if (equiv != null)
            {
                originalPi = equiv.getOriginalPort();
                ni = originalPi.getNodeInst();
                pp = originalPi.getPortProto();
            }
        }
        Set networks = new HashSet();
        networks = NetworkTool.getNetworksOnPort(originalPi, netlist, networks);

        Set markObj = new HashSet();
        for(Iterator it = cell.getArcs(); it.hasNext(); )
        {
            ArcInst ai = it.next();
            Name arcName = ai.getNameKey();
            for (int i=0; i it = netlist.getNodables(); it.hasNext(); ) {
            Nodable no = it.next();
            NodeInst oNi = no.getNodeInst();
            if (oNi == originalNI) continue;
            if (markObj.contains(ni)) continue;

            boolean highlightNo = false;
            for(Iterator eIt = no.getProto().getPorts(); eIt.hasNext(); )
            {
                PortProto oPp = eIt.next();
                Name opName = oPp.getNameKey();
                for (int j=0; j it = cell.getArcs(); it.hasNext(); )
        {
            ArcInst ai = it.next();
            if (!markObj.contains(ai)) continue;
            EPoint c1 = ai.getHeadLocation();
            EPoint c2 = ai.getTailLocation();
            if (outOfPlaceTransform != null) {
                c1 = (EPoint)outOfPlaceTransform.transform(c1, null);
                c2 = (EPoint)outOfPlaceTransform.transform(c2, null);
            }
            ald.drawLine((int)c1.getGridX(), (int)c1.getGridY(), (int)c2.getGridX(), (int)c2.getGridY(), 2, raster);
        }

        // draw dots in all connected nodes
        for (Iterator it = cell.getNodes(); it.hasNext(); )
        {
            NodeInst oNi = it.next();
            if (!markObj.contains(oNi)) continue;

            EPoint c = EPoint.snap(oNi.getTrueCenter());
            if (outOfPlaceTransform != null) {
                c = (EPoint)outOfPlaceTransform.transform(c, null);
            }
            ald.drawOval((int)c.getGridX(), (int)c.getGridY(), 4, raster);

            // connect the center dots to the input arcs
            Point2D nodeCenter = oNi.getTrueCenter();
            for(Iterator pIt = oNi.getConnections(); pIt.hasNext(); )
            {
                Connection con = pIt.next();
                ArcInst ai = con.getArc();
                if (!markObj.contains(ai)) continue;
                EPoint arcEnd = con.getLocation();
                if (arcEnd.getGridX() != nodeCenter.getX() || arcEnd.getY() != nodeCenter.getY())
                {
                    EPoint c1 = arcEnd;
                    EPoint c2 = EPoint.snap(nodeCenter);
                    if (outOfPlaceTransform != null) {
                        c1 = (EPoint)outOfPlaceTransform.transform(c1, null);
                        c2 = (EPoint)outOfPlaceTransform.transform(c2, null);
                    }
                    ald.drawLine((int)c1.getGridX(), (int)c1.getGridY(), (int)c2.getGridX(), (int)c2.getGridY(), 0, raster);
                }
            }
        }
    }

    @Override
	void getHighlightedEObjs(Highlighter highlighter, List list, boolean wantNodes, boolean wantArcs)
    {
        getHighlightedEObjsInternal(getGeometric(), list, wantNodes, wantArcs);
    }

    @Override
    void getHighlightedNodes(Highlighter highlighter, Set set)
    {
        getHighlightedNodesInternal(getGeometric(), set);
    }

    @Override
    void getHighlightedArcs(Highlighter highlighter, Set set)
    {
        getHighlightedArcsInternal(getGeometric(), set);
    }

    @Override
    void getHighlightedNetworks(Set nets, Netlist netlist)
    {
        ElectricObject eObj = eobj;
        if (eObj instanceof NodeInst)
        {
            NodeInst ni = (NodeInst)eObj;
            if (ni.getNumPortInsts() == 1)
            {
                PortInst pi = ni.getOnlyPortInst();
                if (pi != null) eObj = pi;
            }
        }
        if (eObj instanceof PortInst)
        {
            PortInst pi = (PortInst)eObj;
            nets = NetworkTool.getNetworksOnPort(pi, netlist, nets);
//						boolean added = false;
//						for(Iterator aIt = pi.getNodeInst().getConnections(); aIt.hasNext(); )
//						{
//							Connection con = aIt.next();
//							ArcInst ai = con.getArc();
//							int wid = netlist.getBusWidth(ai);
//							for(int i=0; i gotAll = Highlighter.checkOutObject((Geometric)eobj, true, false, specialSelect,
                    searchArea, wnd, directHitDist, false, wnd.getGraphicsPreferences().isShowTempNames());
            if (gotAll.isEmpty()) return null;
            boolean found = false;
            Highlight result = this;
            for(Highlight got : gotAll)
            {
	            if (!(got instanceof HighlightEOBJ))
	                System.out.println("Error?");
	            ElectricObject hObj = got.getElectricObject();
	            ElectricObject hReal = hObj;
	            if (hReal instanceof PortInst) hReal = ((PortInst)hReal).getNodeInst();
	            for(Highlight alreadyDone : highlighter.getHighlights())
	            {
	                if (!(alreadyDone instanceof HighlightEOBJ)) continue;
	                HighlightEOBJ alreadyHighlighted = (HighlightEOBJ)alreadyDone;
	                ElectricObject aHObj = alreadyHighlighted.getElectricObject();
	                ElectricObject aHReal = aHObj;
	                if (aHReal instanceof PortInst) aHReal = ((PortInst)aHReal).getNodeInst();
	                if (hReal == aHReal)
	                {
	                    // found it: adjust the port/point
	                	found = true;
	                    if (hObj != aHObj || alreadyHighlighted.point != ((HighlightEOBJ)got).point)
	                    {
	                    	if (change)
	                    	{
	                            Highlight updated = highlighter.setPoint(alreadyHighlighted, got.getElectricObject(), ((HighlightEOBJ)got).point);
	                            if (alreadyHighlighted == this) result = updated;
	                    	} else
	                    	{
	                    		result = new HighlightEOBJ(alreadyHighlighted, got.getElectricObject(), ((HighlightEOBJ)got).point);
	                    	}
	                    }
	                    break;
	                }
	            }
	            if (found) break;
            }
            return result;
        }
        return null;
    }

    @Override
    public String getInfo()
    {
        String description = "";
        ElectricObject realObj = eobj;

        if (realObj instanceof PortInst)
            realObj = ((PortInst)realObj).getNodeInst();
        if (realObj instanceof NodeInst)
        {
            NodeInst ni = (NodeInst)realObj;
            description = "Node " + ni.describe(true);
        } else if (realObj instanceof ArcInst)
        {
            ArcInst ai = (ArcInst)eobj;
            description = "Arc " + ai.describe(true);
        }
        return description;
    }
}


/**
 *  A Highlight which calls the user's attention to an ElectricObject which happens to be a piece of text.
 */
class HighlightText extends Highlight
{
	/** The highlighted object. */								protected final ElectricObject eobj;
	/** The highlighted variable. */							protected final Variable.Key varKey;

    public HighlightText(ElectricObject e, Cell c, Variable.Key key)
    {
        super(c, null, false);
        this.eobj = e;
        this.varKey = key;
        Class cls = null;
        if (key == NodeInst.NODE_NAME || key == NodeInst.NODE_PROTO)
            cls = NodeInst.class;
        else if (key == ArcInst.ARC_NAME)
            cls = ArcInst.class;
        else if (key == Export.EXPORT_NAME)
            cls = Export.class;
        else if (key == null)
            throw new NullPointerException();
        if (cls != null && !cls.isInstance(e))
            throw new IllegalArgumentException(key + " in " + e);
    }

    @Override
    void internalDescribe(StringBuffer desc)
    {
        if (varKey != null)
        {
        	if (varKey == NodeInst.NODE_NAME)
        	{
	            desc.append("name: ");
	            desc.append(((NodeInst)eobj).getName());
        	} else if (varKey == NodeInst.NODE_PROTO)
        	{
	            desc.append("instance: ");
	            desc.append(((NodeInst)eobj).getProto().getName());
        	} else if (varKey == ArcInst.ARC_NAME)
        	{
	            desc.append("name: ");
	            desc.append(((ArcInst)eobj).getName());
        	} else if (varKey == Export.EXPORT_NAME)
        	{
	            desc.append("export: ");
	            desc.append(((Export)eobj).getName());
        	} else
        	{
	            desc.append("var: ");
	            desc.append(eobj.getParameterOrVariable(varKey).describe(-1));
        	}
        }
    }

    @Override
    public ElectricObject getElectricObject() { return eobj; }

    // creating so HighlightText is not a public class
    @Override
    public boolean isHighlightText() { return true; }

    @Override
    public Variable.Key getVarKey() { return varKey; }

    @Override
    public boolean isValid()
    {
        if (!super.isValid()) return false;
        if (eobj == null || varKey == null) return false;
        if (!eobj.isLinked()) return false;

    	if (varKey == NodeInst.NODE_NAME ||
			varKey == ArcInst.ARC_NAME ||
			varKey == NodeInst.NODE_PROTO ||
			varKey == Export.EXPORT_NAME) return true;
    	return eobj.getParameterOrVariable(varKey) != null;
    }

    @Override
    public boolean sameThing(Highlight obj, boolean exact)
    {
        if (this == obj) return (true);

		// Consider already obj==null
        if (obj == null || getClass() != obj.getClass())
            return (false);

        HighlightText other = (HighlightText)obj;
        if (eobj != other.eobj) return false;
        if (cell != other.cell) return false;
        if (varKey != other.varKey) return false;
        return true;
    }

    @Override
    public void showInternalHighlight(EditWindow wnd, Graphics g, int highOffX, int highOffY,
                                      boolean onlyHighlight)
    {
        Graphics2D g2 = (Graphics2D)g;
        Point2D [] points = Highlighter.describeHighlightText(wnd, eobj, varKey);
        if (points == null) return;
        Point2D [] linePoints = new Point2D[2];
        for(int i=0; i highX) highX = a.x;
//                        if (a.y < lowY) lowY = a.y;
//                        if (a.y > highY) highY = a.y;
//                    }
//                    int cX = (lowX+highX)/2;
//                    int cY = (lowY+highY)/2;
                    if (Math.abs(cX - c.x) > 4 || Math.abs(cY - c.y) > 4)
                    {
                        g.fillOval(c.x-4, c.y-4, 8, 8);
                        g2.setStroke(dottedLine);
                        drawLine(g, wnd, c.x, c.y, cX, cY);
                        g2.setStroke(solidLine);
                    }
                }
            }
        }
    }

//    /**
//	 * Method to tell whether this Highlight is text that stays with its node.
//	 * The two possibilities are (1) text on invisible pins
//	 * (2) export names, when the option to move exports with their labels is requested.
//	 * @return true if this Highlight is text that should move with its node.
//	 */
//    public boolean nodeMovesWithText()
//	{
//		if (varKey != null)
//		{
//			// moving variable text
//			if (!(eobj instanceof NodeInst)) return false;
//			NodeInst ni = (NodeInst)eobj;
//			if (ni.isInvisiblePinWithText()) return true;
//		} else
//		{
//			// moving export text
//			if (!(eobj instanceof Export)) return false;
//			Export pp = (Export)eobj;
//			if (pp.getOriginalPort().getNodeInst().getProto() == Generic.tech.invisiblePinNode) return true;
//			if (User.isMoveNodeWithExport()) return true;
//		}
//		return false;
//	}

    @Override
    public Geometric getGeometric()
    {
        if (DisplayedText.objectMovesWithText(eobj, varKey))
        {
            if (eobj instanceof Export) return ((Export)eobj).getOriginalPort().getNodeInst();
            if (eobj instanceof Geometric) return (Geometric)eobj;
        }
        return null;
    }

    @Override
    void getHighlightedEObjs(Highlighter highlighter, List list, boolean wantNodes, boolean wantArcs)
    {
        getHighlightedEObjsInternal(getGeometric(), list, wantNodes, wantArcs);
    }

    @Override
    void getHighlightedNodes(Highlighter highlighter, Set set)
    {
        getHighlightedNodesInternal(getGeometric(), set);
    }

    @Override
    void getHighlightedArcs(Highlighter highlighter, Set set)
    {
        getHighlightedArcsInternal(getGeometric(), set);
    }

    @Override
    void getHighlightedNetworks(Set nets, Netlist netlist)
    {
        if (/*varKey == null &&*/ eobj instanceof Export)
        {
            Export pp = (Export)eobj;
            int width = netlist.getBusWidth(pp);
            for(int i=0; i list, boolean unique, List getHighlights)
    {
    	DisplayedText dt = makeDisplayedText();
    	if (dt == null) return;
        if (list.contains(dt)) return;

        // if this text is on a selected object, don't include the text
        if (unique)
        {
            ElectricObject onObj = null;
            if (varKey != null)
            {
                if (eobj instanceof Export)
                {
                    onObj = ((Export)eobj).getOriginalPort().getNodeInst();
                } else if (eobj instanceof PortInst)
                {
                    onObj = ((PortInst)eobj).getNodeInst();
                } else if (eobj instanceof Geometric)
                {
                    onObj = eobj;
                }
            }

            // now see if the object is in the list
            if (eobj != null)
            {
                boolean found = false;
                for(Highlight oH : getHighlights)
                {
                    if (!(oH instanceof HighlightEOBJ)) continue;
                    ElectricObject fobj = ((HighlightEOBJ)oH).eobj;
                    if (fobj instanceof PortInst) fobj = ((PortInst)fobj).getNodeInst();
                    if (fobj == onObj) { found = true;   break; }
                }
                if (found) return;
            }
        }

        // add this text
        list.add(dt);
    }

    @Override
    Rectangle2D getHighlightedArea(EditWindow wnd)
    {
        if (wnd != null)
        {
            Poly poly = eobj.computeTextPoly(wnd, varKey);
            if (poly != null) return poly.getBounds2D();
        }
        return null;
    }

    @Override
    Highlight overHighlighted(EditWindow wnd, int x, int y, Highlighter highlighter, boolean change)
    {
        Point2D start = wnd.screenToDatabase(x, y);
        Poly poly = eobj.computeTextPoly(wnd, varKey);
        if (poly != null)
            if (poly.isInside(start)) return this;
        return null;
    }

    @Override
    public String describe()
    {
        String description = "Unknown";
        if (varKey != null && eobj != null)
        {
        	if (varKey == NodeInst.NODE_NAME)
        	{
        		description = "Node name for " + ((NodeInst)eobj).describe(true);
        	} else if (varKey == ArcInst.ARC_NAME)
        	{
        		description = "Arc name for " + ((ArcInst)eobj).describe(true);
        	} else if (varKey == Export.EXPORT_NAME)
        	{
        		description = "Export '" + ((Export)eobj).getName() + "'";
        	} else if (varKey == NodeInst.NODE_PROTO)
        	{
        		description = "Cell instance name " + ((NodeInst)eobj).describe(true);
        	} else
        	{
        		Variable var = eobj.getParameterOrVariable(varKey);
        		if (var != null) description = eobj.getFullDescription(var);
        	}
        }
        return description;
    }

    @Override
    public String getInfo()
    {
        return "Text: " + describe();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy