diff --git a/diylc-library/.classpath b/diylc-library/.classpath new file mode 100644 index 00000000..09ad88fe --- /dev/null +++ b/diylc-library/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/diylc-library/.project b/diylc-library/.project new file mode 100644 index 00000000..d33c5534 --- /dev/null +++ b/diylc-library/.project @@ -0,0 +1,17 @@ + + + diylc-library + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/diylc-library/build.xml b/diylc-library/build.xml new file mode 100644 index 00000000..ec00f750 --- /dev/null +++ b/diylc-library/build.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + Compile with JDK ${java.runtime.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/diylc-library/lib/diylc-core.jar b/diylc-library/lib/diylc-core.jar new file mode 100644 index 00000000..29dd1951 Binary files /dev/null and b/diylc-library/lib/diylc-core.jar differ diff --git a/diylc-library/lib/log4j-1.2.15.jar b/diylc-library/lib/log4j-1.2.15.jar new file mode 100644 index 00000000..c930a6ab Binary files /dev/null and b/diylc-library/lib/log4j-1.2.15.jar differ diff --git a/diylc-library/lib/xstream-1.3.1.jar b/diylc-library/lib/xstream-1.3.1.jar new file mode 100644 index 00000000..4ef4219c Binary files /dev/null and b/diylc-library/lib/xstream-1.3.1.jar differ diff --git a/diylc-library/src/org/diylc/components/boards/AbstractBoard.java b/diylc-library/src/org/diylc/components/boards/AbstractBoard.java new file mode 100644 index 00000000..9c4f89e5 --- /dev/null +++ b/diylc-library/src/org/diylc/components/boards/AbstractBoard.java @@ -0,0 +1,183 @@ +package org.diylc.components.boards; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; + +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +public abstract class AbstractBoard extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Color BOARD_COLOR = Color.decode("#F8EBB3"); + public static Color BORDER_COLOR = BOARD_COLOR.darker(); + public static Color COORDINATE_COLOR = Color.gray.brighter(); + public static float COORDINATE_FONT_SIZE = 9f; + public static Size DEFAULT_WIDTH = new Size(1.5d, SizeUnit.in); + public static Size DEFAULT_HEIGHT = new Size(1.2d, SizeUnit.in); + + protected String value = ""; + protected Point[] controlPoints = new Point[] { + new Point(0, 0), + new Point((int) DEFAULT_WIDTH.convertToPixels(), (int) DEFAULT_HEIGHT.convertToPixels()) }; + protected Point firstPoint = new Point(); + protected Point secondPoint = new Point(); + + protected Color boardColor = BOARD_COLOR; + protected Color borderColor = BORDER_COLOR; + protected Color coordinateColor = COORDINATE_COLOR; + protected Boolean drawCoordinates = true; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(boardColor); + g2d.fillRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y + - firstPoint.y); + g2d.setComposite(oldComposite); + } + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : borderColor); + g2d.drawRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y + - firstPoint.y); + // Do not track any changes that follow because the whole board has been + // tracked so far. + drawingObserver.stopTracking(); + } + + protected void drawCoordinates(Graphics2D g2d, int spacing) { + if (!getDrawCoordinates()) + return; + Point p = new Point(firstPoint); + g2d.setColor(coordinateColor); + g2d.setFont(LABEL_FONT.deriveFont(COORDINATE_FONT_SIZE)); + + int t = 1; + while (p.y < secondPoint.y - spacing) { + p.y += spacing; + super.drawCenteredText(g2d, getCoordinateLabel(t++), p.x + 2, p.y, + HorizontalAlignment.LEFT, VerticalAlignment.CENTER); + } + + p = new Point(firstPoint); + t = 1; + while (p.x < secondPoint.x - spacing) { + p.x += spacing; + super.drawCenteredText(g2d, getCoordinateLabel(t++), p.x, p.y - 2, + HorizontalAlignment.CENTER, VerticalAlignment.TOP); + } + } + + private String getCoordinateLabel(int coordinate) { + String result = ""; + while (coordinate > 0) { + int digit = coordinate % 26; + coordinate /= 26; + if (digit == 0) { + result = 'Z' + result; + coordinate--; + } else { + result = (char) ((int) 'A' + digit - 1) + result; + } + } + return result; + } + + @EditableProperty(name = "Color") + public Color getBoardColor() { + return boardColor; + } + + public void setBoardColor(Color boardColor) { + this.boardColor = boardColor; + } + + @EditableProperty(name = "Coordinate Color") + public Color getCoordinateColor() { + // Null protection for older files + return coordinateColor == null ? COORDINATE_COLOR : coordinateColor; + } + + public void setCoordinateColor(Color coordinateColor) { + this.coordinateColor = coordinateColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "Draw Coordinates") + public boolean getDrawCoordinates() { + // Null protection for older files + return drawCoordinates == null || drawCoordinates; + } + + public void setDrawCoordinates(boolean drawCoordinates) { + this.drawCoordinates = drawCoordinates; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + firstPoint.setLocation(Math.min(controlPoints[0].x, controlPoints[1].x), Math.min( + controlPoints[0].y, controlPoints[1].y)); + secondPoint.setLocation(Math.max(controlPoints[0].x, controlPoints[1].x), Math.max( + controlPoints[0].y, controlPoints[1].y)); + } + + @EditableProperty + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } +} diff --git a/diylc-library/src/org/diylc/components/boards/BlankBoard.java b/diylc-library/src/org/diylc/components/boards/BlankBoard.java new file mode 100644 index 00000000..9c72f0c1 --- /dev/null +++ b/diylc-library/src/org/diylc/components/boards/BlankBoard.java @@ -0,0 +1,27 @@ +package org.diylc.components.boards; + +import java.awt.Graphics2D; + +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; + +@ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board", bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME) +public class BlankBoard extends AbstractBoard { + + private static final long serialVersionUID = 1L; + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BOARD_COLOR); + g2d.fillRect(2, 2, width - 4, height - 4); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(2, 2, width - 4, height - 4); + } + + @Override + public boolean getDrawCoordinates() { + // Override to prevent editing. + return super.getDrawCoordinates(); + } +} diff --git a/diylc-library/src/org/diylc/components/boards/EyeletBoard.java b/diylc-library/src/org/diylc/components/boards/EyeletBoard.java new file mode 100644 index 00000000..5977fa85 --- /dev/null +++ b/diylc-library/src/org/diylc/components/boards/EyeletBoard.java @@ -0,0 +1,116 @@ +package org.diylc.components.boards; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; + +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Eyelet Board", category = "Boards", author = "Branislav Stojkovic", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated board with eyelets", bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME) +public class EyeletBoard extends AbstractBoard { + + private static final long serialVersionUID = 1L; + + public static Color BOARD_COLOR = Color.decode("#CCFFCC"); + public static Color BORDER_COLOR = BOARD_COLOR.darker(); + public static Color EYELET_COLOR = Color.decode("#C3E4ED"); + + public static Size SPACING = new Size(0.5d, SizeUnit.in); + public static Size EYELET_SIZE = new Size(0.2d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(0.1d, SizeUnit.in); + + // private Area copperArea; + protected Size spacing = SPACING; + protected Color eyeletColor = EYELET_COLOR; + + public EyeletBoard() { + super(); + this.boardColor = BOARD_COLOR; + this.borderColor = BORDER_COLOR; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape clip = g2d.getClip(); + if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) + && !clip.contains(secondPoint.x, firstPoint.y)) { + return; + } + super.draw(g2d, componentState, outlineMode, project, drawingObserver); + if (componentState != ComponentState.DRAGGING) { + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + Point p = new Point(firstPoint); + int diameter = getClosestOdd((int) EYELET_SIZE.convertToPixels()); + int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels()); + int spacing = (int) this.spacing.convertToPixels(); + + while (p.y < secondPoint.y - spacing) { + p.x = firstPoint.x; + p.y += spacing; + while (p.x < secondPoint.x - spacing - diameter) { + p.x += spacing; + g2d.setColor(eyeletColor); + g2d.fillOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter); + g2d.setColor(eyeletColor.darker()); + g2d.drawOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, + holeDiameter); + g2d.setColor(eyeletColor.darker()); + g2d.drawOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, + holeDiameter); + } + } + super.drawCoordinates(g2d, spacing); + } + } + + @EditableProperty(name = "Eyelet color") + public Color getEyeletColor() { + return eyeletColor; + } + + public void setEyeletColor(Color padColor) { + this.eyeletColor = padColor; + } + + @EditableProperty + public Size getSpacing() { + return spacing; + } + + public void setSpacing(Size spacing) { + this.spacing = spacing; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BOARD_COLOR); + g2d.fillRect(2, 2, width - 4, height - 4); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(2, 2, width - 4, height - 4); + g2d.setColor(EYELET_COLOR); + g2d.fillOval(width / 4, width / 4, width / 2, width / 2); + g2d.setColor(EYELET_COLOR.darker()); + g2d.drawOval(width / 4, width / 4, width / 2, width / 2); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(width / 2 - 2, width / 2 - 2, 5, 5); + g2d.setColor(EYELET_COLOR.darker()); + g2d.drawOval(width / 2 - 2, width / 2 - 2, 5, 5); + } +} diff --git a/diylc-library/src/org/diylc/components/boards/MarshallPerfBoard.java b/diylc-library/src/org/diylc/components/boards/MarshallPerfBoard.java new file mode 100644 index 00000000..797594b2 --- /dev/null +++ b/diylc-library/src/org/diylc/components/boards/MarshallPerfBoard.java @@ -0,0 +1,110 @@ +package org.diylc.components.boards; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; + +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Marshall Style Perf Board", category = "Boards", author = "Branislav Stojkovic", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated board as found on some Marshall and Trainwreck amps", bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME) +public class MarshallPerfBoard extends AbstractBoard { + + private static final long serialVersionUID = 1L; + + public static Color BOARD_COLOR = Color.decode("#CD8500"); + public static Color BORDER_COLOR = BOARD_COLOR.darker(); + public static Size SPACING = new Size(3 / 8d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(1 / 8d, SizeUnit.in); + + // private Area copperArea; + protected Size spacing = SPACING; + + public MarshallPerfBoard() { + super(); + this.boardColor = BOARD_COLOR; + this.borderColor = BORDER_COLOR; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape clip = g2d.getClip(); + if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) + && !clip.contains(secondPoint.x, firstPoint.y)) { + return; + } + super.draw(g2d, componentState, outlineMode, project, drawingObserver); + if (componentState != ComponentState.DRAGGING) { + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + Point p = new Point(firstPoint); + int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels()); + int spacing = (int) this.spacing.convertToPixels(); + + while (p.y < secondPoint.y - spacing) { + p.x = firstPoint.x; + p.y += spacing; + while (p.x < secondPoint.x - spacing - holeDiameter) { + p.x += spacing; + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, + holeDiameter); + g2d.setColor(borderColor); + g2d.drawOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, + holeDiameter); + } + } + super.drawCoordinates(g2d, spacing); + } + } + + @EditableProperty + public Size getSpacing() { + return spacing; + } + + public void setSpacing(Size spacing) { + this.spacing = spacing; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BOARD_COLOR); + g2d.fillRect(2, 2, width - 4, height - 4); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(2, 2, width - 4, height - 4); + + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(width / 3 - 2, width / 3 - 2, 5, 5); + g2d.setColor(BORDER_COLOR); + g2d.drawOval(width / 3 - 2, width / 3 - 2, 5, 5); + + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(2 * width / 3 - 2, width / 3 - 2, 5, 5); + g2d.setColor(BORDER_COLOR); + g2d.drawOval(2 * width / 3 - 2, width / 3 - 2, 5, 5); + + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(width / 3 - 2, 2 * width / 3 - 2, 5, 5); + g2d.setColor(BORDER_COLOR); + g2d.drawOval(width / 3 - 2, 2 * width / 3 - 2, 5, 5); + + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(2 * width / 3 - 2, 2 * width / 3 - 2, 5, 5); + g2d.setColor(BORDER_COLOR); + g2d.drawOval(2 * width / 3 - 2, 2 * width / 3 - 2, 5, 5); + } +} diff --git a/diylc-library/src/org/diylc/components/boards/PerfBoard.java b/diylc-library/src/org/diylc/components/boards/PerfBoard.java new file mode 100644 index 00000000..c263329e --- /dev/null +++ b/diylc-library/src/org/diylc/components/boards/PerfBoard.java @@ -0,0 +1,108 @@ +package org.diylc.components.boards; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; + +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Perf Board w/ Pads", category = "Boards", author = "Branislav Stojkovic", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated board with solder pads", bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME) +public class PerfBoard extends AbstractBoard { + + private static final long serialVersionUID = 1L; + + public static Color COPPER_COLOR = Color.decode("#DA8A67"); + + public static Size SPACING = new Size(0.1d, SizeUnit.in); + public static Size PAD_SIZE = new Size(0.08d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(0.7d, SizeUnit.mm); + + // private Area copperArea; + protected Size spacing = SPACING; + protected Color padColor = COPPER_COLOR; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape clip = g2d.getClip(); + if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) + && !clip.contains(secondPoint.x, firstPoint.y)) { + return; + } + super.draw(g2d, componentState, outlineMode, project, drawingObserver); + if (componentState != ComponentState.DRAGGING) { + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + Point p = new Point(firstPoint); + int diameter = getClosestOdd((int) PAD_SIZE.convertToPixels()); + int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels()); + int spacing = (int) this.spacing.convertToPixels(); + + while (p.y < secondPoint.y - spacing) { + p.x = firstPoint.x; + p.y += spacing; + while (p.x < secondPoint.x - spacing - diameter) { + p.x += spacing; + g2d.setColor(padColor); + g2d.fillOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter); + g2d.setColor(padColor.darker()); + g2d.drawOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, + holeDiameter); + g2d.setColor(padColor.darker()); + g2d.drawOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, + holeDiameter); + } + } + super.drawCoordinates(g2d, spacing); + } + } + + @EditableProperty(name = "Pad color") + public Color getPadColor() { + return padColor; + } + + public void setPadColor(Color padColor) { + this.padColor = padColor; + } + + @EditableProperty + public Size getSpacing() { + return spacing; + } + + public void setSpacing(Size spacing) { + this.spacing = spacing; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BOARD_COLOR); + g2d.fillRect(2, 2, width - 4, height - 4); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(2, 2, width - 4, height - 4); + g2d.setColor(COPPER_COLOR); + g2d.fillOval(width / 4, width / 4, width / 2, width / 2); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawOval(width / 4, width / 4, width / 2, width / 2); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(width / 2 - 2, width / 2 - 2, 5, 5); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawOval(width / 2 - 2, width / 2 - 2, 5, 5); + } +} diff --git a/diylc-library/src/org/diylc/components/boards/VeroBoard.java b/diylc-library/src/org/diylc/components/boards/VeroBoard.java new file mode 100644 index 00000000..8cd2d7a8 --- /dev/null +++ b/diylc-library/src/org/diylc/components/boards/VeroBoard.java @@ -0,0 +1,144 @@ +package org.diylc.components.boards; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; + +import org.diylc.common.OrientationHV; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Vero Board", category = "Boards", author = "Branislav Stojkovic", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated FR4 board with copper strips connecting all holes in a row", bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME) +public class VeroBoard extends AbstractBoard { + + private static final long serialVersionUID = 1L; + + public static Color STRIP_COLOR = Color.decode("#DA8A67"); + public static Color BORDER_COLOR = BOARD_COLOR.darker(); + + public static Size SPACING = new Size(0.1d, SizeUnit.in); + public static Size STRIP_SIZE = new Size(0.07d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(0.7d, SizeUnit.mm); + + protected Size spacing = SPACING; + protected Color stripColor = STRIP_COLOR; + protected OrientationHV orientation = OrientationHV.HORIZONTAL; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape clip = g2d.getClip(); + if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) + && !clip.contains(secondPoint.x, firstPoint.y)) { + return; + } + super.draw(g2d, componentState, outlineMode, project, drawingObserver); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + Point p = new Point(firstPoint); + int stripSize = getClosestOdd((int) STRIP_SIZE.convertToPixels()); + int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels()); + int spacing = (int) this.spacing.convertToPixels(); + + if (orientation == OrientationHV.HORIZONTAL) { + while (p.y < secondPoint.y - spacing) { + p.x = firstPoint.x; + p.y += spacing; + g2d.setColor(stripColor); + g2d.fillRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing + - p.x, stripSize); + g2d.setColor(stripColor.darker()); + g2d.drawRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing + - p.x, stripSize); + while (p.x < secondPoint.x - spacing - holeSize) { + p.x += spacing; + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize); + g2d.setColor(stripColor.darker()); + g2d.drawOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize); + } + } + } else { + while (p.x < secondPoint.x - spacing) { + p.x += spacing; + p.y = firstPoint.y; + g2d.setColor(stripColor); + g2d.fillRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y + - spacing - p.y); + g2d.setColor(stripColor.darker()); + g2d.drawRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y + - spacing - p.y); + while (p.y < secondPoint.y - spacing - holeSize) { + p.y += spacing; + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize); + g2d.setColor(stripColor.darker()); + g2d.drawOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize); + } + } + } + g2d.setComposite(oldComposite); + super.drawCoordinates(g2d, spacing); + } + } + + @EditableProperty(name = "Strip color") + public Color getStripColor() { + return stripColor; + } + + public void setStripColor(Color padColor) { + this.stripColor = padColor; + } + + @EditableProperty + public Size getSpacing() { + return spacing; + } + + public void setSpacing(Size spacing) { + this.spacing = spacing; + } + + @EditableProperty + public OrientationHV getOrientation() { + return orientation; + } + + public void setOrientation(OrientationHV orientation) { + this.orientation = orientation; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BOARD_COLOR); + g2d.fillRect(2, 2, width - 4, height - 4); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(2, 2, width - 4, height - 4); + g2d.setColor(STRIP_COLOR); + g2d.fillRect(4, width / 4, width - 8, width / 2); + g2d.setColor(STRIP_COLOR.darker()); + g2d.drawRect(4, width / 4, width - 8, width / 2); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(width / 3 - 2, width / 2 - 2, 5, 5); + g2d.fillOval(2 * width / 3 - 2, width / 2 - 2, 5, 5); + g2d.setColor(STRIP_COLOR.darker()); + g2d.drawOval(width / 3 - 2, width / 2 - 2, 5, 5); + g2d.drawOval(2 * width / 3 - 2, width / 2 - 2, 5, 5); + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/AWG.java b/diylc-library/src/org/diylc/components/connectivity/AWG.java new file mode 100644 index 00000000..d1edc701 --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/AWG.java @@ -0,0 +1,15 @@ +package org.diylc.components.connectivity; + +public enum AWG { + + _8, _10, _12, _14, _16, _18, _20, _22, _24, _26, _28, _30; + + @Override + public String toString() { + return "#" + name().replace("_", ""); + } + + public int getValue() { + return Integer.parseInt(name().replace("_", "")); + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/CopperTrace.java b/diylc-library/src/org/diylc/components/connectivity/CopperTrace.java new file mode 100644 index 00000000..52f50f27 --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/CopperTrace.java @@ -0,0 +1,123 @@ +package org.diylc.components.connectivity; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Copper Trace", author = "Branislav Stojkovic", category = "Connectivity", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "Trace", description = "Straight copper trace", zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW) +public class CopperTrace extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size THICKNESS = new Size(1d, SizeUnit.mm); + public static Color COLOR = Color.black; + + private Color leadColor = COLOR; + private Size thickness = THICKNESS; + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3)); + g2d.setColor(COLOR); + g2d.drawLine(1, height - 2, width - 2, 1); + } + + @Override + protected Color getLeadColor(ComponentState componentState) { + return componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : leadColor; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @EditableProperty(name = "Color") + public Color getLeadColor() { + return leadColor; + } + + public void setLeadColor(Color leadColor) { + this.leadColor = leadColor; + } + + @EditableProperty(name = "Width") + public Size getThickness() { + return thickness; + } + + public void setThickness(Size thickness) { + this.thickness = thickness; + } + + @Override + protected int getLeadThickness() { + return (int) getThickness().convertToPixels(); + } + + @Override + protected boolean shouldShadeLeads() { + return false; + } + + public Color getBodyColor() { + return super.getBodyColor(); + } + + @Override + public Color getBorderColor() { + return super.getBorderColor(); + } + + @Override + public Byte getAlpha() { + return super.getAlpha(); + } + + @Override + public Size getLength() { + return super.getLength(); + } + + @Override + public Size getWidth() { + return super.getWidth(); + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } + + @Override + protected Shape getBodyShape() { + return null; + } + + @Override + protected Size getDefaultWidth() { + return null; + } + + @Override + protected Size getDefaultLength() { + return null; + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java b/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java new file mode 100644 index 00000000..282ad685 --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java @@ -0,0 +1,69 @@ +package org.diylc.components.connectivity; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.CubicCurve2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractCurvedComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity", instanceNamePrefix = "Trace", description = "Curved copper trace with two control points", zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW) +public class CurvedTrace extends AbstractCurvedComponent { + + private static final long serialVersionUID = 1L; + + public static Color COLOR = Color.black; + public static Size SIZE = new Size(1d, SizeUnit.mm); + + protected Size size = SIZE; + + @Override + protected Color getDefaultColor() { + return COLOR; + } + + @Override + protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState) { + int thickness = (int) size.convertToPixels(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(thickness)); + Color curveColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color; + g2d.setColor(curveColor); + g2d.draw(curve); + } + + @EditableProperty(name = "Width") + public Size getThickness() { + return size; + } + + public void setThickness(Size size) { + this.size = size; + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } + + @Override + public Byte getAlpha() { + return super.getAlpha(); + } + + @Override + public void setAlpha(Byte alpha) { + super.setAlpha(alpha); + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/Eyelet.java b/diylc-library/src/org/diylc/components/connectivity/Eyelet.java new file mode 100644 index 00000000..4ef45eca --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/Eyelet.java @@ -0,0 +1,140 @@ +package org.diylc.components.connectivity; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; + +import org.diylc.components.AbstractComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Eyelet", category = "Connectivity", author = "Branislav Stojkovic", description = "Eyelet or turret terminal", instanceNamePrefix = "Eyelet", stretchable = false, zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME) +public class Eyelet extends AbstractComponent { + + private static final long serialVersionUID = 1L; + + public static Size SIZE = new Size(0.2d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(0.1d, SizeUnit.in); + public static Color COLOR = Color.decode("#C3E4ED"); + + private Size size = SIZE; + private Size holeSize = HOLE_SIZE; + private Color color = COLOR; + private Point point = new Point(0, 0); + private String value = ""; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int diameter = getClosestOdd((int) size.convertToPixels()); + int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); + g2d.setColor(color); + g2d.fillOval(point.x - diameter / 2, point.y - diameter / 2, diameter, diameter); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color.darker()); + g2d.drawOval(point.x - diameter / 2, point.y - diameter / 2, diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(point.x - holeDiameter / 2, point.y - holeDiameter / 2, holeDiameter, + holeDiameter); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color.darker()); + g2d.drawOval(point.x - holeDiameter / 2, point.y - holeDiameter / 2, holeDiameter, + holeDiameter); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int diameter = getClosestOdd(width / 2); + int holeDiameter = 5; + g2d.setColor(COLOR); + g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(COLOR.darker()); + g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, + holeDiameter); + g2d.setColor(COLOR.darker()); + g2d.drawOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, + holeDiameter); + } + + @EditableProperty + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + @EditableProperty(name = "Hole size") + public Size getHoleSize() { + return holeSize; + } + + public void setHoleSize(Size holeSize) { + this.holeSize = holeSize; + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public Point getControlPoint(int index) { + return point; + } + + @Override + public void setControlPoint(Point point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(name = "Color") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @Override + @EditableProperty + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/HookupWire.java b/diylc-library/src/org/diylc/components/connectivity/HookupWire.java new file mode 100644 index 00000000..1bd235af --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/HookupWire.java @@ -0,0 +1,68 @@ +package org.diylc.components.connectivity; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.CubicCurve2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractCurvedComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity", instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW) +public class HookupWire extends AbstractCurvedComponent { + + private static final long serialVersionUID = 1L; + + public static Color COLOR = Color.green; + public static double INSULATION_THICKNESS_PCT = 0.3; + + protected AWG gauge = AWG._22; + + @Override + protected Color getDefaultColor() { + return COLOR; + } + + @Override + protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, + ComponentState componentState) { + int thickness = (int) (Math.pow(Math.E, -1.12436 - 0.11594 + * gauge.getValue()) + * Constants.PIXELS_PER_INCH * (1 + 2 * INSULATION_THICKNESS_PCT)); + Color curveColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color.darker(); + g2d.setColor(curveColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(thickness)); + g2d.draw(curve); + if (componentState == ComponentState.NORMAL) { + g2d.setColor(color); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke( + thickness - 2)); + g2d.draw(curve); + } + } + + @EditableProperty(name = "AWG") + public AWG getGauge() { + return gauge; + } + + public void setGauge(AWG gauge) { + this.gauge = gauge; + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/Jumper.java b/diylc-library/src/org/diylc/components/connectivity/Jumper.java new file mode 100644 index 00000000..7350179e --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/Jumper.java @@ -0,0 +1,98 @@ +package org.diylc.components.connectivity; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; + +@ComponentDescriptor(name = "Jumper", author = "Branislav Stojkovic", category = "Connectivity", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "J", description = "", zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW) +public class Jumper extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Color COLOR = Color.blue; + + private Color color = COLOR; + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3)); + g2d.setColor(COLOR.darker()); + g2d.drawLine(1, height - 2, width - 2, 1); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(COLOR); + g2d.drawLine(1, height - 2, width - 2, 1); + } + + @Override + public Color getLeadColor(ComponentState componentState) { + return componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public Color getBodyColor() { + return super.getBodyColor(); + } + + @Override + public Color getBorderColor() { + return super.getBorderColor(); + } + + @Override + public Byte getAlpha() { + return super.getAlpha(); + } + + @Override + public Size getLength() { + return super.getLength(); + } + + @Override + public Size getWidth() { + return super.getWidth(); + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } + + @Override + protected Shape getBodyShape() { + return null; + } + + @Override + protected Size getDefaultWidth() { + return null; + } + + @Override + protected Size getDefaultLength() { + return null; + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/Line.java b/diylc-library/src/org/diylc/components/connectivity/Line.java new file mode 100644 index 00000000..001efcd4 --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/Line.java @@ -0,0 +1,106 @@ +package org.diylc.components.connectivity; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; + +@ComponentDescriptor(name = "Line", author = "Branislav Stojkovic", category = "Connectivity", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "LN", description = "", zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW) +public class Line extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Color COLOR = Color.black; + + private Color color = COLOR; + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(COLOR); + g2d.drawLine(1, height - 2, width - 2, 1); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(color); + g2d.drawLine(getControlPoint(0).x, getControlPoint(0).y, getControlPoint(1).x, + getControlPoint(1).y); + } + + @Override + public Color getLeadColor(ComponentState componentState) { + return componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public Color getBodyColor() { + return super.getBodyColor(); + } + + @Override + public Color getBorderColor() { + return super.getBorderColor(); + } + + @Override + public Byte getAlpha() { + return super.getAlpha(); + } + + @Override + public Size getLength() { + return super.getLength(); + } + + @Override + public Size getWidth() { + return super.getWidth(); + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } + + @Override + protected Shape getBodyShape() { + return null; + } + + @Override + protected Size getDefaultWidth() { + return null; + } + + @Override + protected Size getDefaultLength() { + return null; + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/SolderPad.java b/diylc-library/src/org/diylc/components/connectivity/SolderPad.java new file mode 100644 index 00000000..a4cbd0f4 --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/SolderPad.java @@ -0,0 +1,152 @@ +package org.diylc.components.connectivity; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; + +import org.diylc.components.AbstractComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Solder Pad", category = "Connectivity", author = "Branislav Stojkovic", description = "test", instanceNamePrefix = "Pad", stretchable = false, zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.NEVER_SHOW) +public class SolderPad extends AbstractComponent { + + private static final long serialVersionUID = 1L; + + public static Size SIZE = new Size(0.09d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(0.8d, SizeUnit.mm); + public static Color COLOR = Color.black; + + private Size size = SIZE; + private Color color = COLOR; + private Point point = new Point(0, 0); + private Type type = Type.ROUND; + private Size holeSize = HOLE_SIZE; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int diameter = getClosestOdd((int) getSize().convertToPixels()); + int holeDiameter = getClosestOdd((int) getHoleSize().convertToPixels()); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color); + if (type == Type.ROUND) { + g2d.fillOval(point.x - diameter / 2, point.y - diameter / 2, diameter, diameter); + } else { + g2d.fillRect(point.x - diameter / 2, point.y - diameter / 2, diameter, diameter); + } + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(point.x - holeDiameter / 2, point.y - holeDiameter / 2, holeDiameter, + holeDiameter); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int diameter = getClosestOdd(width / 2); + int holeDiameter = 5; + g2d.setColor(COLOR); + g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, + holeDiameter); + } + + @EditableProperty + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + @EditableProperty(name = "Hole") + public Size getHoleSize() { + if (holeSize == null) { + holeSize = HOLE_SIZE; + } + return holeSize; + } + + public void setHoleSize(Size holeSize) { + this.holeSize = holeSize; + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public Point getControlPoint(int index) { + return point; + } + + @Override + public void setControlPoint(Point point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(name = "Color") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @EditableProperty + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } + + static enum Type { + ROUND, SQUARE; + + @Override + public String toString() { + return name().substring(0, 1) + name().substring(1).toLowerCase(); + } + } +} diff --git a/diylc-library/src/org/diylc/components/connectivity/TraceCut.java b/diylc-library/src/org/diylc/components/connectivity/TraceCut.java new file mode 100644 index 00000000..16ab1694 --- /dev/null +++ b/diylc-library/src/org/diylc/components/connectivity/TraceCut.java @@ -0,0 +1,133 @@ +package org.diylc.components.connectivity; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Trace Cut", category = "Connectivity", author = "Branislav Stojkovic", description = "Designates the place where a trace on the vero board needs to be cut", instanceNamePrefix = "Cut", stretchable = false, zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW) +public class TraceCut extends AbstractComponent { + + private static final long serialVersionUID = 1L; + + public static Size SIZE = new Size(0.07d, SizeUnit.in); + public static Color FILL_COLOR = Color.white; + public static Color BORDER_COLOR = Color.red; + public static Color SELECTION_COLOR = Color.blue; + + private Size size = SIZE; + private Color fillColor = FILL_COLOR; + private Color borderColor = BORDER_COLOR; + + protected Point point = new Point(0, 0); + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int size = getClosestOdd((int) this.size.convertToPixels()); + int dotDiameter = size - 6; + g2d.setColor(fillColor); + g2d.fillRect(point.x - size / 2, point.y - size / 2, size, size); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : borderColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.drawRect(point.x - size / 2, point.y - size / 2, size, size); + g2d + .fillOval(point.x - dotDiameter / 2, point.y - dotDiameter / 2, dotDiameter, + dotDiameter); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int size = 16; + int dotDiameter = size / 4 * 2; + g2d.setColor(FILL_COLOR); + g2d.fillRect((width - size) / 2, (height - size) / 2, size, size); + g2d.setColor(BORDER_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.drawRect((width - size) / 2, (height - size) / 2, size, size); + g2d.fillOval((width - dotDiameter) / 2, (height - dotDiameter) / 2, dotDiameter, + dotDiameter); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public Point getControlPoint(int index) { + return point; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point point, int index) { + this.point.setLocation(point); + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } + + @EditableProperty + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + @EditableProperty(name = "Fill") + public Color getFillColor() { + return fillColor; + } + + public void setFillColor(Color fillColor) { + this.fillColor = fillColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @Override + public String getName() { + return super.getName(); + } +} diff --git a/diylc-library/src/org/diylc/components/electromechanical/BatterySnap9V.java b/diylc-library/src/org/diylc/components/electromechanical/BatterySnap9V.java new file mode 100644 index 00000000..461c3c0a --- /dev/null +++ b/diylc-library/src/org/diylc/components/electromechanical/BatterySnap9V.java @@ -0,0 +1,252 @@ +package org.diylc.components.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "9V Battery Snap", category = "Electromechanical", author = "Branislav Stojkovic", description = "", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "BTR") +public class BatterySnap9V extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.darkGray; + private static Size WIDTH = new Size(0.5d, SizeUnit.in); + private static Size LENGTH = new Size(0.75d, SizeUnit.in); + private static Size TERMINAL_DIAMETER = new Size(0.3d, SizeUnit.in); + private static Size TERMINAL_SPACING = new Size(0.5d, SizeUnit.in); + private static Size TERMINAL_BORDER = new Size(0.7d, SizeUnit.mm); + + private String value = ""; + private Point controlPoint = new Point(0, 0); + transient Shape[] body; + private Orientation orientation = Orientation.DEFAULT; + private Color color = BODY_COLOR; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); + g2d.fill(body[0]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : METAL_COLOR); + g2d.fill(body[1]); + g2d.fill(body[2]); + g2d.setComposite(oldComposite); + } + + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color + .brighter(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(body[1]); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(body[2]); + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[3]; + + int x = controlPoint.x; + int y = controlPoint.y; + int width = (int) WIDTH.convertToPixels(); + int length = (int) LENGTH.convertToPixels(); + int totalLength = length + width / 2; + int terminalDiameter = (int) TERMINAL_DIAMETER.convertToPixels(); + int terminalSpacing = (int) TERMINAL_SPACING.convertToPixels(); + int terminalBorder = (int) TERMINAL_BORDER.convertToPixels(); + + Area mainArea = new Area(new Rectangle2D.Double(x, y - width / 2, length, width)); + mainArea.add(new Area(new Ellipse2D.Double(x + length - width / 2, y - width / 2, + width, width))); + + body[0] = mainArea; + + Area terminalArea = new Area(new Ellipse2D.Double(x + (totalLength - terminalSpacing) + / 2 - terminalDiameter / 2, y - terminalDiameter / 2, terminalDiameter, + terminalDiameter)); + + int centerX = x + (totalLength + terminalSpacing) / 2; + int[] terminalX = new int[6]; + int[] terminalY = new int[6]; + + for (int i = 0; i < 6; i++) { + terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) * terminalDiameter / 2); + terminalY[i] = (int) (y + Math.sin(Math.PI / 3 * i) * terminalDiameter / 2); + } + terminalArea.add(new Area(new Polygon(terminalX, terminalY, 6))); + + body[1] = terminalArea; + + terminalArea = new Area(new Ellipse2D.Double(x + (totalLength - terminalSpacing) / 2 + - terminalDiameter / 2 + terminalBorder, y - terminalDiameter / 2 + + terminalBorder, terminalDiameter - 2 * terminalBorder, terminalDiameter - 2 + * terminalBorder)); + + for (int i = 0; i < 6; i++) { + terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) + * (terminalDiameter / 2 + terminalBorder)); + terminalY[i] = (int) (y + Math.sin(Math.PI / 3 * i) + * (terminalDiameter / 2 + terminalBorder)); + } + terminalArea.add(new Area(new Polygon(terminalX, terminalY, 6))); + + body[2] = terminalArea; + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Shape shape : body) { + Area area = (Area) shape; + area.transform(rotation); + } + } + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BODY_COLOR); + g2d.fillOval(width / 4, width / 32, width / 2, width / 2); + g2d.setColor(BODY_COLOR.darker()); + g2d.drawOval(width / 4, width / 32, width / 2, width / 2); + g2d.setColor(BODY_COLOR); + g2d.fillRect(width / 4, width / 32 + width / 4, width / 2, width * 3 / 4 - 2 * width / 32); + g2d.setColor(BODY_COLOR.darker()); + g2d.drawRect(width / 4, width / 32 + width / 4, width / 2, width * 3 / 4 - 2 * width / 32); + g2d.setColor(METAL_COLOR); + g2d.fillOval(width / 4 + 3 * width / 32, width / 32 + 3 * width / 32, width / 2 - 6 * width + / 32, width / 2 - 6 * width / 32); + + int centerX = width / 2; + int centerY = height * 7 / 9; + int terminalDiameter = width / 2 - 4 * width / 32; + int[] terminalX = new int[6]; + int[] terminalY = new int[6]; + + for (int i = 0; i < 6; i++) { + terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) * terminalDiameter / 2); + terminalY[i] = (int) (centerY + Math.sin(Math.PI / 3 * i) * terminalDiameter / 2); + } + g2d.fillPolygon(terminalX, terminalY, 6); + g2d.setColor(METAL_COLOR.darker()); + g2d.drawOval(width / 4 + 3 * width / 32, width / 32 + 3 * width / 32, width / 2 - 6 * width + / 32, width / 2 - 6 * width / 32); + g2d.drawPolygon(terminalX, terminalY, 6); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public Point getControlPoint(int index) { + return controlPoint; + } + + @Override + public void setControlPoint(Point point, int index) { + this.controlPoint.setLocation(point); + // Invalidate the body + body = null; + } + + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + // Invalidate the body + body = null; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } +} diff --git a/diylc-library/src/org/diylc/components/electromechanical/CliffJack1_4.java b/diylc-library/src/org/diylc/components/electromechanical/CliffJack1_4.java new file mode 100644 index 00000000..36621a54 --- /dev/null +++ b/diylc-library/src/org/diylc/components/electromechanical/CliffJack1_4.java @@ -0,0 +1,331 @@ +package org.diylc.components.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.RoundRectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Cliff 1/4\" Jack", category = "Electromechanical", author = "Branislav Stojkovic", description = "Cliff-style closed panel mount 1/4\" phono jack", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J") +public class CliffJack1_4 extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Size SPACING = new Size(0.3d, SizeUnit.in); + private static Size PIN_WIDTH = new Size(0.1d, SizeUnit.in); + private static Size PIN_THICKNESS = new Size(0.02d, SizeUnit.in); + private static Color BODY_COLOR = Color.decode("#666666"); + private static Color NUT_COLOR = Color.decode("#999999"); + private static Color BORDER_COLOR = Color.black; + private static Color LABEL_COLOR = Color.white; + private static Size BODY_WIDTH = new Size(3/4d, SizeUnit.in); + private static Size BODY_LENGTH = new Size(0.9d, SizeUnit.in); + private static Size TAIL_LENGTH = new Size(0.1d, SizeUnit.in); + + private Point[] controlPoints = new Point[] { new Point(0, 0) }; + private JackType type = JackType.MONO; + private Orientation orientation = Orientation.DEFAULT; + transient private Shape[] body; + private String value = ""; + + public CliffJack1_4() { + super(); + updateControlPoints(); + } + + private void updateControlPoints() { + // invalidate body shape + body = null; + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int spacing = (int) SPACING.convertToPixels(); + controlPoints = new Point[type == JackType.STEREO ? 6 : 4]; + + controlPoints[0] = new Point(x, y); + controlPoints[1] = new Point(x, y + 2 * spacing); + controlPoints[2] = new Point(x + 2 * spacing, y); + controlPoints[3] = new Point(x + 2 * spacing, y + 2 * spacing); + if (type == JackType.STEREO) { + controlPoints[4] = new Point(x + spacing, y); + controlPoints[5] = new Point(x + spacing, y + 2 * spacing); + } + + // Apply rotation if necessary + double angle = getAngle(); + if (angle != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y); + for (int i = 1; i < controlPoints.length; i++) { + rotation.transform(controlPoints[i], controlPoints[i]); + } + } + } + + private double getAngle() { + // Apply rotation if necessary + double angle; + switch (orientation) { + case _90: + angle = Math.PI / 2; + break; + case _180: + angle = Math.PI; + break; + case _270: + angle = Math.PI * 3 / 2; + break; + default: + angle = 0; + } + + return angle; + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[5]; + + // Create body. + int bodyLength = (int) BODY_LENGTH.convertToPixels(); + int bodyWidth = (int) BODY_WIDTH.convertToPixels(); + int centerX = (controlPoints[0].x + controlPoints[3].x) / 2; + int centerY = (controlPoints[0].y + controlPoints[3].y) / 2; + body[0] = new Rectangle(centerX - bodyLength / 2, centerY - bodyWidth / 2, bodyLength, + bodyWidth); + + int tailLength = (int) TAIL_LENGTH.convertToPixels(); + body[1] = new RoundRectangle2D.Double(centerX - bodyLength / 2 - tailLength, centerY + - bodyWidth / 4, tailLength * 2, bodyWidth / 2, tailLength, tailLength); + Area tailArea = new Area(body[1]); + tailArea.subtract(new Area(body[0])); + body[1] = tailArea; + + body[2] = new Rectangle(centerX + bodyLength / 2, centerY - bodyWidth / 4, tailLength, + bodyWidth / 2); + + body[3] = new Rectangle(centerX + bodyLength / 2 + tailLength, centerY - bodyWidth / 4, + tailLength, bodyWidth / 2); + tailArea = new Area(body[3]); + int radius = bodyLength / 2 + tailLength * 2; + tailArea.intersect(new Area(new Ellipse2D.Double(centerX - radius, centerY - radius, + radius * 2, radius * 2))); + body[3] = tailArea; + + // Apply rotation if necessary + double angle = getAngle(); + if (angle != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(angle, centerX, + centerY); + for (int i = 0; i < body.length; i++) { + if (body[i] != null) { + Area area = new Area(body[i]); + area.transform(rotation); + body[i] = area; + } + } + } + + // Create pins. + Area pins = new Area(); + + int pinWidth = (int) PIN_WIDTH.convertToPixels(); + int pinThickness = (int) PIN_THICKNESS.convertToPixels(); + for (int i = 0; i < getControlPointCount(); i++) { + Point point = getControlPoint(i); + Rectangle pin; + if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { + pin = new Rectangle(point.x - pinWidth / 2, point.y - pinThickness / 2, + pinWidth, pinThickness); + } else { + pin = new Rectangle(point.x - pinThickness / 2, point.y - pinWidth / 2, + pinThickness, pinWidth); + } + pins.add(new Area(pin)); + } + + body[4] = pins; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + for (int i = 0; i < body.length - 1; i++) { + // Nut is brighter colored. + if (i == body.length - 2) + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : NUT_COLOR); + g2d.fill(body[i]); + } + g2d.setComposite(oldComposite); + } + + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : BORDER_COLOR; + } + + g2d.setColor(finalBorderColor); + for (int i = 0; i < body.length - 1; i++) { + g2d.draw(body[i]); + } + + // Pins are the last piece. + Shape pins = body[body.length - 1]; + g2d.setColor(METAL_COLOR); + g2d.fill(pins); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(pins); + + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + g2d.setFont(LABEL_FONT); + int centerX = (controlPoints[0].x + controlPoints[3].x) / 2; + int centerY = (controlPoints[0].y + controlPoints[3].y) / 2; + drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int bodyWidth = getClosestOdd(width * 3 / 5); + int tailWidth = getClosestOdd(width * 3 / 9); + + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 + / height, 4 * 32 / width, 4 * 32 / width); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 + / height, 4 * 32 / width, 4 * 32 / width); + + g2d.setColor(NUT_COLOR); + g2d.fillRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, + 4 * 32 / width, 4 * 32 / width); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, + 4 * 32 / width, 4 * 32 / width); + + g2d.setColor(BODY_COLOR); + g2d.fillRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + + g2d.setColor(METAL_COLOR); + int pinX1 = getClosestOdd((width - bodyWidth * 3 / 4) / 2); + int pinX2 = getClosestOdd((width + bodyWidth * 3 / 4) / 2) - 1; + g2d.drawLine(pinX1, width * 2 / 8, pinX1, width * 3 / 8); + g2d.drawLine(pinX1, width * 5 / 8, pinX1, width * 6 / 8); + g2d.drawLine(pinX2, width * 2 / 8, pinX2, width * 3 / 8); + g2d.drawLine(pinX2, width * 5 / 8, pinX2, width * 6 / 8); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @EditableProperty + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public JackType getType() { + return type; + } + + public void setType(JackType type) { + this.type = type; + updateControlPoints(); + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + } +} diff --git a/diylc-library/src/org/diylc/components/electromechanical/ClosedJack1_4.java b/diylc-library/src/org/diylc/components/electromechanical/ClosedJack1_4.java new file mode 100644 index 00000000..fc32c2fa --- /dev/null +++ b/diylc-library/src/org/diylc/components/electromechanical/ClosedJack1_4.java @@ -0,0 +1,338 @@ +package org.diylc.components.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Closed 1/4\" Jack", category = "Electromechanical", author = "Branislav Stojkovic", description = "Enclosed panel mount 1/4\" phono jack", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J") +public class ClosedJack1_4 extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Size SPACING = new Size(0.1d, SizeUnit.in); + private static Size LUG_WIDTH = new Size(0.1d, SizeUnit.in); + private static Size LUG_LENGTH = new Size(0.12d, SizeUnit.in); + private static Size LUG_HOLE_SIZE = new Size(1d, SizeUnit.mm); + private static Color BODY_COLOR = Color.decode("#666666"); + private static Color SHAFT_COLOR = Color.decode("#AAAAAA"); + private static Size SHAFT_LENGTH = new Size(0.25d, SizeUnit.in); + private static Size SHAFT_WIDTH = new Size(3d / 8, SizeUnit.in); + private static Color BORDER_COLOR = Color.black; + private static Color LABEL_COLOR = Color.white; + private static Size BODY_WIDTH = new Size(0.65d, SizeUnit.in); + private static Size BODY_LENGTH = new Size(0.8d, SizeUnit.in); + + private Point[] controlPoints = new Point[] { new Point(0, 0) }; + private JackType type = JackType.MONO; + private Orientation orientation = Orientation.DEFAULT; + transient private Shape[] body; + private String value = ""; + + public ClosedJack1_4() { + super(); + updateControlPoints(); + } + + private void updateControlPoints() { + // invalidate body shape + body = null; + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int spacing = (int) SPACING.convertToPixels(); + int bodyLength = (int) BODY_LENGTH.convertToPixels(); + controlPoints = new Point[type == JackType.STEREO ? 3 : 2]; + + controlPoints[0] = new Point(x, y); + controlPoints[1] = new Point(x + bodyLength, y); + if (type == JackType.STEREO) { + controlPoints[2] = new Point(x, y + 2 * spacing); + } + + // Apply rotation if necessary + double angle = getAngle(); + if (angle != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y); + for (int i = 1; i < controlPoints.length; i++) { + rotation.transform(controlPoints[i], controlPoints[i]); + } + } + } + + private double getAngle() { + // Apply rotation if necessary + double angle; + switch (orientation) { + case _90: + angle = Math.PI / 2; + break; + case _180: + angle = Math.PI; + break; + case _270: + angle = Math.PI * 3 / 2; + break; + default: + angle = 0; + } + + return angle; + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[5]; + + // Create body. + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int lugWidth = (int) LUG_WIDTH.convertToPixels(); + int lugLength = (int) LUG_LENGTH.convertToPixels(); + int lugHoleSize = (int) LUG_HOLE_SIZE.convertToPixels(); + int bodyLength = (int) BODY_LENGTH.convertToPixels(); + int bodyWidth = (int) BODY_WIDTH.convertToPixels(); + body[0] = new Area(new Rectangle(x + lugLength, y - bodyWidth / 2, bodyLength, + bodyWidth)); + + int shaftLength = (int) SHAFT_LENGTH.convertToPixels(); + int shaftWidth = (int) SHAFT_WIDTH.convertToPixels(); + Area shaft = new Area(new Rectangle(x + lugLength + bodyLength, y - shaftWidth / 2, + shaftLength, shaftWidth)); + body[1] = shaft; + + double angle = getAngle(); + AffineTransform rotation = null; + if (angle != 0) { + rotation = AffineTransform.getRotateInstance(angle, x, y); + } + + GeneralPath path = new GeneralPath(); + int step = 4; + for (int i = x + lugLength + bodyLength + step; i <= x + lugLength + bodyLength + + shaftLength; i += step) { + Point p = new Point(i, y - shaftWidth / 2 + 1); + if (rotation != null) { + rotation.transform(p, p); + } + path.moveTo(p.x, p.y); + p = new Point(i - step, y + shaftWidth / 2 - 1); + if (rotation != null) { + rotation.transform(p, p); + } + path.lineTo(p.x, p.y); + } + Area pathArea = new Area(path); + pathArea.intersect(shaft); + body[2] = path; + + // Create lugs. + Area lugs = new Area(); + + int spacing = (int) SPACING.convertToPixels(); + Point[] untransformedControlPoints = new Point[type == JackType.STEREO ? 3 : 2]; + + untransformedControlPoints[0] = new Point(x, y); + untransformedControlPoints[1] = new Point(x + bodyLength, y); + if (type == JackType.STEREO) { + untransformedControlPoints[2] = new Point(x, y + 2 * spacing); + } + + for (int i = 0; i < untransformedControlPoints.length; i++) { + Point point = untransformedControlPoints[i]; + Area lug = new Area(new Ellipse2D.Double(point.x - lugWidth / 2, point.y - lugWidth + / 2, lugWidth, lugWidth)); + lug.add(new Area( + new Rectangle(point.x, point.y - lugWidth / 2, lugLength, lugWidth))); + lug.subtract(new Area(new Ellipse2D.Double(point.x - lugHoleSize / 2, point.y + - lugHoleSize / 2, lugHoleSize, lugHoleSize))); + lugs.add(lug); + } + + body[3] = lugs; + + // Rotate everything that's of Area type, e.g. everything but lines. + if (rotation != null) { + for (Shape shape : body) { + if (shape instanceof Area) { + Area area = (Area) shape; + area.transform(rotation); + } + } + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + // Rectangle bounds = body.getBounds(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + g2d.fill(body[0]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : SHAFT_COLOR); + g2d.fill(body[1]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : METAL_COLOR); + g2d.fill(body[3]); + g2d.setComposite(oldComposite); + } + + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : BORDER_COLOR; + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + g2d.draw(body[1]); + if (!outlineMode) { + g2d.setColor(SHAFT_COLOR.darker()); + g2d.fill(body[2]); + g2d.draw(body[2]); + } + + // Pins are the last piece. + g2d.setColor(outlineMode ? finalBorderColor : METAL_COLOR.darker()); + g2d.draw(body[3]); + + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + g2d.setFont(LABEL_FONT); + Rectangle bounds = body[0].getBounds(); + int centerX = bounds.x + bounds.width / 2; + int centerY = bounds.y + bounds.height / 2; + drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int bodyWidth = getClosestOdd(width * 3 / 5); + int tailWidth = getClosestOdd(width * 3 / 10); + + g2d.setColor(SHAFT_COLOR); + g2d.fillRect((width - tailWidth) / 2, 1, tailWidth, height / 2); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((width - tailWidth) / 2, 1, tailWidth, height / 2); + + g2d.setColor(BODY_COLOR); + g2d.fillRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + + g2d.setColor(METAL_COLOR); + + g2d.fillRect(width * 7 / 16, height * 6 / 7 + 1, width / 8, height / 7 - 1); + g2d.fillRect(width * 7 / 16, height / 7 + 2, width / 8, height / 7 - 1); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @EditableProperty + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public JackType getType() { + return type; + } + + public void setType(JackType type) { + this.type = type; + updateControlPoints(); + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + } +} diff --git a/diylc-library/src/org/diylc/components/electromechanical/DCPolarity.java b/diylc-library/src/org/diylc/components/electromechanical/DCPolarity.java new file mode 100644 index 00000000..0f69e82b --- /dev/null +++ b/diylc-library/src/org/diylc/components/electromechanical/DCPolarity.java @@ -0,0 +1,17 @@ +package org.diylc.components.electromechanical; + +public enum DCPolarity { + + NONE("None"), CENTER_POSITIVE("Center Positive"), CENTER_NEGATIVE("Center Negative"); + + private String title; + + private DCPolarity(String title) { + this.title = title; + } + + @Override + public String toString() { + return title; + } +} diff --git a/diylc-library/src/org/diylc/components/electromechanical/JackType.java b/diylc-library/src/org/diylc/components/electromechanical/JackType.java new file mode 100644 index 00000000..babf975a --- /dev/null +++ b/diylc-library/src/org/diylc/components/electromechanical/JackType.java @@ -0,0 +1,11 @@ +package org.diylc.components.electromechanical; + +public enum JackType { + + MONO, STEREO; + + @Override + public String toString() { + return name().substring(0, 1) + name().substring(1).toLowerCase(); + } +} diff --git a/diylc-library/src/org/diylc/components/electromechanical/MiniToggleSwitch.java b/diylc-library/src/org/diylc/components/electromechanical/MiniToggleSwitch.java new file mode 100644 index 00000000..1efdac51 --- /dev/null +++ b/diylc-library/src/org/diylc/components/electromechanical/MiniToggleSwitch.java @@ -0,0 +1,271 @@ +package org.diylc.components.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; +import java.awt.geom.RoundRectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Mini Toggle Switch", category = "Electromechanical", author = "Branislav Stojkovic", description = "Panel mounted mini toggle switch", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "SW") +public class MiniToggleSwitch extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Size SPACING = new Size(0.2d, SizeUnit.in); + private static Size MARGIN = new Size(0.08d, SizeUnit.in); + private static Size CIRCLE_SIZE = new Size(0.09d, SizeUnit.in); + private static Size LUG_WIDTH = new Size(0.060d, SizeUnit.in); + private static Size LUG_THICKNESS = new Size(0.02d, SizeUnit.in); + + private static Color BODY_COLOR = Color.decode("#3299CC"); + private static Color BORDER_COLOR = BODY_COLOR.darker(); + private static Color CIRCLE_COLOR = Color.decode("#FFFFAA"); + + protected Point[] controlPoints = new Point[] { new Point(0, 0) }; + transient protected RoundRectangle2D body; + protected String name; + protected ToggleSwitchType switchType = ToggleSwitchType.DPDT; + + public MiniToggleSwitch() { + super(); + updateControlPoints(); + } + + private void updateControlPoints() { + Point firstPoint = controlPoints[0]; + int spacing = (int) SPACING.convertToPixels(); + switch (switchType) { + case SPST: + controlPoints = new Point[] { firstPoint, + new Point(firstPoint.x, firstPoint.y + spacing) }; + break; + case SPDT: + controlPoints = new Point[] { firstPoint, + new Point(firstPoint.x, firstPoint.y + spacing), + new Point(firstPoint.x, firstPoint.y + 2 * spacing) }; + break; + case DPDT: + controlPoints = new Point[] { firstPoint, + new Point(firstPoint.x, firstPoint.y + spacing), + new Point(firstPoint.x, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + spacing, firstPoint.y), + new Point(firstPoint.x + spacing, firstPoint.y + spacing), + new Point(firstPoint.x + spacing, firstPoint.y + 2 * spacing) }; + break; + case _3PDT: + controlPoints = new Point[] { firstPoint, + new Point(firstPoint.x, firstPoint.y + spacing), + new Point(firstPoint.x, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + spacing, firstPoint.y), + new Point(firstPoint.x + spacing, firstPoint.y + spacing), + new Point(firstPoint.x + spacing, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + 2 * spacing, firstPoint.y), + new Point(firstPoint.x + 2 * spacing, firstPoint.y + spacing), + new Point(firstPoint.x + 2 * spacing, firstPoint.y + 2 * spacing) }; + break; + case _4PDT: + controlPoints = new Point[] { firstPoint, + new Point(firstPoint.x, firstPoint.y + spacing), + new Point(firstPoint.x, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + spacing, firstPoint.y), + new Point(firstPoint.x + spacing, firstPoint.y + spacing), + new Point(firstPoint.x + spacing, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + 2 * spacing, firstPoint.y), + new Point(firstPoint.x + 2 * spacing, firstPoint.y + spacing), + new Point(firstPoint.x + 2 * spacing, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + 3 * spacing, firstPoint.y), + new Point(firstPoint.x + 3 * spacing, firstPoint.y + spacing), + new Point(firstPoint.x + 3 * spacing, firstPoint.y + 2 * spacing) }; + break; + case _5PDT: + controlPoints = new Point[] { firstPoint, + new Point(firstPoint.x, firstPoint.y + spacing), + new Point(firstPoint.x, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + spacing, firstPoint.y), + new Point(firstPoint.x + spacing, firstPoint.y + spacing), + new Point(firstPoint.x + spacing, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + 2 * spacing, firstPoint.y), + new Point(firstPoint.x + 2 * spacing, firstPoint.y + spacing), + new Point(firstPoint.x + 2 * spacing, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + 3 * spacing, firstPoint.y), + new Point(firstPoint.x + 3 * spacing, firstPoint.y + spacing), + new Point(firstPoint.x + 3 * spacing, firstPoint.y + 2 * spacing), + new Point(firstPoint.x + 4 * spacing, firstPoint.y), + new Point(firstPoint.x + 4 * spacing, firstPoint.y + spacing), + new Point(firstPoint.x + 4 * spacing, firstPoint.y + 2 * spacing) }; + break; + } + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + // Reset body shape. + body = null; + } + + @EditableProperty + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @EditableProperty(name = "Type") + @Override + public ToggleSwitchType getValue() { + return switchType; + } + + @Override + public void setValue(ToggleSwitchType value) { + this.switchType = value; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Shape body = getBody(); + // Draw body if available. + if (body != null) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + g2d.fill(body); + g2d.setComposite(oldComposite); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : BORDER_COLOR; + } + g2d.setColor(finalBorderColor); + g2d.draw(body); + } + // Do not track these changes because the whole switch has been tracked + // so far. + drawingObserver.stopTracking(); + // Draw lugs. + int circleDiameter = getClosestOdd((int) CIRCLE_SIZE.convertToPixels()); + int lugWidth = getClosestOdd((int) LUG_WIDTH.convertToPixels()); + int lugHeight = getClosestOdd((int) LUG_THICKNESS.convertToPixels()); + for (Point p : controlPoints) { + if (!outlineMode) { + g2d.setColor(CIRCLE_COLOR); + g2d.fillOval(p.x - circleDiameter / 2, p.y - circleDiameter / 2, circleDiameter, + circleDiameter); + } + g2d.setColor(METAL_COLOR); + g2d.fillRect(p.x - lugWidth / 2, p.y - lugHeight / 2, lugWidth, lugHeight); + } + } + + public RoundRectangle2D getBody() { + if (body == null) { + Point firstPoint = controlPoints[0]; + int margin = (int) MARGIN.convertToPixels(); + int spacing = (int) SPACING.convertToPixels(); + switch (switchType) { + case SPST: + body = new RoundRectangle2D.Double(firstPoint.x - margin, firstPoint.y - margin, + 2 * margin, 2 * margin + spacing, margin, margin); + break; + case SPDT: + body = new RoundRectangle2D.Double(firstPoint.x - margin, firstPoint.y - margin, + 2 * margin, 2 * margin + 2 * spacing, margin, margin); + break; + case DPDT: + body = new RoundRectangle2D.Double(firstPoint.x - margin, firstPoint.y - margin, 2 + * margin + spacing, 2 * margin + 2 * spacing, margin, margin); + break; + case _3PDT: + body = new RoundRectangle2D.Double(firstPoint.x - margin, firstPoint.y - margin, 2 + * margin + 2 * spacing, 2 * margin + 2 * spacing, margin, margin); + break; + case _4PDT: + body = new RoundRectangle2D.Double(firstPoint.x - margin, firstPoint.y - margin, 2 + * margin + 3 * spacing, 2 * margin + 2 * spacing, margin, margin); + break; + case _5PDT: + body = new RoundRectangle2D.Double(firstPoint.x - margin, firstPoint.y - margin, 2 + * margin + 4 * spacing, 2 * margin + 2 * spacing, margin, margin); + break; + } + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int circleSize = 5 * width / 32; + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect(width / 4, 1, width / 2, height - 2, circleSize, circleSize); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(width / 4, 1, width / 2, height - 2, circleSize, circleSize); + for (int i = 1; i <= 3; i++) { + g2d.setColor(CIRCLE_COLOR); + g2d.fillOval(width / 2 - circleSize / 2, i * height / 4 - 3, circleSize, circleSize); + g2d.setColor(METAL_COLOR); + g2d.drawLine(width / 2 - circleSize / 2 + 1, i * height / 4 - 1, width / 2 + circleSize + / 2 - 1, i * height / 4 - 1); + } + } +} diff --git a/diylc-library/src/org/diylc/components/electromechanical/PlasticDCJack.java b/diylc-library/src/org/diylc/components/electromechanical/PlasticDCJack.java new file mode 100644 index 00000000..9cc1944c --- /dev/null +++ b/diylc-library/src/org/diylc/components/electromechanical/PlasticDCJack.java @@ -0,0 +1,247 @@ +package org.diylc.components.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Plastic DC Jack", category = "Electromechanical", author = "Branislav Stojkovic", description = "Panel mount plastic DC jack", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J") +public class PlasticDCJack extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Size LUG_WIDTH = new Size(0.08d, SizeUnit.in); + private static Size LUG_THICKNESS = new Size(0.02d, SizeUnit.in); + private static Size SPACING = new Size(0.1d, SizeUnit.in); + private static Size DIAMETER = new Size(0.5d, SizeUnit.in); + private static Color BODY_COLOR = Color.decode("#666666"); + private static Color PHENOLIC_COLOR = Color.decode("#CD8500"); + private static Color BORDER_COLOR = Color.black; + private static Color MARKING_COLOR = Color.lightGray; + + private Point[] controlPoints = new Point[] { new Point(0, 0), new Point(0, 0), new Point(0, 0) }; + private String value = ""; + private DCPolarity polarity = DCPolarity.CENTER_NEGATIVE; + transient private Shape[] body; + + public PlasticDCJack() { + updateControlPoints(); + } + + private void updateControlPoints() { + // invalidate body shape + body = null; + + int x = controlPoints[0].x; + int y = controlPoints[0].y; + + int spacing = (int) SPACING.convertToPixels(); + controlPoints[1] = new Point(x + spacing, y + spacing); + controlPoints[2] = new Point(x - spacing, y + spacing * 2); + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[4]; + + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int spacing = (int) SPACING.convertToPixels(); + int diameter = getClosestOdd(DIAMETER.convertToPixels()); + body[0] = new Ellipse2D.Double(x - diameter / 2, y + spacing - diameter / 2, diameter, + diameter); + + int rectWidth = (int) (diameter / Math.sqrt(2)) - 2; + body[1] = new Rectangle(x - rectWidth / 2, y + spacing - rectWidth / 2, rectWidth, + rectWidth); + + int lugWidth = getClosestOdd(LUG_WIDTH.convertToPixels()); + int lugThickness = getClosestOdd(LUG_THICKNESS.convertToPixels()); + + Point groundPoint = controlPoints[controlPoints.length - 1]; + Area groundLug = new Area(new Ellipse2D.Double(groundPoint.x + spacing - lugWidth / 2, + groundPoint.y - lugWidth / 2, lugWidth, lugWidth)); + groundLug.add(new Area(new Rectangle(groundPoint.x, groundPoint.y - lugWidth / 2, + spacing, lugWidth))); + groundLug.subtract(new Area(new Ellipse2D.Double( + groundPoint.x + spacing - lugWidth / 6, groundPoint.y - lugWidth / 6, + lugWidth / 3, lugWidth / 3))); + body[2] = groundLug; + + Area lugArea = new Area(); + for (int i = 0; i < controlPoints.length; i++) { + Point point = controlPoints[i]; + if (i == getControlPointCount() - 1) { + lugArea.add(new Area(new Rectangle(point.x - lugThickness / 2, point.y + - lugWidth / 2, lugThickness, lugWidth))); + } else { + lugArea.add(new Area(new Rectangle(point.x - lugWidth / 2, point.y + - lugThickness / 2, lugWidth, lugThickness))); + } + } + body[3] = lugArea; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + g2d.fill(body[0]); + if (!outlineMode) { + g2d.setColor(PHENOLIC_COLOR); + g2d.fill(body[1]); + } + g2d.setComposite(oldComposite); + } + + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : BORDER_COLOR; + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + if (!outlineMode) { + g2d.setColor(PHENOLIC_COLOR.darker()); + g2d.draw(body[1]); + + g2d.setColor(METAL_COLOR); + g2d.fill(body[2]); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(body[2]); + } + + g2d.setColor(METAL_COLOR); + g2d.fill(body[3]); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(body[3]); + + if (!outlineMode && getPolarity() != DCPolarity.NONE) { + int spacing = (int) SPACING.convertToPixels(); + g2d.setColor(MARKING_COLOR); + g2d.setFont(LABEL_FONT.deriveFont(12f)); + drawCenteredText(g2d, getPolarity() == DCPolarity.CENTER_NEGATIVE ? "+" : "-", + controlPoints[0].x, controlPoints[0].y - spacing * 7 / 16, + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + drawCenteredText(g2d, getPolarity() == DCPolarity.CENTER_NEGATIVE ? "_" : "+", + controlPoints[2].x, controlPoints[2].y - spacing * 3 / 4, + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 2 * 32 / width; + int diameter = getClosestOdd(width - margin); + g2d.setColor(BODY_COLOR); + g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(BORDER_COLOR); + g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + int rectWidth = getClosestOdd(((width - 2 * margin) / Math.sqrt(2)) - margin / 2); + g2d.setColor(PHENOLIC_COLOR); + g2d.fillRect((width - rectWidth) / 2, (height - rectWidth) / 2, rectWidth, rectWidth); + g2d.setColor(PHENOLIC_COLOR.darker()); + g2d.drawRect((width - rectWidth) / 2, (height - rectWidth) / 2, rectWidth, rectWidth); + int lugWidth = 4 * 32 / width; + g2d.setColor(METAL_COLOR); + g2d.drawLine((width - lugWidth) / 2, height / 3, (width + lugWidth) / 2, height / 3); + g2d + .drawLine(width * 2 / 3, (height - lugWidth) / 2, width * 2 / 3, + (height + lugWidth) / 2); + g2d.fillOval((width - lugWidth) / 2, height * 2 / 3 - lugWidth / 2, lugWidth, lugWidth); + g2d.fillRect(width / 2 - lugWidth * 3 / 2, height * 2 / 3 - lugWidth / 2, lugWidth * 3 / 2, + lugWidth); + g2d.setColor(PHENOLIC_COLOR); + g2d.fillOval((width - margin) / 2, height * 2 / 3 - margin / 2, margin, margin); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + this.body = null; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @EditableProperty + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public DCPolarity getPolarity() { + if (polarity == null) { + polarity = DCPolarity.CENTER_NEGATIVE; + } + return polarity; + } + + public void setPolarity(DCPolarity polarity) { + this.polarity = polarity; + } +} diff --git a/diylc-library/src/org/diylc/components/electromechanical/ToggleSwitchType.java b/diylc-library/src/org/diylc/components/electromechanical/ToggleSwitchType.java new file mode 100644 index 00000000..6a9e0c2e --- /dev/null +++ b/diylc-library/src/org/diylc/components/electromechanical/ToggleSwitchType.java @@ -0,0 +1,11 @@ +package org.diylc.components.electromechanical; + +public enum ToggleSwitchType { + + SPST, SPDT, DPDT, _3PDT, _4PDT, _5PDT; + + @Override + public String toString() { + return name().replace("_", ""); + } +} diff --git a/diylc-library/src/org/diylc/components/guitar/HumbuckerPickup.java b/diylc-library/src/org/diylc/components/guitar/HumbuckerPickup.java new file mode 100644 index 00000000..41c91200 --- /dev/null +++ b/diylc-library/src/org/diylc/components/guitar/HumbuckerPickup.java @@ -0,0 +1,268 @@ +package org.diylc.components.guitar; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.RoundRectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Humbucker Pickup", category = "Guitar", author = "Branislav Stojkovic", description = "PAF-style humbucker guitar pickup", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP") +public class HumbuckerPickup extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.lightGray; + private static Color POINT_COLOR = Color.darkGray; + private static Size WIDTH = new Size(36.5d, SizeUnit.mm); + private static Size LENGTH = new Size(68.58d, SizeUnit.mm); + private static Size LIP_WIDTH = new Size(12.7d, SizeUnit.mm); + private static Size LIP_LENGTH = new Size(7.9d, SizeUnit.mm); + private static Size EDGE_RADIUS = new Size(4d, SizeUnit.mm); + private static Size POINT_MARGIN = new Size(5d, SizeUnit.mm); + private static Size POINT_SIZE = new Size(3d, SizeUnit.mm); + private static Size LIP_HOLE_SIZE = new Size(1.5d, SizeUnit.mm); + private static Size POLE_SIZE = new Size(3d, SizeUnit.mm); + private static Size POLE_SPACING = new Size(10.1d, SizeUnit.mm); + private static Size COIL_SPACING = new Size(18d, SizeUnit.mm); + + private String value = ""; + private Point controlPoint = new Point(0, 0); + transient Shape[] body; + private Orientation orientation = Orientation.DEFAULT; + private Color color = BODY_COLOR; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); + g2d.fill(body[0]); + g2d.fill(body[1]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : POINT_COLOR); + g2d.fill(body[2]); + g2d.setComposite(oldComposite); + } + + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + g2d.draw(body[1]); + if (!outlineMode) { + g2d.setColor(color.darker()); + g2d.draw(body[3]); + } + + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + g2d.setFont(LABEL_FONT); + Rectangle bounds = body[0].getBounds(); + drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[4]; + + int x = controlPoint.x; + int y = controlPoint.y; + int width = (int) WIDTH.convertToPixels(); + int length = (int) LENGTH.convertToPixels(); + int lipWidth = (int) LIP_WIDTH.convertToPixels(); + int lipLength = (int) LIP_LENGTH.convertToPixels(); + int edgeRadius = (int) EDGE_RADIUS.convertToPixels(); + int pointMargin = (int) POINT_MARGIN.convertToPixels(); + int pointSize = getClosestOdd(POINT_SIZE.convertToPixels()); + int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels()); + + body[0] = new Area(new RoundRectangle2D.Double(x + pointMargin - length, y + - pointMargin, length, width, edgeRadius, edgeRadius)); + body[1] = new Area(new RoundRectangle2D.Double(x + pointMargin - length - lipLength, y + - pointMargin + width / 2 - lipWidth / 2, length + 2 * lipLength, lipWidth, + edgeRadius / 2, edgeRadius / 2)); + Area lipArea = new Area(body[1]); + lipArea.subtract(new Area(body[0])); + lipArea.subtract(new Area(new Ellipse2D.Double( + x + pointMargin - length - lipLength / 2, y - pointMargin + width / 2 + - lipHoleSize / 2, lipHoleSize, lipHoleSize))); + lipArea.subtract(new Area(new Ellipse2D.Double(x + pointMargin + lipLength / 2, y + - pointMargin + width / 2 - lipHoleSize / 2, lipHoleSize, lipHoleSize))); + body[1] = lipArea; + body[2] = new Area(new Ellipse2D.Double(x - pointSize / 2, y - pointSize / 2, + pointSize, pointSize)); + + int poleSize = (int) POLE_SIZE.convertToPixels(); + int poleSpacing = (int) POLE_SPACING.convertToPixels(); + int coilSpacing = (int) COIL_SPACING.convertToPixels(); + int coilMargin = (width - coilSpacing) / 2; + int poleMargin = (length - poleSpacing * 5) / 2; + Area poleArea = new Area(); + for (int i = 0; i < 6; i++) { + Ellipse2D pole = new Ellipse2D.Double(x + pointMargin - length + poleMargin + i + * poleSpacing - poleSize / 2, y - pointMargin + coilMargin - poleSize / 2, + poleSize, poleSize); + poleArea.add(new Area(pole)); + pole = new Ellipse2D.Double(x + pointMargin - length + poleMargin + i * poleSpacing + - poleSize / 2, y - pointMargin + width - coilMargin - poleSize / 2, + poleSize, poleSize); + poleArea.add(new Area(pole)); + } + body[3] = poleArea; + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Shape shape : body) { + Area area = (Area) shape; + area.transform(rotation); + } + } + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int baseWidth = 16 * width / 32; + int baseLength = 27 * width / 32; + + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - baseWidth / 4) / 2, 0, baseWidth / 4, height - 1, + 2 * width / 32, 2 * width / 32); + g2d.setColor(BODY_COLOR.darker()); + g2d.drawRoundRect((width - baseWidth / 4) / 2, 0, baseWidth / 4, height - 1, + 2 * width / 32, 2 * width / 32); + + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - baseWidth) / 2, (height - baseLength) / 2, baseWidth, + baseLength, 4 * width / 32, 4 * width / 32); + g2d.setColor(BODY_COLOR.darker()); + g2d.drawRoundRect((width - baseWidth) / 2, (height - baseLength) / 2, baseWidth, + baseLength, 4 * width / 32, 4 * width / 32); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public Point getControlPoint(int index) { + return controlPoint; + } + + @Override + public void setControlPoint(Point point, int index) { + this.controlPoint.setLocation(point); + // Invalidate the body + body = null; + } + + @EditableProperty(name = "Model") + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + // Invalidate the body + body = null; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } +} diff --git a/diylc-library/src/org/diylc/components/guitar/LeverSwitch.java b/diylc-library/src/org/diylc/components/guitar/LeverSwitch.java new file mode 100644 index 00000000..fe5e368e --- /dev/null +++ b/diylc-library/src/org/diylc/components/guitar/LeverSwitch.java @@ -0,0 +1,370 @@ +package org.diylc.components.guitar; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Lever Switch", category = "Guitar", author = "Branislav Stojkovic", description = "Strat-style lever switch", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "SW") +public class LeverSwitch extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Color BASE_COLOR = Color.lightGray; + private static Color WAFER_COLOR = Color.decode("#CD8500"); + + private static Size BASE_WIDTH = new Size(10d, SizeUnit.mm); + private static Size BASE_LENGTH = new Size(47.5d, SizeUnit.mm); + private static Size WAFER_LENGTH = new Size(40d, SizeUnit.mm); + private static Size WAFER_SPACING = new Size(7.62d, SizeUnit.mm); + private static Size WAFER_THICKNESS = new Size(1.27d, SizeUnit.mm); + private static Size HOLE_SIZE = new Size(2d, SizeUnit.mm); + private static Size HOLE_SPACING = new Size(41.2d, SizeUnit.mm); + private static Size TERMINAL_WIDTH = new Size(2d, SizeUnit.mm); + private static Size TERMINAL_LENGTH = new Size(0.1d, SizeUnit.in); + private static Size TERMINAL_SPACING = new Size(0.1d, SizeUnit.in); + + private String value = ""; + private Point[] controlPoints = new Point[] { new Point(0, 0) }; + transient Shape[] body; + private Orientation orientation = Orientation.DEFAULT; + private LeverSwitchType type = LeverSwitchType.DP3T; + + public LeverSwitch() { + super(); + updateControlPoints(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); + g2d.fill(body[0]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : WAFER_COLOR); + g2d.fill(body[1]); + g2d.setComposite(oldComposite); + } + + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : BASE_COLOR + .darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : WAFER_COLOR + .darker(); + } + + g2d.draw(body[1]); + + g2d.setColor(METAL_COLOR); + g2d.fill(body[2]); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(body[2]); + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[3]; + + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int baseWidth = (int) BASE_WIDTH.convertToPixels(); + int baseLength = (int) BASE_LENGTH.convertToPixels(); + int holeSize = getClosestOdd(HOLE_SIZE.convertToPixels()); + int holeSpacing = (int) HOLE_SPACING.convertToPixels(); + int waferLength = (int) WAFER_LENGTH.convertToPixels(); + int waferSpacing = (int) WAFER_SPACING.convertToPixels(); + int waferThickness = (int) WAFER_THICKNESS.convertToPixels(); + int terminalSpacing = (int) TERMINAL_SPACING.convertToPixels(); + int terminalLength = getClosestOdd(TERMINAL_LENGTH.convertToPixels()); + int terminalWidth = getClosestOdd(TERMINAL_WIDTH.convertToPixels()); + + int baseX = x - terminalLength / 2 - waferSpacing; + int baseY = y + - (baseLength - terminalSpacing * (type == LeverSwitchType.DP3T ? 7 : 12)) / 2; + Area baseArea = new Area(new Rectangle2D.Double(baseX, baseY, baseWidth, baseLength)); + baseArea.subtract(new Area(new Ellipse2D.Double(baseX + baseWidth / 2 - holeSize / 2, + baseY + (baseLength - holeSpacing) / 2 - holeSize / 2, holeSize, holeSize))); + baseArea.subtract(new Area(new Ellipse2D.Double(baseX + baseWidth / 2 - holeSize / 2, + baseY + (baseLength - holeSpacing) / 2 - holeSize / 2 + holeSpacing, holeSize, + holeSize))); + body[0] = baseArea; + + Area waferArea = new Area(new Rectangle2D.Double(x - terminalLength / 2 + - waferThickness / 2, + y - (waferLength - terminalSpacing * (type == LeverSwitchType.DP3T ? 7 : 12)) + / 2, waferThickness, waferLength)); + + if (type == LeverSwitchType._4P5T) { + waferArea.add(new Area(new Rectangle2D.Double(x - terminalLength / 2 + - waferThickness / 2 + waferSpacing, y + - (waferLength - terminalSpacing * (type == LeverSwitchType.DP3T ? 7 : 12)) + / 2, waferThickness, waferLength))); + } + body[1] = waferArea; + + double theta = 0; + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + } + + Area terminalArea = new Area(); + for (Point point : controlPoints) { + Area terminal = new Area(new RoundRectangle2D.Double(point.x - terminalLength / 2, + point.y - terminalWidth / 2, terminalLength, terminalWidth, + terminalWidth / 2, terminalWidth / 2)); + terminal.subtract(new Area( + new RoundRectangle2D.Double(point.x - terminalLength / 4, point.y + - terminalWidth / 4, terminalLength / 2, terminalWidth / 2, + terminalWidth / 2, terminalWidth / 2))); + // Rotate the terminal if needed + if (theta != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(theta, point.x, + point.y); + terminal.transform(rotation); + } + terminalArea.add(terminal); + } + body[2] = terminalArea; + + // Rotate if needed + if (theta != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + // Skip the last one because it's already rotated + for (int i = 0; i < body.length - 1; i++) { + Shape shape = body[i]; + Area area = (Area) shape; + area.transform(rotation); + } + } + } + return body; + } + + private void updateControlPoints() { + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int waferSpacing = (int) WAFER_SPACING.convertToPixels(); + int terminalSpacing = (int) TERMINAL_SPACING.convertToPixels(); + int terminalLength = (int) TERMINAL_LENGTH.convertToPixels(); + + switch (type) { + case DP3T: + controlPoints = new Point[8]; + for (int i = 0; i < 8; i++) { + controlPoints[i] = new Point(x - (i % 2 == 1 ? terminalLength : 0), y + i + * terminalSpacing); + } + break; + case DP5T: + controlPoints = new Point[12]; + for (int i = 0; i < 12; i++) { + controlPoints[i] = new Point(x, y + i * terminalSpacing + + (i >= 6 ? terminalSpacing : 0)); + } + break; + case _4P5T: + controlPoints = new Point[24]; + for (int i = 0; i < 12; i++) { + controlPoints[i] = new Point(x, y + i * terminalSpacing + + (i >= 6 ? terminalSpacing : 0)); + controlPoints[i + 12] = new Point(x + waferSpacing, y + i * terminalSpacing + + (i >= 6 ? terminalSpacing : 0)); + } + break; + } + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Point point : controlPoints) { + rotation.transform(point, point); + } + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setClip(width / 32, width / 32, width, height); + g2d.setColor(BASE_COLOR); + g2d.fillRect(0, 0, width * 2 / 3, height); + g2d.setColor(BASE_COLOR.darker()); + g2d.drawRect(0, 0, width * 2 / 3, height); + g2d.setColor(WAFER_COLOR); + g2d.fillRect(width / 8 * 3, 0, width / 8, height); + g2d.setColor(WAFER_COLOR.darker()); + g2d.drawRect(width / 8 * 3, 0, width / 8, height); + Area terminals = new Area(); + int terminalLength = getClosestOdd(11 * width / 32); + int terminalWidth = getClosestOdd(7 * width / 32); + Area terminal = new Area(new RoundRectangle2D.Double(width / 16 * 7, 4 * width / 32, + terminalLength, terminalWidth, terminalWidth / 2, terminalWidth / 2)); + terminal.subtract(new Area(new RoundRectangle2D.Double(width / 16 * 7 + terminalLength / 4 + + 1, 4 * width / 32 + terminalWidth / 4 + 1, terminalLength / 2, terminalWidth / 2, + terminalWidth / 4, terminalWidth / 4))); + terminals.add(terminal); + terminal = new Area(terminal); + terminal.transform(AffineTransform.getTranslateInstance(-terminalLength, terminalWidth + 2 + * width / 32)); + terminals.add(terminal); + terminal = new Area(terminal); + terminal.transform(AffineTransform.getTranslateInstance(terminalLength, terminalWidth + 2 + * width / 32)); + terminals.add(terminal); + g2d.setColor(METAL_COLOR); + g2d.fill(terminals); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(terminals); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point point, int index) { + this.controlPoints[index].setLocation(point); + // Invalidate the body + body = null; + } + + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + @EditableProperty + public LeverSwitchType getType() { + return type; + } + + public void setType(LeverSwitchType type) { + this.type = type; + updateControlPoints(); + // Invalidate body + this.body = null; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Invalidate the body + body = null; + } + + public enum LeverSwitchType { + DP3T("DP3T (Standard Strat)"), _4P5T("4P5T (Super/Mega)"), DP5T("DP5T"); + + private String title; + + private LeverSwitchType(String title) { + this.title = title; + } + + @Override + public String toString() { + return title; + } + } +} diff --git a/diylc-library/src/org/diylc/components/guitar/SingleCoilPickup.java b/diylc-library/src/org/diylc/components/guitar/SingleCoilPickup.java new file mode 100644 index 00000000..b428a50f --- /dev/null +++ b/diylc-library/src/org/diylc/components/guitar/SingleCoilPickup.java @@ -0,0 +1,254 @@ +package org.diylc.components.guitar; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.RoundRectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Strat Single Coil Pickup", category = "Guitar", author = "Branislav Stojkovic", description = "Strat-style single coil guitar pickup", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP") +public class SingleCoilPickup extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.darkGray; + private static Color POINT_COLOR = Color.lightGray; + private static Size WIDTH = new Size(15.5d, SizeUnit.mm); + private static Size LENGTH = new Size(83.82d, SizeUnit.mm); + private static Size LIP_WIDTH = new Size(5d, SizeUnit.mm); + private static Size LIP_LENGTH = new Size(20d, SizeUnit.mm); + private static Size POINT_SIZE = new Size(3d, SizeUnit.mm); + private static Size HOLE_SIZE = new Size(2d, SizeUnit.mm); + private static Size HOLE_MARGIN = new Size(4d, SizeUnit.mm); + private static Size POLE_SIZE = new Size(3d, SizeUnit.mm); + private static Size POLE_SPACING = new Size(11.68d, SizeUnit.mm); + + private String value = ""; + private Point controlPoint = new Point(0, 0); + transient Shape[] body; + private Orientation orientation = Orientation.DEFAULT; + private Color color = BODY_COLOR; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); + g2d.fill(body[0]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : POINT_COLOR); + g2d.fill(body[1]); + g2d.setComposite(oldComposite); + } + + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color + .brighter(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + if (!outlineMode) { + g2d.draw(body[2]); + } + + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + g2d.setFont(LABEL_FONT); + Rectangle bounds = body[0].getBounds(); + drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[3]; + + int x = controlPoint.x; + int y = controlPoint.y; + int width = (int) WIDTH.convertToPixels(); + int length = (int) LENGTH.convertToPixels(); + int lipWidth = (int) LIP_WIDTH.convertToPixels(); + int lipLength = (int) LIP_LENGTH.convertToPixels(); + int pointSize = getClosestOdd(POINT_SIZE.convertToPixels()); + int holeSize = getClosestOdd(HOLE_SIZE.convertToPixels()); + int holeMargin = getClosestOdd(HOLE_MARGIN.convertToPixels()); + + Area mainArea = new Area(new RoundRectangle2D.Double(x - length / 2, y - lipWidth / 2 + - width, length, width, width, width)); + mainArea.add(new Area(new Polygon(new int[] { x - length / 2 + width / 2, + x + length / 2 - width / 2, x + lipLength / 2, x - lipLength / 2 }, new int[] { + y - lipWidth / 2, y - lipWidth / 2, y + lipWidth / 2, y + lipWidth / 2 }, 4))); + // Cutout holes + mainArea.subtract(new Area(new Ellipse2D.Double(x - length / 2 + holeMargin - holeSize + / 2, y - lipWidth / 2 - width / 2 - holeSize / 2, holeSize, holeSize))); + mainArea.subtract(new Area(new Ellipse2D.Double(x + length / 2 - holeMargin - holeSize + / 2, y - lipWidth / 2 - width / 2 - holeSize / 2, holeSize, holeSize))); + + body[0] = mainArea; + + body[1] = new Area(new Ellipse2D.Double(x - pointSize / 2, y - pointSize / 2, + pointSize, pointSize)); + + int poleSize = (int) POLE_SIZE.convertToPixels(); + int poleSpacing = (int) POLE_SPACING.convertToPixels(); + int poleMargin = (length - poleSpacing * 5) / 2; + Area poleArea = new Area(); + for (int i = 0; i < 6; i++) { + Ellipse2D pole = new Ellipse2D.Double( + x - length / 2 + poleMargin + i * poleSpacing, y - lipWidth / 2 - width / 2 + - poleSize / 2, poleSize, poleSize); + poleArea.add(new Area(pole)); + } + body[2] = poleArea; + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Shape shape : body) { + Area area = (Area) shape; + area.transform(rotation); + } + } + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int bodyWidth = 8 * width / 32; + int bodyLength = 30 * width / 32; + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, + bodyLength, bodyWidth, bodyWidth); + g2d.fillPolygon(new int[] { width * 9 / 16, width * 9 / 16, width * 11 / 16, width * 11 / 16 }, + new int[] { (height - bodyLength) / 2, (height + bodyLength) / 2, height * 5 / 8, + height * 3 / 8 }, 4); + + g2d.setColor(Color.lightGray); + g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32); + g2d.drawLine(width / 2, height - 4 * width / 32, width / 2, height - 4 * width / 32); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public Point getControlPoint(int index) { + return controlPoint; + } + + @Override + public void setControlPoint(Point point, int index) { + this.controlPoint.setLocation(point); + // Invalidate the body + body = null; + } + + @EditableProperty(name = "Model") + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + // Invalidate the body + body = null; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } +} diff --git a/diylc-library/src/org/diylc/components/misc/BOM.java b/diylc-library/src/org/diylc/components/misc/BOM.java new file mode 100644 index 00000000..d84f0153 --- /dev/null +++ b/diylc-library/src/org/diylc/components/misc/BOM.java @@ -0,0 +1,186 @@ +package org.diylc.components.misc; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.geom.Rectangle2D; +import java.util.Iterator; +import java.util.List; + +import org.diylc.components.AbstractComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.BomEntry; +import org.diylc.utils.BomMaker; + +@ComponentDescriptor(name = "Bill of Materials", author = "Branislav Stojkovic", category = "Misc", description = "", instanceNamePrefix = "BOM", zOrder = IDIYComponent.TEXT, stretchable = false, bomPolicy = BomPolicy.NEVER_SHOW) +public class BOM extends AbstractComponent { + + public static Size DEFAULT_SIZE = new Size(10d, SizeUnit.cm); + public static Size SPACING = new Size(0.1d, SizeUnit.in); + public static Color COLOR = Color.black; + public static String DEFAULT_TEXT = "No components to show in the Bill of Materials"; + + private static final long serialVersionUID = 1L; + private Size size = DEFAULT_SIZE; + + private Point point = new Point(0, 0); + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + List bom = BomMaker.getInstance().createBom(project.getComponents()); + // Cleanup entries that do not have a value set. + Iterator iterator = bom.iterator(); + while (iterator.hasNext()) { + BomEntry entry = iterator.next(); + if (entry.getValue() == null || entry.getName().toLowerCase().contains("bom")) { + iterator.remove(); + } + } + g2d.setFont(LABEL_FONT); + g2d.setColor(componentState == ComponentState.DRAGGING + || componentState == ComponentState.SELECTED ? SELECTION_COLOR : COLOR); + // Determine maximum name length and maximum value length to calculate + // number of columns. + FontMetrics fontMetrics = g2d.getFontMetrics(); + int maxNameWidth = 0; + int maxValueWidth = 0; + int maxHeight = 0; + for (BomEntry entry : bom) { + String valueStr; + if (entry.getValue() == null || entry.getValue().trim().isEmpty()) { + valueStr = "qty " + entry.getQuantity().toString(); + } else { + valueStr = entry.getValue().toString(); + } + Rectangle2D stringBounds = fontMetrics.getStringBounds(entry.getName(), g2d); + if (stringBounds.getWidth() > maxNameWidth) { + maxNameWidth = (int) stringBounds.getWidth(); + } + if (stringBounds.getHeight() > maxHeight) { + maxHeight = (int) stringBounds.getHeight(); + } + stringBounds = fontMetrics.getStringBounds(valueStr, g2d); + if (stringBounds.getWidth() > maxValueWidth) { + maxValueWidth = (int) stringBounds.getWidth(); + } + if (stringBounds.getHeight() > maxHeight) { + maxHeight = (int) stringBounds.getHeight(); + } + } + // Calculate maximum entry size. + int maxEntrySize = maxNameWidth + maxValueWidth + 2 * (int) SPACING.convertToPixels(); + int columnCount = (int) size.convertToPixels() / maxEntrySize; + if (columnCount == 0) + columnCount = 1; + int columnWidth = (int) size.convertToPixels() / columnCount; + int entriesPerColumn = (int) Math.ceil(1.d * bom.size() / columnCount); + if (entriesPerColumn == 0) { + g2d.drawString(DEFAULT_TEXT, point.x, point.y); + return; + } + for (int i = 0; i < bom.size(); i++) { + String valueStr; + BomEntry entry = bom.get(i); + if (entry.getValue() == null || entry.getValue().trim().isEmpty()) { + valueStr = "qty " + entry.getQuantity().toString(); + } else { + valueStr = entry.getValue().toString(); + } + int columnIndex = i / entriesPerColumn; + int rowIndex = i % entriesPerColumn; + int x = point.x + columnIndex * columnWidth; + int y = point.y + rowIndex * maxHeight; + g2d.drawString(entry.getName(), x, y); + x += maxNameWidth + SPACING.convertToPixels(); + g2d.drawString(valueStr, x, y); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(Color.white); + g2d.fillRect(width / 8, 0, 6 * width / 8, height - 1); + g2d.setColor(Color.black); + g2d.drawRect(width / 8, 0, 6 * width / 8, height - 1); + g2d.setFont(LABEL_FONT.deriveFont(1f * 9 * width / 32).deriveFont(Font.PLAIN)); + + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle2D rect = fontMetrics.getStringBounds("BOM", g2d); + + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + + // Center text horizontally and vertically. + int x = (width - textWidth) / 2 + 1; + int y = textHeight + 2; + + g2d.drawString("BOM", x, y); + + g2d.setFont(g2d.getFont().deriveFont(1f * 5 * width / 32)); + + fontMetrics = g2d.getFontMetrics(); + rect = fontMetrics.getStringBounds("resistors", g2d); + x = (width - textWidth) / 2 + 1; + y = height / 2 + 2; + g2d.drawString("resistors", x, y); + y += rect.getHeight() - 1; + g2d.drawString("tubes", x, y); + y += rect.getHeight() - 1; + g2d.drawString("diodes", x, y); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public Point getControlPoint(int index) { + return point; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(name = "Width") + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } +} diff --git a/diylc-library/src/org/diylc/components/misc/GroundSymbol.java b/diylc-library/src/org/diylc/components/misc/GroundSymbol.java new file mode 100644 index 00000000..b889d7f3 --- /dev/null +++ b/diylc-library/src/org/diylc/components/misc/GroundSymbol.java @@ -0,0 +1,149 @@ +package org.diylc.components.misc; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Polygon; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Ground Symbol", author = "Branislav Stojkovic", category = "Misc", instanceNamePrefix = "GND", description = "Ground schematic symbol", stretchable = false, zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW) +public class GroundSymbol extends AbstractComponent { + + private static final long serialVersionUID = 1L; + + public static Color COLOR = Color.black; + public static Size SIZE = new Size(0.15d, SizeUnit.in); + + private Point point = new Point(0, 0); + private Color color = COLOR; + private Size size = SIZE; + private GroundSymbolType type = GroundSymbolType.DEFAULT; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + int sizePx = (int) size.convertToPixels(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(color); + int x = point.x; + int y = point.y; + g2d.drawLine(x, y, x, y + sizePx / 6); + if (type == GroundSymbolType.DEFAULT) { + int delta = sizePx / 7; + for (int i = 0; i < 5; i++) { + g2d.drawLine(x - sizePx / 2 + delta * i, y + sizePx / 6 * (i + 1), x + sizePx / 2 + - delta * i, y + sizePx / 6 * (i + 1)); + } + } else { + Polygon poly = new Polygon(new int[] { x - sizePx / 2, x + sizePx / 2, x }, new int[] { + y + sizePx / 6, y + sizePx / 6, y + sizePx }, 3); + g2d.draw(poly); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 3 * width / 32; + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(COLOR); + g2d.drawLine(width / 2, margin * 2, width / 2, margin * 3 + height / 5); + for (int i = 0; i < 5; i++) { + g2d.drawLine(margin * (i + 1), margin * (3 + i) + height / 5, width - margin * (i + 1), + margin * (3 + i) + height / 5); + } + } + + @EditableProperty(name = "Style") + public GroundSymbolType getType() { + return type; + } + + public void setType(GroundSymbolType type) { + this.type = type; + } + + @Override + public Point getControlPoint(int index) { + return point; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @EditableProperty + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public void setControlPoint(Point point, int index) { + this.point = point; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Deprecated + @Override + public Void getValue() { + return null; + } + + @Deprecated + @Override + public void setValue(Void value) { + } + + public static enum GroundSymbolType { + DEFAULT("Default"), TRIANGLE("Triangle"); + + private String title; + + private GroundSymbolType(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + @Override + public String toString() { + return title; + } + } +} diff --git a/diylc-library/src/org/diylc/components/misc/IconImageConverter.java b/diylc-library/src/org/diylc/components/misc/IconImageConverter.java new file mode 100644 index 00000000..6df78527 --- /dev/null +++ b/diylc-library/src/org/diylc/components/misc/IconImageConverter.java @@ -0,0 +1,102 @@ +package org.diylc.components.misc; + +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.MemoryImageSource; +import java.awt.image.PixelGrabber; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +import org.apache.log4j.Logger; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class IconImageConverter implements Converter { + + private static final Logger LOG = Logger.getLogger(IconImageConverter.class); + + @Override + public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + ImageIcon image = (ImageIcon) object; + int width = image.getIconWidth(); + int height = image.getIconHeight(); + int[] pixels = new int[width * height]; + + if (image != null) { + try { + PixelGrabber pg = new PixelGrabber(image.getImage(), 0, 0, width, height, pixels, + 0, width); + pg.grabPixels(); + if ((pg.getStatus() & ImageObserver.ABORT) != 0) { + LOG.error("Failed to load image contents"); + } + } catch (InterruptedException e) { + LOG.error("Image load interrupted"); + } + } + LOG.debug("Writing image to file: " + width + "x" + height); + writer.addAttribute("width", Integer.toString(width)); + writer.addAttribute("height", Integer.toString(height)); + StringBuilder dataBuilder = new StringBuilder(); + int n = 0; + for (int pixel : pixels) { + dataBuilder.append(Integer.toString(pixel, 16)); + dataBuilder.append(","); + n++; + if (n % 16 == 0) { + dataBuilder.append("\n"); + } + } + writer.addAttribute("data", dataBuilder.toString()); + } + + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + int width = Integer.parseInt(reader.getAttribute("width")); + int height = Integer.parseInt(reader.getAttribute("height")); + LOG.debug("Reading image from file: " + width + "x" + height); + int[] pixels = new int[width * height]; + String data = reader.getAttribute("data").replace("\n", ""); + String[] splitData = data.split(","); + for (int i = 0; i < Math.min(splitData.length, pixels.length); i++) { + if (!splitData[i].trim().isEmpty()) { + try { + pixels[i] = Integer.parseInt(splitData[i].trim(), 16); + } catch (Exception e) { + pixels[i] = 0; + } + } + } + + Toolkit toolkit = Toolkit.getDefaultToolkit(); + ColorModel colorModel = ColorModel.getRGBdefault(); + Image image = toolkit.createImage(new MemoryImageSource(width, height, colorModel, pixels, + 0, width)); + + BufferedImage bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + bimg.setRGB(0, 0, width, height, pixels, 0, width); + File outputfile = new File("c:\\saved.png"); + try { + ImageIO.write(bimg, "png", outputfile); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return new ImageIcon(image); + } + + @Override + public boolean canConvert(Class clazz) { + return ImageIcon.class.isAssignableFrom(clazz); + } +} diff --git a/diylc-library/src/org/diylc/components/misc/Image.java b/diylc-library/src/org/diylc/components/misc/Image.java new file mode 100644 index 00000000..7ea90c1d --- /dev/null +++ b/diylc-library/src/org/diylc/components/misc/Image.java @@ -0,0 +1,132 @@ +package org.diylc.components.misc; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; + +import javax.swing.ImageIcon; + +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; + +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@ComponentDescriptor(name = "Image", author = "Branislav Stojkovic", category = "Misc", description = "User defined image", instanceNamePrefix = "Img", zOrder = IDIYComponent.TEXT, stretchable = false, bomPolicy = BomPolicy.NEVER_SHOW) +public class Image extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + public static String DEFAULT_TEXT = "Double click to edit text"; + private static ImageIcon ICON; + private static byte DEFAULT_SCALE = 50; + + static { + String name = "image.png"; + java.net.URL imgURL = Image.class.getResource(name); + if (imgURL != null) { + ICON = new ImageIcon(imgURL, name); + } + } + + private Point point = new Point(0, 0); + @XStreamConverter(IconImageConverter.class) + private ImageIcon image = ICON; + private byte scale = 50; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + double s = 1d * scale / DEFAULT_SCALE; + Point endPoint = new Point((int) (image.getIconWidth() * s), + (int) (image.getIconHeight() * s)); + Shape clip = g2d.getClip(); + if (!clip.contains(point) && !clip.contains(endPoint) + && !clip.contains(point.x, endPoint.y) && !clip.contains(endPoint.x, point.y)) { + return; + } + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + + g2d.scale(s, s); + g2d.drawImage(image.getImage(), (int) (point.x / s), (int) (point.y / s), null); + if (componentState == ComponentState.SELECTED) { + g2d.setComposite(oldComposite); + g2d.scale(1 / s, 1 / s); + g2d.setColor(SELECTION_COLOR); + g2d.drawRect(point.x, point.y, endPoint.x, endPoint.y); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.drawImage(ICON.getImage(), point.x, point.y, null); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public Point getControlPoint(int index) { + return point; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(defaultable = false) + public ImageIcon getImage() { + return image; + } + + public void setImage(ImageIcon image) { + this.image = image; + } + + @EditableProperty(defaultable = false) + public byte getScale() { + return scale; + } + + public void setScale(byte scale) { + this.scale = scale; + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } +} diff --git a/diylc-library/src/org/diylc/components/misc/Label.java b/diylc-library/src/org/diylc/components/misc/Label.java new file mode 100644 index 00000000..0406aa8c --- /dev/null +++ b/diylc-library/src/org/diylc/components/misc/Label.java @@ -0,0 +1,203 @@ +package org.diylc.components.misc; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.geom.Rectangle2D; + +import org.diylc.components.AbstractComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; + +@ComponentDescriptor(name = "Label", author = "Branislav Stojkovic", category = "Misc", description = "User defined label", instanceNamePrefix = "L", zOrder = IDIYComponent.TEXT, stretchable = false, bomPolicy = BomPolicy.NEVER_SHOW) +public class Label extends AbstractComponent { + + public static String DEFAULT_TEXT = "Double click to edit text"; + + private static final long serialVersionUID = 1L; + + private Point point = new Point(0, 0); + private String text = DEFAULT_TEXT; + private Font font = LABEL_FONT; + private Color color = LABEL_COLOR; + private boolean center = true; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + g2d.setColor(componentState == ComponentState.SELECTED ? LABEL_COLOR_SELECTED : color); + g2d.setFont(font); + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle2D rect = fontMetrics.getStringBounds(text, g2d); + + int textHeight = (int) rect.getHeight(); + int textWidth = (int) rect.getWidth(); + + int x; + int y; + if (center) { + // Center text horizontally and vertically + x = point.x - textWidth / 2; + y = point.y - textHeight / 2 + fontMetrics.getAscent(); + } else { + x = point.x; + y = point.y - textHeight; + } + + g2d.drawString(text, x, y); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(LABEL_COLOR); + g2d.setFont(LABEL_FONT.deriveFont(13f * width / 32).deriveFont(Font.PLAIN)); + + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle2D rect = fontMetrics.getStringBounds("Abc", g2d); + + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + + // Center text horizontally and vertically. + int x = (width - textWidth) / 2 + 1; + int y = (height - textHeight) / 2 + fontMetrics.getAscent(); + + g2d.drawString("Abc", x, y); + } + + @EditableProperty + public Font getFont() { + return font; + } + + public void setFont(Font font) { + this.font = font; + } + + // Bold and italic fields are named to be alphabetically after Font. This is + // important! + + @EditableProperty(name = "Font Bold") + public boolean getBold() { + return font.isBold(); + } + + public void setBold(boolean bold) { + if (bold) { + if (font.isItalic()) { + font = font.deriveFont(Font.BOLD + Font.ITALIC); + } else { + font = font.deriveFont(Font.BOLD); + } + } else { + if (font.isItalic()) { + font = font.deriveFont(Font.ITALIC); + } else { + font = font.deriveFont(Font.PLAIN); + } + } + } + + @EditableProperty(name = "Font Italic") + public boolean getItalic() { + return font.isItalic(); + } + + public void setItalic(boolean italic) { + if (italic) { + if (font.isBold()) { + font = font.deriveFont(Font.BOLD + Font.ITALIC); + } else { + font = font.deriveFont(Font.ITALIC); + } + } else { + if (font.isBold()) { + font = font.deriveFont(Font.BOLD); + } else { + font = font.deriveFont(Font.PLAIN); + } + } + } + + @EditableProperty(name = "Font Size") + public int getFontSize() { + return font.getSize(); + } + + public void setFontSize(int size) { + font = font.deriveFont((float) size); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public Point getControlPoint(int index) { + return point; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(defaultable = false) + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public boolean getCenter() { + return center; + } + + public void setCenter(boolean center) { + this.center = center; + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) { + } +} diff --git a/diylc-library/src/org/diylc/components/misc/image.png b/diylc-library/src/org/diylc/components/misc/image.png new file mode 100644 index 00000000..b663869f Binary files /dev/null and b/diylc-library/src/org/diylc/components/misc/image.png differ diff --git a/diylc-library/src/org/diylc/components/passive/AbstractPotentiometer.java b/diylc-library/src/org/diylc/components/passive/AbstractPotentiometer.java new file mode 100644 index 00000000..b6151fbb --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/AbstractPotentiometer.java @@ -0,0 +1,85 @@ +package org.diylc.components.passive; + +import java.awt.Point; + +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Resistance; +import org.diylc.core.measures.ResistanceUnit; + +public abstract class AbstractPotentiometer extends + AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + protected Point[] controlPoints; + + protected Resistance resistance = new Resistance(100d, ResistanceUnit.K); + protected Orientation orientation = Orientation.DEFAULT; + protected Taper taper = Taper.LIN; + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @EditableProperty + public Resistance getResistance() { + return resistance; + } + + public void setResistance(Resistance resistance) { + this.resistance = resistance; + } + + @Override + public PotentiometerValue getValue() { + return new PotentiometerValue(resistance, taper); + } + + @Override + public void setValue(PotentiometerValue value) { + this.resistance = value.getResistance(); + this.taper = value.getTaper(); + } + + @EditableProperty + public Taper getTaper() { + return taper; + } + + public void setTaper(Taper taper) { + this.taper = taper; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + } +} diff --git a/diylc-library/src/org/diylc/components/passive/AxialElectrolyticCapacitor.java b/diylc-library/src/org/diylc/components/passive/AxialElectrolyticCapacitor.java new file mode 100644 index 00000000..327113c6 --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/AxialElectrolyticCapacitor.java @@ -0,0 +1,168 @@ +package org.diylc.components.passive; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.Theme; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Capacitance; +import org.diylc.core.measures.CapacitanceUnit; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.core.measures.VoltageUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Electrolytic Capacitor (axial)", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C", description = "Axial electrolytic capacitor, similar to Sprague Atom, F&T, etc", zOrder = IDIYComponent.COMPONENT) +public class AxialElectrolyticCapacitor extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_WIDTH = new Size(1d / 2, SizeUnit.in); + public static Size DEFAULT_HEIGHT = new Size(1d / 8, SizeUnit.in); + public static Color BODY_COLOR = Color.decode("#EAADEA"); + public static Color BORDER_COLOR = BODY_COLOR.darker(); + public static Color MARKER_COLOR = Color.gray; + public static Color TICK_COLOR = Color.white; + + private Capacitance value = new Capacitance(1d, CapacitanceUnit.uF); + @Deprecated + private Voltage voltage = Voltage._63V; + private org.diylc.core.measures.Voltage voltageNew = new org.diylc.core.measures.Voltage(63d, + VoltageUnit.V); + + private Color markerColor = MARKER_COLOR; + private Color tickColor = TICK_COLOR; + private boolean polarized = true; + + public AxialElectrolyticCapacitor() { + super(); + this.bodyColor = BODY_COLOR; + this.borderColor = BORDER_COLOR; + } + + @EditableProperty + public Capacitance getValue() { + return value; + } + + public void setValue(Capacitance value) { + this.value = value; + } + + @Deprecated + public Voltage getVoltage() { + return voltage; + } + + @Deprecated + public void setVoltage(Voltage voltage) { + this.voltage = voltage; + } + + @EditableProperty(name = "Voltage") + public org.diylc.core.measures.Voltage getVoltageNew() { + // Backward comptibility + if (voltageNew == null) { + voltageNew = voltage.convertToNewFormat(); + voltage = null; + // Clear old value, don't need it anymore + } + return voltageNew; + } + + public void setVoltageNew(org.diylc.core.measures.Voltage voltageNew) { + this.voltageNew = voltageNew; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, width, height / 2); + g2d.setColor(BODY_COLOR); + g2d.fillRect(4, height / 2 - 3, width - 8, 6); + g2d.setColor(MARKER_COLOR); + g2d.fillRect(width - 9, height / 2 - 3, 5, 6); + g2d.setColor(TICK_COLOR); + g2d.drawLine(width - 6, height / 2 - 1, width - 6, height / 2 + 1); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(4, height / 2 - 3, width - 8, 6); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_HEIGHT; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_WIDTH; + } + + @EditableProperty(name = "Marker") + public Color getMarkerColor() { + return markerColor; + } + + public void setMarkerColor(Color coverColor) { + this.markerColor = coverColor; + } + + @EditableProperty(name = "Tick") + public Color getTickColor() { + return tickColor; + } + + public void setTickColor(Color tickColor) { + this.tickColor = tickColor; + } + + @EditableProperty(name = "Polarized") + public boolean getPolarized() { + return polarized; + } + + public void setPolarized(boolean polarized) { + this.polarized = polarized; + } + + @Override + protected Shape getBodyShape() { + return new Rectangle2D.Double(0f, 0f, getLength().convertToPixels(), + getClosestOdd(getWidth().convertToPixels())); + } + + @Override + protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) { + if (polarized) { + int width = getClosestOdd(getWidth().convertToPixels()); + int markerLength = (int) (getLength().convertToPixels() * 0.2); + if (!outlineMode) { + g2d.setColor(markerColor); + g2d.fillRect((int) getLength().convertToPixels() - markerLength, 0, markerLength, + width); + } + Color finalTickColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalTickColor = theme.getOutlineColor(); + } else { + finalTickColor = tickColor; + } + g2d.setColor(finalTickColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.drawLine((int) getLength().convertToPixels() - markerLength / 2, + (int) (width / 2 - width * 0.15), (int) getLength().convertToPixels() + - markerLength / 2, (int) (width / 2 + width * 0.15)); + } + } +} diff --git a/diylc-library/src/org/diylc/components/passive/AxialFilmCapacitor.java b/diylc-library/src/org/diylc/components/passive/AxialFilmCapacitor.java new file mode 100644 index 00000000..b8e8ed9f --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/AxialFilmCapacitor.java @@ -0,0 +1,105 @@ +package org.diylc.components.passive; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Capacitance; +import org.diylc.core.measures.CapacitanceUnit; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.core.measures.VoltageUnit; + +@ComponentDescriptor(name = "Film Capacitor (axial)", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C", description = "Axial film capacitor, similar to Mallory 150s", zOrder = IDIYComponent.COMPONENT) +public class AxialFilmCapacitor extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_WIDTH = new Size(1d / 2, SizeUnit.in); + public static Size DEFAULT_HEIGHT = new Size(1d / 8, SizeUnit.in); + public static Color BODY_COLOR = Color.decode("#FFE303"); + public static Color BORDER_COLOR = BODY_COLOR.darker(); + + private Capacitance value = new Capacitance(22d, CapacitanceUnit.nF); + @Deprecated + private Voltage voltage = Voltage._63V; + private org.diylc.core.measures.Voltage voltageNew = new org.diylc.core.measures.Voltage(63d, + VoltageUnit.V); + + public AxialFilmCapacitor() { + super(); + this.bodyColor = BODY_COLOR; + this.borderColor = BORDER_COLOR; + } + + @Override + protected boolean supportsStandingMode() { + return true; + } + + @EditableProperty + public Capacitance getValue() { + return value; + } + + public void setValue(Capacitance value) { + this.value = value; + } + + @Deprecated + public Voltage getVoltage() { + return voltage; + } + + @Deprecated + public void setVoltage(Voltage voltage) { + this.voltage = voltage; + } + + @EditableProperty(name = "Voltage") + public org.diylc.core.measures.Voltage getVoltageNew() { + // Backward comptibility + if (voltageNew == null) { + voltageNew = voltage.convertToNewFormat(); + voltage = null; + // Clear old value, don't need it anymore + } + return voltageNew; + } + + public void setVoltageNew(org.diylc.core.measures.Voltage voltageNew) { + this.voltageNew = voltageNew; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, width, height / 2); + g2d.setColor(BODY_COLOR); + g2d.fillRect(4, height / 2 - 3, width - 8, 6); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(4, height / 2 - 3, width - 8, 6); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_HEIGHT; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_WIDTH; + } + + @Override + protected Shape getBodyShape() { + return new Rectangle2D.Double(0f, 0f, getLength().convertToPixels(), + getClosestOdd(getWidth().convertToPixels())); + } +} diff --git a/diylc-library/src/org/diylc/components/passive/CapacitorSymbol.java b/diylc-library/src/org/diylc/components/passive/CapacitorSymbol.java new file mode 100644 index 00000000..8f9c3689 --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/CapacitorSymbol.java @@ -0,0 +1,120 @@ +package org.diylc.components.passive; + +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.GeneralPath; + +import org.diylc.components.AbstractSchematicLeadedSymbol; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Capacitance; +import org.diylc.core.measures.CapacitanceUnit; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.core.measures.VoltageUnit; + +@ComponentDescriptor(name = "Capacitor (schematic symbol)", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C", description = "Capacitor schematic symbol with an optional polarity sign", zOrder = IDIYComponent.COMPONENT) +public class CapacitorSymbol extends AbstractSchematicLeadedSymbol { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_LENGTH = new Size(0.05, SizeUnit.in); + public static Size DEFAULT_WIDTH = new Size(0.15, SizeUnit.in); + + private Capacitance value = new Capacitance(22d, CapacitanceUnit.nF); + @Deprecated + private Voltage voltage = Voltage._63V; + private org.diylc.core.measures.Voltage voltageNew = new org.diylc.core.measures.Voltage(63d, + VoltageUnit.V); + private boolean polarized = false; + + @EditableProperty + public Capacitance getValue() { + return value; + } + + public void setValue(Capacitance value) { + this.value = value; + } + + @Deprecated + public Voltage getVoltage() { + return voltage; + } + + @Deprecated + public void setVoltage(Voltage voltage) { + this.voltage = voltage; + } + + @EditableProperty(name = "Voltage") + public org.diylc.core.measures.Voltage getVoltageNew() { + // Backward compatibility + if (voltageNew == null) { + voltageNew = voltage.convertToNewFormat(); + voltage = null; + // Clear old value, don't need it anymore + } + return voltageNew; + } + + public void setVoltageNew(org.diylc.core.measures.Voltage voltageNew) { + this.voltageNew = voltageNew; + } + + @EditableProperty + public boolean getPolarized() { + return polarized; + } + + public void setPolarized(boolean polarized) { + this.polarized = polarized; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, 13, height / 2); + g2d.drawLine(width - 13, height / 2, width, height / 2); + g2d.setColor(COLOR); + g2d.drawLine(14, height / 2 - 6, 14, height / 2 + 6); + g2d.drawLine(width - 14, height / 2 - 6, width - 14, height / 2 + 6); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_WIDTH; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_LENGTH; + } + + @Override + protected Shape getBodyShape() { + GeneralPath polyline = new GeneralPath(); + double length = getLength().convertToPixels(); + double width = getWidth().convertToPixels(); + polyline.moveTo(0, 0); + polyline.lineTo(0, width); + polyline.moveTo(length, 0); + polyline.lineTo(length, width); + return polyline; + } + + @Override + protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) { + if (polarized) { + // Draw + sign. + g2d.setColor(getBorderColor()); + int plusSize = getClosestOdd(getWidth().convertToPixels() / 4); + int x = -plusSize; + int y = plusSize; + g2d.drawLine(x - plusSize / 2, y, x + plusSize / 2, y); + g2d.drawLine(x, y - plusSize / 2, x, y + plusSize / 2); + } + } +} diff --git a/diylc-library/src/org/diylc/components/passive/PotentiometerPanel.java b/diylc-library/src/org/diylc/components/passive/PotentiometerPanel.java new file mode 100644 index 00000000..1ee92aa8 --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/PotentiometerPanel.java @@ -0,0 +1,278 @@ +package org.diylc.components.passive; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.core.ComponentState; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Potentiometer (panel mount)", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.SINGLE_CLICK, instanceNamePrefix = "VR", description = "Panel mount potentiometer with solder lugs", zOrder = IDIYComponent.COMPONENT, stretchable = false) +public class PotentiometerPanel extends AbstractPotentiometer { + + private static final long serialVersionUID = 1L; + + protected static Size BODY_DIAMETER = new Size(1d, SizeUnit.in); + protected static Size SPACING = new Size(0.3d, SizeUnit.in); + protected static Size LUG_DIAMETER = new Size(0.15d, SizeUnit.in); + protected static Color BODY_COLOR = Color.gray.brighter(); + protected static Color BORDER_COLOR = Color.gray; + + protected Size bodyDiameter = BODY_DIAMETER; + protected Size spacing = SPACING; + protected Size lugDiameter = LUG_DIAMETER; + protected Color bodyColor = BODY_COLOR; + protected Color borderColor = BORDER_COLOR; + // Array of 7 elements: 3 lug connectors, 1 pot body and 3 lugs + transient protected Area[] body = null; + + public PotentiometerPanel() { + controlPoints = new Point[] { new Point(0, 0), new Point(0, 0), new Point(0, 0) }; + updateControlPoints(); + } + + protected void updateControlPoints() { + int spacing = (int) this.spacing.convertToPixels(); + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(controlPoints[0].x + spacing, controlPoints[0].y); + controlPoints[2].setLocation(controlPoints[0].x + 2 * spacing, controlPoints[0].y); + break; + case _90: + controlPoints[1].setLocation(controlPoints[0].x, controlPoints[0].y + spacing); + controlPoints[2].setLocation(controlPoints[0].x, controlPoints[0].y + 2 * spacing); + break; + case _180: + controlPoints[1].setLocation(controlPoints[0].x - spacing, controlPoints[0].y); + controlPoints[2].setLocation(controlPoints[0].x - 2 * spacing, controlPoints[0].y); + break; + case _270: + controlPoints[1].setLocation(controlPoints[0].x, controlPoints[0].y - spacing); + controlPoints[2].setLocation(controlPoints[0].x, controlPoints[0].y - 2 * spacing); + break; + default: + break; + } + } + + public Area[] getBody() { + int spacing = (int) this.spacing.convertToPixels(); + int diameter = getClosestOdd(bodyDiameter.convertToPixels()); + if (body == null) { + body = new Area[7]; + + // Add lugs. + int lugDiameter = getClosestOdd(this.lugDiameter.convertToPixels()); + int holeDiameter = getClosestOdd(this.lugDiameter.convertToPixels() / 2); + for (int i = 0; i < 3; i++) { + Area area = new Area(new Ellipse2D.Double(controlPoints[i].x - lugDiameter / 2, + controlPoints[i].y - lugDiameter / 2, lugDiameter, lugDiameter)); + body[4 + i] = area; + } + + switch (orientation) { + case DEFAULT: + body[3] = new Area(new Ellipse2D.Double( + controlPoints[0].x + spacing - diameter / 2, controlPoints[0].y - spacing + / 2 - diameter, diameter, diameter)); + for (int i = 0; i < 3; i++) { + body[i] = new Area(new Rectangle2D.Double( + controlPoints[i].x - holeDiameter / 2, controlPoints[i].y + - (spacing + diameter) / 2, holeDiameter, + (spacing + diameter) / 2)); + } + break; + case _90: + body[3] = new Area(new Ellipse2D.Double(controlPoints[0].x + spacing / 2, + controlPoints[0].y + spacing - diameter / 2, diameter, diameter)); + for (int i = 0; i < 3; i++) { + body[i] = new Area(new Rectangle2D.Double(controlPoints[i].x, + controlPoints[i].y - holeDiameter / 2, (spacing + diameter) / 2, + holeDiameter)); + } + break; + case _180: + body[3] = new Area(new Ellipse2D.Double( + controlPoints[0].x - spacing - diameter / 2, controlPoints[0].y + spacing + / 2, diameter, diameter)); + for (int i = 0; i < 3; i++) { + body[i] = new Area(new Rectangle2D.Double( + controlPoints[i].x - holeDiameter / 2, controlPoints[i].y, + holeDiameter, (spacing + diameter) / 2)); + } + break; + case _270: + body[3] = new Area(new Ellipse2D.Double( + controlPoints[0].x - spacing / 2 - diameter, controlPoints[0].y - spacing + - diameter / 2, diameter, diameter)); + for (int i = 0; i < 3; i++) { + body[i] = new Area(new Rectangle2D.Double(controlPoints[i].x + - (spacing + diameter) / 2, controlPoints[i].y - holeDiameter / 2, + (spacing + diameter) / 2, holeDiameter)); + } + break; + default: + break; + } + for (int i = 0; i < 3; i++) { + for (int j = 3; j < 7; j++) { + body[i].subtract(body[j]); + } + } + // Make holes in the lugs. + for (int i = 0; i < 3; i++) { + body[4 + i].subtract(new Area(new Ellipse2D.Double(controlPoints[i].x + - holeDiameter / 2, controlPoints[i].y - holeDiameter / 2, holeDiameter, + holeDiameter))); + } + } + return body; + } + + @Override + public void setControlPoint(Point point, int index) { + super.setControlPoint(point, index); + body = null; + } + + @Override + public void setOrientation(Orientation orientation) { + super.setOrientation(orientation); + updateControlPoints(); + body = null; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + for (Area shape : getBody()) { + if (shape != null) { + g2d.setColor(bodyColor); + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.fill(shape); + g2d.setComposite(oldComposite); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor); + g2d.draw(shape); + } + } + // Draw caption. + g2d.setFont(LABEL_FONT); + g2d + .setColor(componentState == ComponentState.SELECTED ? LABEL_COLOR_SELECTED + : LABEL_COLOR); + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle2D bodyRect = getBody()[3].getBounds2D(); + Rectangle2D rect = fontMetrics.getStringBounds(getName(), g2d); + + int textHeight = (int) rect.getHeight(); + int textWidth = (int) rect.getWidth(); + int panelHeight = (int) bodyRect.getHeight(); + int panelWidth = (int) bodyRect.getWidth(); + + int x = (panelWidth - textWidth) / 2; + int y = panelHeight / 2 - textHeight + fontMetrics.getAscent(); + + g2d.drawString(getName(), (int) (bodyRect.getX() + x), (int) (bodyRect.getY() + y)); + + // Draw value. + rect = fontMetrics.getStringBounds(getValue().toString(), g2d); + + textHeight = (int) rect.getHeight(); + textWidth = (int) rect.getWidth(); + + x = (panelWidth - textWidth) / 2; + y = panelHeight / 2 + fontMetrics.getAscent(); + + g2d.drawString(getValue().toString(), (int) (bodyRect.getX() + x), + (int) (bodyRect.getY() + y)); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 4 * width / 32; + int spacing = width / 3 - 1; + g2d.setColor(BORDER_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2 * width / 32)); + g2d.drawLine(width / 2 - spacing, height / 2, width / 2 - spacing, height - margin); + g2d.drawLine(width / 2 + spacing, height / 2, width / 2 + spacing, height - margin); + g2d.drawLine(width / 2, height / 2, width / 2, height - margin); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(4 * width / 32)); + g2d.drawLine(width / 2 - spacing, height - margin, width / 2 - spacing, height - margin); + g2d.drawLine(width / 2 + spacing, height - margin, width / 2 + spacing, height - margin); + g2d.drawLine(width / 2, height - margin, width / 2, height - margin); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(BODY_COLOR); + g2d.fillOval(margin, margin / 2, width - 2 * margin, height - 2 * margin); + g2d.setColor(BORDER_COLOR); + g2d.drawOval(margin, margin / 2, width - 2 * margin, height - 2 * margin); + } + + @EditableProperty + public Size getSpacing() { + return spacing; + } + + public void setSpacing(Size spacing) { + this.spacing = spacing; + updateControlPoints(); + body = null; + } + + @EditableProperty(name = "Diameter") + public Size getBodyDiameter() { + return bodyDiameter; + } + + public void setBodyDiameter(Size bodyDiameter) { + this.bodyDiameter = bodyDiameter; + } + + @EditableProperty(name = "Lug size") + public Size getLugDiameter() { + return lugDiameter; + } + + public void setLugDiameter(Size lugDiameter) { + this.lugDiameter = lugDiameter; + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } +} diff --git a/diylc-library/src/org/diylc/components/passive/PotentiometerValue.java b/diylc-library/src/org/diylc/components/passive/PotentiometerValue.java new file mode 100644 index 00000000..26f3caee --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/PotentiometerValue.java @@ -0,0 +1,28 @@ +package org.diylc.components.passive; + +import org.diylc.core.measures.Resistance; + +public class PotentiometerValue { + + private Resistance resistance; + private Taper taper; + + public PotentiometerValue(Resistance resistance, Taper taper) { + super(); + this.resistance = resistance; + this.taper = taper; + } + + public Resistance getResistance() { + return resistance; + } + + public Taper getTaper() { + return taper; + } + + @Override + public String toString() { + return resistance.toString() + " " + taper.toString(); + } +} diff --git a/diylc-library/src/org/diylc/components/passive/Power.java b/diylc-library/src/org/diylc/components/passive/Power.java new file mode 100644 index 00000000..f925e2cb --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/Power.java @@ -0,0 +1,56 @@ +package org.diylc.components.passive; + +import org.diylc.core.measures.PowerUnit; + +public enum Power { + + EIGHT("1/8W"), QUARTER("1/4W"), HALF("1/2W"), ONE("1W"), TWO("2W"), FIVE("5W"), TEN("10W"), FIFTY( + "50W"), HUNDRED("100W"); + + String label; + + Power(String label) { + this.label = label; + } + + @Override + public String toString() { + return label; + } + + public org.diylc.core.measures.Power convertToNewFormat() { + org.diylc.core.measures.Power powerNew; + switch (this) { + case EIGHT: + powerNew = new org.diylc.core.measures.Power(1 / 8d, PowerUnit.W); + break; + case FIVE: + powerNew = new org.diylc.core.measures.Power(5d, PowerUnit.W); + break; + case FIFTY: + powerNew = new org.diylc.core.measures.Power(50d, PowerUnit.W); + break; + case HALF: + powerNew = new org.diylc.core.measures.Power(1 / 2d, PowerUnit.W); + break; + case HUNDRED: + powerNew = new org.diylc.core.measures.Power(100d, PowerUnit.W); + break; + case ONE: + powerNew = new org.diylc.core.measures.Power(1d, PowerUnit.W); + break; + case QUARTER: + powerNew = new org.diylc.core.measures.Power(1 / 4d, PowerUnit.W); + break; + case TEN: + powerNew = new org.diylc.core.measures.Power(10d, PowerUnit.W); + break; + case TWO: + powerNew = new org.diylc.core.measures.Power(2d, PowerUnit.W); + break; + default: + powerNew = new org.diylc.core.measures.Power(1 / 2d, PowerUnit.W); + } + return powerNew; + } +} diff --git a/diylc-library/src/org/diylc/components/passive/RadialCeramicDiskCapacitor.java b/diylc-library/src/org/diylc/components/passive/RadialCeramicDiskCapacitor.java new file mode 100644 index 00000000..876a800d --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/RadialCeramicDiskCapacitor.java @@ -0,0 +1,80 @@ +package org.diylc.components.passive; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Ellipse2D; + +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Capacitance; +import org.diylc.core.measures.CapacitanceUnit; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Ceramic Capacitor (radial)", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C", description = "Standard radial ceramic capacitor", zOrder = IDIYComponent.COMPONENT) +public class RadialCeramicDiskCapacitor extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_WIDTH = new Size(1d / 2, SizeUnit.in); + public static Size DEFAULT_HEIGHT = new Size(1d / 8, SizeUnit.in); + public static Color BODY_COLOR = Color.decode("#F0E68C"); + public static Color BORDER_COLOR = BODY_COLOR.darker(); + + private Capacitance value = new Capacitance(470d, CapacitanceUnit.pF); + private Voltage voltage = Voltage._63V; + + public RadialCeramicDiskCapacitor() { + super(); + this.bodyColor = BODY_COLOR; + this.borderColor = BORDER_COLOR; + } + + @EditableProperty + public Capacitance getValue() { + return value; + } + + public void setValue(Capacitance value) { + this.value = value; + } + + @EditableProperty + public Voltage getVoltage() { + return voltage; + } + + public void setVoltage(Voltage voltage) { + this.voltage = voltage; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, width, height / 2); + g2d.setColor(BODY_COLOR); + g2d.fillOval(4, height / 2 - 3, width - 8, 6); + g2d.setColor(BORDER_COLOR); + g2d.drawOval(4, height / 2 - 3, width - 8, 6); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_HEIGHT; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_WIDTH; + } + + @Override + protected Shape getBodyShape() { + return new Ellipse2D.Double(0f, 0f, getLength().convertToPixels(), getClosestOdd(getWidth() + .convertToPixels())); + } +} diff --git a/diylc-library/src/org/diylc/components/passive/RadialElectrolytic.java b/diylc-library/src/org/diylc/components/passive/RadialElectrolytic.java new file mode 100644 index 00000000..4ca98002 --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/RadialElectrolytic.java @@ -0,0 +1,203 @@ +package org.diylc.components.passive; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.Theme; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Capacitance; +import org.diylc.core.measures.CapacitanceUnit; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.core.measures.VoltageUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Electrolytic Capacitor", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C", description = "Vertical mounted electrolytic capacitor, polarized or bipolar", zOrder = IDIYComponent.COMPONENT) +public class RadialElectrolytic extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_SIZE = new Size(1d / 2, SizeUnit.in); + public static Color BODY_COLOR = Color.decode("#EAADEA"); + public static Color BORDER_COLOR = BODY_COLOR.darker(); + public static Color MARKER_COLOR = Color.gray; + public static Color TICK_COLOR = Color.white; + + private Capacitance value = new Capacitance(1d, CapacitanceUnit.uF); + @Deprecated + private Voltage voltage = Voltage._63V; + private org.diylc.core.measures.Voltage voltageNew = new org.diylc.core.measures.Voltage(63d, + VoltageUnit.V); + + private Color markerColor = MARKER_COLOR; + private Color tickColor = TICK_COLOR; + private boolean polarized = true; + + public RadialElectrolytic() { + super(); + this.bodyColor = BODY_COLOR; + this.borderColor = BORDER_COLOR; + } + + @EditableProperty + public Capacitance getValue() { + return value; + } + + public void setValue(Capacitance value) { + this.value = value; + } + + @Deprecated + public Voltage getVoltage() { + return voltage; + } + + @Deprecated + public void setVoltage(Voltage voltage) { + this.voltage = voltage; + } + + @EditableProperty(name = "Voltage") + public org.diylc.core.measures.Voltage getVoltageNew() { + // Backward comptibility + if (voltageNew == null) { + voltageNew = voltage.convertToNewFormat(); + voltage = null; + // Clear old value, don't need it anymore + } + return voltageNew; + } + + public void setVoltageNew(org.diylc.core.measures.Voltage voltageNew) { + this.voltageNew = voltageNew; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BODY_COLOR); + int margin = 3; + Ellipse2D body = new Ellipse2D.Double(margin, margin, getClosestOdd(width - 2 * margin), + getClosestOdd(width - 2 * margin)); + g2d.fill(body); + Area marker = new Area(body); + marker.subtract(new Area(new Rectangle2D.Double(margin, margin, width - 4 * margin, + getClosestOdd(width - 2 * margin)))); + g2d.setColor(MARKER_COLOR); + g2d.fill(marker); + g2d.setColor(TICK_COLOR); + g2d.drawLine(width - 2 * margin, height / 2 - 2, width - 2 * margin, height / 2 + 2); + g2d.setColor(BORDER_COLOR); + g2d.draw(body); + // g2d.setColor(COVER_COLOR.darker()); + // g2d.drawLine(innerMargin + 2, innerMargin + 2, width - innerMargin - + // 2, width - innerMargin + // - 2); + // g2d.drawLine(innerMargin + 2, width - innerMargin - 2, width - + // innerMargin - 2, + // innerMargin + 2); + } + + @Override + protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) { + if (polarized) { + int totalDiameter = getClosestOdd(getLength().convertToPixels()); + if (!outlineMode) { + Area area = new Area(getBodyShape()); + area.subtract(new Area(new Rectangle2D.Double(0, 0, totalDiameter * 0.8, + totalDiameter))); + g2d.setColor(markerColor); + g2d.fill(area); + } + Color finalTickColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalTickColor = theme.getOutlineColor(); + } else { + finalTickColor = tickColor; + } + g2d.setColor(finalTickColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.drawLine((int) (totalDiameter * 0.9), totalDiameter / 2 + - (int) (totalDiameter * 0.05), (int) (totalDiameter * 0.9), totalDiameter / 2 + + (int) (totalDiameter * 0.05)); + } + // int coverDiameter = getClosestOdd(totalDiameter * 3 / 4); + // g2d.setColor(coverColor); + // int position = (totalDiameter - coverDiameter) / 2; + // g2d.fillOval(position, position, coverDiameter, coverDiameter); + // g2d.setColor(coverColor.darker()); + // g2d.drawLine(position + coverDiameter / 5, position + coverDiameter / + // 5, position + 4 + // * coverDiameter / 5, position + 4 * coverDiameter / 5); + // g2d.drawLine(position + coverDiameter / 5, position + 4 * + // coverDiameter / 5, position + 4 + // * coverDiameter / 5, position + coverDiameter / 5); + } + + @Override + protected Size getDefaultWidth() { + return null; + } + + @Override + public Size getWidth() { + return super.getWidth(); + } + + @Override + protected Size getDefaultLength() { + // We'll reuse width property to set the diameter. + return DEFAULT_SIZE; + } + + @EditableProperty(name = "Diameter") + @Override + public Size getLength() { + return super.getLength(); + } + + @EditableProperty(name = "Marker") + public Color getMarkerColor() { + return markerColor; + } + + public void setMarkerColor(Color coverColor) { + this.markerColor = coverColor; + } + + @EditableProperty(name = "Tick") + public Color getTickColor() { + return tickColor; + } + + public void setTickColor(Color tickColor) { + this.tickColor = tickColor; + } + + @EditableProperty(name = "Polarized") + public boolean getPolarized() { + return polarized; + } + + public void setPolarized(boolean polarized) { + this.polarized = polarized; + } + + @Override + protected Shape getBodyShape() { + return new Ellipse2D.Double(0f, 0f, getClosestOdd(getLength().convertToPixels()), + getClosestOdd(getLength().convertToPixels())); + } +} diff --git a/diylc-library/src/org/diylc/components/passive/RadialFilmCapacitor.java b/diylc-library/src/org/diylc/components/passive/RadialFilmCapacitor.java new file mode 100644 index 00000000..5da8ff4b --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/RadialFilmCapacitor.java @@ -0,0 +1,101 @@ +package org.diylc.components.passive; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.RoundRectangle2D; + +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Capacitance; +import org.diylc.core.measures.CapacitanceUnit; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.core.measures.VoltageUnit; + +@ComponentDescriptor(name = "Film Capacitor (radial)", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C", description = "Radial film capacitor, similar to Sprague Orange Drop", zOrder = IDIYComponent.COMPONENT) +public class RadialFilmCapacitor extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_WIDTH = new Size(1d, SizeUnit.in); + public static Size DEFAULT_HEIGHT = new Size(1d / 4, SizeUnit.in); + public static Color BODY_COLOR = Color.decode("#FF8000"); + public static Color BORDER_COLOR = BODY_COLOR.darker(); + + private Capacitance value = new Capacitance(123d, CapacitanceUnit.nF); + @Deprecated + private Voltage voltage = Voltage._63V; + private org.diylc.core.measures.Voltage voltageNew = new org.diylc.core.measures.Voltage(63d, + VoltageUnit.V); + + public RadialFilmCapacitor() { + super(); + this.bodyColor = BODY_COLOR; + this.borderColor = BORDER_COLOR; + } + + @EditableProperty + public Capacitance getValue() { + return value; + } + + public void setValue(Capacitance value) { + this.value = value; + } + + @Deprecated + public Voltage getVoltage() { + return voltage; + } + + @Deprecated + public void setVoltage(Voltage voltage) { + this.voltage = voltage; + } + + @EditableProperty(name = "Voltage") + public org.diylc.core.measures.Voltage getVoltageNew() { + // Backward comptibility + if (voltageNew == null) { + voltageNew = voltage.convertToNewFormat(); + voltage = null; + // Clear old value, don't need it anymore + } + return voltageNew; + } + + public void setVoltageNew(org.diylc.core.measures.Voltage voltageNew) { + this.voltageNew = voltageNew; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, width, height / 2); + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect(4, height / 2 - 3, width - 8, 6, 5, 5); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(4, height / 2 - 3, width - 8, 6, 5, 5); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_HEIGHT; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_WIDTH; + } + + @Override + protected Shape getBodyShape() { + double radius = getWidth().convertToPixels() * 0.7; + return new RoundRectangle2D.Double(0f, 0f, getLength().convertToPixels(), + getClosestOdd(getWidth().convertToPixels()), radius, radius); + } +} diff --git a/diylc-library/src/org/diylc/components/passive/Resistor.java b/diylc-library/src/org/diylc/components/passive/Resistor.java new file mode 100644 index 00000000..a13adbe3 --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/Resistor.java @@ -0,0 +1,153 @@ +package org.diylc.components.passive; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +import org.diylc.common.ObjectCache; +import org.diylc.common.ResistorColorCode; +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.PositiveMeasureValidator; +import org.diylc.core.measures.PowerUnit; +import org.diylc.core.measures.Resistance; +import org.diylc.core.measures.ResistanceUnit; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Resistor", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "R", description = "", zOrder = IDIYComponent.COMPONENT) +public class Resistor extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_WIDTH = new Size(1d / 2, SizeUnit.in); + public static Size DEFAULT_HEIGHT = new Size(1d / 8, SizeUnit.in); + public static Color BODY_COLOR = Color.decode("#82CFFD"); + public static Color BORDER_COLOR = BODY_COLOR.darker(); + public static int BAND_SPACING = 5; + public static int FIRST_BAND = 4; + + private Resistance value = new Resistance(100d, ResistanceUnit.K); + @Deprecated + private Power power = Power.HALF; + private org.diylc.core.measures.Power powerNew = new org.diylc.core.measures.Power(0.5, + PowerUnit.W); + private ResistorColorCode colorCode = ResistorColorCode._5_BAND; + + public Resistor() { + super(); + this.bodyColor = BODY_COLOR; + this.borderColor = BORDER_COLOR; + } + + @Override + protected boolean supportsStandingMode() { + return true; + } + + @EditableProperty(validatorClass = PositiveMeasureValidator.class) + public Resistance getValue() { + return value; + } + + public void setValue(Resistance value) { + this.value = value; + } + + @Deprecated + public Power getPower() { + return power; + } + + @Deprecated + public void setPower(Power power) { + this.power = power; + } + + @EditableProperty(name = "Power rating") + public org.diylc.core.measures.Power getPowerNew() { + // Backward compatibility + if (powerNew == null) { + powerNew = power.convertToNewFormat(); + // Clear old value, don't need it anymore + power = null; + } + return powerNew; + } + + public void setPowerNew(org.diylc.core.measures.Power powerNew) { + this.powerNew = powerNew; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, width, height / 2); + g2d.setColor(BODY_COLOR); + g2d.fillRect(4, height / 2 - 3, width - 8, 6); + g2d.setColor(Color.red); + g2d.drawLine(7, height / 2 - 3, 7, height / 2 + 3); + g2d.setColor(Color.orange); + g2d.drawLine(11, height / 2 - 3, 11, height / 2 + 3); + g2d.setColor(Color.black); + g2d.drawLine(15, height / 2 - 3, 15, height / 2 + 3); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(4, height / 2 - 3, width - 8, 6); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_HEIGHT; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_WIDTH; + } + + @EditableProperty(name = "Color code") + public ResistorColorCode getColorCode() { + return colorCode; + } + + public void setColorCode(ResistorColorCode colorCode) { + this.colorCode = colorCode; + } + + @Override + protected Shape getBodyShape() { + return new Rectangle2D.Double(0f, 0f, getLength().convertToPixels(), + getClosestOdd(getWidth().convertToPixels())); + } + + @Override + protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) { + // int width = getWidth().convertToPixels(); + if (colorCode == ResistorColorCode.NONE || outlineMode) { + return; + } + int height = getClosestOdd(getWidth().convertToPixels()); + Color[] bands = value.getColorCode(colorCode); + int x = FIRST_BAND; + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + for (int i = 0; i < bands.length; i++) { + g2d.setColor(bands[i]); + g2d.drawLine(x, 1, x, height - 1); + x += BAND_SPACING; + } + } + + @Override + protected int getLabelOffset(int bodyWidth, int labelWidth) { + Color[] bands = value.getColorCode(colorCode); + int bandArea = FIRST_BAND + BAND_SPACING * (bands.length - 1); + // Only offset the label if overlaping with the band area. + if (labelWidth > bodyWidth - 2 * bandArea) + return bandArea / 2; + return 0; + } +} diff --git a/diylc-library/src/org/diylc/components/passive/ResistorSymbol.java b/diylc-library/src/org/diylc/components/passive/ResistorSymbol.java new file mode 100644 index 00000000..2ed5d7ba --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/ResistorSymbol.java @@ -0,0 +1,105 @@ +package org.diylc.components.passive; + +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.GeneralPath; + +import org.diylc.components.AbstractSchematicLeadedSymbol; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.PowerUnit; +import org.diylc.core.measures.Resistance; +import org.diylc.core.measures.ResistanceUnit; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Resistor (schematic symbol)", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "R", description = "Resistor schematic symbol", zOrder = IDIYComponent.COMPONENT) +public class ResistorSymbol extends AbstractSchematicLeadedSymbol { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_LENGTH = new Size(0.3, SizeUnit.in); + public static Size DEFAULT_WIDTH = new Size(0.08, SizeUnit.in); + + private Resistance value = new Resistance(100d, ResistanceUnit.K); + @Deprecated + private Power power = Power.HALF; + private org.diylc.core.measures.Power powerNew = new org.diylc.core.measures.Power(0.5, + PowerUnit.W); + + @EditableProperty + public Resistance getValue() { + return value; + } + + public void setValue(Resistance value) { + this.value = value; + } + + @Deprecated + public Power getPower() { + return power; + } + + @Deprecated + public void setPower(Power power) { + this.power = power; + } + + @EditableProperty(name = "Power rating") + public org.diylc.core.measures.Power getPowerNew() { + // Backward compatibility + if (powerNew == null) { + powerNew = power.convertToNewFormat(); + // Clear old value, don't need it anymore + power = null; + } + return powerNew; + } + + public void setPowerNew(org.diylc.core.measures.Power powerNew) { + this.powerNew = powerNew; + } + + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, 4, height / 2); + g2d.drawLine(width - 4, height / 2, width, height / 2); + g2d.setColor(COLOR); + g2d.drawPolyline(new int[] { 4, 6, 10, 14, 18, 22, 26, 28 }, new int[] { height / 2, + height / 2 + 2, height / 2 - 2, height / 2 + 2, height / 2 - 2, height / 2 + 2, + height / 2 - 2, height / 2 }, 8); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_WIDTH; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_LENGTH; + } + + @Override + protected Shape getBodyShape() { + GeneralPath polyline = new GeneralPath(); + double length = getLength().convertToPixels(); + double width = getWidth().convertToPixels(); + polyline.moveTo(0, width / 2); + polyline.lineTo(length / 16, width); + polyline.lineTo(3 * length / 16, 0); + polyline.lineTo(5 * length / 16, width); + polyline.lineTo(7 * length / 16, 0); + polyline.lineTo(9 * length / 16, width); + polyline.lineTo(11 * length / 16, 0); + polyline.lineTo(13 * length / 16, width); + polyline.lineTo(15 * length / 16, 0); + polyline.lineTo(length, width / 2); + return polyline; + } +} diff --git a/diylc-library/src/org/diylc/components/passive/ResistorValue.java b/diylc-library/src/org/diylc/components/passive/ResistorValue.java new file mode 100644 index 00000000..4fbe5c80 --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/ResistorValue.java @@ -0,0 +1,28 @@ +package org.diylc.components.passive; + +import org.diylc.core.measures.Resistance; + +public class ResistorValue { + + private Resistance resistance; + private Power power; + + public ResistorValue(Resistance resistance, Power power) { + super(); + this.resistance = resistance; + this.power = power; + } + + public Resistance getResistance() { + return resistance; + } + + public Power getPower() { + return power; + } + + @Override + public String toString() { + return resistance.toString() + power.toString(); + } +} diff --git a/diylc-library/src/org/diylc/components/passive/Taper.java b/diylc-library/src/org/diylc/components/passive/Taper.java new file mode 100644 index 00000000..5dcd8f93 --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/Taper.java @@ -0,0 +1,12 @@ +package org.diylc.components.passive; + +public enum Taper { + + LIN, LOG, REV_LOG, W, S; + + @Override + public String toString() { + return name().substring(0, 1).toUpperCase() + + name().substring(1).toLowerCase().replace("_", " "); + } +} diff --git a/diylc-library/src/org/diylc/components/passive/TrimmerPotentiometer.java b/diylc-library/src/org/diylc/components/passive/TrimmerPotentiometer.java new file mode 100644 index 00000000..f117ccf7 --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/TrimmerPotentiometer.java @@ -0,0 +1,375 @@ +package org.diylc.components.passive; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.core.ComponentState; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Trimmer Potentiometer", author = "Branislav Stojkovic", category = "Passive", creationMethod = CreationMethod.SINGLE_CLICK, instanceNamePrefix = "VR", description = "Various types of board mounted trimmer potentiometers", zOrder = IDIYComponent.COMPONENT, stretchable = false) +public class TrimmerPotentiometer extends AbstractPotentiometer { + + private static final long serialVersionUID = 1L; + + protected static Size FLAT_BODY_SIZE = new Size(9.5d, SizeUnit.mm); + protected static Size FLAT_SHAFT_SIZE = new Size(4d, SizeUnit.mm); + protected static Size VERTICAL_BODY_LENGTH = new Size(9.5d, SizeUnit.mm); + protected static Size VERTICAL_BODY_WIDTH = new Size(4.5d, SizeUnit.mm); + protected static Size SPACING = new Size(0.1d, SizeUnit.in); + private static Color BODY_COLOR = Color.decode("#FFFFE0"); + private static Color BORDER_COLOR = Color.decode("#8E8E38"); + private static Color SHAFT_COLOR = Color.decode("#FFFFE0"); + private static Color SHAFT_BORDER_COLOR = Color.decode("#8E8E38"); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); + + protected Color bodyColor = BODY_COLOR; + protected Color borderColor = BORDER_COLOR; + // Array of 7 elements: 3 lug connectors, 1 pot body and 3 lugs + transient protected Shape[] body = null; + + protected TrimmerType type = TrimmerType.FLAT_SMALL; + + public TrimmerPotentiometer() { + controlPoints = new Point[] { new Point(0, 0), new Point(0, 0), new Point(0, 0) }; + updateControlPoints(); + } + + protected void updateControlPoints() { + int spacing = (int) SPACING.convertToPixels(); + int dx1 = 0; + int dy1 = 0; + int dx2 = 0; + int dy2 = 0; + switch (orientation) { + case DEFAULT: + switch (type) { + case FLAT_SMALL: + dx1 = 2 * spacing; + dy1 = spacing; + dx2 = 0; + dy2 = 2 * spacing; + break; + case FLAT_LARGE: + dx1 = 4 * spacing; + dy1 = spacing; + dx2 = 0; + dy2 = 2 * spacing; + break; + case VERTICAL_INLINE: + dx1 = 0; + dy1 = spacing; + dx2 = 0; + dy2 = 2 * spacing; + break; + case VERTICAL_OFFSET: + dx1 = spacing; + dy1 = spacing; + dx2 = 0; + dy2 = 2 * spacing; + break; + } + break; + case _90: + switch (type) { + case FLAT_SMALL: + dx1 = -spacing; + dy1 = 2 * spacing; + dx2 = -2 * spacing; + dy2 = 0; + break; + case FLAT_LARGE: + dx1 = -spacing; + dy1 = 4 * spacing; + dx2 = -2 * spacing; + dy2 = 0; + break; + case VERTICAL_INLINE: + dx1 = -spacing; + dy1 = 0; + dx2 = -2 * spacing; + dy2 = 0; + break; + case VERTICAL_OFFSET: + dx1 = -spacing; + dy1 = spacing; + dx2 = -2 * spacing; + dy2 = 0; + break; + } + break; + case _180: + switch (type) { + case FLAT_SMALL: + dx1 = -2 * spacing; + dy1 = -spacing; + dx2 = 0; + dy2 = -2 * spacing; + break; + case FLAT_LARGE: + dx1 = -4 * spacing; + dy1 = -spacing; + dx2 = 0; + dy2 = -2 * spacing; + break; + case VERTICAL_INLINE: + dx1 = 0; + dy1 = -spacing; + dx2 = 0; + dy2 = -2 * spacing; + break; + case VERTICAL_OFFSET: + dx1 = -spacing; + dy1 = -spacing; + dx2 = 0; + dy2 = -2 * spacing; + break; + } + break; + case _270: + switch (type) { + case FLAT_SMALL: + dx1 = spacing; + dy1 = -2 * spacing; + dx2 = 2 * spacing; + dy2 = 0; + break; + case FLAT_LARGE: + dx1 = spacing; + dy1 = -4 * spacing; + dx2 = 2 * spacing; + dy2 = 0; + break; + case VERTICAL_INLINE: + dx1 = spacing; + dy1 = 0; + dx2 = 2 * spacing; + dy2 = 0; + break; + case VERTICAL_OFFSET: + dx1 = spacing; + dy1 = -spacing; + dx2 = 2 * spacing; + dy2 = 0; + break; + } + break; + default: + break; + } + controlPoints[1].setLocation(controlPoints[0].x + dx1, controlPoints[0].y + dy1); + controlPoints[2].setLocation(controlPoints[0].x + dx2, controlPoints[0].y + dy2); + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[2]; + + // Calculate the center point as center of the minimum bounding + // rectangle. + int centerX = (Math.max(Math.max(controlPoints[0].x, controlPoints[1].x), + controlPoints[2].x) + Math.min( + Math.min(controlPoints[0].x, controlPoints[1].x), controlPoints[2].x)) / 2; + int centerY = (Math.max(Math.max(controlPoints[0].y, controlPoints[1].y), + controlPoints[2].y) + Math.min( + Math.min(controlPoints[0].y, controlPoints[1].y), controlPoints[2].y)) / 2; + + // Calculate body dimensions based on the selected type. + int length = 0; + int width = 0; + switch (type) { + case FLAT_LARGE: + case FLAT_SMALL: + length = getClosestOdd(FLAT_BODY_SIZE.convertToPixels()); + width = length; + int shaftSize = getClosestOdd(FLAT_SHAFT_SIZE.convertToPixels()); + Area shaft = new Area(new Ellipse2D.Double(centerX - shaftSize / 2, centerY + - shaftSize / 2, shaftSize, shaftSize)); + Area slot = new Area(new Rectangle2D.Double(centerX - shaftSize / 2, centerY + - shaftSize / 8, shaftSize, shaftSize / 4)); + slot.transform(AffineTransform.getRotateInstance(Math.PI / 4, centerX, centerY)); + shaft.subtract(slot); + body[1] = shaft; + break; + case VERTICAL_INLINE: + case VERTICAL_OFFSET: + length = getClosestOdd(VERTICAL_BODY_LENGTH.convertToPixels()); + width = getClosestOdd(VERTICAL_BODY_WIDTH.convertToPixels()); + break; + } + if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { + int p = length; + length = width; + width = p; + } + body[0] = new Rectangle2D.Double(centerX - length / 2, centerY - width / 2, length, + width); + } + return body; + } + + @Override + public void setControlPoint(Point point, int index) { + super.setControlPoint(point, index); + body = null; + } + + @Override + public void setOrientation(Orientation orientation) { + super.setOrientation(orientation); + updateControlPoints(); + body = null; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + Shape mainShape = getBody()[0]; + Shape shaftShape = getBody()[1]; + if (mainShape != null) { + g2d.setColor(bodyColor); + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.fill(mainShape); + if (shaftShape != null) { + g2d.setColor(SHAFT_COLOR); + g2d.fill(shaftShape); + g2d.setColor(SHAFT_BORDER_COLOR); + g2d.draw(shaftShape); + } + g2d.setComposite(oldComposite); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : borderColor); + g2d.draw(mainShape); + } + + // Draw pins. + int pinSize = getClosestOdd(PIN_SIZE.convertToPixels()); + for (Point point : controlPoints) { + g2d.setColor(PIN_COLOR); + g2d.fillOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + } + + // Draw label. + g2d.setFont(LABEL_FONT); + g2d + .setColor(componentState == ComponentState.SELECTED ? LABEL_COLOR_SELECTED + : LABEL_COLOR); + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle2D bodyRect = getBody()[0].getBounds2D(); + Rectangle2D rect = fontMetrics.getStringBounds(getName(), g2d); + + int textHeight = (int) rect.getHeight(); + int textWidth = (int) rect.getWidth(); + int panelHeight = (int) bodyRect.getHeight(); + int panelWidth = (int) bodyRect.getWidth(); + + int x = (panelWidth - textWidth) / 2; + int y = (panelHeight - textHeight) / 2 + fontMetrics.getAscent(); + + g2d.drawString(getName(), (int) (bodyRect.getX() + x), (int) (bodyRect.getY() + y)); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 4; + g2d.setColor(BODY_COLOR); + g2d.fillRect(margin, margin, width - 2 * margin, width - 2 * margin); + g2d.setColor(BORDER_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.drawRect(margin, margin, width - 2 * margin, width - 2 * margin); + int shaftSize = 11; + int slotSize = 2; + Area area = new Area(new Ellipse2D.Double(width / 2 - shaftSize / 2, width / 2 - shaftSize + / 2, shaftSize, shaftSize)); + Area slot = new Area(new Rectangle2D.Double(0, width / 2 - slotSize / 2, width, slotSize)); + slot.transform(AffineTransform.getRotateInstance(Math.PI / 4, width / 2, width / 2)); + area.subtract(slot); + g2d.setColor(SHAFT_COLOR); + g2d.fill(area); + g2d.setColor(SHAFT_BORDER_COLOR); + g2d.draw(area); + + int pinSize = 3; + g2d.setColor(PIN_COLOR); + g2d.fillOval(margin - pinSize / 2, 10 - pinSize / 2, pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(margin - pinSize / 2, 10 - pinSize / 2, pinSize, pinSize); + + g2d.setColor(PIN_COLOR); + g2d.fillOval(margin - pinSize / 2, 21 - pinSize / 2, pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(margin - pinSize / 2, 21 - pinSize / 2, pinSize, pinSize); + + g2d.setColor(PIN_COLOR); + g2d.fillOval(width - margin - pinSize / 2, width / 2 - pinSize / 2, pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(width - margin - pinSize / 2, width / 2 - pinSize / 2, pinSize, pinSize); + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty + public TrimmerType getType() { + return type; + } + + public void setType(TrimmerType type) { + this.type = type; + updateControlPoints(); + body = null; + } + + public static enum TrimmerType { + FLAT_LARGE, FLAT_SMALL, VERTICAL_INLINE, VERTICAL_OFFSET; + + @Override + public String toString() { + return name().substring(0, 1) + name().substring(1).toLowerCase().replace("_", " "); + } + } +} diff --git a/diylc-library/src/org/diylc/components/passive/Voltage.java b/diylc-library/src/org/diylc/components/passive/Voltage.java new file mode 100644 index 00000000..e27b308a --- /dev/null +++ b/diylc-library/src/org/diylc/components/passive/Voltage.java @@ -0,0 +1,58 @@ +package org.diylc.components.passive; + +import org.diylc.core.measures.VoltageUnit; + +public enum Voltage { + + _16V, _25V, _63V, _100V, _160V, _250V, _300V, _350V, _400V, _500V, _630V, _1KV; + + @Override + public String toString() { + return name().replace("_", ""); + } + + public org.diylc.core.measures.Voltage convertToNewFormat() { + org.diylc.core.measures.Voltage voltageNew; + switch (this) { + case _100V: + voltageNew = new org.diylc.core.measures.Voltage(100d, VoltageUnit.V); + break; + case _160V: + voltageNew = new org.diylc.core.measures.Voltage(160d, VoltageUnit.V); + break; + case _16V: + voltageNew = new org.diylc.core.measures.Voltage(16d, VoltageUnit.V); + break; + case _1KV: + voltageNew = new org.diylc.core.measures.Voltage(1d, VoltageUnit.KV); + break; + case _250V: + voltageNew = new org.diylc.core.measures.Voltage(250d, VoltageUnit.V); + break; + case _25V: + voltageNew = new org.diylc.core.measures.Voltage(25d, VoltageUnit.V); + break; + case _300V: + voltageNew = new org.diylc.core.measures.Voltage(300d, VoltageUnit.V); + break; + case _350V: + voltageNew = new org.diylc.core.measures.Voltage(350d, VoltageUnit.V); + break; + case _400V: + voltageNew = new org.diylc.core.measures.Voltage(400d, VoltageUnit.V); + break; + case _500V: + voltageNew = new org.diylc.core.measures.Voltage(500d, VoltageUnit.V); + break; + case _630V: + voltageNew = new org.diylc.core.measures.Voltage(630d, VoltageUnit.V); + break; + case _63V: + voltageNew = new org.diylc.core.measures.Voltage(63d, VoltageUnit.V); + break; + default: + voltageNew = new org.diylc.core.measures.Voltage(100d, VoltageUnit.V); + } + return voltageNew; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/AbstractDiodeSymbol.java b/diylc-library/src/org/diylc/components/semiconductors/AbstractDiodeSymbol.java new file mode 100644 index 00000000..2fe93373 --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/AbstractDiodeSymbol.java @@ -0,0 +1,20 @@ +package org.diylc.components.semiconductors; + +import java.awt.Shape; + +import org.diylc.components.AbstractLeadedComponent; + +public abstract class AbstractDiodeSymbol extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + @Override + protected boolean shouldShadeLeads() { + return false; + } + + @Override + protected Shape getBodyShape() { + return null; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/AbstractTransistorSymbol.java b/diylc-library/src/org/diylc/components/semiconductors/AbstractTransistorSymbol.java new file mode 100644 index 00000000..7114e7b4 --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/AbstractTransistorSymbol.java @@ -0,0 +1,173 @@ +package org.diylc.components.semiconductors; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.Display; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +public abstract class AbstractTransistorSymbol extends AbstractComponent { + + private static final long serialVersionUID = 1L; + + public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); + public static Color COLOR = Color.black; + + protected String value = ""; + protected Point[] controlPoints = new Point[] { new Point(0, 0), new Point(0, 0), + new Point(0, 0) }; + protected Color color = COLOR; + protected Display display = Display.NAME; + transient protected Shape[] body; + + public AbstractTransistorSymbol() { + super(); + updateControlPoints(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + Color finalColor; + if (componentState == ComponentState.SELECTED) { + finalColor = SELECTION_COLOR; + } else if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalColor = theme.getOutlineColor(); + } else { + finalColor = color; + } + g2d.setColor(finalColor); + + // Draw transistor + + int x = controlPoints[0].x; + int y = controlPoints[0].y; + + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.draw(body[0]); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(body[1]); + + g2d.fill(body[2]); + + // Draw label + g2d.setFont(LABEL_FONT); + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + drawCenteredText(g2d, display == Display.VALUE ? getValue() : getName(), + x + pinSpacing * 2, y, HorizontalAlignment.LEFT, VerticalAlignment.CENTER); + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + private void updateControlPoints() { + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + // Update control points. + int x = controlPoints[0].x; + int y = controlPoints[0].y; + + controlPoints[1].x = x + pinSpacing * 2; + controlPoints[1].y = y - pinSpacing * 2; + + controlPoints[2].x = x + pinSpacing * 2; + controlPoints[2].y = y + pinSpacing * 2; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @EditableProperty + @Override + public String getValue() { + return this.value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + // Invalidate body + body = null; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @EditableProperty + public Display getDisplay() { + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + /** + * Returns transistor shape consisting of 3 parts, in this order: main body, + * connectors, polarity arrow. + * + * @return + */ + protected abstract Shape[] getBody(); +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/BJTPolarity.java b/diylc-library/src/org/diylc/components/semiconductors/BJTPolarity.java new file mode 100644 index 00000000..15590148 --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/BJTPolarity.java @@ -0,0 +1,11 @@ +package org.diylc.components.semiconductors; + +public enum BJTPolarity { + + NPN, PNP; + + @Override + public String toString() { + return name(); + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/BJTSymbol.java b/diylc-library/src/org/diylc/components/semiconductors/BJTSymbol.java new file mode 100644 index 00000000..95cabfc4 --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/BJTSymbol.java @@ -0,0 +1,98 @@ +package org.diylc.components.semiconductors; + +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; + +import org.diylc.common.ObjectCache; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; + +@ComponentDescriptor(name = "BJT Symbol", author = "Branislav Stojkovic", category = "Semiconductors", instanceNamePrefix = "Q", description = "Bipolar junction transistor schematic symbol", stretchable = false, zOrder = IDIYComponent.COMPONENT) +public class BJTSymbol extends AbstractTransistorSymbol { + + private static final long serialVersionUID = 1L; + + protected BJTPolarity polarity = BJTPolarity.NPN; + + public Shape[] getBody() { + if (body == null) { + body = new Shape[3]; + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + + GeneralPath polyline = new GeneralPath(); + + polyline.moveTo(x + pinSpacing / 2, y - pinSpacing); + polyline.lineTo(x + pinSpacing / 2, y + pinSpacing); + + body[0] = polyline; + + polyline = new GeneralPath(); + + polyline.moveTo(x, y); + polyline.lineTo(x + pinSpacing / 2, y); + polyline.moveTo(x + pinSpacing / 2, y - pinSpacing / 2); + polyline.lineTo(x + pinSpacing * 2, y - pinSpacing); + polyline.lineTo(x + pinSpacing * 2, y - pinSpacing * 2); + polyline.moveTo(x + pinSpacing / 2, y + pinSpacing / 2); + polyline.lineTo(x + pinSpacing * 2, y + pinSpacing); + polyline.lineTo(x + pinSpacing * 2, y + pinSpacing * 2); + body[1] = polyline; + + Area arrow; + double theta; + if (polarity == BJTPolarity.NPN) { + theta = Math.atan(1.0 / 3); + arrow = new Area(new Polygon(new int[] { x + pinSpacing, x + pinSpacing, + x + pinSpacing * 10 / 6 }, new int[] { y - pinSpacing / 5 + pinSpacing / 2, + y + pinSpacing / 5 + pinSpacing / 2, y + pinSpacing / 2 }, 3)); + arrow.transform(AffineTransform.getRotateInstance(theta, x + pinSpacing / 2, y + + pinSpacing / 2)); + } else { + theta = -Math.atan(1.0 / 3); + arrow = new Area(new Polygon(new int[] { x + pinSpacing, x + pinSpacing * 10 / 6, + x + pinSpacing * 10 / 6 }, new int[] { y - pinSpacing / 2, + y - pinSpacing / 5 - pinSpacing / 2, y + pinSpacing / 5 - pinSpacing / 2 }, + 3)); + arrow.transform(AffineTransform.getRotateInstance(theta, x + pinSpacing / 2, y + - pinSpacing / 2)); + } + body[2] = arrow; + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(COLOR); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.drawLine(width / 3, height / 5, width / 3, height * 4 / 5); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.drawLine(width / 8, height / 2, width / 3, height / 2); + + g2d.drawLine(width * 3 / 4, 1, width * 3 / 4, height / 4); + g2d.drawLine(width / 3, height / 3 + 1, width * 3 / 4, height / 4); + + g2d.drawLine(width * 3 / 4, height - 1, width * 3 / 4, height * 3 / 4); + g2d.drawLine(width / 3, height * 2 / 3 - 1, width * 3 / 4, height * 3 / 4); + } + + @EditableProperty(name = "Polarity") + public BJTPolarity getPolarity() { + return polarity; + } + + public void setPolarity(BJTPolarity polarity) { + this.polarity = polarity; + // Invalidate body + body = null; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/DIL_IC.java b/diylc-library/src/org/diylc/components/semiconductors/DIL_IC.java new file mode 100644 index 00000000..2ba52f9e --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/DIL_IC.java @@ -0,0 +1,372 @@ +package org.diylc.components.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.Display; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "DIL IC", author = "Branislav Stojkovic", category = "Semiconductors", instanceNamePrefix = "IC", description = "IC with rectangular housing and two parallel rows of pins", stretchable = false, zOrder = IDIYComponent.COMPONENT) +public class DIL_IC extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.gray; + public static Color BORDER_COLOR = Color.gray.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color INDENT_COLOR = Color.gray.darker(); + public static Color LABEL_COLOR = Color.white; + public static int EDGE_RADIUS = 6; + public static Size PIN_SIZE = new Size(0.04d, SizeUnit.in); + public static Size INDENT_SIZE = new Size(0.07d, SizeUnit.in); + + private String value = ""; + private Orientation orientation = Orientation.DEFAULT; + private PinCount pinCount = PinCount._8; + private Size pinSpacing = new Size(0.1d, SizeUnit.in); + private Size rowSpacing = new Size(0.3d, SizeUnit.in); + private Point[] controlPoints = new Point[] { new Point(0, 0) }; + protected Display display = Display.NAME; + // new Point(0, pinSpacing.convertToPixels()), + // new Point(0, 2 * pinSpacing.convertToPixels()), + // new Point(0, 3 * pinSpacing.convertToPixels()), + // new Point(3 * pinSpacing.convertToPixels(), 0), + // new Point(3 * pinSpacing.convertToPixels(), + // pinSpacing.convertToPixels()), + // new Point(3 * pinSpacing.convertToPixels(), 2 * + // pinSpacing.convertToPixels()), + // new Point(3 * pinSpacing.convertToPixels(), 3 * + // pinSpacing.convertToPixels()) }; + transient private Area[] body; + + public DIL_IC() { + super(); + updateControlPoints(); + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty(name = "Pins") + public PinCount getPinCount() { + return pinCount; + } + + public void setPinCount(PinCount pinCount) { + this.pinCount = pinCount; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @EditableProperty(name = "Pin spacing") + public Size getPinSpacing() { + return pinSpacing; + } + + public void setPinSpacing(Size pinSpacing) { + this.pinSpacing = pinSpacing; + } + + @EditableProperty(name = "Row spacing") + public Size getRowSpacing() { + return rowSpacing; + } + + public void setRowSpacing(Size rowSpacing) { + this.rowSpacing = rowSpacing; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @EditableProperty + public Display getDisplay() { + if (display == null) { + display = Display.VALUE; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + Point firstPoint = controlPoints[0]; + controlPoints = new Point[pinCount.getValue()]; + controlPoints[0] = firstPoint; + int pinSpacing = (int) this.pinSpacing.convertToPixels(); + int rowSpacing = (int) this.rowSpacing.convertToPixels(); + // Update control points. + int dx1; + int dy1; + int dx2; + int dy2; + for (int i = 0; i < pinCount.getValue() / 2; i++) { + switch (orientation) { + case DEFAULT: + dx1 = 0; + dy1 = i * pinSpacing; + dx2 = rowSpacing; + dy2 = i * pinSpacing; + break; + case _90: + dx1 = -i * pinSpacing; + dy1 = 0; + dx2 = -i * pinSpacing; + dy2 = rowSpacing; + break; + case _180: + dx1 = 0; + dy1 = -i * pinSpacing; + dx2 = -rowSpacing; + dy2 = -i * pinSpacing; + break; + case _270: + dx1 = i * pinSpacing; + dy1 = 0; + dx2 = i * pinSpacing; + dy2 = -rowSpacing; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + controlPoints[i] = new Point(firstPoint.x + dx1, firstPoint.y + dy1); + controlPoints[i + pinCount.getValue() / 2] = new Point(firstPoint.x + dx2, firstPoint.y + + dy2); + } + } + + public Area[] getBody() { + if (body == null) { + body = new Area[2]; + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int width; + int height; + int pinSize = (int) PIN_SIZE.convertToPixels(); + int pinSpacing = (int) this.pinSpacing.convertToPixels(); + int rowSpacing = (int) this.rowSpacing.convertToPixels(); + Area indentation = null; + int indentationSize = getClosestOdd(INDENT_SIZE.convertToPixels()); + switch (orientation) { + case DEFAULT: + width = rowSpacing - pinSize; + height = (pinCount.getValue() / 2) * pinSpacing; + x += pinSize / 2; + y -= pinSpacing / 2; + indentation = new Area(new Ellipse2D.Double(x + width / 2 - indentationSize / 2, y + - indentationSize / 2, indentationSize, indentationSize)); + break; + case _90: + width = (pinCount.getValue() / 2) * pinSpacing; + height = rowSpacing - pinSize; + x -= (pinSpacing / 2) + width - pinSpacing; + y += pinSize / 2; + indentation = new Area(new Ellipse2D.Double(x + width - indentationSize / 2, y + + height / 2 - indentationSize / 2, indentationSize, indentationSize)); + break; + case _180: + width = rowSpacing - pinSize; + height = (pinCount.getValue() / 2) * pinSpacing; + x -= rowSpacing - pinSize / 2; + y -= (pinSpacing / 2) + height - pinSpacing; + indentation = new Area(new Ellipse2D.Double(x + width / 2 - indentationSize / 2, y + + height - indentationSize / 2, indentationSize, indentationSize)); + break; + case _270: + width = (pinCount.getValue() / 2) * pinSpacing; + height = rowSpacing - pinSize; + x -= pinSpacing / 2; + y += pinSize / 2 - rowSpacing; + indentation = new Area(new Ellipse2D.Double(x - indentationSize / 2, y + height / 2 + - indentationSize / 2, indentationSize, indentationSize)); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + body[0] = new Area(new RoundRectangle2D.Double(x, y, width, height, EDGE_RADIUS, + EDGE_RADIUS)); + body[1] = indentation; + if (indentation != null) { + indentation.intersect(body[0]); + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Area mainArea = getBody()[0]; + if (!outlineMode) { + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + for (Point point : controlPoints) { + g2d.setColor(PIN_COLOR); + g2d.fillRect(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawRect(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + } + } + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + g2d.fill(mainArea); + g2d.setComposite(oldComposite); + + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : BORDER_COLOR; + } + g2d.setColor(finalBorderColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (outlineMode) { + Area area = new Area(mainArea); + area.subtract(getBody()[1]); + g2d.draw(area); + } else { + g2d.draw(mainArea); + if (getBody()[1] != null) { + g2d.setColor(INDENT_COLOR); + g2d.fill(getBody()[1]); + } + } + // Draw label. + g2d.setFont(LABEL_FONT); + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + String label = display == Display.NAME ? getName() : getValue(); + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = bounds.x + (bounds.width - textWidth) / 2; + int y = bounds.y + (bounds.height - textHeight) / 2 + fontMetrics.getAscent(); + g2d.drawString(label, x, y); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int radius = 6 * width / 32; + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect(width / 6, 1, 4 * width / 6, height - 4, radius, radius); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(width / 6, 1, 4 * width / 6, height - 4, radius, radius); + int pinSize = 2 * width / 32; + g2d.setColor(PIN_COLOR); + for (int i = 0; i < 4; i++) { + g2d.fillRect(width / 6 - pinSize, (height / 5) * (i + 1) - 1, pinSize, pinSize); + g2d.fillRect(5 * width / 6 + 1, (height / 5) * (i + 1) - 1, pinSize, pinSize); + } + } + + public static enum PinCount { + + _4, _6, _8, _10, _12, _14, _16, _18, _20, _22, _24, _26, _28, _30, _32, _34, _36, _38, _40, _42, _44, _46, _48, _50; + + @Override + public String toString() { + return name().replace("_", ""); + } + + public int getValue() { + return Integer.parseInt(toString()); + } + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/DiodePlastic.java b/diylc-library/src/org/diylc/components/semiconductors/DiodePlastic.java new file mode 100644 index 00000000..bd7d4e2f --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/DiodePlastic.java @@ -0,0 +1,111 @@ +package org.diylc.components.semiconductors; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.Theme; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Diode (plastic)", author = "Branislav Stojkovic", category = "Semiconductors", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "D", description = "Plastic diode, like most rectifier, zener, schottky, etc.", zOrder = IDIYComponent.COMPONENT) +public class DiodePlastic extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_WIDTH = new Size(1d / 4, SizeUnit.in); + public static Size DEFAULT_HEIGHT = new Size(1d / 8, SizeUnit.in); + public static Size MARKER_WIDTH = new Size(1d, SizeUnit.mm); + public static Color BODY_COLOR = Color.darkGray; + public static Color MARKER_COLOR = Color.decode("#DDDDDD"); + public static Color LABEL_COLOR = Color.white; + public static Color BORDER_COLOR = BODY_COLOR.darker(); + + private String value = ""; + private Color markerColor = MARKER_COLOR; + + public DiodePlastic() { + super(); + this.labelColor = LABEL_COLOR; + this.bodyColor = BODY_COLOR; + this.borderColor = BORDER_COLOR; + } + + @Override + protected boolean supportsStandingMode() { + return true; + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, width, height / 2); + g2d.setColor(BODY_COLOR); + g2d.fillRect(6, height / 2 - 3, width - 12, 6); + g2d.setColor(MARKER_COLOR); + int markerWidth = 4 * width / 32; + g2d.fillRect(width - 6 - markerWidth, height / 2 - 3, markerWidth, 6); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(6, height / 2 - 3, width - 12, 6); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_HEIGHT; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_WIDTH; + } + + @Override + protected Shape getBodyShape() { + return new Rectangle2D.Double(0f, 0f, getLength().convertToPixels(), + getClosestOdd(getWidth().convertToPixels())); + } + + @Override + protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) { + Color finalMarkerColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalMarkerColor = theme.getOutlineColor(); + } else { + finalMarkerColor = markerColor; + } + g2d.setColor(finalMarkerColor); + int width = (int) getLength().convertToPixels(); + int markerWidth = (int) MARKER_WIDTH.convertToPixels(); + g2d.fillRect(width - markerWidth, 0, markerWidth, getClosestOdd(getWidth() + .convertToPixels())); + } + + @EditableProperty(name = "Marker") + public Color getMarkerColor() { + return markerColor; + } + + public void setMarkerColor(Color markerColor) { + this.markerColor = markerColor; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/FETPolarity.java b/diylc-library/src/org/diylc/components/semiconductors/FETPolarity.java new file mode 100644 index 00000000..f5cc48bb --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/FETPolarity.java @@ -0,0 +1,11 @@ +package org.diylc.components.semiconductors; + +public enum FETPolarity { + + NEGATIVE, POSITIVE; + + @Override + public String toString() { + return name().substring(0, 1) + name().substring(1).toLowerCase(); + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/ICPointCount.java b/diylc-library/src/org/diylc/components/semiconductors/ICPointCount.java new file mode 100644 index 00000000..acca6be6 --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/ICPointCount.java @@ -0,0 +1,22 @@ +package org.diylc.components.semiconductors; + +public enum ICPointCount { + _3("3", 3), _5("5", 5); + + private String title; + private int value; + + private ICPointCount(String title, int value) { + this.title = title; + this.value = value; + } + + @Override + public String toString() { + return title; + } + + public int getValue() { + return value; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/ICSymbol.java b/diylc-library/src/org/diylc/components/semiconductors/ICSymbol.java new file mode 100644 index 00000000..962ae81d --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/ICSymbol.java @@ -0,0 +1,258 @@ +package org.diylc.components.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.Display; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "IC Symbol", author = "Branislav Stojkovic", category = "Semiconductors", instanceNamePrefix = "IC", description = "IC symbol with 3 or 5 contacts", stretchable = false, zOrder = IDIYComponent.COMPONENT) +public class ICSymbol extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); + public static Color BODY_COLOR = Color.white; + public static Color BORDER_COLOR = Color.black; + + protected ICPointCount icPointCount = ICPointCount._5; + protected String value = ""; + protected Point[] controlPoints = new Point[] { new Point(0, 0), new Point(0, 0), + new Point(0, 0), new Point(0, 0), new Point(0, 0) }; + protected Color bodyColor = BODY_COLOR; + protected Color borderColor = BORDER_COLOR; + protected Display display = Display.NAME; + transient private Shape[] body; + + public ICSymbol() { + super(); + updateControlPoints(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + + Shape[] body = getBody(); + + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + g2d.fill(body[0]); + g2d.setComposite(oldComposite); + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = borderColor; + } + g2d.setColor(finalBorderColor); + // Draw contacts + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(body[1]); + // Draw triangle + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.draw(body[0]); + // Draw label + g2d.setFont(LABEL_FONT); + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + int x = (controlPoints[0].x + controlPoints[2].x) / 2; + drawCenteredText(g2d, display == Display.VALUE ? getValue() : getName(), x, + controlPoints[0].y + pinSpacing, HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + // Draw +/- markers + drawCenteredText(g2d, "-", controlPoints[0].x + pinSpacing, controlPoints[0].y, + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + drawCenteredText(g2d, "+", controlPoints[1].x + pinSpacing, controlPoints[1].y, + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 3 * width / 32; + Area area = new Area(new Polygon(new int[] { margin, margin, width - margin }, new int[] { + margin, height - margin, height / 2 }, 3)); + // area.subtract(new Area(new Rectangle2D.Double(0, 0, 2 * margin, + // height))); + area.intersect(new Area(new Rectangle2D.Double(2 * margin, 0, width, height))); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BORDER_COLOR); + g2d.setFont(LABEL_FONT.deriveFont(8f)); + drawCenteredText(g2d, "-", 3 * margin, height / 3, HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + drawCenteredText(g2d, "+", 3 * margin + 1, height * 2 / 3, HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + // g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_ROUND, + // BasicStroke.JOIN_ROUND)); + g2d.draw(area); + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public int getControlPointCount() { + return icPointCount.getValue(); + } + + private void updateControlPoints() { + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + // Update control points. + int x = controlPoints[0].x; + int y = controlPoints[0].y; + + controlPoints[1].x = x; + controlPoints[1].y = y + pinSpacing * 2; + + controlPoints[2].x = x + pinSpacing * 6; + controlPoints[2].y = y + pinSpacing; + + controlPoints[3].x = x + pinSpacing * 3; + controlPoints[3].y = y - pinSpacing; + + controlPoints[4].x = x + pinSpacing * 3; + controlPoints[4].y = y + pinSpacing * 3; + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[2]; + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + int x = controlPoints[0].x; + int y = controlPoints[0].y; + Shape triangle = new Polygon(new int[] { x + pinSpacing / 2, x + pinSpacing * 11 / 2, + x + pinSpacing / 2 }, new int[] { y - pinSpacing * 3 / 2, y + pinSpacing, + y + pinSpacing * 7 / 2 }, 3); + body[0] = triangle; + + GeneralPath polyline = new GeneralPath(); + polyline.moveTo(controlPoints[0].x, controlPoints[0].y); + polyline.lineTo(controlPoints[0].x + pinSpacing / 2, controlPoints[0].y); + polyline.moveTo(controlPoints[1].x, controlPoints[1].y); + polyline.lineTo(controlPoints[1].x + pinSpacing / 2, controlPoints[1].y); + polyline.moveTo(controlPoints[2].x, controlPoints[2].y); + polyline.lineTo(controlPoints[2].x - pinSpacing / 2, controlPoints[2].y); + if (icPointCount == ICPointCount._5) { + polyline.moveTo(controlPoints[3].x, controlPoints[3].y); + polyline.lineTo(controlPoints[3].x, controlPoints[3].y + pinSpacing * 3 / 4); + polyline.moveTo(controlPoints[4].x, controlPoints[4].y); + polyline.lineTo(controlPoints[4].x, controlPoints[4].y - pinSpacing * 3 / 4); + } + body[1] = polyline; + } + return body; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @EditableProperty + @Override + public String getValue() { + return this.value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + @EditableProperty(name = "Contacts") + public ICPointCount getIcPointCount() { + return icPointCount; + } + + public void setIcPointCount(ICPointCount icPointCount) { + this.icPointCount = icPointCount; + updateControlPoints(); + body = null; + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty + public Display getDisplay() { + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/JFETSymbol.java b/diylc-library/src/org/diylc/components/semiconductors/JFETSymbol.java new file mode 100644 index 00000000..3f48f003 --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/JFETSymbol.java @@ -0,0 +1,88 @@ +package org.diylc.components.semiconductors; + +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.GeneralPath; + +import org.diylc.common.ObjectCache; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; + +@ComponentDescriptor(name = "JFET Symbol", author = "Branislav Stojkovic", category = "Semiconductors", instanceNamePrefix = "Q", description = "JFET transistor schematic symbol", stretchable = false, zOrder = IDIYComponent.COMPONENT) +public class JFETSymbol extends AbstractTransistorSymbol { + + private static final long serialVersionUID = 1L; + + protected FETPolarity polarity = FETPolarity.NEGATIVE; + + public Shape[] getBody() { + if (body == null) { + body = new Shape[3]; + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + + GeneralPath polyline = new GeneralPath(); + + polyline.moveTo(x + pinSpacing, y - pinSpacing); + polyline.lineTo(x + pinSpacing, y + pinSpacing); + + body[0] = polyline; + + polyline = new GeneralPath(); + + polyline.moveTo(x, y); + polyline.lineTo(x + pinSpacing, y); + polyline.moveTo(x + pinSpacing, y - pinSpacing * 7 / 8); + polyline.lineTo(x + pinSpacing * 2, y - pinSpacing * 7 / 8); + polyline.lineTo(x + pinSpacing * 2, y - pinSpacing * 2); + polyline.moveTo(x + pinSpacing, y + pinSpacing * 7 / 8); + polyline.lineTo(x + pinSpacing * 2, y + pinSpacing * 7 / 8); + polyline.lineTo(x + pinSpacing * 2, y + pinSpacing * 2); + body[1] = polyline; + + Polygon arrow; + if (polarity == FETPolarity.NEGATIVE) { + arrow = new Polygon(new int[] { x + pinSpacing * 2 / 6, x + pinSpacing * 2 / 6, + x + pinSpacing * 6 / 6 }, new int[] { y - pinSpacing / 5, + y + pinSpacing / 5, y }, 3); + } else { + arrow = new Polygon(new int[] { x + pinSpacing / 6, x + pinSpacing * 5 / 6, + x + pinSpacing * 5 / 6 }, new int[] { y, y + pinSpacing / 5, + y - pinSpacing / 5 }, 3); + } + body[2] = arrow; + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(COLOR); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.drawLine(width / 2, height / 5, width / 2, height * 4 / 5); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.drawLine(width / 5, height / 2, width / 2, height / 2); + + g2d.drawLine(width * 3 / 4, 1, width * 3 / 4, height / 4); + g2d.drawLine(width / 2, height / 4, width * 3 / 4, height / 4); + + g2d.drawLine(width * 3 / 4, height - 1, width * 3 / 4, height * 3 / 4); + g2d.drawLine(width / 2, height * 3 / 4, width * 3 / 4, height * 3 / 4); + } + + @EditableProperty(name = "Channel") + public FETPolarity getPolarity() { + return polarity; + } + + public void setPolarity(FETPolarity polarity) { + this.polarity = polarity; + // Invalidate body + body = null; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/LED.java b/diylc-library/src/org/diylc/components/semiconductors/LED.java new file mode 100644 index 00000000..e58abe2a --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/LED.java @@ -0,0 +1,106 @@ +package org.diylc.components.semiconductors; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractLeadedComponent; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "LED", author = "Branislav Stojkovic", category = "Semiconductors", creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "D", description = "Light Emitting Diode", zOrder = IDIYComponent.COMPONENT) +public class LED extends AbstractLeadedComponent { + + private static final long serialVersionUID = 1L; + + public static Size DEFAULT_SIZE = new Size(5d, SizeUnit.mm); + public static Color BODY_COLOR = Color.decode("#5DFC0A"); + public static Color BORDER_COLOR = BODY_COLOR.darker(); + + private String value = ""; + + public LED() { + super(); + this.bodyColor = BODY_COLOR; + this.borderColor = BORDER_COLOR; + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(LEAD_COLOR); + g2d.drawLine(0, height / 2, width, height / 2); + + int margin = 4 * width / 32; + Area area = new Area(new Ellipse2D.Double(margin, margin, width - 2 * margin, width - 2 + * margin)); + area.intersect(new Area(new Rectangle2D.Double(margin, margin, width - 5 * margin / 2, + width - 2 * margin))); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BORDER_COLOR); + g2d.draw(area); + g2d + .drawOval(margin * 2 - 1, margin * 2 - 1, width - 4 * margin + 2, width - 4 + * margin + 2); + } + + @Override + protected Size getDefaultWidth() { + return DEFAULT_SIZE; + } + + @Override + protected Size getDefaultLength() { + return DEFAULT_SIZE; + } + + @Override + protected Shape getBodyShape() { + int size = getClosestOdd((int) (getLength().convertToPixels() * 1.2)); + Area area = new Area(new Ellipse2D.Double(0, 0, size, size)); + area.intersect(new Area(new Rectangle2D.Double(0, 0, getLength().convertToPixels() * 1.15, + size))); + return area; + } + + @Override + protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) { + if (!outlineMode) { + int size = getClosestOdd((int) (getLength().convertToPixels() * 1.2)); + int innerSize = getClosestOdd(getLength().convertToPixels()); + int x = (size - innerSize) / 2; + Shape s = new Ellipse2D.Double(x, x, innerSize, innerSize); + g2d.setColor(getBorderColor()); + g2d.draw(s); + } + } + + @EditableProperty(name = "Size") + @Override + public Size getLength() { + return super.getLength(); + } + + @Override + public Size getWidth() { + return super.getWidth(); + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/MOSFETSymbol.java b/diylc-library/src/org/diylc/components/semiconductors/MOSFETSymbol.java new file mode 100644 index 00000000..562ea206 --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/MOSFETSymbol.java @@ -0,0 +1,91 @@ +package org.diylc.components.semiconductors; + +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.GeneralPath; + +import org.diylc.common.ObjectCache; +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; + +@ComponentDescriptor(name = "MOSFET Symbol", author = "Branislav Stojkovic", category = "Semiconductors", instanceNamePrefix = "Q", description = "MOSFET transistor schematic symbol", stretchable = false, zOrder = IDIYComponent.COMPONENT) +public class MOSFETSymbol extends AbstractTransistorSymbol { + + private static final long serialVersionUID = 1L; + + protected FETPolarity polarity = FETPolarity.NEGATIVE; + + public Shape[] getBody() { + if (body == null) { + body = new Shape[3]; + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + + GeneralPath polyline = new GeneralPath(); + + polyline.moveTo(x + pinSpacing / 2, y - pinSpacing + 1); + polyline.lineTo(x + pinSpacing / 2, y + pinSpacing - 1); + polyline.moveTo(x + pinSpacing, y - pinSpacing + 1); + polyline.lineTo(x + pinSpacing, y + pinSpacing - 1); + body[0] = polyline; + + polyline = new GeneralPath(); + + polyline.moveTo(x + pinSpacing, y - pinSpacing); + polyline.lineTo(x + pinSpacing * 2, y - pinSpacing); + polyline.moveTo(x + pinSpacing, y + pinSpacing); + polyline.lineTo(x + pinSpacing * 2, y + pinSpacing); + polyline.moveTo(x, y); + polyline.lineTo(x + pinSpacing / 2, y); + polyline.moveTo(x + pinSpacing * 2, y - pinSpacing * 2); + polyline.lineTo(x + pinSpacing * 2, y - pinSpacing); + polyline.moveTo(x + pinSpacing * 2, y + pinSpacing * 2); + polyline.lineTo(x + pinSpacing * 2, y + pinSpacing); + body[1] = polyline; + + Polygon arrow; + if (polarity == FETPolarity.NEGATIVE) { + arrow = new Polygon(new int[] { x + pinSpacing * 8 / 6, x + pinSpacing * 8 / 6, + x + pinSpacing * 12 / 6 }, new int[] { y + pinSpacing * 6 / 5, + y + pinSpacing * 4 / 5, y + pinSpacing }, 3); + } else { + arrow = new Polygon(new int[] { x + pinSpacing * 7 / 6, x + pinSpacing * 11 / 6, + x + pinSpacing * 11 / 6 }, new int[] { y - pinSpacing, + y - pinSpacing * 6 / 5, y - pinSpacing * 4 / 5 }, 3); + } + body[2] = arrow; + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.drawLine(width * 2 / 5, height / 4 + 1, width * 2 / 5, height * 3 / 4 - 1); + g2d.drawLine(width * 3 / 5, height / 4 + 1, width * 3 / 5, height * 3 / 4 - 1); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.drawLine(width / 5, height / 2, width * 2 / 5, height / 2); + + g2d.drawLine(width * 4 / 5, 1, width * 4 / 5, height / 4); + g2d.drawLine(width * 4 / 5, height / 4, width * 3 / 5, height / 4); + + g2d.drawLine(width * 4 / 5, height - 1, width * 4 / 5, height * 3 / 4); + g2d.drawLine(width * 4 / 5, height * 3 / 4, width * 3 / 5, height * 3 / 4); + } + + @EditableProperty(name = "Channel") + public FETPolarity getPolarity() { + return polarity; + } + + public void setPolarity(FETPolarity polarity) { + this.polarity = polarity; + // Invalidate body + body = null; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/TransistorTO220.java b/diylc-library/src/org/diylc/components/semiconductors/TransistorTO220.java new file mode 100644 index 00000000..c29f5cef --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/TransistorTO220.java @@ -0,0 +1,322 @@ +package org.diylc.components.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.Display; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Transistor (TO-220 package)", author = "Branislav Stojkovic", category = "Semiconductors", instanceNamePrefix = "Q", description = "Transistors with metal tab for heat sink mounting", stretchable = false, zOrder = IDIYComponent.COMPONENT) +public class TransistorTO220 extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.gray; + public static Color BORDER_COLOR = Color.gray.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color TAB_COLOR = Color.decode("#C3E4ED"); + public static Color TAB_BORDER_COLOR = TAB_COLOR.darker(); + public static Color LABEL_COLOR = Color.white; + public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); + public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); + public static Size BODY_WIDTH = new Size(0.4d, SizeUnit.in); + public static Size BODY_HEIGHT = new Size(4.5d, SizeUnit.mm); + public static Size TAB_THICKNESS = new Size(1d, SizeUnit.mm); + + private String value = ""; + private Orientation orientation = Orientation.DEFAULT; + private Point[] controlPoints = new Point[] { new Point(0, 0), new Point(0, 0), new Point(0, 0) }; + transient private Shape[] body; + private Color bodyColor = BODY_COLOR; + private Color borderColor = BORDER_COLOR; + private Color tabColor = TAB_COLOR; + private Color tabBorderColor = TAB_BORDER_COLOR; + private Display display = Display.NAME; + + public TransistorTO220() { + super(); + updateControlPoints(); + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + // Update control points. + int x = controlPoints[0].x; + int y = controlPoints[0].y; + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(x, y + pinSpacing); + controlPoints[2].setLocation(x, y + 2 * pinSpacing); + break; + case _90: + controlPoints[1].setLocation(x - pinSpacing, y); + controlPoints[2].setLocation(x - 2 * pinSpacing, y); + break; + case _180: + controlPoints[1].setLocation(x, y - pinSpacing); + controlPoints[2].setLocation(x, y - 2 * pinSpacing); + break; + case _270: + controlPoints[1].setLocation(x + pinSpacing, y); + controlPoints[2].setLocation(x + 2 * pinSpacing, y); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[2]; + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + int bodyWidth = getClosestOdd(BODY_WIDTH.convertToPixels()); + int bodyHeight = getClosestOdd(BODY_HEIGHT.convertToPixels()); + int tabThickness = (int) TAB_THICKNESS.convertToPixels(); + + switch (orientation) { + case DEFAULT: + body[0] = new Rectangle2D.Double(x - bodyHeight / 2, + y + pinSpacing - bodyWidth / 2, bodyHeight, bodyWidth); + body[1] = new Rectangle2D.Double(x + bodyHeight / 2 - tabThickness, y + pinSpacing + - bodyWidth / 2, tabThickness, bodyWidth); + break; + case _90: + body[0] = new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, + y - bodyHeight / 2, bodyWidth, bodyHeight); + body[1] = new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + bodyHeight / 2 + - tabThickness, bodyWidth, tabThickness); + break; + case _180: + body[0] = new Rectangle2D.Double(x - bodyHeight / 2, + y - pinSpacing - bodyWidth / 2, bodyHeight, bodyWidth); + body[1] = new Rectangle2D.Double(x - bodyHeight / 2, + y - pinSpacing - bodyWidth / 2, tabThickness, bodyWidth); + break; + case _270: + body[0] = new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, + y - bodyHeight / 2, bodyWidth, bodyHeight); + body[1] = new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, + y - bodyHeight / 2, bodyWidth, tabThickness); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + Shape mainArea = getBody()[0]; + Shape tabArea = getBody()[1]; + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + g2d.fill(mainArea); + Color finalTabColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalTabColor = theme.getOutlineColor(); + } else { + finalTabColor = tabColor; + } + g2d.setColor(finalTabColor); + g2d.fill(tabArea); + g2d.setComposite(oldComposite); + if (!outlineMode) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(tabBorderColor); + g2d.draw(tabArea); + } + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : borderColor; + } + g2d.setColor(finalBorderColor); + g2d.draw(mainArea); + + // Draw pins. + if (!outlineMode) { + for (Point point : controlPoints) { + g2d.setColor(PIN_COLOR); + g2d.fillOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + } + } + + // Draw label. + g2d.setFont(LABEL_FONT); + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + String label = (getDisplay() == Display.NAME) ? getName() : getValue(); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = bounds.x + (bounds.width - textWidth) / 2; + int y = bounds.y + (bounds.height - textHeight) / 2 + fontMetrics.getAscent(); + g2d.drawString(label, x, y); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BODY_COLOR); + int margin = 2 * width / 32; + int thickness = 7 * width / 32; + g2d.fillRect(margin, (height - thickness) / 2, width - margin * 2, thickness); + g2d.setColor(TAB_COLOR); + g2d.fillRect(margin, (height + thickness) / 2 - margin - 1, width - margin * 2, margin); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(margin, (height - thickness) / 2, width - margin * 2, thickness); + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "Tab") + public Color getTabColor() { + return tabColor; + } + + public void setTabColor(Color tabColor) { + this.tabColor = tabColor; + } + + @EditableProperty(name = "Tab border") + public Color getTabBorderColor() { + return tabBorderColor; + } + + public void setTabBorderColor(Color tabBorderColor) { + this.tabBorderColor = tabBorderColor; + } + + @EditableProperty + public Display getDisplay() { + if (display == null) { + display = Display.NAME; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } +} diff --git a/diylc-library/src/org/diylc/components/semiconductors/TransistorTO92.java b/diylc-library/src/org/diylc/components/semiconductors/TransistorTO92.java new file mode 100644 index 00000000..033bcc41 --- /dev/null +++ b/diylc-library/src/org/diylc/components/semiconductors/TransistorTO92.java @@ -0,0 +1,282 @@ +package org.diylc.components.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.Display; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Transistor (TO-92 package)", author = "Branislav Stojkovic", category = "Semiconductors", instanceNamePrefix = "Q", description = "Transistor with small plastic or epoxy body", stretchable = false, zOrder = IDIYComponent.COMPONENT) +public class TransistorTO92 extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.gray; + public static Color BORDER_COLOR = Color.gray.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color LABEL_COLOR = Color.white; + public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); + public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); + public static Size BODY_DIAMETER = new Size(0.2d, SizeUnit.in); + + private String value = ""; + private Orientation orientation = Orientation.DEFAULT; + private Point[] controlPoints = new Point[] { new Point(0, 0), new Point(0, 0), new Point(0, 0) }; + transient private Area body; + private Color bodyColor = BODY_COLOR; + private Color borderColor = BORDER_COLOR; + protected Display display = Display.NAME; + + public TransistorTO92() { + super(); + updateControlPoints(); + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + // Update control points. + int x = controlPoints[0].x; + int y = controlPoints[0].y; + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(x, y + pinSpacing); + controlPoints[2].setLocation(x, y + 2 * pinSpacing); + break; + case _90: + controlPoints[1].setLocation(x - pinSpacing, y); + controlPoints[2].setLocation(x - 2 * pinSpacing, y); + break; + case _180: + controlPoints[1].setLocation(x, y - pinSpacing); + controlPoints[2].setLocation(x, y - 2 * pinSpacing); + break; + case _270: + controlPoints[1].setLocation(x + pinSpacing, y); + controlPoints[2].setLocation(x + 2 * pinSpacing, y); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + + public Area getBody() { + if (body == null) { + int x = controlPoints[0].x; + int y = controlPoints[0].y; + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + int bodyDiameter = getClosestOdd(BODY_DIAMETER.convertToPixels()); + + switch (orientation) { + case DEFAULT: + body = new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y + pinSpacing + - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + body.subtract(new Area(new Rectangle2D.Double(x - bodyDiameter, y + pinSpacing + - bodyDiameter / 2, 3 * bodyDiameter / 4, bodyDiameter))); + break; + case _90: + body = new Area(new Ellipse2D.Double(x - pinSpacing - bodyDiameter / 2, y + - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + body.subtract(new Area(new Rectangle2D.Double(x - pinSpacing - bodyDiameter / 2, y + - bodyDiameter, bodyDiameter, 3 * bodyDiameter / 4))); + break; + case _180: + body = new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - pinSpacing + - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + body.subtract(new Area(new Rectangle2D.Double(x + bodyDiameter / 4, y - pinSpacing + - bodyDiameter / 2, 3 * bodyDiameter / 4, bodyDiameter))); + break; + case _270: + body = new Area(new Ellipse2D.Double(x + pinSpacing - bodyDiameter / 2, y + - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + body.subtract(new Area(new Rectangle2D.Double(x + pinSpacing - bodyDiameter / 2, y + + bodyDiameter / 4, bodyDiameter, 3 * bodyDiameter / 4))); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + Area mainArea = getBody(); + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + g2d.fill(mainArea); + g2d.setComposite(oldComposite); + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : borderColor; + } + g2d.setColor(finalBorderColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(mainArea); + + if (!outlineMode) { + for (Point point : controlPoints) { + g2d.setColor(PIN_COLOR); + g2d.fillOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + } + } + + // Draw label. + g2d.setFont(LABEL_FONT); + Color finalLabelColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme + .getOutlineColor(); + } else { + finalLabelColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + String label = (getDisplay() == Display.NAME) ? getName() : getValue(); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = bounds.x + (bounds.width - textWidth) / 2; + int y = bounds.y + (bounds.height - textHeight) / 2 + fontMetrics.getAscent(); + g2d.drawString(label, x, y); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 3 * width / 32; + Area area = new Area(new Ellipse2D.Double(margin / 2, margin, width - 2 * margin, width - 2 + * margin)); + // area.subtract(new Area(new Rectangle2D.Double(0, 0, 2 * margin, + // height))); + area.intersect(new Area(new Rectangle2D.Double(2 * margin, 0, width, height))); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BORDER_COLOR); + g2d.draw(area); + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty + public Display getDisplay() { + if (display == null) { + display = Display.NAME; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } +} diff --git a/diylc-library/src/org/diylc/components/tube/TubeSocket.java b/diylc-library/src/org/diylc/components/tube/TubeSocket.java new file mode 100644 index 00000000..52c5ca47 --- /dev/null +++ b/diylc-library/src/org/diylc/components/tube/TubeSocket.java @@ -0,0 +1,327 @@ +package org.diylc.components.tube; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Tube Socket", author = "Branislav Stojkovic", category = "Tubes", instanceNamePrefix = "V", description = "Various types of tube/valve sockets", stretchable = false, zOrder = IDIYComponent.COMPONENT) +public class TubeSocket extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.decode("#FFFFE0"); + private static Color BORDER_COLOR = Color.decode("#8E8E38"); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Size PIN_SIZE = new Size(1d, SizeUnit.mm); + public static Size HOLE_SIZE = new Size(5d, SizeUnit.mm); + public static Size TICK_SIZE = new Size(2d, SizeUnit.mm); + + private Base base = Base.B9A; + private String type = ""; + private Orientation orientation = Orientation.DEFAULT; + // private Mount mount = Mount.CHASSIS; + + private Point[] controlPoints = new Point[] { new Point(0, 0) }; + + transient private Shape body; + + public TubeSocket() { + super(); + updateControlPoints(); + } + + @EditableProperty + public Base getBase() { + return base; + } + + public void setBase(Base base) { + this.base = base; + updateControlPoints(); + // Reset body shape + body = null; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape + body = null; + } + + // @EditableProperty + // public Mount getMount() { + // return mount; + // } + // + // public void setMount(Mount mount) { + // this.mount = mount; + // } + + private void updateControlPoints() { + Point firstPoint = controlPoints[0]; + int pinCount; + int pinCircleDiameter; + boolean hasEmptySpace; + switch (base) { + case B7G: + pinCount = 7; + pinCircleDiameter = getClosestOdd(new Size(12d, SizeUnit.mm).convertToPixels()); + hasEmptySpace = true; + break; + case OCTAL: + pinCount = 8; + pinCircleDiameter = getClosestOdd(new Size(17.5d, SizeUnit.mm).convertToPixels()); + hasEmptySpace = false; + break; + case B9A: + pinCount = 9; + pinCircleDiameter = getClosestOdd(new Size(21d, SizeUnit.mm).convertToPixels()); + hasEmptySpace = true; + break; + default: + throw new RuntimeException("Unexpected base: " + base); + } + double angleIncrement = Math.PI * 2 / (hasEmptySpace ? (pinCount + 1) : pinCount); + double initialAngleOffset = hasEmptySpace ? angleIncrement : (angleIncrement / 2); + double initialAngle; + switch (orientation) { + case DEFAULT: + initialAngle = Math.PI / 2 + initialAngleOffset; + break; + case _90: + initialAngle = Math.PI + initialAngleOffset; + break; + case _180: + initialAngle = 3 * Math.PI / 2 + initialAngleOffset; + break; + case _270: + initialAngle = initialAngleOffset; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + controlPoints = new Point[pinCount + 1]; + double angle = initialAngle; + controlPoints[0] = firstPoint; + for (int i = 0; i < pinCount; i++) { + controlPoints[i + 1] = new Point((int) (firstPoint.getX() + Math.cos(angle) + * pinCircleDiameter / 2), (int) (firstPoint.getY() + Math.sin(angle) + * pinCircleDiameter / 2)); + angle += angleIncrement; + } + } + + public Shape getBody() { + if (body == null) { + int bodyDiameter; + switch (base) { + case B7G: + bodyDiameter = getClosestOdd(new Size(17d, SizeUnit.mm).convertToPixels()); + break; + case B9A: + bodyDiameter = getClosestOdd(new Size(19d, SizeUnit.mm).convertToPixels()); + break; + case OCTAL: + bodyDiameter = getClosestOdd(new Size(24.5d, SizeUnit.mm).convertToPixels()); + break; + default: + throw new RuntimeException("Unexpected base: " + base); + } + body = new Ellipse2D.Double(controlPoints[0].x - bodyDiameter / 2, controlPoints[0].y + - bodyDiameter / 2, bodyDiameter, bodyDiameter); + Area bodyArea = new Area(body); + int holeSize = getClosestOdd(HOLE_SIZE.convertToPixels()); + bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].x - holeSize / 2, + controlPoints[0].y - holeSize / 2, holeSize, holeSize))); + if (base == Base.OCTAL) { + int tickSize = getClosestOdd(TICK_SIZE.convertToPixels()); + double angle = 0; + switch (orientation) { + case DEFAULT: + angle = Math.PI / 2; + break; + case _90: + angle = Math.PI; + break; + case _180: + angle = 3 * Math.PI / 2; + break; + case _270: + angle = 0; + break; + } + int centerX = (int) (controlPoints[0].x + Math.cos(angle) * holeSize / 2); + int centerY = (int) (controlPoints[0].y + Math.sin(angle) * holeSize / 2); + bodyArea.subtract(new Area(new Ellipse2D.Double(centerX - tickSize / 2, centerY + - tickSize / 2, tickSize, tickSize))); + } + body = bodyArea; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + // g2d.setColor(Color.black); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + // for (int i = 0; i < controlPoints.length; i++) { + // g2d.drawString(Integer.toString(i), controlPoints[i].x, + // controlPoints[i].y); + // } + // Draw body + Shape body = getBody(); + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha + / MAX_ALPHA)); + } + if (componentState != ComponentState.DRAGGING) { + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + g2d.fill(body); + } + g2d.setComposite(oldComposite); + Color finalBorderColor; + if (outlineMode) { + Theme theme = (Theme) ConfigurationManager.getInstance().readObject( + IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme + .getOutlineColor(); + } else { + finalBorderColor = componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : BORDER_COLOR; + } + g2d.setColor(finalBorderColor); + g2d.draw(body); + // Draw pins + if (!outlineMode) { + int pinSize = getClosestOdd(PIN_SIZE.convertToPixels()); + for (int i = 1; i < controlPoints.length; i++) { + g2d.setColor(PIN_COLOR); + g2d.fillOval(controlPoints[i].x - pinSize / 2, controlPoints[i].y - pinSize / 2, + pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(controlPoints[i].x - pinSize / 2, controlPoints[i].y - pinSize / 2, + pinSize, pinSize); + } + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + Area area = new Area(new Ellipse2D.Double(1, 1, width - 2, width - 2)); + int center = width / 2; + area.subtract(new Area(new Ellipse2D.Double(center - 2, center - 2, 5, 5))); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BORDER_COLOR); + g2d.draw(area); + + int radius = width / 2 - 6; + for (int i = 0; i < 8; i++) { + int x = (int) (center + Math.cos(i * Math.PI / 4) * radius); + int y = (int) (center + Math.sin(i * Math.PI / 4) * radius); + g2d.setColor(PIN_COLOR); + g2d.fillOval(x - 1, y - 1, 3, 3); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(x - 1, y - 1, 3, 3); + } + } + + @Override + public Point getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + @EditableProperty(name = "Type") + public String getValue() { + return type; + } + + @Override + public void setValue(String value) { + this.type = value; + } + + @Override + public boolean isControlPointSticky(int index) { + return index > 0; + } + + @Override + public void setControlPoint(Point point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + static enum Base { + B9A("Noval B9A"), OCTAL("Octal"), B7G("Small-button B7G"); + + String name; + + private Base(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + + static enum Mount { + CHASSIS("Chassis"), PCB("PCB"); + + String name; + + private Mount(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } +}