/*******************************************************************************
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package hr.fer.zemris.vhdllab.applets.editor.schema2.model.drawers;
import hr.fer.zemris.vhdllab.applets.editor.schema2.constants.Constants;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaWire;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IWireDrawer;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.DrawingProperties;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Rect2d;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.WireSegment;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.XYLocation;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
public class DefaultWireDrawer implements IWireDrawer {
/* static fields */
public static final int NODE_SIZE = 5;
private static final String ETC_STRING = "...";
private static final int MIN_DIST_BETWEEN_SEGS = 250;
private static final int NAME_FONT_SIZE = Constants.FONT_CANVAS_SMALL.getSize();
private static final int MIN_SEG_DIM = NAME_FONT_SIZE * 5;
/* private fields */
private ISchemaWire wire_to_draw;
private String name;
private int ndim, nlength;
/* ctors */
public DefaultWireDrawer(ISchemaWire wireToDraw) {
wire_to_draw = wireToDraw;
}
/* methods */
public void draw(Graphics2D graphics, DrawingProperties properties) {
/* draw nodes */
for (XYLocation node : wire_to_draw.getNodes()) {
graphics.fillOval(node.x - NODE_SIZE / 2, node.y - NODE_SIZE / 2,
NODE_SIZE, NODE_SIZE);
}
/* draw segments */
if (!properties.drawingWireNames)
for (WireSegment segment : wire_to_draw.getSegments()) {
/* just draw lines */
XYLocation start = segment.getStart(), end = segment.getEnd();
graphics.drawLine(start.x, start.y, end.x, end.y);
}
else {
/* draw lines and names */
Rect2d bounds = wire_to_draw.getBounds();
int centerx = bounds.left + bounds.width / 2, centery = bounds.top + bounds.height / 2;
int xmid = 0, ymid = 0, currentmin = 0;
int xul = 0, yul = 0, xur = 0, yur = 0;
int xdl = 0, ydl = 0, xdr = 0, ydr = 0;
WireSegment sul = null, sur = null, sdl = null, sdr = null, smid = null;
boolean found = false;
name = wire_to_draw.getName().toString();
nlength = name.length();
ndim = nlength * NAME_FONT_SIZE;
/* draw segments and find places for name of the wire */
for (WireSegment segment : wire_to_draw.getSegments()) {
XYLocation start = segment.getStart(), end = segment.getEnd();
int segcntrx = (start.x + end.x) / 2, segcntry = (start.y + end.y) / 2;
graphics.drawLine(start.x, start.y, end.x, end.y);
if (segment.length() >= MIN_SEG_DIM) {
if (!found) {
xul = xur = xdl = xdr = xmid = segcntrx;
yul = yur = ydl = ydr = ymid = segcntry;
sul = sur = sdl = sdr = smid = segment;
currentmin = Math.abs(xmid - centerx) + Math.abs(ymid - centery);
found = true;
} else {
if (segcntrx < xul && segcntry < yul) {
xul = segcntrx; yul = segcntry; sul = segment;
}
if (segcntrx > xur && segcntry < yur) {
xur = segcntrx; yur = segcntry; sur = segment;
}
if (segcntrx < xdl && segcntry > ydl) {
xdl = segcntrx; ydl = segcntry; sdl = segment;
}
if (segcntrx > xdr && segcntry > ydr) {
xdr = segcntrx; ydr = segcntry; sdr = segment;
}
int tmpmin = Math.abs(segcntrx - centerx) + Math.abs(segcntry - centery);
if (tmpmin < currentmin) {
xmid = segcntrx;
ymid = segcntry;
smid = segment;
currentmin = tmpmin;
}
}
}
}
/* place wire name */
if (found) {
Font oldf = graphics.getFont();
Color oldc = graphics.getColor();
graphics.setFont(Constants.FONT_CANVAS_SMALL);
int r = oldc.getRed() + 170; r = (r > 240) ? (240) : (r);
int g = oldc.getGreen() + 170; g = (g > 240) ? (240) : (g);
int b = oldc.getBlue() + 170; b = (b > 240) ? (240) : (b);
graphics.setColor(new Color(r, g, b));
/* place middle */
placeName(graphics, xmid, ymid, smid);
/* place upper left */
if ((Math.abs(xmid - xul) + Math.abs(ymid - yul)) > MIN_DIST_BETWEEN_SEGS) {
placeName(graphics, xul, yul, sul);
}
/* place upper right */
if ((Math.abs(xmid - xur) + Math.abs(ymid - yur)) > MIN_DIST_BETWEEN_SEGS
&& (Math.abs(xur - xul) + Math.abs(yur - yul)) > MIN_DIST_BETWEEN_SEGS)
{
placeName(graphics, xur, yur, sur);
}
/* place lower right */
if ((Math.abs(xmid - xdr) + Math.abs(ymid - ydr)) > MIN_DIST_BETWEEN_SEGS
&& (Math.abs(xur - xdr) + Math.abs(yur - ydr)) > MIN_DIST_BETWEEN_SEGS)
{
placeName(graphics, xdr, ydr, sdr);
}
/* place lower left */
if ((Math.abs(xmid - xdl) + Math.abs(ymid - ydl)) > MIN_DIST_BETWEEN_SEGS
&& (Math.abs(xul - xdl) + Math.abs(yul - ydl)) > MIN_DIST_BETWEEN_SEGS
&& (Math.abs(xdr - xdl) + Math.abs(ydr - ydl)) > MIN_DIST_BETWEEN_SEGS)
{
placeName(graphics, xdl, ydl, sdl);
}
graphics.setFont(oldf);
graphics.setColor(oldc);
}
}
}
private void placeName(Graphics2D g, int x, int y, WireSegment segment) {
String nname = name;
int seglen = segment.length(), nndim = ndim, nnlength = nlength;
/* shorten string if necessary */
if (seglen <= ndim) {
/* string is surely longer than 4 chars, that was checked before */
int avchars = seglen / NAME_FONT_SIZE;
nname = name.substring(0, avchars - 3).concat(ETC_STRING);
nnlength = nname.length();
nndim = nnlength * NAME_FONT_SIZE;
}
/* draw string */
if (segment.isVertical()) {
x++;
for (int i = 0, yp = y - nndim / 2; i < nnlength; i++, yp += NAME_FONT_SIZE) {
char c = nname.charAt(i);
g.drawString(String.valueOf(c), x, yp);
}
} else {
g.drawString(nname, x - nndim / 3, y - 2);
}
}
}