From 1b7f24bae4b3ca0630862ace2936246835d5b93e Mon Sep 17 00:00:00 2001 From: Branislav Stojkovic Date: Sat, 15 Dec 2018 19:19:05 +0100 Subject: [PATCH] Two new trimmer potentiometer types --- .../passive/TrimmerPotentiometer.java | 978 +++++++++--------- diylc/diylc-swing/library/main.jar | Bin 433347 -> 433800 bytes diylc/diylc-swing/update.xml | 4 + 3 files changed, 515 insertions(+), 467 deletions(-) diff --git a/diylc/diylc-library/src/org/diylc/components/passive/TrimmerPotentiometer.java b/diylc/diylc-library/src/org/diylc/components/passive/TrimmerPotentiometer.java index 9d8d3a4c..e9b5ca26 100644 --- a/diylc/diylc-library/src/org/diylc/components/passive/TrimmerPotentiometer.java +++ b/diylc/diylc-library/src/org/diylc/components/passive/TrimmerPotentiometer.java @@ -1,474 +1,518 @@ /* + * + * 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.passive; - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2018 held jointly by the individual authors. +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 java.awt.geom.RoundRectangle2D; - This file is part of DIYLC. +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.Display; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.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; +import org.diylc.utils.Constants; - 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. +@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 { - 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. + private static final long serialVersionUID = 1L; - You should have received a copy of the GNU General Public License - along with DIYLC. If not, see . + protected static Size FLAT_BODY_SIZE = new Size(9.5d, SizeUnit.mm); + protected static Size FLAT_LARGE_SIZE = new Size(13d, SizeUnit.mm); + protected static Size FLAT_SMALL_BODY_SIZE = new Size(5d, SizeUnit.mm); + protected static Size FLAT_SHAFT_SIZE = new Size(4.5d, 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 ROUNDED_EDGE = new Size(1d, 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 static Display DISPLAY = Display.NAME; -*/ -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.appframework.miscutils.ConfigurationManager; -import org.diylc.common.Display; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.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; -import org.diylc.utils.Constants; - -@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 static Display DISPLAY = Display.NAME; - - protected Color bodyColor = BODY_COLOR; - protected Color borderColor = BORDER_COLOR; - protected Display display = DISPLAY; - // 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; - case VERTICAL_OFFSET_BIG_GAP: - dx1 = 2 * 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; - case VERTICAL_OFFSET_BIG_GAP: - dx1 = -spacing; - dy1 = 2 * 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; - case VERTICAL_OFFSET_BIG_GAP: - dx1 = -2 * 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; - case VERTICAL_OFFSET_BIG_GAP: - dx1 = spacing; - dy1 = -2 * 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: - case VERTICAL_OFFSET_BIG_GAP: - length = getClosestOdd(VERTICAL_BODY_LENGTH.convertToPixels()); - width = getClosestOdd(VERTICAL_BODY_WIDTH.convertToPixels()); - break; - } - if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { - int p = length; - length = width; - width = p; - } - body[0] = new Rectangle2D.Double(centerX - length / 2, centerY - width / 2, length, width); - } - return body; - } - - @Override - public void setControlPoint(Point point, int index) { - super.setControlPoint(point, index); - body = null; - } - - @Override - public void setOrientation(Orientation orientation) { - super.setOrientation(orientation); - updateControlPoints(); - body = null; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - Shape mainShape = getBody()[0]; - Shape shaftShape = getBody()[1]; - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - 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)); - } - if (!outlineMode) { - g2d.fill(mainShape); - } - if (!outlineMode && shaftShape != null) { - g2d.setColor(SHAFT_COLOR); - g2d.fill(shaftShape); - g2d.setColor(SHAFT_BORDER_COLOR); - g2d.draw(shaftShape); - } - g2d.setComposite(oldComposite); - Color finalBorderColor; - if (outlineMode) { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor; - } - g2d.setColor(finalBorderColor); - g2d.draw(mainShape); - } - - // Draw pins. - int pinSize = getClosestOdd(PIN_SIZE.convertToPixels()); - for (Point point : controlPoints) { - if (!outlineMode) { - g2d.setColor(PIN_COLOR); - g2d.fillOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); - } - g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); - g2d.drawOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); - } - - // Draw label. - g2d.setFont(project.getFont()); - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : LABEL_COLOR; - } - - String label = ""; - label = (getDisplay() == Display.NAME) ? getName() : (getValue() == null ? "" : getValue().toString()); - if (getDisplay() == Display.NONE) { - label = ""; - } - if (getDisplay() == Display.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - - g2d.setColor(finalLabelColor); - FontMetrics fontMetrics = g2d.getFontMetrics(); - Rectangle2D bodyRect = getBody()[0].getBounds2D(); - Rectangle2D rect = fontMetrics.getStringBounds(label, 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(label, (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 - public Display getDisplay() { - if (display == null) { - display = DISPLAY; - } - return display; - } - - public void setDisplay(Display display) { - this.display = display; - } - - @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, VERTICAL_OFFSET_BIG_GAP; - - @Override - public String toString() { - return name().substring(0, 1) + name().substring(1).toLowerCase().replace("_", " "); - } - } -} + protected Color bodyColor = BODY_COLOR; + protected Color borderColor = BORDER_COLOR; + protected Display display = DISPLAY; + // 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 (getOrientation()) { + case DEFAULT: + switch (getType()) { + case FLAT_SMALL: + case FLAT_XSMALL: + 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 FLAT_XLARGE: + dx1 = 5 * spacing; + dy1 = 2 * spacing; + dx2 = 0; + dy2 = 4 * 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; + case VERTICAL_OFFSET_BIG_GAP: + dx1 = 2 * spacing; + dy1 = spacing; + dx2 = 0; + dy2 = 2 * spacing; + break; + } + break; + case _90: + switch (getType()) { + case FLAT_SMALL: + case FLAT_XSMALL: + 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 FLAT_XLARGE: + dx1 = -2 * spacing; + dy1 = 5 * spacing; + dx2 = -4 * 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; + case VERTICAL_OFFSET_BIG_GAP: + dx1 = -spacing; + dy1 = 2 * spacing; + dx2 = -2 * spacing; + dy2 = 0; + break; + } + break; + case _180: + switch (getType()) { + case FLAT_SMALL: + case FLAT_XSMALL: + 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 FLAT_XLARGE: + dx1 = -5 * spacing; + dy1 = -2 * spacing; + dx2 = 0; + dy2 = -4 * 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; + case VERTICAL_OFFSET_BIG_GAP: + dx1 = -2 * spacing; + dy1 = -spacing; + dx2 = 0; + dy2 = -2 * spacing; + break; + } + break; + case _270: + switch (getType()) { + case FLAT_SMALL: + case FLAT_XSMALL: + 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 FLAT_XLARGE: + dx1 = 2 * spacing; + dy1 = -5 * spacing; + dx2 = 4 * 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; + case VERTICAL_OFFSET_BIG_GAP: + dx1 = spacing; + dy1 = -2 * 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 (getType()) { + case FLAT_LARGE: + case FLAT_SMALL: + case FLAT_XSMALL: + case FLAT_XLARGE: + if (getType() == TrimmerType.FLAT_XSMALL) + length = getClosestOdd(FLAT_SMALL_BODY_SIZE.convertToPixels()); + else if (getType() == TrimmerType.FLAT_XLARGE) + length = getClosestOdd(FLAT_LARGE_SIZE.convertToPixels()); + else + 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: + case VERTICAL_OFFSET_BIG_GAP: + 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; + } + double edge = ROUNDED_EDGE.convertToPixels(); + body[0] = new RoundRectangle2D.Double(centerX - length / 2, centerY - width / 2, length, width, edge, edge); + } + return body; + } + + @Override + public void setControlPoint(Point point, int index) { + super.setControlPoint(point, index); + body = null; + } + + @Override + public void setOrientation(Orientation orientation) { + super.setOrientation(orientation); + updateControlPoints(); + body = null; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + Shape mainShape = getBody()[0]; + Shape shaftShape = getBody()[1]; + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + 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)); + } + if (!outlineMode) { + g2d.fill(mainShape); + } + if (!outlineMode && shaftShape != null) { + g2d.setColor(SHAFT_COLOR); + g2d.fill(shaftShape); + g2d.setColor(SHAFT_BORDER_COLOR); + g2d.draw(shaftShape); + } + g2d.setComposite(oldComposite); + Color finalBorderColor; + if (outlineMode) { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor; + } + g2d.setColor(finalBorderColor); + g2d.draw(mainShape); + } + + // Draw pins. + int pinSize = getClosestOdd(PIN_SIZE.convertToPixels()); + for (Point point : controlPoints) { + if (!outlineMode) { + g2d.setColor(PIN_COLOR); + g2d.fillOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + } + g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); + g2d.drawOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); + } + + // Draw label. + g2d.setFont(project.getFont()); + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + + String label = ""; + label = (getDisplay() == Display.NAME) ? getName() : (getValue() == null ? "" : getValue().toString()); + if (getDisplay() == Display.NONE) { + label = ""; + } + if (getDisplay() == Display.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + + g2d.setColor(finalLabelColor); + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle2D bodyRect = getBody()[0].getBounds2D(); + Rectangle2D rect = fontMetrics.getStringBounds(label, 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(label, (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 + public Display getDisplay() { + if (display == null) { + display = DISPLAY; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @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_SMALL("Horizontal Small 1"), FLAT_XSMALL("Horizontal Small 2"), FLAT_LARGE("Horizontal Medium"), FLAT_XLARGE( + "Horizontal Large"), VERTICAL_INLINE("Vertical Inline"), VERTICAL_OFFSET("Vertical Offset 1"), VERTICAL_OFFSET_BIG_GAP( + "Vertical Offset 2"); + + String label; + + private TrimmerType(String label) { + this.label = label; + } + + @Override + public String toString() { + return label;// name().substring(0, 1) + name().substring(1).toLowerCase().replace("_", " "); + } + } +} diff --git a/diylc/diylc-swing/library/main.jar b/diylc/diylc-swing/library/main.jar index b2f6e813733b1f557dd69d58347bcd3505f47c1c..9764897681e9ab8c476dcec0d4abba0daa80a29d 100644 GIT binary patch delta 19500 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 delta 19568 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 NEW_FEATURE Holding "shift" key switches mouse wheel scrolling from vertical to horizontal + + + NEW_FEATURE + Two new trimmer potentiometer types IMPROVEMENT