diff --git a/Library/.classpath b/Library/.classpath new file mode 100644 index 00000000..85279d70 --- /dev/null +++ b/Library/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Library/.project b/Library/.project new file mode 100644 index 00000000..18f823d0 --- /dev/null +++ b/Library/.project @@ -0,0 +1,17 @@ + + + Library + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/Library/build.xml b/Library/build.xml new file mode 100644 index 00000000..bd2075b4 --- /dev/null +++ b/Library/build.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + Compile with JDK ${java.runtime.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Library/lib/diylc.jar b/Library/lib/diylc.jar new file mode 100644 index 00000000..2815b211 Binary files /dev/null and b/Library/lib/diylc.jar differ diff --git a/Library/lib/log4j-1.2.15.jar b/Library/lib/log4j-1.2.15.jar new file mode 100644 index 00000000..c930a6ab Binary files /dev/null and b/Library/lib/log4j-1.2.15.jar differ diff --git a/Library/lib/xstream-1.3.1.jar b/Library/lib/xstream-1.3.1.jar new file mode 100644 index 00000000..4ef4219c Binary files /dev/null and b/Library/lib/xstream-1.3.1.jar differ diff --git a/Library/src/org/diylc/components/boards/AbstractBoard.java b/Library/src/org/diylc/components/boards/AbstractBoard.java new file mode 100644 index 00000000..23300cac --- /dev/null +++ b/Library/src/org/diylc/components/boards/AbstractBoard.java @@ -0,0 +1,121 @@ +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.ObjectCache; +import org.diylc.components.AbstractTransparentComponent; +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; + +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 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; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, 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(); + } + + @EditableProperty(name = "Color") + public Color getBoardColor() { + return boardColor; + } + + public void setBoardColor(Color boardColor) { + this.boardColor = boardColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @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/Library/src/org/diylc/components/boards/BlankBoard.java b/Library/src/org/diylc/components/boards/BlankBoard.java new file mode 100644 index 00000000..8fd4958e --- /dev/null +++ b/Library/src/org/diylc/components/boards/BlankBoard.java @@ -0,0 +1,20 @@ +package org.diylc.components.boards; + +import java.awt.Graphics2D; + +import org.diylc.core.IDIYComponent; +import org.diylc.core.annotations.ComponentDescriptor; + +@ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board") +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); + } +} diff --git a/Library/src/org/diylc/components/boards/EyeletBoard.java b/Library/src/org/diylc/components/boards/EyeletBoard.java new file mode 100644 index 00000000..c40703fd --- /dev/null +++ b/Library/src/org/diylc/components/boards/EyeletBoard.java @@ -0,0 +1,115 @@ +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.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 = "Eyelet Board", category = "Boards", author = "Branislav Stojkovic", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated board with eyelets") +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, 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, 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); + } + } + } + } + + @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/Library/src/org/diylc/components/boards/MarshallPerfBoard.java b/Library/src/org/diylc/components/boards/MarshallPerfBoard.java new file mode 100644 index 00000000..e635e753 --- /dev/null +++ b/Library/src/org/diylc/components/boards/MarshallPerfBoard.java @@ -0,0 +1,109 @@ +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.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 = "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") +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, 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, 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); + } + } + } + } + + @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/Library/src/org/diylc/components/boards/PerfBoard.java b/Library/src/org/diylc/components/boards/PerfBoard.java new file mode 100644 index 00000000..461f9863 --- /dev/null +++ b/Library/src/org/diylc/components/boards/PerfBoard.java @@ -0,0 +1,107 @@ +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.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 = "Perf Board w/ Pads", category = "Boards", author = "Branislav Stojkovic", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated board with solder pads") +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, 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, 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); + } + } + } + } + + @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/Library/src/org/diylc/components/boards/VeroBoard.java b/Library/src/org/diylc/components/boards/VeroBoard.java new file mode 100644 index 00000000..a17a1b61 --- /dev/null +++ b/Library/src/org/diylc/components/boards/VeroBoard.java @@ -0,0 +1,142 @@ +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.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") +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, 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, 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); + } + } + + @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/Library/src/org/diylc/components/connectivity/AWG.java b/Library/src/org/diylc/components/connectivity/AWG.java new file mode 100644 index 00000000..d1edc701 --- /dev/null +++ b/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/Library/src/org/diylc/components/connectivity/CopperTrace.java b/Library/src/org/diylc/components/connectivity/CopperTrace.java new file mode 100644 index 00000000..428e4a00 --- /dev/null +++ b/Library/src/org/diylc/components/connectivity/CopperTrace.java @@ -0,0 +1,122 @@ +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.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) +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/Library/src/org/diylc/components/connectivity/CurvedTrace.java b/Library/src/org/diylc/components/connectivity/CurvedTrace.java new file mode 100644 index 00000000..0255f09f --- /dev/null +++ b/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.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; + +@ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity", instanceNamePrefix = "Trace", description = "Curved copper trace with two control points", zOrder = IDIYComponent.TRACE) +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 getSize() { + return size; + } + + public void setSize(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/Library/src/org/diylc/components/connectivity/Eyelet.java b/Library/src/org/diylc/components/connectivity/Eyelet.java new file mode 100644 index 00000000..5614bda1 --- /dev/null +++ b/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.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 = "Eyelet", category = "Connectivity", author = "Branislav Stojkovic", description = "Eyelet or turret terminal", instanceNamePrefix = "Eyelet", stretchable = false, zOrder = IDIYComponent.TRACE + 0.1) +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, 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/Library/src/org/diylc/components/connectivity/HookupWire.java b/Library/src/org/diylc/components/connectivity/HookupWire.java new file mode 100644 index 00000000..aa9832e1 --- /dev/null +++ b/Library/src/org/diylc/components/connectivity/HookupWire.java @@ -0,0 +1,63 @@ +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.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) +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/Library/src/org/diylc/components/connectivity/Jumper.java b/Library/src/org/diylc/components/connectivity/Jumper.java new file mode 100644 index 00000000..b39fa2cb --- /dev/null +++ b/Library/src/org/diylc/components/connectivity/Jumper.java @@ -0,0 +1,97 @@ +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.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) +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/Library/src/org/diylc/components/connectivity/SolderPad.java b/Library/src/org/diylc/components/connectivity/SolderPad.java new file mode 100644 index 00000000..f1b59ae3 --- /dev/null +++ b/Library/src/org/diylc/components/connectivity/SolderPad.java @@ -0,0 +1,139 @@ +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.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 = "Solder Pad", category = "Connectivity", author = "Branislav Stojkovic", description = "test", instanceNamePrefix = "Pad", stretchable = false, zOrder = IDIYComponent.TRACE + 0.1) +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; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int diameter = getClosestOdd((int) size.convertToPixels()); + int holeDiameter = getClosestOdd((int) HOLE_SIZE.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; + } + + @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/Library/src/org/diylc/components/connectivity/TraceCut.java b/Library/src/org/diylc/components/connectivity/TraceCut.java new file mode 100644 index 00000000..106821f3 --- /dev/null +++ b/Library/src/org/diylc/components/connectivity/TraceCut.java @@ -0,0 +1,132 @@ +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.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) +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, 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/Library/src/org/diylc/components/electromechanical/MiniToggleSwitch.java b/Library/src/org/diylc/components/electromechanical/MiniToggleSwitch.java new file mode 100644 index 00000000..e5f47aad --- /dev/null +++ b/Library/src/org/diylc/components/electromechanical/MiniToggleSwitch.java @@ -0,0 +1,253 @@ +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.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; + +@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_HEIGHT = new Size(0.03d, SizeUnit.in); + + private static Color BODY_COLOR = Color.decode("#3299CC"); + private static Color BORDER_COLOR = BODY_COLOR.darker(); + private static Color CIRCLE_COLOR = Color.red; + private static Color LUG_COLOR = Color.decode("#00B2EE"); + + 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, 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(BODY_COLOR); + g2d.fill(body); + g2d.setComposite(oldComposite); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : BORDER_COLOR); + 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_HEIGHT.convertToPixels()); + for (Point p : controlPoints) { + g2d.setColor(CIRCLE_COLOR); + g2d.fillOval(p.x - circleDiameter / 2, p.y - circleDiameter / 2, circleDiameter, + circleDiameter); + g2d.setColor(LUG_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); + g2d.setColor(CIRCLE_COLOR); + for (int i = 1; i <= 3; i++) { + g2d.fillOval(width / 2 - circleSize / 2, i * height / 4 - 3, circleSize, circleSize); + } + } +} diff --git a/Library/src/org/diylc/components/electromechanical/ToggleSwitchType.java b/Library/src/org/diylc/components/electromechanical/ToggleSwitchType.java new file mode 100644 index 00000000..6a9e0c2e --- /dev/null +++ b/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/Library/src/org/diylc/components/misc/BOM.java b/Library/src/org/diylc/components/misc/BOM.java new file mode 100644 index 00000000..e95dc10a --- /dev/null +++ b/Library/src/org/diylc/components/misc/BOM.java @@ -0,0 +1,171 @@ +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.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.swing.plugins.file.BomEntry; +import org.diylc.swing.plugins.file.BomMaker; + +@ComponentDescriptor(name = "Bill of Materials", author = "Branislav Stojkovic", category = "Misc", description = "", instanceNamePrefix = "BOM", zOrder = IDIYComponent.TEXT, stretchable = false) +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, 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) { + 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(entry.getValue().toString(), 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; + 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++) { + int columnIndex = i / entriesPerColumn; + int rowIndex = i % entriesPerColumn; + int x = point.x + columnIndex * columnWidth; + int y = point.y + rowIndex * maxHeight; + g2d.drawString(bom.get(i).getName(), x, y); + x += maxNameWidth + SPACING.convertToPixels(); + g2d.drawString(bom.get(i).getValue().toString(), 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/Library/src/org/diylc/components/misc/IconImageConverter.java b/Library/src/org/diylc/components/misc/IconImageConverter.java new file mode 100644 index 00000000..6df78527 --- /dev/null +++ b/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/Library/src/org/diylc/components/misc/Image.java b/Library/src/org/diylc/components/misc/Image.java new file mode 100644 index 00000000..eaea7448 --- /dev/null +++ b/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.Theme; +import org.diylc.core.VisibilityPolicy; +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) +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, 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/Library/src/org/diylc/components/misc/Label.java b/Library/src/org/diylc/components/misc/Label.java new file mode 100644 index 00000000..d8f4a071 --- /dev/null +++ b/Library/src/org/diylc/components/misc/Label.java @@ -0,0 +1,202 @@ +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.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) +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, 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/Library/src/org/diylc/components/misc/image.png b/Library/src/org/diylc/components/misc/image.png new file mode 100644 index 00000000..b663869f Binary files /dev/null and b/Library/src/org/diylc/components/misc/image.png differ diff --git a/Library/src/org/diylc/components/passive/AbstractPotentiometer.java b/Library/src/org/diylc/components/passive/AbstractPotentiometer.java new file mode 100644 index 00000000..b6151fbb --- /dev/null +++ b/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/Library/src/org/diylc/components/passive/AxialElectrolyticCapacitor.java b/Library/src/org/diylc/components/passive/AxialElectrolyticCapacitor.java new file mode 100644 index 00000000..c0fbf7bf --- /dev/null +++ b/Library/src/org/diylc/components/passive/AxialElectrolyticCapacitor.java @@ -0,0 +1,136 @@ +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.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; + +@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); + private Voltage voltage = Voltage._63V; + + 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; + } + + @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.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) { + if (polarized) { + int markerLength = (int) (getLength().convertToPixels() * 0.2); + g2d.setColor(markerColor); + int width = getClosestOdd(getWidth().convertToPixels()); + g2d + .fillRect((int) getLength().convertToPixels() - markerLength, 0, markerLength, + width); + g2d.setColor(tickColor); + 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/Library/src/org/diylc/components/passive/AxialFilmCapacitor.java b/Library/src/org/diylc/components/passive/AxialFilmCapacitor.java new file mode 100644 index 00000000..9b75f089 --- /dev/null +++ b/Library/src/org/diylc/components/passive/AxialFilmCapacitor.java @@ -0,0 +1,86 @@ +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; + +@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); + private Voltage voltage = Voltage._63V; + + 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; + } + + @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.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/Library/src/org/diylc/components/passive/CapacitorSymbol.java b/Library/src/org/diylc/components/passive/CapacitorSymbol.java new file mode 100644 index 00000000..1baa740b --- /dev/null +++ b/Library/src/org/diylc/components/passive/CapacitorSymbol.java @@ -0,0 +1,101 @@ +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.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; + +@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); + private Voltage voltage = Voltage._63V; + private boolean polarized = false; + + @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; + } + + @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) { + 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/Library/src/org/diylc/components/passive/PotentiometerPanel.java b/Library/src/org/diylc/components/passive/PotentiometerPanel.java new file mode 100644 index 00000000..e4ce854f --- /dev/null +++ b/Library/src/org/diylc/components/passive/PotentiometerPanel.java @@ -0,0 +1,279 @@ +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.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; + +@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, 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/Library/src/org/diylc/components/passive/PotentiometerValue.java b/Library/src/org/diylc/components/passive/PotentiometerValue.java new file mode 100644 index 00000000..26f3caee --- /dev/null +++ b/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/Library/src/org/diylc/components/passive/Power.java b/Library/src/org/diylc/components/passive/Power.java new file mode 100644 index 00000000..18f6d77c --- /dev/null +++ b/Library/src/org/diylc/components/passive/Power.java @@ -0,0 +1,18 @@ +package org.diylc.components.passive; + +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; + } +} diff --git a/Library/src/org/diylc/components/passive/RadialCeramicDiskCapacitor.java b/Library/src/org/diylc/components/passive/RadialCeramicDiskCapacitor.java new file mode 100644 index 00000000..876a800d --- /dev/null +++ b/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/Library/src/org/diylc/components/passive/RadialElectrolytic.java b/Library/src/org/diylc/components/passive/RadialElectrolytic.java new file mode 100644 index 00000000..e3326209 --- /dev/null +++ b/Library/src/org/diylc/components/passive/RadialElectrolytic.java @@ -0,0 +1,171 @@ +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.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; + +@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); + private Voltage voltage = Voltage._63V; + + 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; + } + + @EditableProperty + public Voltage getVoltage() { + return voltage; + } + + public void setVoltage(Voltage voltage) { + this.voltage = voltage; + } + + 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) { + if (polarized) { + int totalDiameter = getClosestOdd(getLength().convertToPixels()); + Area area = new Area(getBodyShape()); + area + .subtract(new Area(new Rectangle2D.Double(0, 0, totalDiameter * 0.8, + totalDiameter))); + g2d.setColor(markerColor); + g2d.fill(area); + g2d.setColor(tickColor); + 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/Library/src/org/diylc/components/passive/RadialFilmCapacitor.java b/Library/src/org/diylc/components/passive/RadialFilmCapacitor.java new file mode 100644 index 00000000..044b7f14 --- /dev/null +++ b/Library/src/org/diylc/components/passive/RadialFilmCapacitor.java @@ -0,0 +1,82 @@ +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; + +@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); + private Voltage voltage = Voltage._63V; + + 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; + } + + @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.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/Library/src/org/diylc/components/passive/Resistor.java b/Library/src/org/diylc/components/passive/Resistor.java new file mode 100644 index 00000000..e9556419 --- /dev/null +++ b/Library/src/org/diylc/components/passive/Resistor.java @@ -0,0 +1,122 @@ +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.Theme; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.PositiveMeasureValidator; +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 = "test", 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(); + + private Resistance value = new Resistance(123d, ResistanceUnit.K); + private Power power = Power.HALF; + 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; + } + + @EditableProperty + public Power getPower() { + return power; + } + + public void setPower(Power power) { + this.power = power; + } + + 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) { + // int width = getWidth().convertToPixels(); + if (colorCode == ResistorColorCode.NONE) { + return; + } + int height = getClosestOdd(getWidth().convertToPixels()); + Color[] bands = value.getColorCode(colorCode); + int x = 4; + 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 += 5; + } + } +} diff --git a/Library/src/org/diylc/components/passive/ResistorSymbol.java b/Library/src/org/diylc/components/passive/ResistorSymbol.java new file mode 100644 index 00000000..32c2aa0c --- /dev/null +++ b/Library/src/org/diylc/components/passive/ResistorSymbol.java @@ -0,0 +1,84 @@ +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.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 = "", 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); + private Power power = Power.HALF; + + @EditableProperty + public Resistance getValue() { + return value; + } + + public void setValue(Resistance value) { + this.value = value; + } + + @EditableProperty + public Power getPower() { + return power; + } + + public void setPower(Power power) { + this.power = power; + } + + 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/Library/src/org/diylc/components/passive/ResistorValue.java b/Library/src/org/diylc/components/passive/ResistorValue.java new file mode 100644 index 00000000..4fbe5c80 --- /dev/null +++ b/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/Library/src/org/diylc/components/passive/Taper.java b/Library/src/org/diylc/components/passive/Taper.java new file mode 100644 index 00000000..5dcd8f93 --- /dev/null +++ b/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/Library/src/org/diylc/components/passive/TrimmerPotentiometer.java b/Library/src/org/diylc/components/passive/TrimmerPotentiometer.java new file mode 100644 index 00000000..8b03bc26 --- /dev/null +++ b/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, 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/Library/src/org/diylc/components/passive/Voltage.java b/Library/src/org/diylc/components/passive/Voltage.java new file mode 100644 index 00000000..f8719b24 --- /dev/null +++ b/Library/src/org/diylc/components/passive/Voltage.java @@ -0,0 +1,11 @@ +package org.diylc.components.passive; + +public enum Voltage { + + _16V, _25V, _63V, _100V, _160V, _250V, _300V, _350V, _400V, _500V, _630V, _1KV; + + @Override + public String toString() { + return name().replace("_", ""); + } +} diff --git a/Library/src/org/diylc/components/semiconductors/DIL_IC.java b/Library/src/org/diylc/components/semiconductors/DIL_IC.java new file mode 100644 index 00000000..84cf3f10 --- /dev/null +++ b/Library/src/org/diylc/components/semiconductors/DIL_IC.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.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; + +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.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; + +@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) }; + // 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; + } + + @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, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + Area mainArea = getBody()[0]; + 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(BODY_COLOR); + g2d.fill(mainArea); + g2d.setComposite(oldComposite); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : BORDER_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(mainArea); + if (getBody()[1] != null) { + g2d.setColor(INDENT_COLOR); + g2d.fill(getBody()[1]); + } + // Draw label. + g2d.setFont(LABEL_FONT); + g2d.setColor(LABEL_COLOR); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(getName(), 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(getName(), 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; + + @Override + public String toString() { + return name().replace("_", ""); + } + + public int getValue() { + return Integer.parseInt(toString()); + } + } +} diff --git a/Library/src/org/diylc/components/semiconductors/DiodePlastic.java b/Library/src/org/diylc/components/semiconductors/DiodePlastic.java new file mode 100644 index 00000000..107351d1 --- /dev/null +++ b/Library/src/org/diylc/components/semiconductors/DiodePlastic.java @@ -0,0 +1,99 @@ +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.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 = "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(1.5d, 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) { + g2d.setColor(markerColor); + 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/Library/src/org/diylc/components/semiconductors/LED.java b/Library/src/org/diylc/components/semiconductors/LED.java new file mode 100644 index 00000000..bc41eaaf --- /dev/null +++ b/Library/src/org/diylc/components/semiconductors/LED.java @@ -0,0 +1,105 @@ +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.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; + +@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) { + 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/Library/src/org/diylc/components/semiconductors/TransistorTO220.java b/Library/src/org/diylc/components/semiconductors/TransistorTO220.java new file mode 100644 index 00000000..5af95c74 --- /dev/null +++ b/Library/src/org/diylc/components/semiconductors/TransistorTO220.java @@ -0,0 +1,270 @@ +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.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; + +@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(0.05d, 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 Shape[] body; + private Color bodyColor = BODY_COLOR; + private Color borderColor = BORDER_COLOR; + private Color tabColor = TAB_COLOR; + private Color tabBorderColor = TAB_BORDER_COLOR; + + 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, 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(bodyColor); + g2d.fill(mainArea); + g2d.setColor(tabColor); + g2d.fill(tabArea); + g2d.setComposite(oldComposite); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(tabBorderColor); + g2d.draw(tabArea); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : borderColor); + g2d.draw(mainArea); + + // Draw pins. + 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(LABEL_COLOR); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(getName(), 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(getName(), 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; + } +} diff --git a/Library/src/org/diylc/components/semiconductors/TransistorTO92.java b/Library/src/org/diylc/components/semiconductors/TransistorTO92.java new file mode 100644 index 00000000..8890e497 --- /dev/null +++ b/Library/src/org/diylc/components/semiconductors/TransistorTO92.java @@ -0,0 +1,240 @@ +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.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; + +@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; + + 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, 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(bodyColor); + g2d.fill(mainArea); + g2d.setComposite(oldComposite); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : borderColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(mainArea); + + 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(LABEL_COLOR); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(getName(), 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(getName(), 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; + } +} diff --git a/Library/src/org/diylc/components/tube/TubeSocket.java b/Library/src/org/diylc/components/tube/TubeSocket.java new file mode 100644 index 00000000..4b4243ca --- /dev/null +++ b/Library/src/org/diylc/components/tube/TubeSocket.java @@ -0,0 +1,311 @@ +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.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.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; + +@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(14d, 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, 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(BODY_COLOR); + g2d.fill(body); + } + g2d.setComposite(oldComposite); + g2d.setColor(componentState == ComponentState.SELECTED + || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : BORDER_COLOR); + g2d.draw(body); + // Draw pins + 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; + } + } +}