diff --git a/ diy-layout-creator --username bancika@gmail.com/diylc-core/library/main.jar b/ diy-layout-creator --username bancika@gmail.com/diylc-core/library/main.jar index 229c37b4..9c31d586 100644 Binary files a/ diy-layout-creator --username bancika@gmail.com/diylc-core/library/main.jar and b/ diy-layout-creator --username bancika@gmail.com/diylc-core/library/main.jar differ diff --git a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/common/ComponentType.java b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/common/ComponentType.java index effcd692..a20fd58c 100644 --- a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/common/ComponentType.java +++ b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/common/ComponentType.java @@ -28,11 +28,12 @@ public class ComponentType { private boolean stretchable; private BomPolicy bomPolicy; private boolean autoEdit; + private boolean rotatable; public ComponentType(String name, String description, CreationMethod creationMethod, String category, String namePrefix, String author, Icon icon, Class> instanceClass, double zOrder, boolean flexibleZOrder, - boolean stretchable, BomPolicy bomPolicy, boolean autoEdit) { + boolean stretchable, BomPolicy bomPolicy, boolean autoEdit, boolean rotatable) { super(); this.name = name; this.description = description; @@ -47,6 +48,7 @@ public class ComponentType { this.stretchable = stretchable; this.bomPolicy = bomPolicy; this.autoEdit = autoEdit; + this.rotatable = rotatable; } public String getName() { @@ -100,6 +102,10 @@ public class ComponentType { public boolean isAutoEdit() { return autoEdit; } + + public boolean isRotatable() { + return rotatable; + } @Override public String toString() { diff --git a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/common/ISelectionProcessor.java b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/common/ISelectionProcessor.java index 2f0716c4..5a332b2e 100644 --- a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/common/ISelectionProcessor.java +++ b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/common/ISelectionProcessor.java @@ -34,8 +34,8 @@ public interface ISelectionProcessor { List> findComponentsAt(Point point); /** - * Expands the current selection to include surrounding components. - * Options are controlled with expansionMode flag. + * Expands the current selection to include surrounding components. Options + * are controlled with expansionMode flag. * * @param expansionMode */ @@ -44,5 +44,13 @@ public interface ISelectionProcessor { /** * 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); } diff --git a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/core/annotations/ComponentDescriptor.java b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/core/annotations/ComponentDescriptor.java index a4fa6880..c2927ec0 100644 --- a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/core/annotations/ComponentDescriptor.java +++ b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/core/annotations/ComponentDescriptor.java @@ -76,5 +76,11 @@ public @interface ComponentDescriptor { * mode. */ boolean autoEdit() default true; + + /** + * @return true if component may be rotated, false otherwise + * @return + */ + boolean rotatable() default true; } diff --git a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/ComponentProcessor.java b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/ComponentProcessor.java index 6b809bb2..28bbc0b9 100644 --- a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/ComponentProcessor.java +++ b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/ComponentProcessor.java @@ -69,6 +69,7 @@ public class ComponentProcessor { boolean stretchable; BomPolicy bomPolicy; boolean autoEdit; + boolean rotatable; if (clazz.isAnnotationPresent(ComponentDescriptor.class)) { ComponentDescriptor annotation = clazz.getAnnotation(ComponentDescriptor.class); name = annotation.name(); @@ -82,6 +83,7 @@ public class ComponentProcessor { stretchable = annotation.stretchable(); bomPolicy = annotation.bomPolicy(); autoEdit = annotation.autoEdit(); + rotatable = annotation.rotatable(); } else { name = clazz.getSimpleName(); description = ""; @@ -94,6 +96,7 @@ public class ComponentProcessor { stretchable = true; bomPolicy = BomPolicy.SHOW_ALL_NAMES; autoEdit = true; + rotatable = true; } icon = null; // Draw component icon. @@ -115,7 +118,7 @@ public class ComponentProcessor { } ComponentType componentType = new ComponentType(name, description, creationMethod, category, namePrefix, author, icon, clazz, zOrder, flexibleZOrder, stretchable, - bomPolicy, autoEdit); + bomPolicy, autoEdit, rotatable); componentTypeMap.put(clazz.getName(), componentType); return componentType; } diff --git a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/InstantiationManager.java b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/InstantiationManager.java index 8663aee8..d352dffa 100644 --- a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/InstantiationManager.java +++ b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/InstantiationManager.java @@ -42,7 +42,7 @@ public class InstantiationManager { private static final ComponentType clipboardType = new ComponentType( "Clipboard contents", "Components from the clipboard", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, - false, null, false); + false, null, false, true); public InstantiationManager() { } diff --git a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/Presenter.java b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/Presenter.java index 02f15083..6f6834d2 100644 --- a/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/Presenter.java +++ b/ diy-layout-creator --username bancika@gmail.com/diylc-core/src/org/diylc/presenter/Presenter.java @@ -6,6 +6,7 @@ import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.dnd.DnDConstants; +import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Point2D; import java.io.BufferedInputStream; @@ -40,6 +41,8 @@ import org.diylc.common.IComponentFiler; import org.diylc.common.IKeyProcessor; import org.diylc.common.IPlugIn; import org.diylc.common.IPlugInPort; +import org.diylc.common.Orientation; +import org.diylc.common.OrientationHV; import org.diylc.common.PropertyWrapper; import org.diylc.components.connectivity.SolderPad; import org.diylc.core.ExpansionMode; @@ -625,6 +628,28 @@ public class Presenter implements IPlugInPort { 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. boolean sticky = ConfigurationManager.getInstance().readBoolean( IPlugInPort.STICKY_POINTS_KEY, true); @@ -636,12 +661,6 @@ public class Presenter implements IPlugInPort { includeStuckComponents(controlPointMap); } - boolean snapToGrid = ConfigurationManager.getInstance().readBoolean( - IPlugInPort.SNAP_TO_GRID_KEY, true); - if (shiftDown) { - snapToGrid = !snapToGrid; - } - int d; if (snapToGrid) { d = (int) currentProject.getGridSpacing().convertToPixels(); @@ -1025,35 +1044,6 @@ public class Presenter implements IPlugInPort { int height = (int) currentProject.getHeight().convertToPixels(); 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, Set> 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, Set> entry = controlPointMap .entrySet().iterator().next(); @@ -1133,6 +1123,133 @@ public class Presenter implements IPlugInPort { 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> 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>) 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 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> 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 public void dragEnded(Point point) { LOG.debug(String.format("dragEnded(%s)", point));