better d&d of control points

doc
This commit is contained in:
bancika
2011-01-06 00:23:59 +00:00
parent b33d1c3e37
commit e612b39b26
10 changed files with 124 additions and 70 deletions
@@ -1,31 +1,6 @@
<map> <map>
<entry>
<string>defaults</string>
<map>
<entry>
<string>com.diyfever.diylc.components.MockComponentInstance:C</string>
<com.diyfever.diylc.model.measures.Capacitance>
<value>22.0</value>
<unit class="com.diyfever.diylc.model.measures.CapacitanceUnit">uF</unit>
</com.diyfever.diylc.model.measures.Capacitance>
</entry>
<entry>
<string>com.diyfever.diylc.components.MockComponentInstance:Color</string>
<awt-color>
<red>255</red>
<green>0</green>
<blue>0</blue>
<alpha>255</alpha>
</awt-color>
</entry>
</map>
</entry>
<entry> <entry>
<string>metric</string> <string>metric</string>
<boolean>true</boolean> <boolean>true</boolean>
</entry> </entry>
<entry>
<string>lastPath</string>
<string>C:\Documents and Settings\Branislav Stojkovic\Desktop</string>
</entry>
</map> </map>
@@ -127,7 +127,7 @@ public abstract class AbstractLeadedDIYComponent<T> implements IDIYComponent<T>
(int) (shapeRect.height - textRect.getHeight()) / 2 + fontMetrics.getAscent()); (int) (shapeRect.height - textRect.getHeight()) / 2 + fontMetrics.getAscent());
} }
@EditableProperty @EditableProperty(defaultable = false)
public String getName() { public String getName() {
return name; return name;
} }
@@ -162,6 +162,7 @@ public abstract class AbstractLeadedDIYComponent<T> implements IDIYComponent<T>
return result; return result;
} }
@SuppressWarnings("unchecked")
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
@@ -38,7 +38,7 @@ public class DIL_IC implements IDIYComponent<String> {
new Point((int) (3 * Constants.GRID), (int) (2 * Constants.GRID)), new Point((int) (3 * Constants.GRID), (int) (2 * Constants.GRID)),
new Point((int) (3 * Constants.GRID), (int) (3 * Constants.GRID)) }; new Point((int) (3 * Constants.GRID), (int) (3 * Constants.GRID)) };
@EditableProperty @EditableProperty(defaultable = false)
public String getName() { public String getName() {
return name; return name;
} }
@@ -17,7 +17,7 @@ import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit; import org.diylc.core.measures.SizeUnit;
@ComponentDescriptor(name = "Mock", author = "bancika", category = "Sample", instanceNamePrefix = "M", desciption = "test") @ComponentDescriptor(name = "Mock", author = "bancika", category = "Sample", instanceNamePrefix = "M", desciption = "test")
public class MockDIYComponent implements IDIYComponent<Object> { public class MockDIYComponent implements IDIYComponent<Capacitance> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -82,7 +82,7 @@ public class MockDIYComponent implements IDIYComponent<Object> {
return c; return c;
} }
public void setC(Capacitance c) { public void setValue(Capacitance c) {
this.c = c; this.c = c;
} }
@@ -23,11 +23,12 @@ public class ComponentType {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Class<? extends IDIYComponent> instanceClass; private Class<? extends IDIYComponent> instanceClass;
private ComponentLayer layer; private ComponentLayer layer;
private boolean stretchable;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public ComponentType(String name, String description, String category, String namePrefix, public ComponentType(String name, String description, String category, String namePrefix,
String author, Icon icon, Class<? extends IDIYComponent> instanceClass, String author, Icon icon, Class<? extends IDIYComponent> instanceClass,
ComponentLayer layer) { ComponentLayer layer, boolean stretchable) {
super(); super();
this.name = name; this.name = name;
this.description = description; this.description = description;
@@ -37,6 +38,7 @@ public class ComponentType {
this.icon = icon; this.icon = icon;
this.instanceClass = instanceClass; this.instanceClass = instanceClass;
this.layer = layer; this.layer = layer;
this.stretchable = stretchable;
} }
public String getName() { public String getName() {
@@ -72,6 +74,10 @@ public class ComponentType {
return layer; return layer;
} }
public boolean isStretchable() {
return stretchable;
}
@Override @Override
public String toString() { public String toString() {
return name; return name;
@@ -30,16 +30,49 @@ import org.diylc.core.annotations.EditableProperty;
*/ */
public interface IDIYComponent<T> extends Serializable { public interface IDIYComponent<T> extends Serializable {
/**
* @return component instance name.
*/
String getName(); String getName();
/**
* Updates component instance name.
*
* @param name
*/
void setName(String name); void setName(String name);
/**
* @return component value.
*/
T getValue(); T getValue();
/**
* Updates component value.
*
* @param value
*/
void setValue(T value);
/**
* @return number of control points for this component instance. May vary
* between two instances of the same type, e.g. DIL IC with 8 and 16
* pins will have 8 or 16 pins although they are of the same type.
*/
int getControlPointCount(); int getControlPointCount();
/**
* @param index
* @return control point at the specified index.
*/
Point getControlPoint(int index); Point getControlPoint(int index);
/**
* Updates the control point at the specified index.
*
* @param point
* @param index
*/
void setControlPoint(Point point, int index); void setControlPoint(Point point, int index);
/** /**
@@ -52,7 +85,8 @@ public interface IDIYComponent<T> extends Serializable {
void draw(Graphics2D g2d, ComponentState componentState, Project project); void draw(Graphics2D g2d, ComponentState componentState, Project project);
/** /**
* Draws icon representation of the component. * Draws icon representation of the component. This should not depend on
* component state, i.e. it should be treated as a static method.
* *
* @param g2d * @param g2d
* @param width * @param width
@@ -16,16 +16,18 @@ public @interface EditableProperty {
/** /**
* Returns property name. If left blank property name will be extracted from * Returns property name. If left blank property name will be extracted from
* the getter name, e.g. getter <code>getXYZ</code> will induce property * the getter name, e.g. getter <code>getXYZ</code> will induce property
* name <code>XYZ</code>. * name <code>XYZ</code>. <br>
* Default value is blank.
* *
* @return * @return
*/ */
String name() default ""; String name() default "";
/** /**
* If true, application may set default value for this property. * If true, application may set default value for this property. <br>
* Default value is true.
* *
* @return * @return
*/ */
boolean defaultable() default false; boolean defaultable() default true;
} }
@@ -19,6 +19,7 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -66,17 +67,19 @@ public class Presenter implements IPlugInPort {
public static final int CONTROL_POINT_SENSITIVITY = 4; public static final int CONTROL_POINT_SENSITIVITY = 4;
public static final int ICON_SIZE = 32; public static final int ICON_SIZE = 32;
public static boolean ENABLE_ANTIALIASING = true; public static boolean ENABLE_ANTIALIASING = true;
public static boolean DEBUG_COMPONENT_AREAS = false;
private double zoomLevel = 1; private double zoomLevel = 1;
private Map<IDIYComponent<?>, Area> componentAreaMap; private Map<IDIYComponent<?>, Area> componentAreaMap;
private Project currentProject; private Project currentProject;
private Map<String, List<ComponentType>> componentTypes; private Map<String, List<ComponentType>> componentTypes;
private Map<Class<? extends IDIYComponent>, ComponentType> componentTypeMap;
private List<IPlugIn> plugIns; private List<IPlugIn> plugIns;
private ComponentSelection selectedComponents; private ComponentSelection selectedComponents;
// List of components that have at least one of their control points // Maps components that have at least one dragged point to set of indices
// under the last recorded mouse position. // that designate which of their control points are being dragged.
private Map<IDIYComponent<?>, Integer> componentControlPointMap; private Map<IDIYComponent<?>, Set<Integer>> controlPointMap;
private Cloner cloner; private Cloner cloner;
@@ -98,6 +101,8 @@ public class Presenter implements IPlugInPort {
private ComponentType componentSlot; private ComponentType componentSlot;
private boolean snapToGrid = true;
public Presenter(IView view) { public Presenter(IView view) {
super(); super();
this.view = view; this.view = view;
@@ -151,7 +156,7 @@ public class Presenter implements IPlugInPort {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
} }
} }
if (componentControlPointMap != null && !componentControlPointMap.isEmpty()) { if (controlPointMap != null && !controlPointMap.isEmpty()) {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
} }
} }
@@ -189,6 +194,7 @@ public class Presenter implements IPlugInPort {
if (componentTypes == null) { if (componentTypes == null) {
LOG.info("Loading component types."); LOG.info("Loading component types.");
componentTypes = new HashMap<String, List<ComponentType>>(); componentTypes = new HashMap<String, List<ComponentType>>();
componentTypeMap = new HashMap<Class<? extends IDIYComponent>, ComponentType>();
List<Class<?>> componentTypeClasses = JarScanner.getInstance().scanFolder("library/", List<Class<?>> componentTypeClasses = JarScanner.getInstance().scanFolder("library/",
IDIYComponent.class); IDIYComponent.class);
for (Class<?> clazz : componentTypeClasses) { for (Class<?> clazz : componentTypeClasses) {
@@ -202,6 +208,7 @@ public class Presenter implements IPlugInPort {
Icon icon; Icon icon;
Class<? extends IDIYComponent> instanceClass = (Class<? extends IDIYComponent>) clazz; Class<? extends IDIYComponent> instanceClass = (Class<? extends IDIYComponent>) clazz;
ComponentLayer layer; ComponentLayer layer;
boolean stretchable;
if (annotation == null) { if (annotation == null) {
name = clazz.getSimpleName(); name = clazz.getSimpleName();
description = ""; description = "";
@@ -209,6 +216,7 @@ public class Presenter implements IPlugInPort {
namePrefix = "Unknown"; namePrefix = "Unknown";
author = "Unknown"; author = "Unknown";
layer = ComponentLayer.COMPONENT; layer = ComponentLayer.COMPONENT;
stretchable = true;
} else { } else {
name = annotation.name(); name = annotation.name();
description = annotation.desciption(); description = annotation.desciption();
@@ -216,6 +224,7 @@ public class Presenter implements IPlugInPort {
namePrefix = annotation.instanceNamePrefix(); namePrefix = annotation.instanceNamePrefix();
author = annotation.author(); author = annotation.author();
layer = annotation.componentLayer(); layer = annotation.componentLayer();
stretchable = annotation.stretchable();
} }
icon = null; icon = null;
// Draw component icon. // Draw component icon.
@@ -232,7 +241,8 @@ public class Presenter implements IPlugInPort {
e.printStackTrace(); e.printStackTrace();
} }
ComponentType componentType = new ComponentType(name, description, category, ComponentType componentType = new ComponentType(name, description, category,
namePrefix, author, icon, instanceClass, layer); namePrefix, author, icon, instanceClass, layer, stretchable);
componentTypeMap.put(instanceClass, componentType);
List<ComponentType> nestedList; List<ComponentType> nestedList;
if (componentTypes.containsKey(componentType.getCategory())) { if (componentTypes.containsKey(componentType.getCategory())) {
nestedList = componentTypes.get(componentType.getCategory()); nestedList = componentTypes.get(componentType.getCategory());
@@ -353,11 +363,13 @@ public class Presenter implements IPlugInPort {
} }
// // Draw component area for test // // Draw component area for test
// g2d.setStroke(new BasicStroke()); if (DEBUG_COMPONENT_AREAS) {
// g2d.setColor(Color.red); g2d.setStroke(new BasicStroke());
// for (Area area : componentAreaMap.values()) { g2d.setColor(Color.red);
// g2d.draw(area); for (Area area : componentAreaMap.values()) {
// } g2d.draw(area);
}
}
} }
@Override @Override
@@ -433,7 +445,7 @@ public class Presenter implements IPlugInPort {
@Override @Override
public void mouseMoved(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown) { public void mouseMoved(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown) {
Map<IDIYComponent<?>, Integer> components = new HashMap<IDIYComponent<?>, Integer>(); Map<IDIYComponent<?>, Set<Integer>> components = new HashMap<IDIYComponent<?>, Set<Integer>>();
Point scaledPoint = scalePoint(point); Point scaledPoint = scalePoint(point);
for (IDIYComponent<?> component : currentProject.getComponents()) { for (IDIYComponent<?> component : currentProject.getComponents()) {
for (int i = 0; i < component.getControlPointCount(); i++) { for (int i = 0; i < component.getControlPointCount(); i++) {
@@ -441,7 +453,17 @@ public class Presenter implements IPlugInPort {
if (shouldShowControlPointsFor(component)) { if (shouldShowControlPointsFor(component)) {
try { try {
if (scaledPoint.distance(controlPoint) < CONTROL_POINT_SENSITIVITY) { if (scaledPoint.distance(controlPoint) < CONTROL_POINT_SENSITIVITY) {
components.put(component, i); Set<Integer> indices = new HashSet<Integer>();
ComponentType componentType = componentTypeMap
.get(component.getClass());
if (componentType.isStretchable()) {
indices.add(i);
} else {
for (int j = 0; j < component.getControlPointCount(); j++) {
indices.add(j);
}
}
components.put(component, indices);
break; break;
} }
} catch (Exception e) { } catch (Exception e) {
@@ -455,8 +477,8 @@ public class Presenter implements IPlugInPort {
break; break;
} }
} }
if (!components.equals(componentControlPointMap)) { if (!components.equals(controlPointMap)) {
componentControlPointMap = components; controlPointMap = components;
messageDispatcher.dispatchMessage(EventType.AVAILABLE_CTRL_POINTS_CHANGED, components); messageDispatcher.dispatchMessage(EventType.AVAILABLE_CTRL_POINTS_CHANGED, components);
} }
} }
@@ -484,10 +506,10 @@ public class Presenter implements IPlugInPort {
Point scaledPoint = scalePoint(point); Point scaledPoint = scalePoint(point);
previousDragPoint = scaledPoint; previousDragPoint = scaledPoint;
List<IDIYComponent<?>> components = findComponentsAt(scaledPoint); List<IDIYComponent<?>> components = findComponentsAt(scaledPoint);
if (!componentControlPointMap.isEmpty()) { if (!controlPointMap.isEmpty()) {
// If we're dragging control points reset selection. // If we're dragging control points reset selection.
selectedComponents.clear(); selectedComponents.clear();
selectedComponents.addAll(componentControlPointMap.keySet()); selectedComponents.addAll(controlPointMap.keySet());
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents); messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents);
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
} else if (components.isEmpty()) { } else if (components.isEmpty()) {
@@ -514,24 +536,39 @@ public class Presenter implements IPlugInPort {
return false; return false;
} }
Point scaledPoint = scalePoint(point); Point scaledPoint = scalePoint(point);
if (!componentControlPointMap.isEmpty()) { if (!controlPointMap.isEmpty()) {
// We're dragging control point(s). // We're dragging control point(s).
IDIYComponent<?> firstComponent = componentControlPointMap.keySet().iterator().next(); // IDIYComponent<?> firstComponent =
Point controlPoint = firstComponent.getControlPoint(componentControlPointMap // controlPointMap.keySet().iterator().next();
.get(firstComponent)); // Point controlPoint = firstComponent
if (controlPoint == null) { // .getControlPoint(controlPointMap.get(firstComponent));
LOG.warn("Control point not found in the map!"); // if (controlPoint == null) {
// LOG.warn("Control point not found in the map!");
// }
// int x = (int) (Math.round((controlPoint.x + scaledPoint.x -
// previousDragPoint.x)
// / Constants.GRID) * Constants.GRID);
// int y = (int) (Math.round((controlPoint.y + scaledPoint.y -
// previousDragPoint.y)
// / Constants.GRID) * Constants.GRID);
// previousDragPoint.setLocation(x, y);
int dx = (point.x - previousDragPoint.x);
int dy = (point.y - previousDragPoint.y);
if (snapToGrid) {
dx = (int) (Math.round(dx / Constants.GRID) * Constants.GRID);
dy = (int) (Math.round(dy / Constants.GRID) * Constants.GRID);
} }
int x = (int) (Math.round((controlPoint.x + scaledPoint.x - previousDragPoint.x)
/ Constants.GRID) * Constants.GRID); previousDragPoint.translate(dx, dy);
int y = (int) (Math.round((controlPoint.y + scaledPoint.y - previousDragPoint.y)
/ Constants.GRID) * Constants.GRID);
previousDragPoint.setLocation(x, y);
// Update all points. // Update all points.
for (Map.Entry<IDIYComponent<?>, Integer> entry : componentControlPointMap.entrySet()) { for (Map.Entry<IDIYComponent<?>, Set<Integer>> entry : controlPointMap.entrySet()) {
Point p = new Point(x, y); IDIYComponent<?> c = entry.getKey();
entry.getKey().setControlPoint(p, entry.getValue()); for (Integer index : entry.getValue()) {
Point p = c.getControlPoint(index);
p.translate(dx, dy);
c.setControlPoint(p, index);
}
} }
// dragStartPoint = point; // dragStartPoint = point;
} else if (selectedComponents.isEmpty()) { } else if (selectedComponents.isEmpty()) {
@@ -8,7 +8,7 @@ import java.awt.Toolkit;
public class Constants { public class Constants {
public static final float GRID = Toolkit.getDefaultToolkit().getScreenResolution() / 10f; public static final float GRID = (int) (Toolkit.getDefaultToolkit().getScreenResolution() / 10f);
public static Color CANVAS_COLOR = Color.white; public static Color CANVAS_COLOR = Color.white;
public static Color GRID_COLOR = new Color(240, 240, 240); public static Color GRID_COLOR = new Color(240, 240, 240);
@@ -13,14 +13,13 @@ import org.diylc.plugins.file.BomEntry;
import org.diylc.plugins.file.BomMaker; import org.diylc.plugins.file.BomMaker;
import org.junit.Test; import org.junit.Test;
public class BomMakerTest { public class BomMakerTest {
@Test @Test
public void testCreateBom() { public void testCreateBom() {
List<IDIYComponent<?>> components = new ArrayList<IDIYComponent<?>>(); List<IDIYComponent<?>> components = new ArrayList<IDIYComponent<?>>();
MockDIYComponent c1 = new MockDIYComponent(); MockDIYComponent c1 = new MockDIYComponent();
c1.setC(new Capacitance(3d, CapacitanceUnit.pF)); c1.setValue(new Capacitance(3d, CapacitanceUnit.pF));
components.add(c1); components.add(c1);
components.add(new MockDIYComponent()); components.add(new MockDIYComponent());
components.add(new MockDIYComponent()); components.add(new MockDIYComponent());