Added ability to set board size explicitly by typing in dimensions,

instead of dragging two control points
This commit is contained in:
bancika
2020-03-26 18:02:16 +01:00
parent a500ccb165
commit 8364d05a94
23 changed files with 379 additions and 274 deletions
@@ -29,5 +29,5 @@ package org.diylc.core;
public class AllowAllValidator implements IPropertyValidator { public class AllowAllValidator implements IPropertyValidator {
@Override @Override
public void validate(Object value) throws ValidationException {} public void validate(Object owner, Object value) throws ValidationException {}
} }
@@ -45,7 +45,7 @@ import org.diylc.core.annotations.EditableProperty;
* *
* @param <T> type of component values, e.g. Resistance for resistors or String for transistors. * @param <T> type of component values, e.g. Resistance for resistors or String for transistors.
*/ */
public interface IDIYComponent<T> extends Serializable { public interface IDIYComponent<T> extends Serializable, Cloneable {
public static final int CHASSIS = 1; public static final int CHASSIS = 1;
public static final int BOARD = 2; public static final int BOARD = 2;
@@ -28,9 +28,10 @@ package org.diylc.core;
*/ */
public interface IPropertyValidator { public interface IPropertyValidator {
/** /**
* @param owner
* @param value * @param value
* @throws ValidationException if validation fails. Message will contain the reason. * @throws ValidationException if validation fails. Message will contain the reason.
*/ */
void validate(Object value) throws ValidationException; void validate(Object owner, Object value) throws ValidationException;
} }
@@ -45,7 +45,7 @@ import org.diylc.core.measures.SizeUnit;
* *
* @author Branislav Stojkovic * @author Branislav Stojkovic
*/ */
public class Project implements Serializable { public class Project implements Serializable, Cloneable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -292,8 +292,8 @@ public class Project implements Serializable {
public static class SpacingValidator extends PositiveMeasureValidator { public static class SpacingValidator extends PositiveMeasureValidator {
@Override @Override
public void validate(Object value) throws ValidationException { public void validate(Object owner, Object value) throws ValidationException {
super.validate(value); super.validate(owner, value);
Size size = (Size) value; Size size = (Size) value;
if (size.compareTo(new Size(0.1d, SizeUnit.mm)) < 0) { if (size.compareTo(new Size(0.1d, SizeUnit.mm)) < 0) {
throw new ValidationException("must be at least 0.1mm"); throw new ValidationException("must be at least 0.1mm");
@@ -21,8 +21,8 @@
*/ */
package org.diylc.core.annotations; package org.diylc.core.annotations;
import org.diylc.core.IPropertyValidator; import org.diylc.core.IPropertyValidator;
import org.diylc.core.ValidationException; import org.diylc.core.ValidationException;
import org.diylc.core.measures.AbstractMeasure; import org.diylc.core.measures.AbstractMeasure;
/** /**
@@ -34,7 +34,7 @@ import org.diylc.core.measures.AbstractMeasure;
public class PositiveMeasureValidator implements IPropertyValidator { public class PositiveMeasureValidator implements IPropertyValidator {
@Override @Override
public void validate(Object value) throws ValidationException { public void validate(Object owner, Object value) throws ValidationException {
if (value == null) if (value == null)
return; return;
if (value instanceof AbstractMeasure) { if (value instanceof AbstractMeasure) {
@@ -21,8 +21,8 @@
*/ */
package org.diylc.core.annotations; package org.diylc.core.annotations;
import org.diylc.core.IPropertyValidator; import org.diylc.core.IPropertyValidator;
import org.diylc.core.ValidationException; import org.diylc.core.ValidationException;
import org.diylc.core.measures.AbstractMeasure; import org.diylc.core.measures.AbstractMeasure;
/** /**
@@ -34,7 +34,7 @@ import org.diylc.core.measures.AbstractMeasure;
public class PositiveNonZeroMeasureValidator implements IPropertyValidator { public class PositiveNonZeroMeasureValidator implements IPropertyValidator {
@Override @Override
public void validate(Object value) throws ValidationException { public void validate(Object owner, Object value) throws ValidationException {
if (value == null) if (value == null)
return; return;
if (value instanceof AbstractMeasure) { if (value instanceof AbstractMeasure) {
@@ -53,15 +53,6 @@ public class AbstractMeasure<T extends Enum<? extends Unit>> implements Serializ
public T getUnit() { public T getUnit() {
return unit; return unit;
}
/***
* Flag that designates if measure value should be converted between different units. eg. 2.54mm <-> 0.1in
*
* @return
*/
public boolean isConvertible() {
return false;
} }
@Override @Override
@@ -65,10 +65,5 @@ public class Size extends AbstractMeasure<SizeUnit> implements Comparable<Size>
@Override @Override
public int compareTo(Size o) { public int compareTo(Size o) {
return new Double(value * unit.getFactor()).compareTo(o.getValue() * o.getUnit().getFactor()); return new Double(value * unit.getFactor()).compareTo(o.getValue() * o.getUnit().getFactor());
}
@Override
public boolean isConvertible() {
return true;
} }
} }
@@ -2710,6 +2710,10 @@
<changeType>NEW_FEATURE</changeType> <changeType>NEW_FEATURE</changeType>
<description>Added "Tape Measure" component for measuring the distance between any two points on the drawing</description> <description>Added "Tape Measure" component for measuring the distance between any two points on the drawing</description>
</org.diylc.appframework.update.Change> </org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added ability to set board size explicitly by typing in dimensions, instead of dragging two control points</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change> <org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType> <changeType>NEW_FEATURE</changeType>
<description>New app bundle for Mac OS using appbundler instead of javabundler</description> <description>New app bundle for Mac OS using appbundler instead of javabundler</description>
Binary file not shown.
@@ -65,11 +65,17 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
protected CoordinateOrigin coordinateOrigin = CoordinateOrigin.Top_Left; protected CoordinateOrigin coordinateOrigin = CoordinateOrigin.Top_Left;
protected CoordinateDisplay coordinateDisplay = CoordinateDisplay.One_Side; protected CoordinateDisplay coordinateDisplay = CoordinateDisplay.One_Side;
protected CoordinateType yType = CoordinateType.Letters; protected CoordinateType yType = CoordinateType.Letters;
protected Size length;
protected Size width;
protected BoardSizingMode mode = BoardSizingMode.TwoPoints;
@Override @Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) { IDrawingObserver drawingObserver) {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
Point finalSecondPoint = getFinalSecondPoint();
Composite oldComposite = g2d.getComposite(); Composite oldComposite = g2d.getComposite();
// render as transparent when dragging // render as transparent when dragging
@@ -78,7 +84,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
} }
g2d.setColor(boardColor); g2d.setColor(boardColor);
g2d.fillRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y); g2d.fillRect(firstPoint.x, firstPoint.y, finalSecondPoint.x - firstPoint.x, finalSecondPoint.y - firstPoint.y);
g2d.setComposite(oldComposite); g2d.setComposite(oldComposite);
// Do not track any changes that follow because the whole board has been // Do not track any changes that follow because the whole board has been
@@ -86,7 +92,17 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
drawingObserver.stopTracking(); drawingObserver.stopTracking();
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: borderColor); : borderColor);
g2d.drawRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y); g2d.drawRect(firstPoint.x, firstPoint.y, finalSecondPoint.x - firstPoint.x, finalSecondPoint.y - firstPoint.y);
}
protected Point getFinalSecondPoint() {
Point finalSecondPoint;
if (getMode() == BoardSizingMode.TwoPoints)
finalSecondPoint = secondPoint;
else
finalSecondPoint = new Point((int)(firstPoint.x + getLength().convertToPixels()),
(int)(firstPoint.y + getWidth().convertToPixels()));
return finalSecondPoint;
} }
protected void drawCoordinates(Graphics2D g2d, int spacing, Project project) { protected void drawCoordinates(Graphics2D g2d, int spacing, Project project) {
@@ -97,6 +113,8 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
int halfSpace = spacing / 2; int halfSpace = spacing / 2;
CoordinateOrigin origin = getCoordinateOrigin(); CoordinateOrigin origin = getCoordinateOrigin();
Point finalSecondPoint = getFinalSecondPoint();
if (getCoordinateDisplay() != CoordinateDisplay.None) { if (getCoordinateDisplay() != CoordinateDisplay.None) {
int range; int range;
int yOffset; int yOffset;
@@ -104,12 +122,12 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
Point drawPoint = new Point(firstPoint); Point drawPoint = new Point(firstPoint);
if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Top_Right) { if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Top_Right) {
range = (int) ((secondPoint.y - firstPoint.y + halfSpace) / spacing); range = (int) ((finalSecondPoint.y - firstPoint.y + halfSpace) / spacing);
yOffset = spacing; yOffset = spacing;
} else { } else {
range = (int) ((secondPoint.y - firstPoint.y + halfSpace) / spacing); range = (int) ((finalSecondPoint.y - firstPoint.y + halfSpace) / spacing);
yOffset = -spacing; yOffset = -spacing;
drawPoint.y = secondPoint.y; drawPoint.y = finalSecondPoint.y;
} }
for (int c = 1; c < range; c++) { for (int c = 1; c < range; c++) {
@@ -122,7 +140,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
HorizontalAlignment.LEFT, VerticalAlignment.CENTER); HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) { if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) {
StringUtils.drawCenteredText(g2d, label, StringUtils.drawCenteredText(g2d, label,
secondPoint.x - xOffset, drawPoint.y, finalSecondPoint.x - xOffset, drawPoint.y,
HorizontalAlignment.RIGHT, VerticalAlignment.CENTER); HorizontalAlignment.RIGHT, VerticalAlignment.CENTER);
} }
} }
@@ -135,12 +153,12 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
Point drawPoint = new Point(firstPoint); Point drawPoint = new Point(firstPoint);
if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Bottom_Left) { if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Bottom_Left) {
range = (int) ((secondPoint.x - firstPoint.x + halfSpace) / spacing); range = (int) ((finalSecondPoint.x - firstPoint.x + halfSpace) / spacing);
xOffset = spacing; xOffset = spacing;
} else { } else {
range = (int) ((secondPoint.x - firstPoint.x + halfSpace) / spacing); range = (int) ((finalSecondPoint.x - firstPoint.x + halfSpace) / spacing);
xOffset = -spacing; xOffset = -spacing;
drawPoint.x = secondPoint.x; drawPoint.x = finalSecondPoint.x;
} }
for (int c = 1; c < range; c++) { for (int c = 1; c < range; c++) {
@@ -152,7 +170,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
HorizontalAlignment.CENTER, VerticalAlignment.TOP); HorizontalAlignment.CENTER, VerticalAlignment.TOP);
if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) { if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) {
StringUtils.drawCenteredText(g2d, label, StringUtils.drawCenteredText(g2d, label,
drawPoint.x, (int) (secondPoint.y - COORDINATE_FONT_SIZE), drawPoint.x, (int) (finalSecondPoint.y - COORDINATE_FONT_SIZE),
HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM); HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
} }
} }
@@ -263,7 +281,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
@Override @Override
public VisibilityPolicy getControlPointVisibilityPolicy(int index) { public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
return VisibilityPolicy.WHEN_SELECTED; return getMode() == BoardSizingMode.TwoPoints ? VisibilityPolicy.WHEN_SELECTED : VisibilityPolicy.NEVER;
} }
@Override @Override
@@ -285,7 +303,36 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }
@EditableProperty(name = "Explicit Length", validatorClass = BoardModeValidator.class)
public Size getLength() {
return length;
}
public void setLength(Size length) {
this.length = length;
}
@EditableProperty(name = "Explicit Width", validatorClass = BoardModeValidator.class)
public Size getWidth() {
return width;
}
public void setWidth(Size width) {
this.width = width;
}
@EditableProperty(name = "Sizing Mode")
public BoardSizingMode getMode() {
if (mode == null)
mode = BoardSizingMode.TwoPoints;
return mode;
}
public void setMode(BoardSizingMode mode) {
this.mode = mode;
}
public static enum CoordinateType { public static enum CoordinateType {
Letters, Numbers Letters, Numbers
} }
@@ -307,4 +354,19 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
return super.toString().replace('_', ' '); return super.toString().replace('_', ' ');
}; };
} }
public static enum BoardSizingMode {
TwoPoints("Opposing Points"), Explicit("Explicit Dimensions");
private String label;
private BoardSizingMode(String label) {
this.label = label;
}
@Override
public String toString() {
return label;
}
}
} }
@@ -25,6 +25,7 @@ import java.awt.AlphaComposite;
import java.awt.Color; import java.awt.Color;
import java.awt.Composite; import java.awt.Composite;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Shape; import java.awt.Shape;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
@@ -57,12 +58,14 @@ public class BlankBoard extends AbstractBoard {
@Override @Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) { IDrawingObserver drawingObserver) {
Point finalSecondPoint = getFinalSecondPoint();
Shape clip = g2d.getClip(); Shape clip = g2d.getClip();
if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, finalSecondPoint.y)
&& !clip.contains(secondPoint.x, firstPoint.y)) { && !clip.contains(finalSecondPoint.x, firstPoint.y)) {
return; return;
} }
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
if (componentState != ComponentState.DRAGGING) { if (componentState != ComponentState.DRAGGING) {
@@ -72,9 +75,9 @@ public class BlankBoard extends AbstractBoard {
} }
g2d.setColor(boardColor); g2d.setColor(boardColor);
if (getType() == Type.SQUARE) if (getType() == Type.SQUARE)
g2d.fillRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y); g2d.fillRect(firstPoint.x, firstPoint.y, finalSecondPoint.x - firstPoint.x, finalSecondPoint.y - firstPoint.y);
else else
g2d.fillOval(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y); g2d.fillOval(firstPoint.x, firstPoint.y, finalSecondPoint.x - firstPoint.x, finalSecondPoint.y - firstPoint.y);
g2d.setComposite(oldComposite); g2d.setComposite(oldComposite);
} }
// Do not track any changes that follow because the whole board has been // Do not track any changes that follow because the whole board has been
@@ -83,9 +86,9 @@ public class BlankBoard extends AbstractBoard {
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: borderColor); : borderColor);
if (getType() == Type.SQUARE) if (getType() == Type.SQUARE)
g2d.drawRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y); g2d.drawRect(firstPoint.x, firstPoint.y, finalSecondPoint.x - firstPoint.x, finalSecondPoint.y - firstPoint.y);
else else
g2d.drawOval(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y); g2d.drawOval(firstPoint.x, firstPoint.y, finalSecondPoint.x - firstPoint.x, finalSecondPoint.y - firstPoint.y);
} }
@Override @Override
@@ -0,0 +1,19 @@
package org.diylc.components.boards;
import org.diylc.components.boards.AbstractBoard.BoardSizingMode;
import org.diylc.core.IPropertyValidator;
import org.diylc.core.ValidationException;
import org.diylc.core.measures.Size;
public class BoardModeValidator implements IPropertyValidator {
public BoardModeValidator() {}
@Override
public void validate(Object owner, Object value) throws ValidationException {
AbstractBoard board = (AbstractBoard)owner;
Size size = (Size)value;
if (board.getMode() == BoardSizingMode.Explicit && (value == null || size.getValue() == null || size.getUnit() == null))
throw new ValidationException("Dimensions are required when mode is set to " + BoardSizingMode.Explicit);
}
}
@@ -68,10 +68,12 @@ public class EyeletBoard extends AbstractBoard {
@Override @Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) { IDrawingObserver drawingObserver) {
Point finalSecondPoint = getFinalSecondPoint();
Shape clip = g2d.getClip(); Shape clip = g2d.getClip();
if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, finalSecondPoint.y)
&& !clip.contains(secondPoint.x, firstPoint.y)) { && !clip.contains(finalSecondPoint.x, firstPoint.y)) {
return; return;
} }
super.draw(g2d, componentState, outlineMode, project, drawingObserver); super.draw(g2d, componentState, outlineMode, project, drawingObserver);
@@ -84,10 +86,10 @@ public class EyeletBoard extends AbstractBoard {
int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels()); int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels());
int spacing = (int) this.spacing.convertToPixels(); int spacing = (int) this.spacing.convertToPixels();
while (p.y < secondPoint.y - spacing) { while (p.y < finalSecondPoint.y - spacing) {
p.x = firstPoint.x; p.x = firstPoint.x;
p.y += spacing; p.y += spacing;
while (p.x < secondPoint.x - spacing - diameter) { while (p.x < finalSecondPoint.x - spacing - diameter) {
p.x += spacing; p.x += spacing;
g2d.setColor(eyeletColor); g2d.setColor(eyeletColor);
g2d.fillOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter); g2d.fillOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter);
@@ -66,10 +66,12 @@ public class MarshallPerfBoard extends AbstractBoard {
@Override @Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) { IDrawingObserver drawingObserver) {
Point finalSecondPoint = getFinalSecondPoint();
Shape clip = g2d.getClip(); Shape clip = g2d.getClip();
if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, finalSecondPoint.y)
&& !clip.contains(secondPoint.x, firstPoint.y)) { && !clip.contains(finalSecondPoint.x, firstPoint.y)) {
return; return;
} }
super.draw(g2d, componentState, outlineMode, project, drawingObserver); super.draw(g2d, componentState, outlineMode, project, drawingObserver);
@@ -81,10 +83,10 @@ public class MarshallPerfBoard extends AbstractBoard {
int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels()); int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels());
int spacing = (int) this.spacing.convertToPixels(); int spacing = (int) this.spacing.convertToPixels();
while (p.y < secondPoint.y - spacing) { while (p.y < finalSecondPoint.y - spacing) {
p.x = firstPoint.x; p.x = firstPoint.x;
p.y += spacing; p.y += spacing;
while (p.x < secondPoint.x - spacing - holeDiameter) { while (p.x < finalSecondPoint.x - spacing - holeDiameter) {
p.x += spacing; p.x += spacing;
g2d.setColor(Constants.CANVAS_COLOR); g2d.setColor(Constants.CANVAS_COLOR);
g2d.fillOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, holeDiameter); g2d.fillOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, holeDiameter);
@@ -61,10 +61,12 @@ public class PerfBoard extends AbstractBoard {
@Override @Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) { IDrawingObserver drawingObserver) {
Point finalSecondPoint = getFinalSecondPoint();
Shape clip = g2d.getClip(); Shape clip = g2d.getClip();
if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, finalSecondPoint.y)
&& !clip.contains(secondPoint.x, firstPoint.y)) { && !clip.contains(finalSecondPoint.x, firstPoint.y)) {
return; return;
} }
super.draw(g2d, componentState, outlineMode, project, drawingObserver); super.draw(g2d, componentState, outlineMode, project, drawingObserver);
@@ -77,10 +79,10 @@ public class PerfBoard extends AbstractBoard {
int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels()); int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels());
int spacing = (int) this.spacing.convertToPixels(); int spacing = (int) this.spacing.convertToPixels();
while (p.y < secondPoint.y - spacing) { while (p.y < finalSecondPoint.y - spacing) {
p.x = firstPoint.x; p.x = firstPoint.x;
p.y += spacing; p.y += spacing;
while (p.x < secondPoint.x - spacing - diameter) { while (p.x < finalSecondPoint.x - spacing - diameter) {
p.x += spacing; p.x += spacing;
g2d.setColor(padColor); g2d.setColor(padColor);
g2d.fillOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter); g2d.fillOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter);
@@ -64,10 +64,12 @@ public class TriPadBoard extends AbstractBoard {
@Override @Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) { IDrawingObserver drawingObserver) {
Point finalSecondPoint = getFinalSecondPoint();
Shape clip = g2d.getClip(); Shape clip = g2d.getClip();
if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, finalSecondPoint.y)
&& !clip.contains(secondPoint.x, firstPoint.y)) { && !clip.contains(finalSecondPoint.x, firstPoint.y)) {
return; return;
} }
super.draw(g2d, componentState, outlineMode, project, drawingObserver); super.draw(g2d, componentState, outlineMode, project, drawingObserver);
@@ -82,13 +84,13 @@ public class TriPadBoard extends AbstractBoard {
int spacing = (int) this.spacing.convertToPixels(); int spacing = (int) this.spacing.convertToPixels();
if (orientation == OrientationHV.HORIZONTAL) { if (orientation == OrientationHV.HORIZONTAL) {
while (p.y < secondPoint.y - spacing) { while (p.y < finalSecondPoint.y - spacing) {
p.x = firstPoint.x; p.x = firstPoint.x;
p.y += spacing; p.y += spacing;
while (p.x + spacing < secondPoint.x) { while (p.x + spacing < finalSecondPoint.x) {
int remainingSpace = secondPoint.x - p.x; int remainingSpace = finalSecondPoint.x - p.x;
int spacesToDraw = stripSpan; int spacesToDraw = stripSpan;
if (remainingSpace < (stripSize + (stripSpan * spacing))) { if (remainingSpace < (stripSize + (stripSpan * spacing))) {
@@ -111,7 +113,7 @@ public class TriPadBoard extends AbstractBoard {
// draw holes // draw holes
p.x = firstPoint.x; p.x = firstPoint.x;
while (p.x < secondPoint.x - spacing - holeSize) { while (p.x < finalSecondPoint.x - spacing - holeSize) {
p.x += spacing; p.x += spacing;
g2d.setColor(Constants.CANVAS_COLOR); g2d.setColor(Constants.CANVAS_COLOR);
g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize); g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize);
@@ -120,13 +122,13 @@ public class TriPadBoard extends AbstractBoard {
} }
} }
} else { } else {
while (p.x < secondPoint.x - spacing) { while (p.x < finalSecondPoint.x - spacing) {
p.x += spacing; p.x += spacing;
p.y = firstPoint.y; p.y = firstPoint.y;
while (p.y + spacing < secondPoint.y) { while (p.y + spacing < finalSecondPoint.y) {
int remainingSpace = secondPoint.y - p.y; int remainingSpace = finalSecondPoint.y - p.y;
int spacesToDraw = stripSpan; int spacesToDraw = stripSpan;
if (remainingSpace < (stripSize + (stripSpan * spacing))) { if (remainingSpace < (stripSize + (stripSpan * spacing))) {
@@ -148,7 +150,7 @@ public class TriPadBoard extends AbstractBoard {
// draw holes // draw holes
p.y = firstPoint.y; p.y = firstPoint.y;
while (p.y < secondPoint.y - spacing - holeSize) { while (p.y < finalSecondPoint.y - spacing - holeSize) {
p.y += spacing; p.y += spacing;
g2d.setColor(Constants.CANVAS_COLOR); g2d.setColor(Constants.CANVAS_COLOR);
g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize); g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize);
@@ -64,10 +64,12 @@ public class VeroBoard extends AbstractBoard {
@Override @Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) { IDrawingObserver drawingObserver) {
Point finalSecondPoint = getFinalSecondPoint();
Shape clip = g2d.getClip(); Shape clip = g2d.getClip();
if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, secondPoint.y) if (checkPointsClipped(clip) && !clip.contains(firstPoint.x, finalSecondPoint.y)
&& !clip.contains(secondPoint.x, firstPoint.y)) { && !clip.contains(finalSecondPoint.x, firstPoint.y)) {
return; return;
} }
super.draw(g2d, componentState, outlineMode, project, drawingObserver); super.draw(g2d, componentState, outlineMode, project, drawingObserver);
@@ -82,16 +84,16 @@ public class VeroBoard extends AbstractBoard {
int spacing = (int) this.spacing.convertToPixels(); int spacing = (int) this.spacing.convertToPixels();
if (orientation == OrientationHV.HORIZONTAL) { if (orientation == OrientationHV.HORIZONTAL) {
while (p.y < secondPoint.y - spacing) { while (p.y < finalSecondPoint.y - spacing) {
p.x = firstPoint.x; p.x = firstPoint.x;
p.y += spacing; p.y += spacing;
g2d.setColor(stripColor); g2d.setColor(stripColor);
drawingObserver.startTrackingContinuityArea(true); drawingObserver.startTrackingContinuityArea(true);
g2d.fillRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing - p.x, stripSize); g2d.fillRect(p.x + spacing / 2, p.y - stripSize / 2, finalSecondPoint.x - spacing - p.x, stripSize);
drawingObserver.stopTrackingContinuityArea(); drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker()); g2d.setColor(stripColor.darker());
g2d.drawRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing - p.x, stripSize); g2d.drawRect(p.x + spacing / 2, p.y - stripSize / 2, finalSecondPoint.x - spacing - p.x, stripSize);
while (p.x < secondPoint.x - spacing - holeSize) { while (p.x < finalSecondPoint.x - spacing - holeSize) {
p.x += spacing; p.x += spacing;
g2d.setColor(Constants.CANVAS_COLOR); g2d.setColor(Constants.CANVAS_COLOR);
g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize); g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize);
@@ -100,16 +102,16 @@ public class VeroBoard extends AbstractBoard {
} }
} }
} else { } else {
while (p.x < secondPoint.x - spacing) { while (p.x < finalSecondPoint.x - spacing) {
p.x += spacing; p.x += spacing;
p.y = firstPoint.y; p.y = firstPoint.y;
g2d.setColor(stripColor); g2d.setColor(stripColor);
drawingObserver.startTrackingContinuityArea(true); drawingObserver.startTrackingContinuityArea(true);
g2d.fillRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y - spacing - p.y); g2d.fillRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, finalSecondPoint.y - spacing - p.y);
drawingObserver.stopTrackingContinuityArea(); drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker()); g2d.setColor(stripColor.darker());
g2d.drawRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y - spacing - p.y); g2d.drawRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, finalSecondPoint.y - spacing - p.y);
while (p.y < secondPoint.y - spacing - holeSize) { while (p.y < finalSecondPoint.y - spacing - holeSize) {
p.y += spacing; p.y += spacing;
g2d.setColor(Constants.CANVAS_COLOR); g2d.setColor(Constants.CANVAS_COLOR);
g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize); g2d.fillOval(p.x - holeSize / 2, p.y - holeSize / 2, holeSize, holeSize);
@@ -193,7 +193,7 @@ public class DiodeSymbol extends AbstractTubeSymbol {
public class HeaterValidator implements IPropertyValidator { public class HeaterValidator implements IPropertyValidator {
@Override @Override
public void validate(Object value) throws ValidationException { public void validate(Object owner, Object value) throws ValidationException {
if (value != null && value instanceof Boolean) { if (value != null && value instanceof Boolean) {
boolean b = (Boolean) value; boolean b = (Boolean) value;
if (!b && getDirectlyHeated()) { if (!b && getDirectlyHeated()) {
Binary file not shown.
Binary file not shown.
@@ -89,7 +89,7 @@ public class MeasureEditor extends Container {
try { try {
Constructor<?> ctor = property.getType().getConstructors()[0]; Constructor<?> ctor = property.getType().getConstructors()[0];
Double newValue = valueField.getValue(); Double newValue = valueField.getValue();
if (newValue != null && property.isReadOnly() && measure.isConvertible()) { if (newValue != null && property.isReadOnly()) {
double oldFactor = ((Unit)((AbstractMeasure<?>)property.getValue()).getUnit()).getFactor(); double oldFactor = ((Unit)((AbstractMeasure<?>)property.getValue()).getUnit()).getFactor();
double newFactor = ((Unit)unitBox.getSelectedItem()).getFactor(); double newFactor = ((Unit)unitBox.getSelectedItem()).getFactor();
newValue = newValue * oldFactor / newFactor; newValue = newValue * oldFactor / newFactor;
@@ -111,7 +111,7 @@ public class MeasureEditor extends Container {
if (property.isReadOnly()) { if (property.isReadOnly()) {
valueField.setEnabled(false); valueField.setEnabled(false);
unitBox.setEnabled(measure.isConvertible()); unitBox.setEnabled(true);
} }
if (!property.isUnique()) { if (!property.isUnique()) {
@@ -1,195 +1,215 @@
/* /*
*
* 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
* <http://www.gnu.org/licenses/>.
*
*/
package org.diylc.swing.gui.editor;
DIY Layout Creator (DIYLC). import java.awt.Component;
Copyright (c) 2009-2018 held jointly by the individual authors. import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
This file is part of DIYLC. import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
DIYLC is free software: you can redistribute it and/or modify import org.apache.log4j.Logger;
it under the terms of the GNU General Public License as published by import org.diylc.common.PropertyWrapper;
the Free Software Foundation, either version 3 of the License, or import org.diylc.core.ValidationException;
(at your option) any later version. import org.diylc.swingframework.ButtonDialog;
DIYLC is distributed in the hope that it will be useful, public class PropertyEditorDialog extends ButtonDialog {
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 private static final Logger LOG = Logger.getLogger(PropertyEditorDialog.class);
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ private static final long serialVersionUID = 1L;
package org.diylc.swing.gui.editor;
private static final String DEFAULT_BOX_TOOLTIP =
import java.awt.Component; "<html>If this box is checked application will use the current value as a<br>default when creating new components of the same type</html>";
import java.awt.Dimension;
import java.awt.GridBagConstraints; private List<PropertyWrapper> properties;
import java.awt.GridBagLayout; private Set<PropertyWrapper> defaultedProperties;
import java.awt.Insets; private Component componentToFocus = null;
import java.awt.event.ActionEvent; private boolean saveDefaults;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter; public PropertyEditorDialog(JFrame owner, List<PropertyWrapper> properties, String title,
import java.awt.event.KeyEvent; boolean saveDefaults) {
import java.util.HashSet; super(owner, title, new String[] {ButtonDialog.OK, ButtonDialog.CANCEL});
import java.util.List; this.saveDefaults = saveDefaults;
import java.util.Set;
LOG.debug("Creating property editor for: " + properties);
import javax.swing.BorderFactory;
import javax.swing.JCheckBox; this.properties = properties;
import javax.swing.JComponent; this.defaultedProperties = new HashSet<PropertyWrapper>();
import javax.swing.JFrame;
import javax.swing.JLabel; setMinimumSize(new Dimension(240, 40));
import javax.swing.JOptionPane;
import javax.swing.JPanel; layoutGui();
setLocationRelativeTo(owner);
import org.apache.log4j.Logger; }
import org.diylc.common.PropertyWrapper;
import org.diylc.core.ValidationException; @Override
import org.diylc.swingframework.ButtonDialog; protected boolean validateInput(String button) {
if (button.equals(ButtonDialog.OK)) {
public class PropertyEditorDialog extends ButtonDialog { Object testObject = null;
if (properties.size() > 0) {
private static final Logger LOG = Logger.getLogger(PropertyEditorDialog.class); if (properties.get(0).getOwnerObject() instanceof Cloneable) {
try {
private static final long serialVersionUID = 1L; Object object = ((Cloneable) properties.get(0).getOwnerObject());
Method method = object.getClass().getMethod("clone");
private static final String DEFAULT_BOX_TOOLTIP = method.setAccessible(true);
"<html>If this box is checked application will use the current value as a<br>default when creating new components of the same type</html>"; testObject = method.invoke(object);
for (PropertyWrapper property : properties) {
private List<PropertyWrapper> properties; property.writeTo(testObject);
private Set<PropertyWrapper> defaultedProperties; }
private Component componentToFocus = null; } catch (Exception e) {
private boolean saveDefaults; LOG.warn("Could not clone test object", e);
testObject = properties.get(0).getOwnerObject();
public PropertyEditorDialog(JFrame owner, List<PropertyWrapper> properties, String title, boolean saveDefaults) { }
super(owner, title, new String[] {ButtonDialog.OK, ButtonDialog.CANCEL}); } else {
this.saveDefaults = saveDefaults; testObject = properties.get(0).getOwnerObject();
}
LOG.debug("Creating property editor for: " + properties); }
for (PropertyWrapper property : properties) {
this.properties = properties; try {
this.defaultedProperties = new HashSet<PropertyWrapper>(); property.getValidator().validate(testObject, property.getValue());
} catch (ValidationException ve) {
setMinimumSize(new Dimension(240, 40)); JOptionPane.showMessageDialog(PropertyEditorDialog.this,
"Input error for \"" + property.getName() + "\": " + ve.getMessage(), "Error",
layoutGui(); JOptionPane.ERROR_MESSAGE);
setLocationRelativeTo(owner); return false;
} }
}
@Override }
protected boolean validateInput(String button) { return true;
if (button.equals(ButtonDialog.OK)) { }
for (PropertyWrapper property : properties) {
try { private JPanel createEditorFields() {
property.getValidator().validate(property.getValue()); JPanel editorPanel = new JPanel(new GridBagLayout());
} catch (ValidationException ve) { editorPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
JOptionPane.showMessageDialog(PropertyEditorDialog.this, "Input error for \"" + property.getName() + "\": "
+ ve.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); GridBagConstraints gbc = new GridBagConstraints();
return false;
} gbc.gridy = 0;
}
} gbc.anchor = GridBagConstraints.FIRST_LINE_START;
return true;
} for (PropertyWrapper property : properties) {
gbc.gridx = 0;
private JPanel createEditorFields() { gbc.fill = GridBagConstraints.NONE;
JPanel editorPanel = new JPanel(new GridBagLayout()); gbc.weightx = 0;
editorPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); gbc.insets = new Insets(4, 2, 2, 2);
gbc.anchor = GridBagConstraints.WEST;
GridBagConstraints gbc = new GridBagConstraints(); editorPanel.add(new JLabel(property.getName() + ": "), gbc);
gbc.gridy = 0; gbc.gridx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.FIRST_LINE_START; gbc.weightx = 1;
gbc.insets = new Insets(2, 2, 2, 2);
for (PropertyWrapper property : properties) {
gbc.gridx = 0; Component editor = FieldEditorFactory.createFieldEditor(property);
gbc.fill = GridBagConstraints.NONE; editor.addKeyListener(new KeyAdapter() {
gbc.weightx = 0;
gbc.insets = new Insets(4, 2, 2, 2); @Override
gbc.anchor = GridBagConstraints.WEST; public void keyPressed(KeyEvent e) {
editorPanel.add(new JLabel(property.getName() + ": "), gbc); if (e.getKeyCode() == KeyEvent.VK_ENTER) {
getButton(OK).doClick();
gbc.gridx = 1; } else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
gbc.fill = GridBagConstraints.HORIZONTAL; getButton(CANCEL).doClick();
gbc.weightx = 1; }
gbc.insets = new Insets(2, 2, 2, 2); }
});
Component editor = FieldEditorFactory.createFieldEditor(property); editorPanel.add(editor, gbc);
editor.addKeyListener(new KeyAdapter() {
if (property.isDefaultable()) {
@Override gbc.gridx = 2;
public void keyPressed(KeyEvent e) { gbc.fill = GridBagConstraints.NONE;
if (e.getKeyCode() == KeyEvent.VK_ENTER) { gbc.weightx = 0;
getButton(OK).doClick();
} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { if (saveDefaults && !property.isReadOnly()) {
getButton(CANCEL).doClick(); editorPanel.add(createDefaultCheckBox(property), gbc);
} }
} }
});
editorPanel.add(editor, gbc); if (property.getName().equalsIgnoreCase("value")) {
componentToFocus = editor;
if (property.isDefaultable()) { }
gbc.gridx = 2;
gbc.fill = GridBagConstraints.NONE; // Make value field focused
gbc.weightx = 0; try {
if (componentToFocus == null
if (saveDefaults && !property.isReadOnly()) { && property.getGetter().getName().equalsIgnoreCase("getValue")) {
editorPanel.add(createDefaultCheckBox(property), gbc); componentToFocus = editor;
} }
} } catch (Exception e1) {
LOG.warn("Could not determine editor component to focus", e1);
if (property.getName().equalsIgnoreCase("value")) { }
componentToFocus = editor;
} gbc.gridy++;
}
// Make value field focused
try { return editorPanel;
if (componentToFocus == null && property.getGetter().getName().equalsIgnoreCase("getValue")) { }
componentToFocus = editor;
} private JCheckBox createDefaultCheckBox(final PropertyWrapper property) {
} catch (Exception e1) { final JCheckBox checkBox = new JCheckBox();
LOG.warn("Could not determine editor component to focus", e1); checkBox.setToolTipText(DEFAULT_BOX_TOOLTIP);
} checkBox.addActionListener(new ActionListener() {
gbc.gridy++; @Override
} public void actionPerformed(ActionEvent e) {
if (checkBox.isSelected()) {
return editorPanel; defaultedProperties.add(property);
} } else {
defaultedProperties.remove(property);
private JCheckBox createDefaultCheckBox(final PropertyWrapper property) { }
final JCheckBox checkBox = new JCheckBox(); }
checkBox.setToolTipText(DEFAULT_BOX_TOOLTIP); });
checkBox.addActionListener(new ActionListener() { return checkBox;
}
@Override
public void actionPerformed(ActionEvent e) { public Set<PropertyWrapper> getDefaultedProperties() {
if (checkBox.isSelected()) { return defaultedProperties;
defaultedProperties.add(property); }
} else {
defaultedProperties.remove(property); @Override
} public void setVisible(boolean b) {
} if (b && componentToFocus != null) {
}); componentToFocus.requestFocusInWindow();
return checkBox; componentToFocus = null;
} }
super.setVisible(b);
public Set<PropertyWrapper> getDefaultedProperties() { }
return defaultedProperties;
} @Override
protected JComponent getMainComponent() {
@Override return createEditorFields();
public void setVisible(boolean b) { }
if (b && componentToFocus != null) { }
componentToFocus.requestFocusInWindow();
componentToFocus = null;
}
super.setVisible(b);
}
@Override
protected JComponent getMainComponent() {
return createEditorFields();
}
}