mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-07 12:24:58 +10:00
Added read-only "Length" property to curved components (i.e. "Hookup
Wire") that calculates total length of the curve
This commit is contained in:
@@ -75,12 +75,19 @@ public class PropertyWrapper implements Cloneable {
|
||||
// }
|
||||
|
||||
public void writeTo(Object object) throws IllegalArgumentException, IllegalAccessException,
|
||||
InvocationTargetException, SecurityException, NoSuchMethodException {
|
||||
InvocationTargetException, SecurityException, NoSuchMethodException {
|
||||
// nothing to do if no setter
|
||||
if (setter == null)
|
||||
return;
|
||||
object.getClass().getMethod(setter, type).invoke(object, this.value);
|
||||
}
|
||||
|
||||
public Method getGetter() throws SecurityException, NoSuchMethodException {
|
||||
return getOwnerObject().getClass().getMethod(getter);
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return setter == null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
@@ -24,7 +24,10 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.LineStyle;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.core.ComponentState;
|
||||
@@ -299,7 +302,7 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
|
||||
|
||||
public void setStyle(LineStyle style) {
|
||||
this.style = style;
|
||||
}
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Boolean getSmooth() {
|
||||
@@ -321,6 +324,32 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Size getLength() {
|
||||
double d = 0;
|
||||
Point[] p = getControlPoints();
|
||||
if (getPointCount() == PointCount.TWO) {
|
||||
d = p[0].distance(p[1]);
|
||||
} else if (getPointCount() == PointCount.THREE) {
|
||||
d = calculateLength(p[0], p[1], p[1], p[2]);
|
||||
} else if (getPointCount() == PointCount.FOUR) {
|
||||
d = calculateLength(p[0], p[1], p[2], p[3]);
|
||||
} else if (getPointCount() == PointCount.FIVE) {
|
||||
d = calculateLength(p[0], p[1], p[2]) + calculateLength(p[2], p[3], p[4]);
|
||||
} else if (getPointCount() == PointCount.SEVEN) {
|
||||
d = calculateLength(p[0], p[1], p[2], p[3]) + calculateLength(p[3], p[4], p[5], p[6]);
|
||||
}
|
||||
|
||||
SizeUnit unit;
|
||||
if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.METRIC_KEY, true))
|
||||
unit = SizeUnit.mm;
|
||||
else
|
||||
unit = SizeUnit.in;
|
||||
|
||||
d = d * SizeUnit.px.getFactor() / unit.getFactor();
|
||||
return new Size(d, unit);
|
||||
}
|
||||
|
||||
public enum PointCount {
|
||||
TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7);
|
||||
@@ -336,4 +365,44 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
|
||||
return name().substring(0, 1) + name().substring(1).toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
// calculate length of quad curve
|
||||
private double calculateLength(Point2D a, Point2D b, Point2D c) {
|
||||
double vx = 2 * (b.getX() - a.getX());
|
||||
double vy = 2 * (b.getY() - a.getY());
|
||||
double wx = c.getX() - 2 * b.getX() + a.getX();
|
||||
double wy = c.getY() - 2 * b.getY() + a.getY();
|
||||
|
||||
double uu = 4 * (wx * wx + wy * wy);
|
||||
|
||||
if (uu < 0.00001) {
|
||||
return (float) Math.sqrt((c.getX() - a.getX()) * (c.getX() - a.getX()) + (c.getY() - a.getY()) * (c.getY() - a.getY()));
|
||||
}
|
||||
|
||||
double vv = 4 * (vx * wx + vy * wy);
|
||||
double ww = vx * vx + vy * vy;
|
||||
|
||||
double t1 = (float) (2 * Math.sqrt(uu * (uu + vv + ww)));
|
||||
double t2 = 2 * uu + vv;
|
||||
double t3 = vv * vv - 4 * uu * ww;
|
||||
double t4 = (float) (2 * Math.sqrt(uu * ww));
|
||||
|
||||
return (float) ((t1 * t2 - t3 * Math.log(t2 + t1) - (vv * t4 - t3 * Math.log(vv + t4)))
|
||||
/ (8 * Math.pow(uu, 1.5)));
|
||||
}
|
||||
|
||||
private double curveThreshold = 10;
|
||||
|
||||
// approximately calculate length of Bezier curves by subdivision
|
||||
private double calculateLength(Point2D a, Point2D b, Point2D c, Point2D d) {
|
||||
double distance = a.distance(d);
|
||||
if (distance < curveThreshold)
|
||||
return distance;
|
||||
CubicCurve2D curve = new CubicCurve2D.Double(a.getX(), a.getY(), b.getX(), b.getY(), c.getX(), c.getY(), d.getX(), d.getY());
|
||||
CubicCurve2D left = new CubicCurve2D.Double();
|
||||
CubicCurve2D right = new CubicCurve2D.Double();
|
||||
curve.subdivide(left, right);
|
||||
return calculateLength(left.getP1(), left.getCtrlP1(), left.getCtrlP2(), left.getP2()) +
|
||||
calculateLength(right.getP1(), right.getCtrlP1(), right.getCtrlP2(), right.getP2());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,9 +41,6 @@ public class AbstractMeasure<T extends Enum<? extends Unit>> implements Serializ
|
||||
protected Double value;
|
||||
protected T unit;
|
||||
|
||||
// public AbstractMeasure() {
|
||||
// }
|
||||
|
||||
public AbstractMeasure(Double value, T unit) {
|
||||
super();
|
||||
this.value = value;
|
||||
@@ -54,23 +51,19 @@ public class AbstractMeasure<T extends Enum<? extends Unit>> implements Serializ
|
||||
return value;
|
||||
}
|
||||
|
||||
// public void setValue(Double value) {
|
||||
// this.value = value;
|
||||
// }
|
||||
|
||||
public T getUnit() {
|
||||
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;
|
||||
}
|
||||
|
||||
// public void setUnit(T multiplier) {
|
||||
// this.unit = multiplier;
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public Object clone() throws CloneNotSupportedException {
|
||||
// return super.clone();
|
||||
// }
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
||||
@@ -65,5 +65,10 @@ public class Size extends AbstractMeasure<SizeUnit> implements Comparable<Size>
|
||||
@Override
|
||||
public int compareTo(Size o) {
|
||||
return new Double(value * unit.getFactor()).compareTo(o.getValue() * o.getUnit().getFactor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConvertible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,11 @@ public class ComparatorFactory {
|
||||
propertyNameComparator = new Comparator<PropertyWrapper>() {
|
||||
|
||||
@Override
|
||||
public int compare(PropertyWrapper o1, PropertyWrapper o2) {
|
||||
public int compare(PropertyWrapper o1, PropertyWrapper o2) {
|
||||
if (o1.isReadOnly() && !o2.isReadOnly())
|
||||
return 1;
|
||||
if (!o1.isReadOnly() && o2.isReadOnly())
|
||||
return -1;
|
||||
int comp = new Integer(o1.getSortOrder()).compareTo(o2.getSortOrder());
|
||||
if (comp != 0)
|
||||
return comp;
|
||||
|
||||
@@ -151,7 +151,7 @@ public class ComponentProcessor {
|
||||
List<PropertyWrapper> properties = new ArrayList<PropertyWrapper>();
|
||||
for (Method getter : clazz.getMethods()) {
|
||||
if (getter.getName().startsWith("get")) {
|
||||
try {
|
||||
|
||||
if (getter.isAnnotationPresent(EditableProperty.class) && !getter.isAnnotationPresent(Deprecated.class)
|
||||
// since Java 8 in generic classes we get properties of both the generic type and Object
|
||||
// added this condition to skip Object property that we do not need
|
||||
@@ -163,16 +163,20 @@ public class ComponentProcessor {
|
||||
} else {
|
||||
name = annotation.name();
|
||||
}
|
||||
IPropertyValidator validator = getPropertyValidator(annotation.validatorClass());
|
||||
Method setter = clazz.getMethod("set" + getter.getName().substring(3), getter.getReturnType());
|
||||
IPropertyValidator validator = getPropertyValidator(annotation.validatorClass());
|
||||
|
||||
String setterName = null;
|
||||
try {
|
||||
Method setter = clazz.getMethod("set" + getter.getName().substring(3), getter.getReturnType());
|
||||
setterName = setter.getName();
|
||||
} catch (NoSuchMethodException e) {
|
||||
LOG.debug("No matching setter found for \"" + getter.getName() + "\". Skipping...");
|
||||
}
|
||||
PropertyWrapper property =
|
||||
new PropertyWrapper(name, getter.getReturnType(), getter.getName(), setter.getName(),
|
||||
new PropertyWrapper(name, getter.getReturnType(), getter.getName(), setterName,
|
||||
annotation.defaultable(), validator, annotation.sortOrder());
|
||||
properties.add(property);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
LOG.debug("No matching setter found for \"" + getter.getName() + "\". Skipping...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2726,6 +2726,10 @@
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added ability to collapse and expand the component tree panel to the left edge of the screen</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added read-only "Length" property to curved components (i.e. "Hookup Wire") that calculates total length of the curve</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added "Renumber On Paste" option in the "Config" menu</description>
|
||||
|
||||
Binary file not shown.
@@ -134,6 +134,9 @@
|
||||
<arg value="/Fdiylc-${diylc.version}-win"/>
|
||||
<arg value="install.iss"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="universal" depends="jar">
|
||||
<zip destfile="${build.dir}/diylc-${diylc.version}.zip">
|
||||
<zipfileset dir="${jar.dir}" includes="diylc.jar" />
|
||||
<zipfileset dir="${jar.dir}/lib" prefix="lib" />
|
||||
@@ -144,11 +147,12 @@
|
||||
<zipfileset dir="." includes="splash.png" />
|
||||
<zipfileset dir="." includes="run.sh" />
|
||||
<zipfileset dir="." includes="diylc.l4j.ini" />
|
||||
<zipfileset dir="." includes="diylc.exe" />
|
||||
<zipfileset dir="." includes="diylc.exe" />
|
||||
<zipfileset dir="icons" includes="*.png" prefix="icons" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<target name="full" depends="win,mac"/>
|
||||
<target name="full" depends="win,mac,universal"/>
|
||||
|
||||
<target name="javadoc">
|
||||
<javadoc access="public" author="true" classpathref="class.path" destdir="doc" nodeprecated="false" nodeprecatedlist="false" noindex="false" nonavbar="false" notree="false" source="1.6" splitindex="true" use="true" version="true">
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB |
Binary file not shown.
Binary file not shown.
@@ -38,7 +38,9 @@ public class BooleanEditor extends JCheckBox {
|
||||
|
||||
public BooleanEditor(final PropertyWrapper property) {
|
||||
super();
|
||||
setSelected((Boolean) property.getValue());
|
||||
setSelected((Boolean) property.getValue());
|
||||
if (property.isReadOnly())
|
||||
setEnabled(false);
|
||||
addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -63,7 +63,12 @@ public class ByteEditor extends JPanel {
|
||||
}
|
||||
|
||||
final JSlider slider = new JSlider();
|
||||
final DoubleTextField valueField = new DoubleTextField();
|
||||
final DoubleTextField valueField = new DoubleTextField();
|
||||
|
||||
if (property.isReadOnly()) {
|
||||
slider.setEnabled(false);
|
||||
valueField.setEnabled(false);
|
||||
}
|
||||
|
||||
final double percentFactor = (double) default100Percent / _100PercentValue;
|
||||
|
||||
|
||||
@@ -72,7 +72,12 @@ public class ColorEditor extends JPanel {
|
||||
|
||||
gbc.gridx++;
|
||||
gbc.insets = new Insets(0, 0, 0, 0);
|
||||
add(getColorField(), gbc);
|
||||
add(getColorField(), gbc);
|
||||
|
||||
if (property.isReadOnly()) {
|
||||
getColorField().setEnabled(false);
|
||||
getColorLabel().setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public JLabel getColorLabel() {
|
||||
|
||||
@@ -41,7 +41,9 @@ public class EnumEditor extends JComboBox {
|
||||
|
||||
public EnumEditor(final PropertyWrapper property) {
|
||||
this.property = property;
|
||||
Object[] values = property.getType().getEnumConstants();
|
||||
Object[] values = property.getType().getEnumConstants();
|
||||
if (property.isReadOnly())
|
||||
setEnabled(false);
|
||||
setModel(new DefaultComboBoxModel(values));
|
||||
setSelectedItem(property.getValue());
|
||||
addItemListener(new ItemListener() {
|
||||
|
||||
@@ -42,7 +42,9 @@ public class FontEditor extends FontChooserComboBox {
|
||||
private final PropertyWrapper property;
|
||||
|
||||
public FontEditor(final PropertyWrapper property) {
|
||||
this.property = property;
|
||||
this.property = property;
|
||||
if (property.isReadOnly())
|
||||
setEnabled(false);
|
||||
((JTextField) getEditor().getEditorComponent()).setBorder(BorderFactory.createCompoundBorder(
|
||||
((JTextField) getEditor().getEditorComponent()).getBorder(), BorderFactory.createEmptyBorder(0, 2, 0, 0)));
|
||||
setSelectedItem(((Font) property.getValue()).getName());
|
||||
|
||||
@@ -41,7 +41,9 @@ public class ImageEditor extends JButton {
|
||||
private static final String title = "Click to load image file";
|
||||
|
||||
public ImageEditor(final PropertyWrapper property) {
|
||||
super(property.isUnique() ? title : ("(multi value) " + title));
|
||||
super(property.isUnique() ? title : ("(multi value) " + title));
|
||||
if (property.isReadOnly())
|
||||
setEnabled(false);
|
||||
addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,7 +37,9 @@ public class IntEditor extends DoubleTextField {
|
||||
private Color oldBg = getBackground();
|
||||
|
||||
public IntEditor(final PropertyWrapper property) {
|
||||
setLayout(new BorderLayout());
|
||||
setLayout(new BorderLayout());
|
||||
if (property.isReadOnly())
|
||||
setEnabled(false);
|
||||
setValue((double) (Integer) property.getValue());
|
||||
addPropertyChangeListener(DoubleTextField.VALUE_PROPERTY, new PropertyChangeListener() {
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@ public class MeasureArrayEditor extends Container {
|
||||
values[i] = measure[i] == null ? null : measure[i].getValue();
|
||||
}
|
||||
valueField = new DoubleArrayTextField(measure == null ? null : values);
|
||||
if (property.isReadOnly())
|
||||
valueField.setEnabled(false);
|
||||
oldBg = valueField.getBackground();
|
||||
valueField.addPropertyChangeListener(
|
||||
DoubleArrayTextField.VALUE_PROPERTY,
|
||||
|
||||
@@ -56,7 +56,7 @@ public class MeasureEditor extends Container {
|
||||
@SuppressWarnings("unchecked")
|
||||
public MeasureEditor(final PropertyWrapper property) {
|
||||
setLayout(new BorderLayout());
|
||||
final AbstractMeasure<?> measure = ((AbstractMeasure<?>) property.getValue());
|
||||
final AbstractMeasure<?> measure = ((AbstractMeasure<?>) property.getValue());
|
||||
valueField = new DoubleTextField(measure == null ? null : measure.getValue());
|
||||
oldBg = valueField.getBackground();
|
||||
valueField.addPropertyChangeListener(DoubleTextField.VALUE_PROPERTY, new PropertyChangeListener() {
|
||||
@@ -87,9 +87,16 @@ public class MeasureEditor extends Container {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
try {
|
||||
Constructor<?> ctor = property.getType().getConstructors()[0];
|
||||
Constructor<?> ctor = property.getType().getConstructors()[0];
|
||||
Double newValue = valueField.getValue();
|
||||
if (newValue != null && property.isReadOnly() && measure.isConvertible()) {
|
||||
double oldFactor = ((Unit)((AbstractMeasure<?>)property.getValue()).getUnit()).getFactor();
|
||||
double newFactor = ((Unit)unitBox.getSelectedItem()).getFactor();
|
||||
newValue = newValue * oldFactor / newFactor;
|
||||
valueField.setValue(newValue);
|
||||
}
|
||||
AbstractMeasure<?> newMeasure =
|
||||
(AbstractMeasure<?>) ctor.newInstance(valueField.getValue(),
|
||||
(AbstractMeasure<?>) ctor.newInstance(newValue,
|
||||
(Enum<? extends Unit>) unitBox.getSelectedItem());
|
||||
property.setValue(newMeasure);
|
||||
property.setChanged(true);
|
||||
@@ -100,7 +107,12 @@ public class MeasureEditor extends Container {
|
||||
}
|
||||
}
|
||||
});
|
||||
add(unitBox, BorderLayout.EAST);
|
||||
add(unitBox, BorderLayout.EAST);
|
||||
|
||||
if (property.isReadOnly()) {
|
||||
valueField.setEnabled(false);
|
||||
unitBox.setEnabled(measure.isConvertible());
|
||||
}
|
||||
|
||||
if (!property.isUnique()) {
|
||||
valueField.setBackground(Constants.MULTI_VALUE_COLOR);
|
||||
|
||||
@@ -50,7 +50,9 @@ public class MultiLineStringEditor extends JScrollPane {
|
||||
public MultiLineStringEditor(PropertyWrapper property) {
|
||||
super();
|
||||
this.property = property;
|
||||
setViewportView(getTextArea());
|
||||
setViewportView(getTextArea());
|
||||
if (property.isReadOnly())
|
||||
getTextArea().setEnabled(false);
|
||||
setPreferredSize(new Dimension(192, 64));
|
||||
setBorder(border);
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public class PropertyEditorDialog extends ButtonDialog {
|
||||
gbc.fill = GridBagConstraints.NONE;
|
||||
gbc.weightx = 0;
|
||||
|
||||
if (saveDefaults) {
|
||||
if (saveDefaults && !property.isReadOnly()) {
|
||||
editorPanel.add(createDefaultCheckBox(property), gbc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@ public class StringEditor extends JTextField {
|
||||
|
||||
public StringEditor(PropertyWrapper property) {
|
||||
super(property.getValue() == null ? "" : (String) property.getValue());
|
||||
this.property = property;
|
||||
this.property = property;
|
||||
if (property.isReadOnly())
|
||||
setEnabled(false);
|
||||
this.setColumns(32);
|
||||
getDocument().addDocumentListener(new DocumentListener() {
|
||||
|
||||
|
||||
@@ -42,7 +42,9 @@ public class StringListEditor extends JComboBox {
|
||||
private final PropertyWrapper property;
|
||||
|
||||
public StringListEditor(final PropertyWrapper property) throws Exception {
|
||||
this.property = property;
|
||||
this.property = property;
|
||||
if (property.isReadOnly())
|
||||
setEnabled(false);
|
||||
String listFunctionName = property.getGetter().getAnnotation(DynamicList.class).availableValueFunction();
|
||||
Method function = property.getOwnerObject().getClass().getMethod(listFunctionName);
|
||||
Object[] values = (Object[]) function.invoke(property.getOwnerObject());
|
||||
|
||||
Reference in New Issue
Block a user