diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml index c249d74c..614d3cd9 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/update.xml +++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml @@ -4237,7 +4237,11 @@ NEW_FEATURE Added 'Solder Lug' component - + + + NEW_FEATURE + Added 'PCB Terminal Block' component + IMPROVEMENT Use scroll buttons in 'Tabbed Toolbar' instead of arranging tabs into multiple lines when the screen is not large enough to show them all diff --git a/diylc/diylc-library/lib/diylc-core.jar b/diylc/diylc-library/lib/diylc-core.jar index e1e1e025..f75afc7a 100644 Binary files a/diylc/diylc-library/lib/diylc-core.jar and b/diylc/diylc-library/lib/diylc-core.jar differ diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/PCBTerminalBlock.java b/diylc/diylc-library/src/org/diylc/components/connectivity/PCBTerminalBlock.java new file mode 100644 index 00000000..24453970 --- /dev/null +++ b/diylc/diylc-library/src/org/diylc/components/connectivity/PCBTerminalBlock.java @@ -0,0 +1,325 @@ +/* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors. + * + * This file is part of DIYLC. + * + * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with DIYLC. If not, see + * . + * + */ +package org.diylc.components.connectivity; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.connectivity.PCBTerminalBlock.PCBTerminalBlockCount; +import org.diylc.components.transform.PCBTerminalBlockTransformer; +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 = "PCB Terminal Block", category = "Connectivity", + author = "Branislav Stojkovic", description = "Horizontal PCB terminal block with 5mm pitch", + zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "TB", autoEdit = false, + enableCache = true, transformer = PCBTerminalBlockTransformer.class) +public class PCBTerminalBlock extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Size SPACING = new Size(5d, SizeUnit.mm); + private static Size WIDTH = new Size(7.7d, SizeUnit.mm); + private static Size CIRCLE_SIZE = new Size(3d, SizeUnit.mm); + private static Size OFFSET = new Size(4.5d, SizeUnit.mm); + + private static Color BODY_COLOR = Color.decode("#90AB66"); + private static Color BORDER_COLOR = BODY_COLOR.darker(); + private static Color CIRCLE_COLOR = LIGHT_METAL_COLOR; + + protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + transient protected Shape[] body; + protected PCBTerminalBlockCount count = PCBTerminalBlockCount._3; + private Orientation orientation = Orientation.DEFAULT; + + private Color bodyColor = BODY_COLOR; + private Color borderColor = BORDER_COLOR; + + public PCBTerminalBlock() { + super(); + updateControlPoints(); + } + + private void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + int spacing = (int) SPACING.convertToPixels(); + controlPoints = new Point2D[count.getCount()]; + controlPoints[0] = firstPoint; + + for (int i = 1; i < controlPoints.length; i++) { + controlPoints[i] = new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing * i); + } + + if (orientation != Orientation.DEFAULT) { + AffineTransform xform = AffineTransform.getRotateInstance(orientation.toRadians(), + firstPoint.getX(), firstPoint.getY()); + for (int i = 1; i < controlPoints.length; i++) { + xform.transform(controlPoints[i], controlPoints[i]); + } + } + } + + @Override + public Point2D 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(Point2D point, int index) { + controlPoints[index].setLocation(point); + // Reset body shape. + body = null; + } + + @EditableProperty(name = "Pins") + @Override + public PCBTerminalBlockCount getValue() { + return count; + } + + @Override + public void setValue(PCBTerminalBlockCount value) { + this.count = value; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty + public Orientation getOrientation() { + if (orientation == null) { + orientation = Orientation.DEFAULT; + } + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Shape[] body = getBody(); + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, + Constants.DEFAULT_THEME); + // Draw body if available. + if (body != null) { + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite( + AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); + g2d.fill(body[0]); + g2d.setComposite(oldComposite); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + Color finalBorderColor; + if (outlineMode) { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING + ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + g2d.setColor(getBorderColor()); + g2d.draw(body[1]); + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING + ? SELECTION_COLOR + : getBorderColor(); + } + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + } + // 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()); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2f)); + for (Point2D p : controlPoints) { + if (outlineMode) { + // g2d.setColor(Constants.TRANSPARENT_COLOR); + // drawingObserver.startTrackingContinuityArea(true); + // g2d.fillRect((int)(p.getX() - lugWidth / 2), (int)(p.getY() - lugHeight / 2), lugWidth, + // lugHeight); + // drawingObserver.stopTrackingContinuityArea(); + + g2d.setColor(theme.getOutlineColor()); + } else { + g2d.setColor(CIRCLE_COLOR); + g2d.fillOval((int) (p.getX() - circleDiameter / 2), (int) (p.getY() - circleDiameter / 2), + circleDiameter, circleDiameter); + + g2d.setColor(CIRCLE_COLOR.darker()); + g2d.drawLine((int) (p.getX() + Math.cos(Math.PI / 4) * circleDiameter / 2), + (int) (p.getY() + Math.sin(Math.PI / 4) * circleDiameter / 2), + (int) (p.getX() + Math.cos(5 * Math.PI / 4) * circleDiameter / 2), + (int) (p.getY() + Math.sin(5 * Math.PI / 4) * circleDiameter / 2)); + } + } + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[2]; + Point2D firstPoint = controlPoints[0]; + int spacing = (int) SPACING.convertToPixels(); + int pointCount = count.getCount(); + int width = (int) WIDTH.convertToPixels(); + int offset = (int) OFFSET.convertToPixels(); + + body[0] = new Rectangle2D.Double(firstPoint.getX() - offset, firstPoint.getY() - spacing / 2, + width, pointCount * spacing); + body[1] = new Rectangle2D.Double(firstPoint.getX() - spacing / 2, firstPoint.getY() - spacing / 2, + spacing, pointCount * spacing); + + if (orientation != Orientation.DEFAULT) { + AffineTransform xform = AffineTransform.getRotateInstance(orientation.toRadians(), + firstPoint.getX(), firstPoint.getY()); + Area b = new Area(body[0]); + b.transform(xform); + body[0] = b; + + b = new Area(body[1]); + b.transform(xform); + body[1] = b; + } + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int circleSize = 6 * width / 32; + g2d.setColor(BODY_COLOR); + g2d.fillRect((int) (width / 4d - 2), 1, width / 2, height - 2); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((int) (width / 4d - 2), 1, width / 2, height - 2); + g2d.drawRect((int) (width / 3d), 1, (int) (width / 3d), height - 2); + for (int i = 1; i <= 3; i++) { + g2d.setColor(CIRCLE_COLOR); + g2d.fillOval(width / 2 - circleSize / 2, (int) (i * height / 4d - circleSize / 2), circleSize, circleSize); + } + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + if (bodyColor == null) + bodyColor = BODY_COLOR; + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + if (borderColor == null) + borderColor = BORDER_COLOR; + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + + @Override + public String getControlPointNodeName(int index) { + // we don't want the block to produce any nodes, it just makes connections + return null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @Override + public Rectangle2D getCachingBounds() { + int margin = 20; + Rectangle2D bounds = getBody()[0].getBounds2D(); + return new Rectangle2D.Double(bounds.getX() - margin, bounds.getY() - margin, + bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin); + } + + static enum PCBTerminalBlockCount { + _2("Two"), _3("Three"), _4("Four"), _5("Five"), _6("Six"), _7("Seven"), _8("Eight"), _9( + "Nine"), _10("Ten"); + + private String label; + + PCBTerminalBlockCount(String label) { + this.label = label; + } + + public int getCount() { + return Integer.parseInt(name().substring(1)); + } + + @Override + public String toString() { + return label; + } + } +} diff --git a/diylc/diylc-library/src/org/diylc/components/transform/PCBTerminalBlockTransformer.java b/diylc/diylc-library/src/org/diylc/components/transform/PCBTerminalBlockTransformer.java new file mode 100644 index 00000000..4d251313 --- /dev/null +++ b/diylc/diylc-library/src/org/diylc/components/transform/PCBTerminalBlockTransformer.java @@ -0,0 +1,109 @@ +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2018 held jointly by the individual authors. + + This file is part of DIYLC. + + DIYLC is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DIYLC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DIYLC. If not, see . + +*/ +package org.diylc.components.transform; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import org.diylc.common.IComponentTransformer; +import org.diylc.common.Orientation; +import org.diylc.components.connectivity.PCBTerminalBlock; +import org.diylc.core.IDIYComponent; + +public class PCBTerminalBlockTransformer implements IComponentTransformer { + + @Override + public boolean canRotate(IDIYComponent component) { + return component.getClass().equals(PCBTerminalBlock.class); + } + + @Override + public boolean canMirror(IDIYComponent component) { + return component.getClass().equals(PCBTerminalBlock.class); + } + + @Override + public boolean mirroringChangesCircuit() { + return false; + } + + @Override + public void rotate(IDIYComponent component, Point2D center, int direction) { + AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.getX(), center.getY()); + for (int index = 0; index < component.getControlPointCount(); index++) { + Point2D p = new Point2D.Double(); + rotate.transform(component.getControlPoint(index), p); + component.setControlPoint(p, index); + } + + PCBTerminalBlock block = (PCBTerminalBlock) component; + Orientation o = block.getOrientation(); + int oValue = o.ordinal(); + oValue += direction; + if (oValue < 0) + oValue = Orientation.values().length - 1; + if (oValue >= Orientation.values().length) + oValue = 0; + o = Orientation.values()[oValue]; + block.setOrientation(o); + } + + @SuppressWarnings("incomplete-switch") + @Override + public void mirror(IDIYComponent component, Point2D center, int direction) { + PCBTerminalBlock block = (PCBTerminalBlock) component; + double dx = center.getX() - block.getControlPoint(0).getX(); + double dy = center.getY() - block.getControlPoint(0).getY(); + if (direction == IComponentTransformer.HORIZONTAL) { + Orientation o = block.getOrientation(); + switch (o) { + case _90: + o = Orientation._270; + break; + case _270: + o = Orientation._90; + } + + for (int i = 0; i < block.getControlPointCount(); i++) { + Point2D p = block.getControlPoint(i); + block.setControlPoint(new Point2D.Double(p.getX() + 2 * dx, p.getY()), i); + } + + block.setOrientation(o); + } else { + Orientation o = block.getOrientation(); + switch (o) { + case DEFAULT: + o = Orientation._180; + break; + case _180: + o = Orientation.DEFAULT; + } + + for (int i = 0; i < block.getControlPointCount(); i++) { + Point2D p = block.getControlPoint(i); + block.setControlPoint(new Point2D.Double(p.getX(), p.getY() + 2 * dy), i); + } + + block.setOrientation(o); + } + } +} diff --git a/diylc/diylc-swing/dict.txt b/diylc/diylc-swing/dict.txt index 9565c0e9..692971ab 100644 --- a/diylc/diylc-swing/dict.txt +++ b/diylc/diylc-swing/dict.txt @@ -49,6 +49,7 @@ AWG Alternate And Angle Offset +Apply Model B-C-E BJT Background Box @@ -85,6 +86,7 @@ Double Rods Drop E+ E-B-C BJT +Eight English Espaņol Filament Voltage @@ -107,6 +109,7 @@ Maximum number of switching combinations exceeded. Allowed: %s, actual: %s NPN Nand Nederlands +Nine Non-shorting Nor Not @@ -145,6 +148,8 @@ Source Style Source Type Srpski Stroke +TB2 +Ten Terminal Timing Tubular Beveled diff --git a/diylc/diylc-swing/lib/diylc-core.jar b/diylc/diylc-swing/lib/diylc-core.jar index e1e1e025..f75afc7a 100644 Binary files a/diylc/diylc-swing/lib/diylc-core.jar and b/diylc/diylc-swing/lib/diylc-core.jar differ diff --git a/diylc/diylc-swing/library/main.jar b/diylc/diylc-swing/library/main.jar index c7d64e05..2857fa78 100644 Binary files a/diylc/diylc-swing/library/main.jar and b/diylc/diylc-swing/library/main.jar differ