diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml index 55b83e75..7bd6d63e 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/update.xml +++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml @@ -2777,7 +2777,11 @@ NEW_FEATURE Added "Dot Spacing" property in project settings that shows dots on every N-th grid line intersection - + + + NEW_FEATURE + Added "P-0+o (Proto) Board" component by Kristian BlÃ¥sol + BUG_FIX Issues with circuit analysis introduced in version 4.0.1. Wires and jumpers are made non-conductive by mistake. @@ -2796,8 +2800,12 @@ BUG_FIX - Humbucker doesn't render second coil poles properly in certain scenarios + "Humbucker Pickup" doesn't render second coil poles properly in certain scenarios + + BUG_FIX + Minor fix in tracking conductive areas + https://github.com/bancika/diy-layout-creator/releases diff --git a/diylc/diylc-library/src/org/diylc/components/boards/ProtoBoard.java b/diylc/diylc-library/src/org/diylc/components/boards/ProtoBoard.java new file mode 100644 index 00000000..b254adfa --- /dev/null +++ b/diylc/diylc-library/src/org/diylc/components/boards/ProtoBoard.java @@ -0,0 +1,655 @@ +/* + + 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.boards; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.geom.AffineTransform; + +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "P-0+o (Proto) Board", category = "Boards", author = "Branislav Stojkovic", + description = "A prototyping board for modular synths, central bus with V+ GND and V-", instanceNamePrefix = "BB", + zOrder = IDIYComponent.BOARD, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, + keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME) +public class ProtoBoard extends AbstractComponent { + + private static final long serialVersionUID = 1L; + + public static Color FILL_COLOR = Color.decode("#0B3B0B"); + public static Color BORDER_COLOR = FILL_COLOR.darker(); + public static Size SPACING = new Size(0.1d, SizeUnit.in); + public static Color SELECTION_COLOR = Color.red; + public static Color PAD_COLOR = Color.decode("#D2D2D2"); + public static Color UNDERSIDE_PAD_COLOR = Color.decode("#A8A8DA"); + public static Color UNDERSIDE_LINE_COLOR = Color.decode("#CDCDFF"); + public static Color HOLE_COLOR = Color.black; + + public static float COORDINATE_FONT_SIZE = 9f; + public static Color COORDINATE_COLOR = Color.gray.brighter(); + + public static Color SEPARATOR_COLOR = Color.white; + public static Color SCREEN_COLOR = Color.decode("#CAD4CA"); + + public static Size PAD_SIZE = new Size(2d, SizeUnit.mm); + public static int ROW_COUNT = 33; + + public static Size WIDTH_SIZE = new Size(2d, SizeUnit.in); + public static Size LENGTH_SIZE = new Size(4d, SizeUnit.in); + + private static int[] SEGMENTS = new int[] { 2, 3, 3, 3, 3, 2 }; + private static int[] SEGMENTS_SUM = new int[] { 0, 2, 5, 8, 11, 14 }; + private static int[] GAPS = new int[] { 1, 0, 2, 0, 0, 0 }; + private static int[] SEGMENTS_STARTS = new int[] { 0, 3, 6, 11, 14, 17 }; + + protected Point point = new Point(0, 0); + + protected PowerStripPosition powerStripPosition; + protected Orientation orientation; + protected Boolean markUndersidePads = true; + + @SuppressWarnings("incomplete-switch") + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + + // adjust the angle + double theta = 0; + switch (getOrientation()) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + if (theta != 0) { + g2d.rotate(theta, point.x, point.y); + } + + double spacing = SPACING.convertToPixels(); + + // draw body + g2d.setColor(FILL_COLOR); + int width = (int) WIDTH_SIZE.convertToPixels(); + int length = (int) LENGTH_SIZE.convertToPixels(); + + g2d.fillRect(point.x, point.y, width, length); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : BORDER_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.drawRect(point.x, point.y, width, length); + + drawingObserver.stopTracking(); + + int padSize = getClosestOdd(PAD_SIZE.convertToPixels()); + int holeSize = getClosestOdd(padSize / 2); + + g2d.setFont(LABEL_FONT.deriveFont(COORDINATE_FONT_SIZE)); + + int xOffset = 1; + int yOffset = 5; + + g2d.setColor(PAD_COLOR.brighter()); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(padSize / 4)); + + drawingObserver.startTrackingContinuityArea(true); + + // draw segment connectors + for (int y = 0; y < ROW_COUNT; y++) { + for (int segment = 0; segment < SEGMENTS.length; segment++) { + drawingObserver.setContinuityMarker("SEGMENT=" + segment + ";ROW=" + y); + g2d.drawLine((int) (point.x + (xOffset + SEGMENTS_STARTS[segment]) * spacing), + (int) (point.y + (yOffset + y) * spacing), + (int) (point.x + (xOffset + SEGMENTS_STARTS[segment] + SEGMENTS[segment] - 1) * spacing), + (int) (point.y + (yOffset + y) * spacing)); + } + } + drawingObserver.setContinuityMarker(null); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(padSize / 4)); + + // draw central mini pad connectors, top row + for (int y = 0; y < ROW_COUNT; y++) { + // top row + g2d.drawLine((int) (point.x + (1 + SEGMENTS_SUM[3]) * spacing), (int) (point.y + (yOffset + y - 0.25d) * spacing + 1), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing), (int) (point.y + (yOffset + y - 0.25d) * spacing + 1)); + g2d.drawLine((int) (point.x + (1 + SEGMENTS_SUM[3] + 3) * spacing), (int) (point.y + (yOffset + y - 0.25d) * spacing + 1), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 2.5) * spacing), (int) (point.y + (yOffset + y - 0.25d) * spacing + 1)); + } + + g2d.setColor(getMarkUndersidePads() ? UNDERSIDE_LINE_COLOR : PAD_COLOR.brighter()); + + // bottom row. + for (int y = 0; y < ROW_COUNT; y++) { + g2d.drawLine((int) (point.x + (1 + SEGMENTS_SUM[3]) * spacing), (int) (point.y + (yOffset + y + 0.25d) * spacing + 1), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1) * spacing), (int) (point.y + (yOffset + y + 0.25d) * spacing + 1)); + g2d.drawLine((int) (point.x + (1 + SEGMENTS_SUM[3] + 3) * spacing), (int) (point.y + (yOffset + y + 0.25d) * spacing + 1), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 2) * spacing), (int) (point.y + (yOffset + y + 0.25d) * spacing + 1)); + } + + // vertical ground line + g2d.drawLine((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing), (int) (point.y + (yOffset - 1.5) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing), (int) (point.y + (yOffset + ROW_COUNT + 0.5) * spacing)); + + g2d.setColor(PAD_COLOR.brighter()); + + // traces to top and bottom 3 pads + g2d.drawPolyline(new int[] { + (int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.2) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.2) * spacing)}, + new int[] { + (int) (point.y + (yOffset - 1.5) * spacing), + (int) (point.y + (yOffset - 1) * spacing), + (int) (point.y + (yOffset - 0.3) * spacing)}, 3); + g2d.drawPolyline(new int[] { + (int) (point.x + (1 + SEGMENTS_SUM[3] + 2.5) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.8) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.8) * spacing)}, + new int[] { + (int) (point.y + (yOffset - 1.5) * spacing), + (int) (point.y + (yOffset - 1) * spacing), + (int) (point.y + (yOffset - 0.3) * spacing)}, 3); + + g2d.drawPolyline(new int[] { + (int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.2) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.2) * spacing)}, + new int[] { + (int) (point.y + (yOffset + ROW_COUNT + 0.5) * spacing), + (int) (point.y + (yOffset + ROW_COUNT) * spacing), + (int) (point.y + (yOffset + ROW_COUNT - 0.35) * spacing)}, 3); + g2d.drawPolyline(new int[] { + (int) (point.x + (1 + SEGMENTS_SUM[3] + 2.5) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.8) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.8) * spacing)}, + new int[] { + (int) (point.y + (yOffset + ROW_COUNT + 0.5) * spacing), + (int) (point.y + (yOffset + ROW_COUNT) * spacing), + (int) (point.y + (yOffset + ROW_COUNT - 0.35) * spacing)}, 3); + + drawingObserver.stopTrackingContinuityArea(); + + int miniPadSize = getClosestOdd((2d * spacing - 6) / 5); + + // draw top mini pad traces + g2d.setColor(PAD_COLOR.brighter()); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(padSize / 4)); + drawingObserver.startTrackingContinuityArea(true); + g2d.drawLine((int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing), (int) (point.y + 1 * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing), (int) (point.y + 3.5 * spacing)); + g2d.drawLine((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing + miniPadSize / 2), (int) (point.y + 1 * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing + miniPadSize / 2), (int) (point.y + 3.5 * spacing)); + g2d.drawLine((int) (point.x + (1 + SEGMENTS_SUM[3] + 2.5) * spacing), (int) (point.y + 1 * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 2.5) * spacing), (int) (point.y + 3.5 * spacing)); + drawingObserver.stopTrackingContinuityArea(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + // vertical separators + g2d.setColor(SEPARATOR_COLOR); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + + g2d.drawLine((int) (point.x + (1 + SEGMENTS_STARTS[2] - 0.5) * spacing), (int) (point.y + (yOffset - 1) * spacing), + (int) (point.x + (1 + SEGMENTS_STARTS[2] - 0.5) * spacing), (int) (point.y + (yOffset + ROW_COUNT -0.5) * spacing)); + g2d.drawLine((int) (point.x + (1 + SEGMENTS_STARTS[4] - 0.5) * spacing), (int) (point.y + (yOffset - 1) * spacing), + (int) (point.x + (1 + SEGMENTS_STARTS[4] - 0.5) * spacing), (int) (point.y + (yOffset + ROW_COUNT -0.5) * spacing)); + g2d.fillRect((int) (point.x + (1 + SEGMENTS_STARTS[1] - 1.25) * spacing), (int) (point.y + (yOffset - 1) * spacing), + (int)(0.5 * spacing), (int) ((ROW_COUNT + 0.5) * spacing)); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + // draw main pads + for (int segment = 0; segment < SEGMENTS.length; segment++) { + for (int y = 0; y < ROW_COUNT; y++) { + for (int x = 0; x < SEGMENTS[segment]; x++) { + int padX = (int) (point.x + (xOffset + x) * spacing); + int padY = (int) (point.y + (yOffset + y) * spacing); + + drawingObserver.startTrackingContinuityArea(true); + drawingObserver.setContinuityMarker("SEGMENT=" + segment + ";ROW=" + y); + + g2d.setColor(PAD_COLOR); + if ((segment == 2 && x == 2) || (segment == 3 && x == 0)) + g2d.fillRect(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + else + g2d.fillOval(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + + drawingObserver.setContinuityMarker(null); + + drawingObserver.stopTrackingContinuityArea(); + + g2d.setColor(PAD_COLOR.darker()); + if ((segment == 2 && x == 2) || (segment == 3 && x == 0)) + g2d.drawRect(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + else + g2d.drawOval(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + + g2d.setColor(HOLE_COLOR); + g2d.fillOval(padX - holeSize / 2, padY - holeSize / 2, holeSize, holeSize); + + // Draw horizontal labels + if (y == 0) { + g2d.setColor(COORDINATE_COLOR); + StringUtils.drawCenteredText(g2d, Integer.toString(SEGMENTS_SUM[segment] + x + 1), padX, (int) (point.y + (yOffset - 1) * spacing) - 1, + HorizontalAlignment.CENTER, VerticalAlignment.TOP); + } + } + } + + xOffset += SEGMENTS[segment] + GAPS[segment]; + } + + // Draw top and bottom 3 pads + for (int y = 0; y < 2; y++) { + g2d.setColor(SEPARATOR_COLOR); + g2d.drawRect((int) (point.x + (1 + SEGMENTS_SUM[3]) * spacing), (int) (point.y + (yOffset - 2 + y * (ROW_COUNT + 2)) * spacing), + (int)(3 * spacing), (int)spacing); + + drawingObserver.startTrackingContinuityArea(true); + + for (int x = 0; x < 3; x++) { + int padX = (int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5 + x) * spacing); + int padY = (int) (point.y + (yOffset - 1.5 + y * (ROW_COUNT + 2)) * spacing); + + g2d.setColor(PAD_COLOR); + + if (x == 0) + drawingObserver.setContinuityMarker("columnA"); + else if (x == 2) + drawingObserver.setContinuityMarker("columnC"); + + if (x == 2) + g2d.fillRect(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + else + g2d.fillOval(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + + drawingObserver.setContinuityMarker(null); + + g2d.setColor(PAD_COLOR.darker()); + if (x == 2) + g2d.drawRect(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + else + g2d.drawOval(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + g2d.setColor(HOLE_COLOR); + g2d.fillOval(padX - holeSize / 2, padY - holeSize / 2, holeSize, holeSize); + } + + drawingObserver.stopTrackingContinuityArea(); + } + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + + g2d.setColor(SCREEN_COLOR); + g2d.fillRect((int) (point.x + width - 1.5 * spacing), point.y + 2, (int) (spacing), (int) (2 * spacing)); + g2d.setColor(SEPARATOR_COLOR); + g2d.drawRect((int) (point.x + width - 5.5 * spacing), point.y + 2, (int) (5 * spacing), (int) (2 * spacing)); + + g2d.drawLine((int) (point.x + width - 5.5 * spacing), (int) (point.y + 2 * spacing) + 8, + (int) (point.x + width - 5.5 * spacing), (int) (point.y + 3.5 * spacing)); + g2d.drawLine((int) (point.x + width - 4.5 * spacing), (int) (point.y + 2 * spacing + 8), + (int) (point.x + width - 4.5 * spacing), (int) (point.y + 3.5 * spacing)); + g2d.drawLine((int) (point.x + width - 1.5 * spacing), (int) (point.y + 2 * spacing + 8), + (int) (point.x + width - 1.5 * spacing), (int) (point.y + 3.5 * spacing)); + + g2d.setColor(PAD_COLOR.brighter()); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(padSize / 4)); + + drawingObserver.startTrackingContinuityArea(true); + + // Draw two horizontal connections in the top-right section + g2d.drawLine((int) (point.x + width - 4 * spacing), (int) (point.y + 0.5 * spacing), (int) (point.x + width - (2) * spacing), (int) (point.y + 0.5 * spacing)); + g2d.drawLine((int) (point.x + width - 4 * spacing), (int) (point.y + 1.5 * spacing), (int) (point.x + width - (2) * spacing), (int) (point.y + 1.5 * spacing)); + + // Draw top-right pads + for (int x = 0; x < 6; x++) { + int padX = (int) (point.x + width - (x + 1) * spacing); + + g2d.setColor(PAD_COLOR.brighter()); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(padSize / 4)); + g2d.drawLine(padX, (int) (point.y + 0.5 * spacing), padX, (int) (point.y + 3 * spacing)); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + for (int y = 0; y < 3; y++) { + + int padY = (int) (point.y + (y + (y == 2 ? 0.5 : 0) + 0.5) * spacing); + + if (x == 0) + drawingObserver.setContinuityMarker("-12V"); + else if (x == 4) + drawingObserver.setContinuityMarker("+12V"); + else if (x == 5) + drawingObserver.setContinuityMarker("+5V"); + else + drawingObserver.setContinuityMarker("GND"); + + g2d.setColor(PAD_COLOR); + if (x >= 4) + g2d.fillRect(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + else + g2d.fillOval(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + + drawingObserver.setContinuityMarker(null); + + g2d.setColor(PAD_COLOR.darker()); + if (x >= 4) + g2d.drawRect(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + else + g2d.drawOval(padX - padSize / 2, padY - padSize / 2, padSize, padSize); + g2d.setColor(HOLE_COLOR); + g2d.fillOval(padX - holeSize / 2, padY - holeSize / 2, holeSize, holeSize); + } + } + + drawingObserver.stopTrackingContinuityArea(); + + // draw top mini pads + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + for (int y = 0; y < 4; y++) { + int padY = (int) (point.y + (0.5 * y + 1) * spacing); + int[] padXs = new int[] {(int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing - miniPadSize - 2), (int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing), + (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) - miniPadSize / 2 - 2, (int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) + miniPadSize / 2 + 1, + (int) (point.x + (1 + SEGMENTS_SUM[3] + 2.5) * spacing), (int) (point.x + (1 + SEGMENTS_SUM[3] + 2.5) * spacing + miniPadSize + 2)}; + + for (int i = 0; i < padXs.length; i++) { + int padX = padXs[i]; + drawingObserver.startTrackingContinuityArea(true); + + if (i == 0 || i == 2 || i == 5) { + switch (y) { + case 0: drawingObserver.setContinuityMarker("+5V"); + break; + case 1: drawingObserver.setContinuityMarker("+12V"); + break; + case 2: drawingObserver.setContinuityMarker("GND"); + break; + case 3: drawingObserver.setContinuityMarker("-12V"); + break; + } + } + + g2d.setColor(PAD_COLOR); + g2d.fillRect(padX - miniPadSize / 2, padY - miniPadSize / 2, miniPadSize, miniPadSize); + + drawingObserver.setContinuityMarker(null); + + drawingObserver.stopTrackingContinuityArea(); + g2d.setColor(PAD_COLOR.darker()); + g2d.drawRect(padX - miniPadSize / 2, padY - miniPadSize / 2, miniPadSize, miniPadSize); + } + } + + g2d.setColor(COORDINATE_COLOR); + + // Draw top labels + StringUtils.drawCenteredText(g2d, "+5V", (int) (point.x + (1 + SEGMENTS_SUM[3] - 0.3) * spacing), (int) (point.y + 1 * spacing) + 1, + HorizontalAlignment.RIGHT, VerticalAlignment.CENTER); + StringUtils.drawCenteredText(g2d, "+12V", (int) (point.x + (1 + SEGMENTS_SUM[3] - 0.3) * spacing), (int) (point.y + 1.5 * spacing) + 1, + HorizontalAlignment.RIGHT, VerticalAlignment.CENTER); + StringUtils.drawCenteredText(g2d, "GND", (int) (point.x + (1 + SEGMENTS_SUM[3] - 0.3) * spacing), (int) (point.y + 2 * spacing) + 1, + HorizontalAlignment.RIGHT, VerticalAlignment.CENTER); + StringUtils.drawCenteredText(g2d, "-12V", (int) (point.x + (1 + SEGMENTS_SUM[3] - 0.3) * spacing), (int) (point.y + 2.5 * spacing) + 1, + HorizontalAlignment.RIGHT, VerticalAlignment.CENTER); + + // Draw top-right labels + int labelY = (int) (point.y + 3.3 * spacing); + StringUtils.drawCenteredText(g2d, "+5V", (int) (point.x + width - 6 * spacing), labelY, HorizontalAlignment.CENTER, VerticalAlignment.TOP); + StringUtils.drawCenteredText(g2d, "+", (int) (point.x + width - 5 * spacing) - 6, labelY, HorizontalAlignment.CENTER, VerticalAlignment.TOP); + StringUtils.drawCenteredText(g2d, " 12V", (int) (point.x + width - 5 * spacing) + 2, labelY, HorizontalAlignment.CENTER, VerticalAlignment.TOP); + StringUtils.drawCenteredText(g2d, "GND", (int) (point.x + width - 3 * spacing), labelY, HorizontalAlignment.CENTER, VerticalAlignment.TOP); + StringUtils.drawCenteredText(g2d, "-12V", (int) (point.x + width - 1 * spacing), labelY, HorizontalAlignment.CENTER, VerticalAlignment.TOP); + + // Draw vertical labels + byte A = "A".getBytes()[0]; + byte a = "a".getBytes()[0]; + for (int y = 0; y < ROW_COUNT; y++) { + int padY = (int) (point.y + (yOffset + y) * spacing); + String label; + if (y >= 26) + label = new String(new byte[] {(byte) (a + y - 26)}); + else + label = new String(new byte[] {(byte) (A + y)}); + StringUtils.drawCenteredText(g2d, label, (int) (point.x + spacing * 0.35), padY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + StringUtils.drawCenteredText(g2d, label, (int) (point.x + width - spacing * 0.35), padY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + g2d.setColor(PAD_COLOR.brighter()); + g2d.setFont(LABEL_FONT.deriveFont(COORDINATE_FONT_SIZE + 2)); + + StringUtils.drawCenteredText(g2d, "P-0+o by:\nKristian Blåsol 2019", (int) (point.x + width * 0.70d), (int) (point.y + (yOffset + ROW_COUNT + 0.4) * spacing), + HorizontalAlignment.LEFT, VerticalAlignment.TOP); + + // draw central mini pads + for (int y = 0; y < ROW_COUNT; y++) { + g2d.setColor(PAD_COLOR); + + drawingObserver.startTrackingContinuityArea(true); + + // top row + g2d.fillRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing) + 1, (int) (point.y + (yOffset + y - 0.5d) * spacing + 2), miniPadSize, miniPadSize); + drawingObserver.setContinuityMarker("columnA"); + g2d.fillRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing) + miniPadSize + 3, (int) (point.y + (yOffset + y - 0.5d) * spacing + 2), miniPadSize, miniPadSize); + drawingObserver.setContinuityMarker("columnC"); + g2d.fillRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) + 3, (int) (point.y + (yOffset + y - 0.5d) * spacing + 2), miniPadSize, miniPadSize); + drawingObserver.setContinuityMarker(null); + g2d.fillRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) + miniPadSize + 5, (int) (point.y + (yOffset + y - 0.5d) * spacing + 2), miniPadSize, miniPadSize); + + drawingObserver.stopTrackingContinuityArea(); + + g2d.setColor(PAD_COLOR.darker()); + g2d.drawRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing) + 1, (int) (point.y + (yOffset + y - 0.5d) * spacing + 2), miniPadSize, miniPadSize); + g2d.drawRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 0.5) * spacing) + miniPadSize + 3, (int) (point.y + (yOffset + y - 0.5d) * spacing + 2), miniPadSize, miniPadSize); + + g2d.setColor(getMarkUndersidePads() ? UNDERSIDE_PAD_COLOR : PAD_COLOR); + + drawingObserver.startTrackingContinuityArea(true); + + // bottom row + + g2d.fillRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) - miniPadSize / 2, (int) (point.y + (yOffset + y + 0.5d) * spacing - 1 - miniPadSize), miniPadSize, miniPadSize); +// drawingObserver.setContinuityMarker("columnB"); + g2d.fillRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) - miniPadSize * 3 / 2 - 2, (int) (point.y + (yOffset + y + 0.5d) * spacing - 1 - miniPadSize), miniPadSize, miniPadSize); +// drawingObserver.setContinuityMarker("null"); + g2d.fillRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) + miniPadSize / 2 + 3, (int) (point.y + (yOffset + y + 0.5d) * spacing - 1 - miniPadSize), miniPadSize, miniPadSize); + + drawingObserver.stopTrackingContinuityArea(); + + g2d.setColor((getMarkUndersidePads() ? UNDERSIDE_PAD_COLOR : PAD_COLOR).darker()); + + g2d.drawRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) + 3, (int) (point.y + (yOffset + y - 0.5d) * spacing + 2), miniPadSize, miniPadSize); + g2d.drawRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) + miniPadSize + 5, (int) (point.y + (yOffset + y - 0.5d) * spacing + 2), miniPadSize, miniPadSize); + + g2d.drawRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) - miniPadSize / 2, (int) (point.y + (yOffset + y + 0.5d) * spacing - 1 - miniPadSize), miniPadSize, miniPadSize); + g2d.drawRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) - miniPadSize * 3 / 2 - 2, (int) (point.y + (yOffset + y + 0.5d) * spacing - 1 - miniPadSize), miniPadSize, miniPadSize); + g2d.drawRect((int) (point.x + (1 + SEGMENTS_SUM[3] + 1.5) * spacing) + miniPadSize / 2 + 3, (int) (point.y + (yOffset + y + 0.5d) * spacing - 1 - miniPadSize), miniPadSize, miniPadSize); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + int arc = 4 / factor; + g2d.setColor(FILL_COLOR); + g2d.fillRect(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); + + g2d.setColor(PAD_COLOR); + g2d.fillRoundRect(width / 3 - 2 / factor, width / 3 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor), arc, arc); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(width / 3 - 2 / factor, width / 3 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor), arc, arc); + + g2d.setColor(PAD_COLOR); + g2d.fillRoundRect(2 * width / 3 - 2 / factor, width / 3 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor), arc, arc); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(2 * width / 3 - 2 / factor, width / 3 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor), arc, arc); + + g2d.setColor(PAD_COLOR); + g2d.fillRoundRect(width / 3 - 2 / factor, 2 * width / 3 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor), arc, arc); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(width / 3 - 2 / factor, 2 * width / 3 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor), arc, arc); + + g2d.setColor(PAD_COLOR); + g2d.fillRoundRect(2 * width / 3 - 2 / factor, 2 * width / 3 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor), arc, arc); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(2 * width / 3 - 2 / factor, 2 * width / 3 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor), arc, arc); + } + + @EditableProperty + public Orientation getOrientation() { + if (orientation == null) + orientation = Orientation.DEFAULT; + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + } + + @EditableProperty(name = "Power Strip") + public PowerStripPosition getPowerStripPosition() { + if (powerStripPosition == null) + powerStripPosition = PowerStripPosition.Inline; + return powerStripPosition; + } + + public void setPowerStripPosition(PowerStripPosition powerStripPosition) { + this.powerStripPosition = powerStripPosition; + } + + @EditableProperty(name = "Mark Underside Pads") + public Boolean getMarkUndersidePads() { + return markUndersidePads; + } + + public void setMarkUndersidePads(Boolean markUndersidePads) { + this.markUndersidePads = markUndersidePads; + } + + @Override + public int getControlPointCount() { + return 2; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @SuppressWarnings("incomplete-switch") + @Override + public Point getControlPoint(int index) { + if (index == 0) + return point; + + // create a synthetic second control point for clipping check and to make sure that we cannot drag the right side of the board off the screen + + // adjust the angle + double theta = 0; + switch (getOrientation()) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + int width = (int) WIDTH_SIZE.convertToPixels(); + int length = (int) LENGTH_SIZE.convertToPixels(); + Point secondPoint = new Point((int) (point.x + width), (int) (point.y + length)); + if (theta != 0) { + AffineTransform tx = AffineTransform.getRotateInstance(theta, point.x, point.y); + tx.transform(secondPoint, secondPoint); + } + return secondPoint; + } + + @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) { + if (index == 0) + this.point.setLocation(point); + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) {} + + @Override + public String getControlPointNodeName(int index) { + return null; + } + + public enum PowerStripPosition { + Inline, Offset + } +} diff --git a/diylc/diylc-swing/library/main.jar b/diylc/diylc-swing/library/main.jar index efa8e7bb..81a548d4 100644 Binary files a/diylc/diylc-swing/library/main.jar and b/diylc/diylc-swing/library/main.jar differ