Ability to rotate selection

This commit is contained in:
bancika
2013-04-25 14:37:19 +00:00
parent 5cb9824da4
commit 171ebf4473
7 changed files with 181 additions and 41 deletions
@@ -28,11 +28,12 @@ public class ComponentType {
private boolean stretchable; private boolean stretchable;
private BomPolicy bomPolicy; private BomPolicy bomPolicy;
private boolean autoEdit; private boolean autoEdit;
private boolean rotatable;
public ComponentType(String name, String description, CreationMethod creationMethod, public ComponentType(String name, String description, CreationMethod creationMethod,
String category, String namePrefix, String author, Icon icon, String category, String namePrefix, String author, Icon icon,
Class<? extends IDIYComponent<?>> instanceClass, double zOrder, boolean flexibleZOrder, Class<? extends IDIYComponent<?>> instanceClass, double zOrder, boolean flexibleZOrder,
boolean stretchable, BomPolicy bomPolicy, boolean autoEdit) { boolean stretchable, BomPolicy bomPolicy, boolean autoEdit, boolean rotatable) {
super(); super();
this.name = name; this.name = name;
this.description = description; this.description = description;
@@ -47,6 +48,7 @@ public class ComponentType {
this.stretchable = stretchable; this.stretchable = stretchable;
this.bomPolicy = bomPolicy; this.bomPolicy = bomPolicy;
this.autoEdit = autoEdit; this.autoEdit = autoEdit;
this.rotatable = rotatable;
} }
public String getName() { public String getName() {
@@ -100,6 +102,10 @@ public class ComponentType {
public boolean isAutoEdit() { public boolean isAutoEdit() {
return autoEdit; return autoEdit;
} }
public boolean isRotatable() {
return rotatable;
}
@Override @Override
public String toString() { public String toString() {
@@ -34,8 +34,8 @@ public interface ISelectionProcessor {
List<IDIYComponent<?>> findComponentsAt(Point point); List<IDIYComponent<?>> findComponentsAt(Point point);
/** /**
* Expands the current selection to include surrounding components. * Expands the current selection to include surrounding components. Options
* Options are controlled with <code>expansionMode</code> flag. * are controlled with <code>expansionMode</code> flag.
* *
* @param expansionMode * @param expansionMode
*/ */
@@ -44,5 +44,13 @@ public interface ISelectionProcessor {
/** /**
* Selects all components in the project. * Selects all components in the project.
*/ */
void selectAll(); void selectAll();
/**
* Rotates selection for 90 degrees.
*
* @param direction
* 1 for clockwise, -1 for counter-clockwise
*/
void rotateSelection(int direction);
} }
@@ -76,5 +76,11 @@ public @interface ComponentDescriptor {
* mode. * mode.
*/ */
boolean autoEdit() default true; boolean autoEdit() default true;
/**
* @return true if component may be rotated, false otherwise
* @return
*/
boolean rotatable() default true;
} }
@@ -69,6 +69,7 @@ public class ComponentProcessor {
boolean stretchable; boolean stretchable;
BomPolicy bomPolicy; BomPolicy bomPolicy;
boolean autoEdit; boolean autoEdit;
boolean rotatable;
if (clazz.isAnnotationPresent(ComponentDescriptor.class)) { if (clazz.isAnnotationPresent(ComponentDescriptor.class)) {
ComponentDescriptor annotation = clazz.getAnnotation(ComponentDescriptor.class); ComponentDescriptor annotation = clazz.getAnnotation(ComponentDescriptor.class);
name = annotation.name(); name = annotation.name();
@@ -82,6 +83,7 @@ public class ComponentProcessor {
stretchable = annotation.stretchable(); stretchable = annotation.stretchable();
bomPolicy = annotation.bomPolicy(); bomPolicy = annotation.bomPolicy();
autoEdit = annotation.autoEdit(); autoEdit = annotation.autoEdit();
rotatable = annotation.rotatable();
} else { } else {
name = clazz.getSimpleName(); name = clazz.getSimpleName();
description = ""; description = "";
@@ -94,6 +96,7 @@ public class ComponentProcessor {
stretchable = true; stretchable = true;
bomPolicy = BomPolicy.SHOW_ALL_NAMES; bomPolicy = BomPolicy.SHOW_ALL_NAMES;
autoEdit = true; autoEdit = true;
rotatable = true;
} }
icon = null; icon = null;
// Draw component icon. // Draw component icon.
@@ -115,7 +118,7 @@ public class ComponentProcessor {
} }
ComponentType componentType = new ComponentType(name, description, creationMethod, ComponentType componentType = new ComponentType(name, description, creationMethod,
category, namePrefix, author, icon, clazz, zOrder, flexibleZOrder, stretchable, category, namePrefix, author, icon, clazz, zOrder, flexibleZOrder, stretchable,
bomPolicy, autoEdit); bomPolicy, autoEdit, rotatable);
componentTypeMap.put(clazz.getName(), componentType); componentTypeMap.put(clazz.getName(), componentType);
return componentType; return componentType;
} }
@@ -42,7 +42,7 @@ public class InstantiationManager {
private static final ComponentType clipboardType = new ComponentType( private static final ComponentType clipboardType = new ComponentType(
"Clipboard contents", "Components from the clipboard", "Clipboard contents", "Components from the clipboard",
CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false,
false, null, false); false, null, false, true);
public InstantiationManager() { public InstantiationManager() {
} }
@@ -6,6 +6,7 @@ import java.awt.Graphics2D;
import java.awt.Point; import java.awt.Point;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.dnd.DnDConstants; import java.awt.dnd.DnDConstants;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area; import java.awt.geom.Area;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
@@ -40,6 +41,8 @@ import org.diylc.common.IComponentFiler;
import org.diylc.common.IKeyProcessor; import org.diylc.common.IKeyProcessor;
import org.diylc.common.IPlugIn; import org.diylc.common.IPlugIn;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.Orientation;
import org.diylc.common.OrientationHV;
import org.diylc.common.PropertyWrapper; import org.diylc.common.PropertyWrapper;
import org.diylc.components.connectivity.SolderPad; import org.diylc.components.connectivity.SolderPad;
import org.diylc.core.ExpansionMode; import org.diylc.core.ExpansionMode;
@@ -625,6 +628,28 @@ public class Presenter implements IPlugInPort {
return false; return false;
} }
boolean snapToGrid = ConfigurationManager.getInstance().readBoolean(
IPlugInPort.SNAP_TO_GRID_KEY, true);
if (shiftDown) {
snapToGrid = !snapToGrid;
}
if (altDown) {
Project oldProject = null;
if (key == IKeyProcessor.VK_RIGHT) {
oldProject = currentProject.clone();
rotateComponents(this.selectedComponents, 1, snapToGrid);
} else if (key == IKeyProcessor.VK_LEFT) {
oldProject = currentProject.clone();
rotateComponents(this.selectedComponents, -1, snapToGrid);
} else
return false;
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, currentProject.clone(), "Rotate Selection");
messageDispatcher.dispatchMessage(EventType.REPAINT);
return true;
}
// Expand control points to include all stuck components. // Expand control points to include all stuck components.
boolean sticky = ConfigurationManager.getInstance().readBoolean( boolean sticky = ConfigurationManager.getInstance().readBoolean(
IPlugInPort.STICKY_POINTS_KEY, true); IPlugInPort.STICKY_POINTS_KEY, true);
@@ -636,12 +661,6 @@ public class Presenter implements IPlugInPort {
includeStuckComponents(controlPointMap); includeStuckComponents(controlPointMap);
} }
boolean snapToGrid = ConfigurationManager.getInstance().readBoolean(
IPlugInPort.SNAP_TO_GRID_KEY, true);
if (shiftDown) {
snapToGrid = !snapToGrid;
}
int d; int d;
if (snapToGrid) { if (snapToGrid) {
d = (int) currentProject.getGridSpacing().convertToPixels(); d = (int) currentProject.getGridSpacing().convertToPixels();
@@ -1025,35 +1044,6 @@ public class Presenter implements IPlugInPort {
int height = (int) currentProject.getHeight().convertToPixels(); int height = (int) currentProject.getHeight().convertToPixels();
if (controlPointMap.size() == 1) { if (controlPointMap.size() == 1) {
// Determine how much we should move the components by trying to
// move the center point of the affected rectangle to preserve
// spacing.
// int minX = Integer.MAX_VALUE;
// int minY = Integer.MAX_VALUE;
// int maxX = Integer.MIN_VALUE;
// int maxY = Integer.MIN_VALUE;
// for (Map.Entry<IDIYComponent<?>, Set<Integer>> entry :
// controlPointMap
// .entrySet()) {
// for (int i : entry.getValue()) {
// Point p = entry.getKey().getControlPoint(i);
// if (minX > p.x) {
// minX = p.x;
// }
// if (maxX < p.x) {
// maxX = p.x;
// }
// if (minY > p.y) {
// minY = p.y;
// }
// if (maxY < p.y) {
// maxY = p.y;
// }
// }
// }
// int centerX = (maxX + minX) / 2;
// int centerY = (maxY + minY) / 2;
Map.Entry<IDIYComponent<?>, Set<Integer>> entry = controlPointMap Map.Entry<IDIYComponent<?>, Set<Integer>> entry = controlPointMap
.entrySet().iterator().next(); .entrySet().iterator().next();
@@ -1133,6 +1123,133 @@ public class Presenter implements IPlugInPort {
return new Point(actualDx, actualDy); return new Point(actualDx, actualDy);
} }
@Override
public void rotateSelection(int direction) {
if (!selectedComponents.isEmpty()) {
Project oldProject = currentProject.clone();
rotateComponents(this.selectedComponents, direction, isSnapToGrid());
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, currentProject.clone(), "Rotate Selection");
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
}
/**
*
* @param direction
* 1 for clockwise, -1 for counter-clockwise
*/
private void rotateComponents(List<IDIYComponent<?>> components,
int direction, boolean snapToGrid) {
Point center = getCenterOf(components, snapToGrid);
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2
* direction, center.x, center.y);
// Update all points to new location.
for (IDIYComponent<?> component : components) {
drawingManager.invalidateComponent(component);
ComponentType type = ComponentProcessor.getInstance()
.extractComponentTypeFrom(
(Class<? extends IDIYComponent<?>>) component
.getClass());
if (type.isRotatable()) {
for (int index = 0; index < component.getControlPointCount(); index++) {
Point p = new Point(component.getControlPoint(index));
rotate.transform(p, p);
component.setControlPoint(p, index);
}
// If component has orientation, change it too
List<PropertyWrapper> newProperties = ComponentProcessor
.getInstance().extractProperties(component.getClass());
for (PropertyWrapper property : newProperties) {
if (property.getType() == Orientation.class) {
try {
property.readFrom(component);
Orientation orientation = (Orientation) property
.getValue();
Orientation[] values = Orientation.values();
int newIndex = orientation.ordinal() + direction;
if (newIndex < 0)
newIndex = values.length - 1;
else if (newIndex >= values.length)
newIndex = 0;
property.setValue(values[newIndex]);
property.writeTo(component);
} catch (Exception e) {
LOG.error(
"Could not change component orientation for "
+ component.getName(), e);
}
} else if (property.getType() == OrientationHV.class) {
try {
property.readFrom(component);
OrientationHV orientation = (OrientationHV) property
.getValue();
property
.setValue(OrientationHV.values()[1 - orientation
.ordinal()]);
property.writeTo(component);
} catch (Exception e) {
LOG.error(
"Could not change component orientation for "
+ component.getName(), e);
}
}
}
} else {
// Non-rotatable
Point componentCenter = getCenterOf(Arrays
.asList(new IDIYComponent<?>[] { component }), false);
Point rotatedComponentCenter = new Point();
rotate.transform(componentCenter, rotatedComponentCenter);
for (int index = 0; index < component.getControlPointCount(); index++) {
Point p = new Point(component.getControlPoint(index));
p.translate(rotatedComponentCenter.x - componentCenter.x,
rotatedComponentCenter.y - componentCenter.y);
component.setControlPoint(p, index);
}
}
}
}
private Point getCenterOf(List<IDIYComponent<?>> components,
boolean snapToGrid) {
// Determine center of rotation
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
for (IDIYComponent<?> component : components) {
for (int i = 0; i < component.getControlPointCount(); i++) {
Point p = component.getControlPoint(i);
if (minX > p.x) {
minX = p.x;
}
if (maxX < p.x) {
maxX = p.x;
}
if (minY > p.y) {
minY = p.y;
}
if (maxY < p.y) {
maxY = p.y;
}
}
}
int centerX = (maxX + minX) / 2;
int centerY = (maxY + minY) / 2;
if (snapToGrid) {
CalcUtils
.roundToGrid(centerX, this.currentProject.getGridSpacing());
CalcUtils
.roundToGrid(centerY, this.currentProject.getGridSpacing());
}
return new Point(centerX, centerY);
}
@Override @Override
public void dragEnded(Point point) { public void dragEnded(Point point) {
LOG.debug(String.format("dragEnded(%s)", point)); LOG.debug(String.format("dragEnded(%s)", point));